commit 25e0b87fb3ba33a4528688ac1ab36a289d7fa44d Author: zhipeng.hu Date: Thu Apr 7 16:16:22 2022 +0800 init diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..1684a48 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,88 @@ +--- +kind: pipeline +type: docker +name: default + +volumes: +- name: gopath + host: + path: /usr/local/path/gopath + +steps: + - name: code-analysis + image: aosapps/drone-sonar-plugin + settings: + sonar_host: http://192.168.1.252:19000 + sonar_token: c38d5625bfd0c9027cbb54ddb80968d6b7601733 + when: + target: ["develop","test","pre"] + + - name: golang-build + image: golang + volumes: + - name: gopath + path: /go + commands: + - export GOPROXY=gitea.241210.com,mirrors.aliyun.com/goproxy/,gocenter.io,proxy.golang.org,goproxy.cn,gonexus.dev + - export GOPRIVATE=gitea.241210.com + - cd web/ +# - export GOPROXY=https://gocenter.io +# - export GOPROXY=https://proxy.golang.org +# - export GOPROXY=https://goproxy.cn +# - export GOPROXY=https://mirrors.aliyun.com/goproxy/ +# - export GOPROXY=https://gonexus.dev + - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o gy-uuos-web + when: + target: ["develop","test","pre"] + + - name: docker-push + image: plugins/docker + settings: + username: docker-push + password: WeWlh6hGYCtxO4r + repo: repository.241210.com/repository/gyys/drone/gy-uuos + dockerfile: web/Dockerfile + registry: https://repository.241210.com + tags: ${DRONE_BUILD_NUMBER} + when: + target: ["develop","test","pre"] + + - name: deployment-replace + image: repository.241210.com/repository/base/kubectl:4 + commands: + - cd web/ + - sed -i 's!IMAGE_PATH:IMAGE_TAG!'repository.241210.com/repository/gyys/drone/gy-uuos:${DRONE_BUILD_NUMBER}'!g' deployment.yaml + when: + target: ["develop","test","pre"] + + - name: deploy + image: repository.241210.com/repository/base/kubectl:4 + commands: + - cd web/ + - kubectl --kubeconfig /kube/${CI_BUILD_TARGET:-develop} apply -f deployment.yaml + when: + target: ["develop","test","pre"] + ## 使用参数推送稳定镜像 + - name: deployment-replace-prod + image: repository.241210.com/repository/base/kubectl:4 + commands: + - cd web/ + - sed -i 's!IMAGE_PATH:IMAGE_TAG!'${IMAGE}'!g' deployment.yaml + when: + target: ["exp","prod"] + + - name: deploy-prod + image: repository.241210.com/repository/base/kubectl:4 + commands: + - cd web/ + - kubectl --kubeconfig /kube/${CI_BUILD_TARGET} apply -f deployment.yaml + when: + target: ["exp","prod"] +# - name: ding +# image: lddsb/drone-dingtalk-message +# settings: +# token: f09f64151159f9243e771503ae4a5ef5af3e079f6828b464c17ea2bb291523c2 +# type: markdown +# sha_link: true +# when: +# status: [success, failure] diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..081b737 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 数据源本地存储已忽略文件 +/dataSources/ +/dataSources.local.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..48391bc --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/stu_uuos.iml b/.idea/stu_uuos.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/.idea/stu_uuos.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/config/api_addr.go b/config/api_addr.go new file mode 100644 index 0000000..9c2f5c8 --- /dev/null +++ b/config/api_addr.go @@ -0,0 +1,5 @@ +package config + +type ApiAddress struct { + WarningQuery string `yaml:"warningQuery"` +} diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..0d961ed --- /dev/null +++ b/config/config.go @@ -0,0 +1,116 @@ +package config + +import ( + "gitea.baoapi.com/root/stu_uuos/util" + "github.com/micro/go-micro/v2/config" +) + +var conf *Config + +type Config struct { + Version string + ServiceName string + Address int + SinglePoint bool + Domain string + DB *Database // postgress -> gy_uums + DB2 *Database // postgress -> gy_order + DB3 *Database // postgress -> gy_cloud + Log *Log + LogrusHttp *LogrusHttp + ApiAddr *ApiAddress `yaml:"apiAddr"` + Redis *Redis + Nats *Nats + JWT *Jwt + Minio *Minio + Micro *Micro + Gather *Gather + Gyys *Gyys + Mail *Mail + CompanyWxSync *CompanyWxSync +} + +type Gather struct { + Domain string + Userid string + Orgid string +} + +type Gyys struct { + Domain string +} + +type Nats struct { + Addr string + Subject map[string]string +} + +type Jwt struct { + SigningKey string +} + +type Micro struct { + Registry Registry + Service Service +} + +type Registry struct { + Name string + Addrs string +} + +type Service struct { + Cipher string +} + +//CompanyWxSync 运营企业微信同步 +type CompanyWxSync struct { + Id string //商户id + PartyId string //目标部门id +} + +func GetConfig() *Config { + return conf +} + +func Init() { + if conf != nil { + return + } + f, err := util.FindFile("conf.yaml") + if err != nil { + panic(err) + } + util.PrintInfo(f) + if err := config.LoadFile(f); err != nil { + panic(err) + } + conf = &Config{} + if err := config.Scan(conf); err != nil { + panic(err) + } + + util.PrintJSON(conf) + go watch(f) +} + +func watch(f string) { + w, err := config.Watch(f) + if err != nil { + util.PrintErr(err) + return + } + + v, err := w.Next() + if err != nil { + util.PrintErr(err) + return + } + + if err := v.Scan(conf); err != nil { + util.PrintErr(err) + } + + util.PrintInfo("the config file 'conf.yaml' has been changed:") + util.PrintJSON(conf) +} diff --git a/config/db.go b/config/db.go new file mode 100644 index 0000000..58ac185 --- /dev/null +++ b/config/db.go @@ -0,0 +1,9 @@ +package config + +type Database struct { + Host string + Port int + User string + Password string + Dbname string +} diff --git a/config/log.go b/config/log.go new file mode 100644 index 0000000..70bc52a --- /dev/null +++ b/config/log.go @@ -0,0 +1,19 @@ +package config + +type Log struct { + Out string + Formatter string + JsonPrettyPrint bool + OutColor bool + MinLevel string + ReportCaller bool + MaxFileSize uint64 + WithLinkFile bool + FilePath string + FileName string + RotationTime string + MaxAge string + MaxRemainCount uint + TimestampFormat string + DisableSorting bool +} diff --git a/config/logrusHttp.go b/config/logrusHttp.go new file mode 100644 index 0000000..9d95e56 --- /dev/null +++ b/config/logrusHttp.go @@ -0,0 +1,6 @@ +package config + +type LogrusHttp struct { + Url string + LogLvl string +} diff --git a/config/mail.go b/config/mail.go new file mode 100644 index 0000000..e4fc2c6 --- /dev/null +++ b/config/mail.go @@ -0,0 +1,9 @@ +package config + +type Mail struct { + Username string `yaml:"username"` + Password string `yaml:"password"` + Host string `yaml:"host"` + Port int `yaml:"port"` + UsingTls bool `yaml:"usingTls"` +} diff --git a/config/minio.go b/config/minio.go new file mode 100644 index 0000000..2719d66 --- /dev/null +++ b/config/minio.go @@ -0,0 +1,9 @@ +package config + +type Minio struct { + Addr string + AccessKeyID string + SecretAccessKey string + Ssl bool + DefaultBucketName string +} diff --git a/config/org.go b/config/org.go new file mode 100644 index 0000000..2094f85 --- /dev/null +++ b/config/org.go @@ -0,0 +1,6 @@ +package config + +var ( + //移动组织配置 商户层级最多5级,加上门诊、调剂中心 最多6级 + MaxMainlevel = 5 +) diff --git a/config/redis.go b/config/redis.go new file mode 100644 index 0000000..6b3c1ce --- /dev/null +++ b/config/redis.go @@ -0,0 +1,8 @@ +package config + +type Redis struct { + IsUp bool + Addr string + OrderNumKey string + OrderNumDefault string +} diff --git a/config/sms.go b/config/sms.go new file mode 100644 index 0000000..48209bd --- /dev/null +++ b/config/sms.go @@ -0,0 +1,10 @@ +package config + +const ( + RegionId = "cn-hangzhou" + AccessKeyId = "LTAI4FhgikZtv9aA2LjMvX7a" + AccessSecret = "REB3Rd8CVJL5aRQNjcKbc82vJMX1IB" + SignName = "归源易生" + TemplateCode = "SMS_193015765" + CodeLength = 6 +) diff --git a/constant/errorCode.go b/constant/errorCode.go new file mode 100644 index 0000000..657d100 --- /dev/null +++ b/constant/errorCode.go @@ -0,0 +1,44 @@ +package constant + +type ErrorCode int + +type ErrCodeInfo struct { + Code ErrorCode `json:"code"` + Msg string `json:"msg"` +} + +const ( + Success ErrorCode = 0 //成功 [SUCCESS] + IllegalAccess ErrorCode = 600000 //未登陆或非法访问 + AuthorizationExpired ErrorCode = 600001 //授权已经过期 + ErrorInfo ErrorCode = 600002 //错误信息 + ParamInvalid ErrorCode = 601000 //无效的请求参数 [Invalid request parameters] + ServerError ErrorCode = 601001 //服务器内部错误 [Server internal error] + NotFound ErrorCode = 601002 //not found + RecordNotFound ErrorCode = 601003 //记录没有发现 + ErrorUserNameOrPassword ErrorCode = 601004 //用户名或密码错误 + SaveFailed ErrorCode = 601005 //保存失败 + EncryptionDataFailed ErrorCode = 601006 //加密用户数据失败 + CheckSuccess ErrorCode = 601007 //检测配置成功 + CheckFail ErrorCode = 601008 //检测配置成功 + FireReqLimit ErrorCode = 601009 //请求达到限制阈值 + RepeatName ErrorCode = 604003 //该名称已存在 +) + +var ErrCode = map[ErrorCode]ErrCodeInfo{ + Success: ErrCodeInfo{Success, "SUCCESS"}, + IllegalAccess: ErrCodeInfo{IllegalAccess, "No login or illegal access"}, + AuthorizationExpired: ErrCodeInfo{AuthorizationExpired, "authorization expired"}, + ErrorInfo: ErrCodeInfo{ErrorInfo, "error message"}, + ParamInvalid: ErrCodeInfo{ParamInvalid, "Invalid request parameters"}, + ServerError: ErrCodeInfo{ServerError, "Server internal error"}, + NotFound: ErrCodeInfo{NotFound, "not found"}, + RecordNotFound: ErrCodeInfo{RecordNotFound, "record not found"}, + ErrorUserNameOrPassword: ErrCodeInfo{RecordNotFound, "error username or password"}, + SaveFailed: ErrCodeInfo{SaveFailed, "save failed"}, + EncryptionDataFailed: ErrCodeInfo{EncryptionDataFailed, "Encryption Data Failed"}, + CheckSuccess: ErrCodeInfo{EncryptionDataFailed, "check success"}, + CheckFail: ErrCodeInfo{EncryptionDataFailed, "check fail"}, + FireReqLimit: ErrCodeInfo{Code: FireReqLimit, Msg: "request times limit"}, + RepeatName: ErrCodeInfo{Code: RepeatName, Msg: "request param repeat name"}, +} diff --git a/constant/time.go b/constant/time.go new file mode 100644 index 0000000..d66b64f --- /dev/null +++ b/constant/time.go @@ -0,0 +1,14 @@ +package constant + +import "time" + +const Loc = "Asia/Shanghai" + +func GetLocalZone() (location *time.Location) { + var err error + location, err = time.LoadLocation(Loc) + if err != nil { + panic(err) + } + return +} diff --git a/entity/fm_org.go b/entity/fm_org.go new file mode 100644 index 0000000..a864bcb --- /dev/null +++ b/entity/fm_org.go @@ -0,0 +1,56 @@ +package entity + +import ( + "gitea.baoapi.com/root/stu_uuos/util" + "github.com/jinzhu/gorm" + "time" +) + +// FmOrg 机构-管理设备 +type FmOrg struct { + Id string `json:"id" gorm:"column:id;type:uuid;primaryKey"` //组织id + Name string `json:"name" gorm:"column:name;type:varchar(200);not null"` //名称 + Alias string `json:"alias" gorm:"column:alias;type:varchar(200)"` //机构简称 + Contacts string `json:"contacts" gorm:"column:contacts;type:varchar(100)"` //设备负责联系人 + Mobile string `json:"mobile" gorm:"column:mobile;type:varchar(100)"` //手机号 + Summary string `json:"summary" gorm:"column:summary;type:varchar(200)"` //简介 + Type int `json:"type" gorm:"column:type;type:int;default:1"` //类型 1:商户 3 门诊 4 调剂中心 + Pid string `json:"pid" gorm:"column:pid;type:uuid"` //上级id 一级 0 + Level int `json:"level" gorm:"column:level;type:int"` //(商户 1、2、3 、4;其他类型填0或空) + Province string `json:"province" gorm:"column:province;type:varchar(255)"` //省 + City string `json:"city" gorm:"column:city;type:varchar(255)"` //市 + District string `json:"district" gorm:"column:district;type:varchar(255)"` //区/县 + Addr string `json:"addr" gorm:"column:addr;type:varchar(255)"` //详细地址 + OrgRootId string `json:"org_root_id" gorm:"column:org_root_id;type:uuid"` //根id + CreatedAt time.Time `json:"created_at" form:"created_at"` + UpdatedAt time.Time `json:"updated_at" form:"updated_at"` + DeletedAt *time.Time `json:"deleted_at" form:"deleted_at" sql:"index"` +} + +type FmOrgReq struct { + Id string `json:"id"` //组织id + Name string `json:"name" binding:"required"` //名称 + Alias string `json:"alias"` //机构简称 + Contacts string `json:"contacts"` //设备负责联系人 + Mobile string `json:"mobile"` //手机号 + Summary string `json:"summary" ` //简介 + Type int `json:"type" binding:"required"` //类型 1:商户 3 门诊 4 调剂中心 + Pid string `json:"pid" binding:"required"` //上级id 一级 0 + Level int `json:"level"` //(商户 1、2、3 、4;其他类型填0或空) + Province string `json:"province"` //省 + City string `json:"city"` //市 + District string `json:"district"` //区/县 + Addr string `json:"addr"` //详细地址 + OrgRootId string `json:"org_root_id"` //根id + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + DeletedAt *time.Time `json:"deleted_at"` +} + +func (deo *FmOrg) BeforeCreate(scope *gorm.Scope) error { + deo.Id = util.GUUID.NewV1().String() + if deo.Pid == util.EmptyUUID { + deo.OrgRootId = deo.Id + } + return nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2e2194e --- /dev/null +++ b/go.mod @@ -0,0 +1,111 @@ +module gitea.baoapi.com/root/stu_uuos + +go 1.17 + +require ( + github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 + github.com/bwmarrin/snowflake v0.3.0 + github.com/gin-gonic/gin v1.7.7 + github.com/go-redis/redis/v8 v8.11.5 + github.com/golang/protobuf v1.5.2 + github.com/jinzhu/gorm v1.9.16 + github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible + github.com/micro/go-micro/v2 v2.9.1 + github.com/micro/go-plugins/logger/logrus/v2 v2.9.1 + github.com/micro/go-plugins/registry/consul/v2 v2.9.1 + github.com/micro/go-plugins/registry/etcdv3/v2 v2.9.1 + github.com/micro/go-plugins/registry/kubernetes/v2 v2.9.1 + github.com/micro/go-plugins/registry/nats/v2 v2.9.1 + github.com/micro/go-plugins/wrapper/trace/opentracing/v2 v2.9.1 + github.com/mozillazg/go-pinyin v0.19.0 + github.com/nats-io/nats.go v1.13.0 + github.com/opentracing/opentracing-go v1.2.0 + github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 + github.com/satori/go.uuid v1.2.0 + github.com/shopspring/decimal v1.3.1 + github.com/sirupsen/logrus v1.8.1 + github.com/uber/jaeger-client-go v2.30.0+incompatible + github.com/uber/jaeger-lib v2.4.1+incompatible + golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 + golang.org/x/text v0.3.7 + gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df +) + +require ( + github.com/BurntSushi/toml v0.3.1 // indirect + github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect + github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect + github.com/bitly/go-simplejson v0.5.0 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/coreos/etcd v3.3.18+incompatible // indirect + github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect + github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect + github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/emirpasic/gods v1.12.0 // indirect + github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-git/gcfg v1.5.0 // indirect + github.com/go-git/go-billy/v5 v5.0.0 // indirect + github.com/go-git/go-git/v5 v5.1.0 // indirect + github.com/go-playground/locales v0.13.0 // indirect + github.com/go-playground/universal-translator v0.17.0 // indirect + github.com/go-playground/validator/v10 v10.4.1 // indirect + github.com/gogo/protobuf v1.2.1 // indirect + github.com/google/uuid v1.1.1 // indirect + github.com/hashicorp/consul/api v1.3.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.1 // indirect + github.com/hashicorp/go-immutable-radix v1.0.0 // indirect + github.com/hashicorp/go-rootcerts v1.0.0 // indirect + github.com/hashicorp/golang-lru v0.5.3 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/hashicorp/serf v0.8.2 // indirect + github.com/hpcloud/tail v1.0.0 // indirect + github.com/imdario/mergo v0.3.9 // indirect + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/json-iterator/go v1.1.9 // indirect + github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect + github.com/leodido/go-urn v1.2.0 // indirect + github.com/lestrrat-go/strftime v1.0.5 // indirect + github.com/lib/pq v1.3.0 // indirect + github.com/mattn/go-isatty v0.0.12 // indirect + github.com/micro/cli/v2 v2.1.2 // indirect + github.com/miekg/dns v1.1.27 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/hashstructure v1.0.0 // indirect + github.com/mitchellh/mapstructure v1.1.2 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/nats-io/nkeys v0.3.0 // indirect + github.com/nats-io/nuid v1.0.1 // indirect + github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect + github.com/patrickmn/go-cache v2.1.0+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/russross/blackfriday/v2 v2.0.1 // indirect + github.com/sergi/go-diff v1.1.0 // indirect + github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect + github.com/stretchr/testify v1.7.0 // indirect + github.com/ugorji/go/codec v1.1.7 // indirect + github.com/xanzy/ssh-agent v0.2.1 // indirect + go.uber.org/atomic v1.5.0 // indirect + go.uber.org/multierr v1.3.0 // indirect + go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee // indirect + go.uber.org/zap v1.13.0 // indirect + golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f // indirect + golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect + golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect + golang.org/x/tools v0.0.0-20191216173652-a0e659d51361 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1 // indirect + google.golang.org/grpc v1.26.0 // indirect + google.golang.org/protobuf v1.26.0 // indirect + gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect + gopkg.in/fsnotify.v1 v1.4.7 // indirect + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect + gopkg.in/warnings.v0 v0.1.2 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + honnef.co/go/tools v0.0.1-2019.2.3 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..d356886 --- /dev/null +++ b/go.sum @@ -0,0 +1,833 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v32.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest/autorest v0.1.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg= +github.com/Azure/go-autorest/autorest v0.5.0/go.mod h1:9HLKlQjVBH6U3oDfsXOeVc56THsLPw1L03yban4xThw= +github.com/Azure/go-autorest/autorest/adal v0.1.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E= +github.com/Azure/go-autorest/autorest/adal v0.2.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E= +github.com/Azure/go-autorest/autorest/azure/auth v0.1.0/go.mod h1:Gf7/i2FUpyb/sGBLIFxTBzrNzBo7aPXXE3ZVeDRwdpM= +github.com/Azure/go-autorest/autorest/azure/cli v0.1.0/go.mod h1:Dk8CUAt/b/PzkfeRsWzVG9Yj3ps8mS8ECztu43rdU8U= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/tracing v0.1.0/go.mod h1:ROEEAFwXycQw7Sn3DXNtEedEvdeRAgDr0izn4z5Ij88= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= +github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/hcsshim v0.8.7-0.20191101173118-65519b62243c/go.mod h1:7xhjOwRV2+0HXGmM0jxaEu+ZiXJFoVZOTfL/dmqbrD8= +github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks= +github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 h1:rFw4nCn9iMW+Vajsk51NtYIcwSTkXr+JGrMd36kTDJw= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.0/go.mod h1:zpDJeKyp9ScW4NNrbdr+Eyxvry3ilGPewKoXw3XGN1k= +github.com/alangpierce/go-forceexport v0.0.0-20160317203124-8f1d6941cd75/go.mod h1:uAXEEpARkRhCZfEvy/y0Jcc888f9tHCc1W7/UeEtreE= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190808125512-07798873deee/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ= +github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= +github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/aws/aws-sdk-go v1.23.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/bwmarrin/discordgo v0.20.2/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q= +github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= +github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= +github.com/caddyserver/certmagic v0.10.6/go.mod h1:Y8jcUBctgk/IhpAzlHKfimZNyXCkfGgRTC0orl8gROQ= +github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= +github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/cloudflare-go v0.10.2/go.mod h1:qhVI5MKwBGhdNU89ZRz2plgYutcJ5PCekLxXn56w6SY= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/coreos/bbolt v1.3.3 h1:n6AiVyVRKQFNb6mJlwESEvvLoDyiTzXX7ORAUlkeBdY= +github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.18+incompatible h1:Zz1aXgDrFFi1nadh58tA9ktt06cmPTwNNP3dXwIq1lE= +github.com/coreos/etcd v3.3.18+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +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 h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpu/goacmedns v0.0.1/go.mod h1:sesf/pNnCYwUevQEQfEwY0Y3DydlQWSGZbaMElOWxok= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.9/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/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= +github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +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-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/dnsimple/dnsimple-go v0.30.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v1.4.2-0.20191101170500-ac7306503d23/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/ef-ds/deque v1.0.4-0.20190904040645-54cb57c252a1/go.mod h1:HvODWzv6Y6kBf3Ah2WzN1bHjDUezGLaAhwuWVwfpEJs= +github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= +github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= +github.com/evanphx/json-patch/v5 v5.0.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/exoscale/egoscale v0.18.1/go.mod h1:Z7OOdzzTOz1Q1PjQXumlz9Wn/CddH0zSYdCF3rnBKXE= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c/go.mod h1:pFdJbAhRf7rh6YYMUdIQGyzne6zYL1tCUW8QV2B3UfY= +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/fsouza/go-dockerclient v1.6.0/go.mod h1:YWwtNPuL4XTX1SKJQk86cWPmmqwx+4np9qfPbb+znGc= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= +github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= +github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-acme/lego/v3 v3.4.0/go.mod h1:xYbLDuxq3Hy4bMUT1t9JIuz6GWIWb3m5X+TeTHYaT7M= +github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM= +github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git-fixtures/v4 v4.0.1 h1:q+IFMfLx200Q3scvt2hN79JsEzy4AmBTp/pqnefH+Bc= +github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= +github.com/go-git/go-git/v5 v5.1.0 h1:HxJn9g/E7eYvKW3Fm7Jt4ee8LXfPOm/H1cdDu8vEssk= +github.com/go-git/go-git/v5 v5.1.0/go.mod h1:ZKfuPUoY1ZqIG4QG9BDBh3G4gLM5zvPuSJAozQrZuyM= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-ini/ini v1.44.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-log/log v0.2.0 h1:z8i91GBudxD5L3RmF0KVpetCbcGWAV7q1Tw1eRwQM9Q= +github.com/go-log/log v0.2.0/go.mod h1:xzCnwajcues/6w7lne3yK2QU7DBPW7kqbgPGG5AF65U= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.3/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 h1:THDBEeQ9xZ8JEaCLyLQqXMMdRqNr0QAUJTIkQAUtFjg= +github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5 h1:UImYN5qQ8tuGpGE16ZmjvcTtTw24zw1QAp/SlnNrZhI= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= +github.com/hashicorp/consul/api v1.3.0 h1:HXNYlRkkM/t+Y/Yhxtwcy02dlYwIaoxzvxPnS+cqy78= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/sdk v0.3.0 h1:UOxjlb4xVNF93jak1mzzoBatyFju9nrkxpVwIp/QqxQ= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= +github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0 h1:Rqb66Oo1X/eSV1x66xbDccZjhJigjg0+e82kpwzSwCI= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +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/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3 h1:EmmoJme1matNzb+hMpDuR/0sbJSUisxyqBGG676r31M= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2 h1:YZ7UKsJv+hKjqGVUUbtE3HNj79Eln2oQ75tniF6iPt0= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4= +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/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o= +github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= +github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/kolo/xmlrpc v0.0.0-20190717152603-07c4ee3fd181/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA= +github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= +github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4= +github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA= +github.com/lestrrat-go/strftime v1.0.5 h1:A7H3tT8DhTz8u65w+JRpiBxM4dINQhUXAZnhBa2xeOE= +github.com/lestrrat-go/strftime v1.0.5/go.mod h1:E1nN3pCbtMSu1yjSVeyuRFVm/U0xoR76fd03sz+Qz4g= +github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= +github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/linode/linodego v0.10.0/go.mod h1:cziNP7pbvE3mXIPneHj0oRY8L1WtGEIKlZ8LANE4eXA= +github.com/liquidweb/liquidweb-go v1.6.0/go.mod h1:UDcVnAMDkZxpw4Y7NOHkqoeiGacVLEIG/i5J9cyixzQ= +github.com/lucas-clemente/quic-go v0.14.1/go.mod h1:Vn3/Fb0/77b02SGhQk36KzOUmXgVpFfizUfW5WMaqyU= +github.com/marten-seemann/chacha20 v0.2.0/go.mod h1:HSdjFau7GzYRj+ahFNwsO3ouVJr1HFkWoEwNDb4TMtE= +github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI= +github.com/marten-seemann/qtls v0.4.1/go.mod h1:pxVXcHHw1pNIt8Qo0pwSYQEoZ8yYOOPXTCZLQQunvRc= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA= +github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= +github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/micro/cli/v2 v2.1.2 h1:43J1lChg/rZCC1rvdqZNFSQDrGT7qfMrtp6/ztpIkEM= +github.com/micro/cli/v2 v2.1.2/go.mod h1:EguNh6DAoWKm9nmk+k/Rg0H3lQnDxqzu5x5srOtGtYg= +github.com/micro/go-micro/v2 v2.9.1 h1:+S9koIrNWARjpP6k2TZ7kt0uC9zUJtNXzIdZTZRms7Q= +github.com/micro/go-micro/v2 v2.9.1/go.mod h1:x55ZM3Puy0FyvvkR3e0ha0xsE9DFwfPSUMWAIbFY0SY= +github.com/micro/go-plugins/logger/logrus/v2 v2.9.1 h1:miGge8+erAzgy8yvJWey/5BQ/nxXYMhBMT0OHwhDdqw= +github.com/micro/go-plugins/logger/logrus/v2 v2.9.1/go.mod h1:tZ9rAgyKQnl0CAneVRzE2vjd4hOaP6sNTSWOBoMoGRo= +github.com/micro/go-plugins/registry/consul/v2 v2.9.1 h1:3IRsR8B9rEsjY4UXvhlkItEi0F/48LBOGdF3J8qLPMY= +github.com/micro/go-plugins/registry/consul/v2 v2.9.1/go.mod h1:k+12oSCZwN0lYcWeiJ2Y12FWLP02fwJEJk6+EV5n6Io= +github.com/micro/go-plugins/registry/etcdv3/v2 v2.9.1 h1:5o2rfcmObTiu1ixEpdIw7Wn2qObvBO8MU9YpSY3dJR0= +github.com/micro/go-plugins/registry/etcdv3/v2 v2.9.1/go.mod h1:wqj9V63R/0CkWgzzKMOhfoiKtRqlUkf+cwuTjY3x9HY= +github.com/micro/go-plugins/registry/kubernetes/v2 v2.9.1 h1:lHC7DaAOL0OA8nLKmb3DcRSYr8HpgUOW+Lpvhp+iZI4= +github.com/micro/go-plugins/registry/kubernetes/v2 v2.9.1/go.mod h1:VmKy2vY/1g2j9G2bLKNv+Y3qFhkd+TEhnWtpTpHlnzU= +github.com/micro/go-plugins/registry/nats/v2 v2.9.1 h1:EiLTVJQyAw6LC/+mpqc/H1Ti8lvnUW7qUgVjBzEG2qg= +github.com/micro/go-plugins/registry/nats/v2 v2.9.1/go.mod h1:jXwlUYN8LFmiD3QBVi/zLJsssCgcS2ZC66kfPdMUBKE= +github.com/micro/go-plugins/wrapper/trace/opentracing/v2 v2.9.1 h1:5wnqJv5RLyVQArcZI6qhPJt7tLi6W8cnvNcC0dfy8x0= +github.com/micro/go-plugins/wrapper/trace/opentracing/v2 v2.9.1/go.mod h1:JyDIUQgJ0noSBbxW2cuNWVAxmKXF5VeTbJ8JY1S1160= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.27 h1:aEH/kqUzUxGJ/UHcEKdJY+ugH6WEzsEBBSPa8zuy1aM= +github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed/go.mod h1:3rdaFaCv4AyBgu5ALFM0+tSuHrBh6v692nyQe3ikrq0= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/hashstructure v1.0.0 h1:ZkRJX1CyOoTkar7p/mLS5TZU4nJ1Rn/F8u9dGS02Q3Y= +github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mozillazg/go-pinyin v0.19.0 h1:p+J8/kjJ558KPvVGYLvqBhxf8jbZA2exSLCs2uUVN8c= +github.com/mozillazg/go-pinyin v0.19.0/go.mod h1:iR4EnMMRXkfpFVV5FMi4FNB6wGq9NV6uDWbUuPhP4Yc= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8= +github.com/nats-io/jwt v0.3.2 h1:+RB5hMpXUUA2dfxuhBTEkMOrYmM+gKIZYS1KjSostMI= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.6 h1:qAaHZaS8pRRNQLFaiBA1rq5WynyEGp9DFgmMfoaiXGY= +github.com/nats-io/nats-server/v2 v2.1.6/go.mod h1:BL1NOtaBQ5/y97djERRVWNouMW7GT3gxnmbE/eC8u8A= +github.com/nats-io/nats.go v1.9.2/go.mod h1:AjGArbfyR50+afOUotNX2Xs5SYHf+CoOa5HH1eEl2HE= +github.com/nats-io/nats.go v1.13.0 h1:LvYqRB5epIzZWQp6lmeltOOZNLqCvm4b+qfvzZO03HE= +github.com/nats-io/nats.go v1.13.0/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.4/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s= +github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8= +github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nlopes/slack v0.6.1-0.20191106133607-d06c2a2b3249/go.mod h1:JzQ9m3PMAqcpeCam7UaHSuBuupz7CmpjehYMayT6YOk= +github.com/nrdcg/auroradns v1.0.0/go.mod h1:6JPXKzIRzZzMqtTDgueIhTi6rFf1QvYE/HzqidhOhjw= +github.com/nrdcg/dnspod-go v0.4.0/go.mod h1:vZSoFSFeQVm2gWLMkyX61LZ8HI3BaqtHZWgPTGKr6KQ= +github.com/nrdcg/goinwx v0.6.1/go.mod h1:XPiut7enlbEdntAqalBIqcYcTEVhpv/dKWgDCX2SwKQ= +github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/oracle/oci-go-sdk v7.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= +github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ= +github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw= +github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo= +github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sacloud/libsacloud v1.26.1/go.mod h1:79ZwATmHLIFZIMd7sxA3LwzVy/B77uj3LDoToVTxDoQ= +github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= +github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= +github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7/go.mod h1:imsgLplxEC/etjIhdr3dNzV3JeT27LbVu5pYWm0JCBY= +github.com/tmc/grpc-websocket-proxy v0.0.0-20200122045848-3419fae592fc h1:yUaosFVTJwnltaHbSNC3i82I92quFs+OFPRl8kNMVwo= +github.com/tmc/grpc-websocket-proxy v0.0.0-20200122045848-3419fae592fc/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/transip/gotransip v0.0.0-20190812104329-6d8d9179b66f/go.mod h1:i0f4R4o2HM0m3DZYQWsj6/MEowD57VzoH0v3d7igeFY= +github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= +github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= +github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= +github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vultr/govultr v0.1.4/go.mod h1:9H008Uxr/C4vFNGLqKx232C206GL0PBHzOP0809bGNA= +github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= +github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= +github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNyAMPVWllTNOf/qKDze4p9o= +golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180611182652-db08ff08e862/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361 h1:RIIXAeV6GvDBuADKumTODatUqANFZ+5BPMnzsy4hulY= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1 h1:aQktFqmDE2yjveXJlVIfslDFmFnUXSqG0i6KRcJAeMc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= +gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= +gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= +gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ns1/ns1-go.v2 v2.0.0-20190730140822-b51389932cbc/go.mod h1:VV+3haRsgDiVLxyifmMBrBIuCWFBPYKbRssXB9z67Hw= +gopkg.in/resty.v1 v1.9.1/go.mod h1:vo52Hzryw9PnPHcJfPsBiFW62XhNx5OczbV9y+IMpgc= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/telegram-bot-api.v4 v4.6.4/go.mod h1:5DpGO5dbumb40px+dXcwCpcjmeHNYLpk0bp3XRNvWDM= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/lib/db/db.go b/lib/db/db.go new file mode 100644 index 0000000..1f8d925 --- /dev/null +++ b/lib/db/db.go @@ -0,0 +1,58 @@ +package db + +import ( + "gitea.baoapi.com/root/stu_uuos/logger" + "gitea.baoapi.com/root/stu_uuos/util" + "github.com/jinzhu/gorm" + log "github.com/micro/go-micro/v2/logger" +) + +var db *gorm.DB +var db2 *gorm.DB +var db3 *gorm.DB + +func Init() { + openPostgres() + db = postgresDB + + openPostgres2() + db2 = postgresDB2 + + openPostgres3() + db3 = postgresDB3 +} + +func DB() *gorm.DB { + return db +} + +func DB2() *gorm.DB { + return db2 +} + +func DB3() *gorm.DB { + return db3 +} + +func Close() error { + if err := postgresDB.Close(); err != nil { + log.Errorf("%v close error", "db") + } + + if err := postgresDB2.Close(); err != nil { + log.Errorf("%v close error", "db2") + } + if err := postgresDB3.Close(); err != nil { + log.Errorf("%v close error", "db3") + } + util.PrintInfo("close database connections") + return nil +} + +func dbCfg(db *gorm.DB) { + db.SingularTable(true) + db.LogMode(true) + db.SetLogger(logger.GetLogger()) + db.DB().SetMaxOpenConns(50) + db.DB().SetMaxIdleConns(20) +} diff --git a/lib/db/init_table.go b/lib/db/init_table.go new file mode 100644 index 0000000..0b377b9 --- /dev/null +++ b/lib/db/init_table.go @@ -0,0 +1,14 @@ +package db + +import ( + "gitea.baoapi.com/root/stu_uuos/entity" + "gitea.baoapi.com/root/stu_uuos/util" +) + +//注册数据库表 +func InitTable() { + db.AutoMigrate( + &entity.FmOrg{}, + ) + util.PrintInfo("register table success") +} diff --git a/lib/db/postgres.go b/lib/db/postgres.go new file mode 100644 index 0000000..868561e --- /dev/null +++ b/lib/db/postgres.go @@ -0,0 +1,92 @@ +package db + +import ( + "fmt" + + "gitea.baoapi.com/root/stu_uuos/config" + "gitea.baoapi.com/root/stu_uuos/logger" + "gitea.baoapi.com/root/stu_uuos/util" + "github.com/jinzhu/gorm" + _ "github.com/jinzhu/gorm/dialects/postgres" + log "github.com/micro/go-micro/v2/logger" +) + +var postgresDB *gorm.DB +var postgresDB2 *gorm.DB +var postgresDB3 *gorm.DB + +func openPostgres() { + dataSourceName := fmt.Sprintf( + "host=%s port=%d user=%s dbname=%s password=%s sslmode=disable", + config.GetConfig().DB.Host, + config.GetConfig().DB.Port, + config.GetConfig().DB.User, + config.GetConfig().DB.Dbname, + config.GetConfig().DB.Password, + ) + + db, err := gorm.Open("postgres", dataSourceName) + if err != nil { + log.Fatal("failed to connect database: ", err) + } + + dbCfg(db) + postgresDB = db + + util.PrintInfo(fmt.Sprintf("connection to postgres database: %s", dataSourceName)) +} + +func openPostgres2() { + dataSourceName := fmt.Sprintf( + "host=%s port=%d user=%s dbname=%s password=%s sslmode=disable", + config.GetConfig().DB2.Host, + config.GetConfig().DB2.Port, + config.GetConfig().DB2.User, + config.GetConfig().DB2.Dbname, + config.GetConfig().DB2.Password, + ) + + db, err := gorm.Open("postgres", dataSourceName) + if err != nil { + log.Fatal("failed to connect database: ", err) + } + + //dbCfg(db) + db.LogMode(true) + db.SetLogger(logger.GetLogger()) + db.DB().SetMaxOpenConns(20) + db.DB().SetMaxIdleConns(10) + db.SingularTable(true) + postgresDB2 = db + + util.PrintInfo(fmt.Sprintf("connection to postgres database: %s", dataSourceName)) +} + +func openPostgres3() { + dataSourceName := fmt.Sprintf( + "host=%s port=%d user=%s dbname=%s password=%s sslmode=disable", + config.GetConfig().DB3.Host, + config.GetConfig().DB3.Port, + config.GetConfig().DB3.User, + config.GetConfig().DB3.Dbname, + config.GetConfig().DB3.Password, + ) + + db, err := gorm.Open("postgres", dataSourceName) + if err != nil { + log.Fatal("failed to connect database: ", err) + } + + //dbCfg(db) + db.LogMode(true) + db.SetLogger(logger.GetLogger()) + db.DB().SetMaxOpenConns(20) + db.DB().SetMaxIdleConns(10) + postgresDB3 = db + + util.PrintInfo(fmt.Sprintf("connection to postgres database: %s", dataSourceName)) +} + +func PostgresDB() *gorm.DB { + return postgresDB +} diff --git a/lib/logruspan/init.go b/lib/logruspan/init.go new file mode 100644 index 0000000..f6a07bc --- /dev/null +++ b/lib/logruspan/init.go @@ -0,0 +1,101 @@ +package logruspan + +import ( + "bytes" + "encoding/json" + "fmt" + "gitea.baoapi.com/root/stu_uuos/config" + "github.com/sirupsen/logrus" + "log" + "net/http" + "time" +) + +//setupLogrus 初始化logrus 同时把logrus的logger var 引用到这个common.Logger +func setupLogrus(cc config.LogrusHttp) error { + + logLvl, err := logrus.ParseLevel(cc.LogLvl) + if err != nil { + return err + } + Lobj.SetLevel(logLvl) + Lobj.SetReportCaller(true) + Lobj.SetFormatter(&logrus.JSONFormatter{}) + + esh := newHttpHook(cc) + Lobj.AddHook(esh) + return nil +} + +var Lobj *logrus.Logger + +func LogInitHttp() { + cc := *config.GetConfig().LogrusHttp + Lobj = logrus.New() + err := setupLogrus(cc) + if err != nil { + log.Fatal(err) + } +} + +//esHook 自定义的ES hook +type esHook struct { + client *http.Client + Url string + Cont string +} + +//newEsHook 初始化 +func newHttpHook(cc config.LogrusHttp) *esHook { + //application/json;charset:utf-8; + es := &http.Client{} + return &esHook{ + client: es, + Url: cc.Url + "/logger", + Cont: "application/json;charset:utf-8;", + } +} + +//Fire logrus hook interface 方法 +func (hook *esHook) Fire(entry *logrus.Entry) error { + go hook.sendHttp(entry) + return nil +} + +//Levels logrus hook interface 方法 +func (hook *esHook) Levels() []logrus.Level { + return []logrus.Level{ + logrus.PanicLevel, + logrus.FatalLevel, + logrus.ErrorLevel, + logrus.InfoLevel, + } +} + +//sendEs 异步发送日志到es +func (hook *esHook) sendHttp(e *logrus.Entry) { + defer func() { + if r := recover(); r != nil { + fmt.Println("send entry to http failed: ", r) + } + }() + + ins := map[string]interface{}{} + for kk, vv := range e.Data { + ins[kk] = vv + } + + ins["time"] = time.Now().Local() + ins["level"] = e.Level + ins["message"] = e.Message + ins["caller"] = fmt.Sprintf("%s:%d %#v", e.Caller.File, e.Caller.Line, e.Caller.Func) + + bs, err := json.Marshal(ins) + br := bytes.NewBuffer(bs) + + _, err = hook.client.Post(hook.Url, hook.Cont, br) + if err != nil { + logrus.Println(err) + } + +} diff --git a/lib/mail/mail.go b/lib/mail/mail.go new file mode 100644 index 0000000..0914acf --- /dev/null +++ b/lib/mail/mail.go @@ -0,0 +1,82 @@ +package mail + +import ( + "crypto/tls" + "fmt" + "mime" + "path/filepath" + "strings" + + conf "gitea.baoapi.com/root/stu_uuos/config" + + "gopkg.in/gomail.v2" +) + +type EMailClient struct { + from string + host string + port int + username string + password string + to []string + subject []string + content []string + attach []string +} + +func NewClient() *EMailClient { + return &EMailClient{ + from: conf.GetConfig().Mail.Username, + host: conf.GetConfig().Mail.Host, + port: conf.GetConfig().Mail.Port, + username: conf.GetConfig().Mail.Username, + password: conf.GetConfig().Mail.Password, + } +} + +func (c *EMailClient) AddTo(to ...string) { + c.to = append(c.to, to...) +} + +func (c *EMailClient) AddSubject(subject ...string) { + c.subject = append(c.subject, subject...) +} + +func (c *EMailClient) AddContent(content ...string) { + c.content = append(c.content, content...) +} + +func (c *EMailClient) AddAttach(attach ...string) { + c.attach = append(c.attach, attach...) +} + +func (c *EMailClient) Send() error { + m := gomail.NewMessage() + + m.SetHeader("From", c.from) + m.SetHeader("To", c.to...) + m.SetHeader("Subject", c.subject...) + + buf := strings.Builder{} + + for _, s := range c.content { + buf.WriteString("

" + s + "

") + } + + for _, v := range c.attach { + fileName := filepath.Base(v) + m.Attach(v, gomail.Rename(fileName), + gomail.SetHeader(map[string][]string{ + "Content-Disposition": []string{ + fmt.Sprintf(`attachment; filename="%s"`, mime.QEncoding.Encode("UTF-8", fileName)), + }, + })) + } + + m.SetBody("text/html", buf.String()) + + d := gomail.NewDialer(c.host, c.port, c.username, c.password) + d.TLSConfig = &tls.Config{InsecureSkipVerify: true} + + return d.DialAndSend(m) +} diff --git a/lib/micro/client.go b/lib/micro/client.go new file mode 100644 index 0000000..4a484df --- /dev/null +++ b/lib/micro/client.go @@ -0,0 +1,33 @@ +package gomicro + +import ( + "github.com/micro/go-micro/v2" + "github.com/micro/go-micro/v2/client" + "github.com/micro/go-micro/v2/client/selector" +) + +//call E.g: +/* + service := NewMicroService(func(rsp interface{}) error { + r := rsp.(*MyResponse) + r.Message = "hello error~: service not found!" + return nil + }) + yourService := pb.NewYourService("your micro service name", service.Client()) +*/ +// defRsp fuseResponse 为熔断时的默认响应处理 +func NewMicroService(defRsp fuseResponse) micro.Service { + se := selector.NewSelector( + selector.SetStrategy(selector.RoundRobin), + ) + + service := micro.NewService( + micro.Selector(se), + micro.WrapClient(func(client client.Client) client.Client { + return &HystrixWrapper{client, defRsp} + }), + micro.WrapClient(NewLogWrapper), + ) + + return service +} diff --git a/lib/micro/hystrix_wrapper.go b/lib/micro/hystrix_wrapper.go new file mode 100644 index 0000000..97422d5 --- /dev/null +++ b/lib/micro/hystrix_wrapper.go @@ -0,0 +1,56 @@ +package gomicro + +import ( + "context" + + "github.com/afex/hystrix-go/hystrix" + "github.com/micro/go-micro/v2/client" +) + +type HystrixWrapper struct { + client.Client + fuseResponse +} + +type fuseResponse func(rsp interface{}) error + +func NewHystrixWrapper(c client.Client) client.Client { + return &HystrixWrapper{Client: c} +} + +func (c *HystrixWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error { + name := req.Service() + "." + req.Endpoint() + + hystrix.ConfigureCommand(name, + hystrix.CommandConfig{ + Timeout: 5000, // 超时时间(毫秒) + MaxConcurrentRequests: 1000, + ErrorPercentThreshold: 25, + SleepWindow: 5000, + }) + + return hystrix.Do(name, func() error { + return c.Client.Call(ctx, req, rsp) + }, func(e error) error { + if c.fuseResponse != nil { + return c.fuseResponse(rsp) + } + return nil + }) +} + +/*func SendCircuitMetrics() { + hystrixStreamHandler := hystrix.NewStreamHandler() + hystrixStreamHandler.Start() + go http.ListenAndServe(net.JoinHostPort("", "81"), hystrixStreamHandler) + + c, err := plugins.InitializeStatsdCollector(&plugins.StatsdCollectorConfig{ + StatsdAddr: "localhost:8125", + Prefix: "myapp.hystrix", + }) + if err != nil { + log.Fatalf("could not initialize statsd client: %v", err) + } + + metricCollector.Registry.Register(c.NewStatsdCollector) +}*/ diff --git a/lib/micro/log_wrapper.go b/lib/micro/log_wrapper.go new file mode 100644 index 0000000..47513f1 --- /dev/null +++ b/lib/micro/log_wrapper.go @@ -0,0 +1,21 @@ +package gomicro + +import ( + "context" + + "github.com/micro/go-micro/v2/client" + log "github.com/micro/go-micro/v2/logger" +) + +type LogWrapper struct { + client.Client +} + +func (c *LogWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error { + log.Infof("call service: %s(%s)", req.Service(), req.Endpoint()) + return c.Client.Call(ctx, req, rsp) +} + +func NewLogWrapper(c client.Client) client.Client { + return &LogWrapper{c} +} diff --git a/lib/micro/tls.go b/lib/micro/tls.go new file mode 100644 index 0000000..e649982 --- /dev/null +++ b/lib/micro/tls.go @@ -0,0 +1,51 @@ +package gomicro + +import ( + "crypto/tls" + "gitea.baoapi.com/root/stu_uuos/util" + log "github.com/micro/go-micro/v2/logger" +) + +func LoadTlsConfig() *tls.Config { + pemFile, err := util.FindFile("cert/2990195__241210.com.pem") + if err != nil { + log.Fatalf("load pem cert err: %v", err) + } + + keyFile, err := util.FindFile("cert/2990195__241210.com.key") + if err != nil { + log.Fatalf("load key cert err: %v", err) + } + + util.PrintInfo(pemFile) + util.PrintInfo(keyFile) + + cert, err := tls.LoadX509KeyPair(pemFile, keyFile) + if err != nil { + log.Fatalf("tls.LoadX509KeyPair err: %v", err) + } + + /*caFile, err := util.FindFile("cert/ca.pem") + if err != nil { + log.Fatalf("load CA cert err: %v", err) + } + + certPool := x509.NewCertPool() + ca, err := ioutil.ReadFile(caFile) + if err != nil { + log.Fatalf("ioutil.ReadFile err: %v", err) + } + + if ok := certPool.AppendCertsFromPEM(ca); !ok { + log.Fatalf("certPool.AppendCertsFromPEM err") + }*/ + + tlsCfg := &tls.Config{ + Certificates: []tls.Certificate{cert}, + //ClientAuth: tls.RequireAndVerifyClientCert, + //ClientCAs: certPool, + InsecureSkipVerify: true, + } + + return tlsCfg +} diff --git a/lib/micro/tracer.go b/lib/micro/tracer.go new file mode 100644 index 0000000..6eb251a --- /dev/null +++ b/lib/micro/tracer.go @@ -0,0 +1,78 @@ +package gomicro + +import ( + "gitea.baoapi.com/root/stu_uuos/config" + log "github.com/micro/go-micro/v2/logger" + "github.com/micro/go-micro/v2/server" + ocplugin "github.com/micro/go-plugins/wrapper/trace/opentracing/v2" + opentracing "github.com/opentracing/opentracing-go" + "github.com/uber/jaeger-client-go" + jaegercfg "github.com/uber/jaeger-client-go/config" + jaegerlog "github.com/uber/jaeger-client-go/log" + "github.com/uber/jaeger-client-go/rpcmetrics" + "github.com/uber/jaeger-lib/metrics" + "io" + "time" +) + +func NewTracerHandlerWrapper() server.HandlerWrapper { + tracer, _, err := NewTracer(config.GetConfig().ServiceName, "") //"127.0.0.1:16686") + if err != nil { + log.Fatal(err) + } + return ocplugin.NewHandlerWrapper(tracer) +} + +// NewTracer 创建一个jaeger Tracer +func NewTracer(serviceName string, addr string) (opentracing.Tracer, io.Closer, error) { + //os.Setenv("JAEGER_SERVICE_NAME", "not-effective") + //cfg, err := jaegercfg.FromEnv() + + cfg := jaegercfg.Configuration{ + ServiceName: serviceName, + Sampler: &jaegercfg.SamplerConfig{ + Type: jaeger.SamplerTypeConst, + Param: 1, + }, + Reporter: &jaegercfg.ReporterConfig{ + LogSpans: true, + BufferFlushInterval: 1 * time.Second, + //CollectorEndpoint :"http://192.168.0.111:14268/api/traces", + //LocalAgentHostPort: "192.168.0.111:6831", + }, + } + + jaegerLogger := jaegerlog.StdLogger + metricsFactory := metrics.NullFactory + + //metricsFactory := jprom.New().Namespace(metrics.NSOptions{Name: serviceName, Tags: nil}) + //jaegerLogger := jaegerLoggerAdapter{log.With("serviceName", serviceName)} + + sender, err := jaeger.NewUDPTransport(addr, 0) + if err != nil { + return nil, nil, err + } + + reporter := jaeger.NewRemoteReporter(sender) + + tracer, closer, err := cfg.NewTracer( + jaegercfg.Logger(jaegerLogger), + jaegercfg.Metrics(metricsFactory), + jaegercfg.Reporter(reporter), + jaegercfg.Observer(rpcmetrics.NewObserver(metricsFactory, rpcmetrics.DefaultNameNormalizer)), + ) + if err != nil { + log.Error("cannot initialize Jaeger Tracer", err) + return nil, nil, err + } + + /*defer func() { + if err := closer.Close(); err != nil { + log.Error(err) + } + }()*/ + + opentracing.SetGlobalTracer(tracer) + + return tracer, closer, nil +} diff --git a/lib/micro/tracer_wrapper.go b/lib/micro/tracer_wrapper.go new file mode 100644 index 0000000..e6c381d --- /dev/null +++ b/lib/micro/tracer_wrapper.go @@ -0,0 +1 @@ +package gomicro diff --git a/lib/nats/nats.go b/lib/nats/nats.go new file mode 100644 index 0000000..533e533 --- /dev/null +++ b/lib/nats/nats.go @@ -0,0 +1,20 @@ +package nats + +import ( + "gitea.baoapi.com/root/stu_uuos/config" + "github.com/nats-io/nats.go" + "log" +) + +var NatsClient = &nats.Conn{} + +func Init() { + var err error + NatsClient, err = nats.Connect(config.GetConfig().Nats.Addr) + if err != nil { + log.Panicf("Nats Panic: %v\n", err) + return + } + log.Println(" Nats Connect") + return +} diff --git a/lib/protobuf/json.go b/lib/protobuf/json.go new file mode 100644 index 0000000..c9142a1 --- /dev/null +++ b/lib/protobuf/json.go @@ -0,0 +1,25 @@ +package protobuf + +import ( + "github.com/golang/protobuf/jsonpb" + "github.com/golang/protobuf/proto" +) + +func ToJson(pb proto.Message) (string, error) { + // 编码 protobuf 对象到 json + m := &jsonpb.Marshaler{} + m.OrigName = true // 使用 protobuf 定义的字段名称,而不是驼峰名称,便于识别 + jsData, err := m.MarshalToString(pb) + if err != nil { + return "", err + } + return jsData, nil +} + +func ToPrtobuf(s string, p proto.Message) error { + err := jsonpb.UnmarshalString(s, p) + if err != nil { + return err + } + return nil +} diff --git a/lib/protobuf/time.go b/lib/protobuf/time.go new file mode 100644 index 0000000..6018eea --- /dev/null +++ b/lib/protobuf/time.go @@ -0,0 +1,24 @@ +package protobuf + +import ( + "github.com/golang/protobuf/ptypes" + "github.com/golang/protobuf/ptypes/timestamp" + "log" + "time" +) + +func MarshalTime(t time.Time) *timestamp.Timestamp { + pt, err := ptypes.TimestampProto(t) + if err != nil { + log.Printf("time to proto time error: %v", err) + } + return pt +} + +func UnMarshalTime(pt *timestamp.Timestamp) *time.Time { + t, err := ptypes.Timestamp(pt) + if err != nil { + log.Printf("time to proto time error: %v", err) + } + return &t +} diff --git a/lib/redis/dirve.go b/lib/redis/dirve.go new file mode 100644 index 0000000..313ca3b --- /dev/null +++ b/lib/redis/dirve.go @@ -0,0 +1,27 @@ +package redis + +import ( + "context" + "gitea.baoapi.com/root/stu_uuos/config" + redisv8 "github.com/go-redis/redis/v8" + "log" +) + +var Rdb *redisv8.Client + +func Init() { + cfg := config.GetConfig().Redis + var err error + Rdb = redisv8.NewClient( + &redisv8.Options{ + Addr: cfg.Addr, + Password: "", + DB: 1, + }) + _, err = Rdb.Ping(context.Background()).Result() + if err != nil { + log.Fatalf("redis error: %v\n", err) + return + } + return +} diff --git a/logger/logger.go b/logger/logger.go new file mode 100644 index 0000000..0e324ba --- /dev/null +++ b/logger/logger.go @@ -0,0 +1,35 @@ +package logger + +import ( + micrologger "github.com/micro/go-micro/v2/logger" + micrologrus "github.com/micro/go-plugins/logger/logrus/v2" +) + +type Logger struct { + micrologger.Logger +} + +var defaultLogger Logger + +func Init() { + logrusLogger := newLogrusLogger() + + micrologger.DefaultLogger = micrologrus.NewLogger( + micrologrus.WithLogger(logrusLogger), + micrologger.WithFields(map[string]interface{}{ + "gy-order": "v3.0.1", + }), + ) + defaultLogger.Logger = micrologger.DefaultLogger + //zapLogger := newZapLogger() + //micrologger.DefaultLogger = micrologger.NewLogger(micrologger.WithOutput(os.Stdout)) + //micrologger.DefaultLogger = micrologger.NewLogger(microzap.WithConfig(zap.Config{})) +} + +func (l Logger) Print(v ...interface{}) { + l.Log(micrologger.DebugLevel, v) +} + +func GetLogger() Logger { + return defaultLogger +} diff --git a/logger/logrus.go b/logger/logrus.go new file mode 100644 index 0000000..c41882b --- /dev/null +++ b/logger/logrus.go @@ -0,0 +1,285 @@ +package logger + +import ( + "bytes" + "encoding/json" + "fmt" + "gitea.baoapi.com/root/stu_uuos/config" + rotatelogs "github.com/lestrrat-go/file-rotatelogs" + "github.com/rifflock/lfshook" + "github.com/sirupsen/logrus" + "os" + "path" + "path/filepath" + "regexp" + "runtime" + "strings" + "time" +) + +const ( + nocolor logColor = 0 + red logColor = 31 + green logColor = 32 + yellow logColor = 33 + blue logColor = 36 + gray logColor = 37 +) + +type TextLogFormatter struct { + Conf *config.Config +} + +type logOutTarget string +type logFormatter string +type logLevel string +type logColor int + +const ( + Std logOutTarget = "std" + File logOutTarget = "file" +) +const ( + Text logFormatter = "text" + Json logFormatter = "json" +) +const ( + Unknown logLevel = "UNKNOWN" + Trc logLevel = "TRC" + Dbg logLevel = "DBG" + Inf logLevel = "INF" + Wrn logLevel = "WRN" + Err logLevel = "ERR" + Fat logLevel = "FAT" + Pan logLevel = "PAN" +) + +func newLogrusLogger() *logrus.Logger { + conf := config.GetConfig() + logger := logrus.New() + + lvl, err := logrus.ParseLevel(conf.Log.MinLevel) + if err != nil { + panic(err) + } + + logger.Level = lvl + logger.ReportCaller = conf.Log.ReportCaller + + if conf.Log.Formatter == string(Text) { + logger.Formatter = &TextLogFormatter{conf} + } else { + logger.Formatter = &logrus.JSONFormatter{ + TimestampFormat: conf.Log.TimestampFormat, + PrettyPrint: conf.Log.JsonPrettyPrint, + CallerPrettyfier: func(f *runtime.Frame) (string, string) { + filename, line, funcName := getRuntimeLocation() + + if len(filename) == 0 { + _, filename = path.Split(f.File) + } else { + filename = fmt.Sprintf("%s:%d", filename, line) + } + + if len(funcName) == 0 { + s := strings.Split(f.Function, ".") + funcName = s[len(s)-1] + } + + return funcName, filename + }, + } + } + + if conf.Log.Out == string(File) { + hook := newLfsHook(conf, logger.Formatter) + logger.AddHook(hook) + } else { + logger.SetOutput(os.Stdout) + } + + return logger +} + +func (f *TextLogFormatter) Format(entry *logrus.Entry) ([]byte, error) { + var b *bytes.Buffer + + if entry.Buffer != nil { + b = entry.Buffer + } else { + b = &bytes.Buffer{} + } + + lt, lc := parseLevel(entry) + fn, line, funcName := getEntryRuntimeLocation(entry) + caller := "" + + if entry.HasCaller() && f.Conf.Log.ReportCaller { + caller = fmt.Sprintf("%s:%d %s", fn, line, funcName) + } + + if f.Conf.Log.Out == string(Std) && f.Conf.Log.OutColor { //只有控制台输出才需要输出颜色,文件输出不需要颜色。 + _, err := fmt.Fprintf(b, "%s \x1b[%dm[%s] \x1b[0m%s - %s ", + entry.Time.Format(f.Conf.Log.TimestampFormat), lc, lt, caller, entry.Message) + if err != nil { + panic(err) + } + } else { + _, err := fmt.Fprintf(b, "%s [%s] %s | %-44s ", + entry.Time.Format(f.Conf.Log.TimestampFormat), lt, caller, entry.Message) + if err != nil { + panic(err) + } + } + + if len(entry.Data) > 0 { + outJsonEntry(b, entry) + } + + b.WriteByte('\n') + return b.Bytes(), nil +} + +func parseLevel(entry *logrus.Entry) (logLevel, logColor) { + lt := Unknown + var lc logColor + + switch entry.Level { + case logrus.TraceLevel: + lt = Trc + lc = gray + case logrus.DebugLevel: + lt = Dbg + lc = gray + case logrus.InfoLevel: + lt = Inf + lc = blue + case logrus.WarnLevel: + lt = Wrn + lc = yellow + case logrus.ErrorLevel: + lt = Err + lc = red + case logrus.FatalLevel: + lt = Fat + lc = red + case logrus.PanicLevel: + lt = Pan + lc = red + } + + return lt, lc +} + +func outJsonEntry(b *bytes.Buffer, entry *logrus.Entry) { + jb, err := json.Marshal(entry.Data) + if err != nil { + panic(err) + } + + if _, err = fmt.Fprint(b, string(jb)); err != nil { + panic(err) + } +} + +func newLfsHook(conf *config.Config, formatter logrus.Formatter) logrus.Hook { + filePathName := path.Join(conf.Log.FilePath, conf.Log.FileName) + + var opts []rotatelogs.Option + + // 生成软链,指向最新日志文件 + opts = append(opts, rotatelogs.WithLinkName(filePathName)) + // 日志切割时间间隔 + du1, err := time.ParseDuration(conf.Log.RotationTime) + if err != nil { + panic(err) + } + + if du1.Minutes() < 1 { + panic(fmt.Errorf("日志切割时间 %v 太短", du1)) + } + + opts = append(opts, rotatelogs.WithRotationTime(du1)) + du2, err := time.ParseDuration(conf.Log.MaxAge) + if err != nil { + panic(err) + } + + if du2.Minutes() > 0 && du2.Minutes() < 1 { + panic(fmt.Errorf("日志保留时间 %v 太短", du1)) + } + + // WithMaxAge 和 WithRotationCount 二者只能设置一个 + if du2.Minutes() > 0 { + // 文件最长保存时间 + opts = append(opts, rotatelogs.WithMaxAge(du2)) + } else if conf.Log.MaxRemainCount > 0 { + //最多保存文件个数 + opts = append(opts, rotatelogs.WithRotationCount(conf.Log.MaxRemainCount)) + } else { + // 默认设置为文件最长保存时间一个月 + opts = append(opts, rotatelogs.WithMaxAge(time.Hour*24*30)) + } + + writer, err := rotatelogs.New(filePathName+".%Y%m%d%H%M", opts...) + if err != nil { + panic(err) + } + + lfsHook := lfshook.NewHook(lfshook.WriterMap{ + logrus.TraceLevel: writer, + logrus.DebugLevel: writer, + logrus.InfoLevel: writer, + logrus.WarnLevel: writer, + logrus.ErrorLevel: writer, + logrus.FatalLevel: writer, + logrus.PanicLevel: writer, + }, formatter) + + return lfsHook +} + +func getEntryRuntimeLocation(entry *logrus.Entry) (filename string, line int, funcName string) { + filename, line, funcName = getRuntimeLocation() + + if len(filename) == 0 && line == 0 && len(funcName) == 0 { + filename = filepath.Base(entry.Caller.File) + line = entry.Caller.Line + funcName = filepath.Base(entry.Caller.Function) + } + + return filename, line, funcName +} + +var logRegexp = regexp.MustCompile(`config*|model*|entity*|db*|constant*|srv*|web*|handler*|router*|util*|micro*`) +var excludeRegexp = regexp.MustCompile(`logger*|logrus*`) + +// 获取正在运行的文件名称、文件所在行、函数名 +func getRuntimeLocation() (filename string, line int, funcName string) { + var pc uintptr + var ok bool + var i int + + for { + pc, filename, line, ok = runtime.Caller(i) + + if ok && (logRegexp.MatchString(filename) && !excludeRegexp.MatchString(filename)) { + funcName = runtime.FuncForPC(pc).Name() + fns := strings.Split(funcName, "/") + + if len(fns) > 1 { + dir := strings.Join(fns[1:len(fns)-1], "/") + directPkg := strings.Split(fns[len(fns)-1], ".")[0] + + filename = fmt.Sprintf("%s/%s/%s", dir, directPkg, filepath.Base(filename)) + } + + funcName = filepath.Base(funcName) + break + } + + i++ + } + + return filename, line, funcName +} diff --git a/micro/base.go b/micro/base.go new file mode 100644 index 0000000..0b2f294 --- /dev/null +++ b/micro/base.go @@ -0,0 +1,61 @@ +package micro + +import ( + "gitea.baoapi.com/root/stu_uuos/config" + "strings" + + "github.com/micro/go-micro/v2" + "github.com/micro/go-micro/v2/registry" + "github.com/micro/go-plugins/registry/consul/v2" + "github.com/micro/go-plugins/registry/etcdv3/v2" + "github.com/micro/go-plugins/registry/kubernetes/v2" + "github.com/micro/go-plugins/registry/nats/v2" +) + +type MicroService struct { + micro.Service + ServiceName string +} + +func InitMicro() { + //NewCipherService() +} + +func newService(clientName string) micro.Service { + return micro.NewService( + micro.Name(clientName), + micro.Version("latest"), + micro.Registry(newRegistry()), + ) +} + +func newRegistry() registry.Registry { + var reg registry.Registry + + switch config.GetConfig().Micro.Registry.Name { + case "etcd", "etcdv3": + reg = etcdv3.NewRegistry( + registry.Addrs(parseAddrs()...), + ) + case "kubernetes": + reg = kubernetes.NewRegistry( + registry.Addrs(parseAddrs()...), + ) + case "consul": + reg = consul.NewRegistry( + registry.Addrs(parseAddrs()...), + ) + case "nats": + reg = nats.NewRegistry( + registry.Addrs(parseAddrs()...), + ) + default: + panic("registry unknown") + } + + return reg +} + +func parseAddrs() []string { + return strings.Split(config.GetConfig().Micro.Registry.Addrs, ",") +} diff --git a/util/character.go b/util/character.go new file mode 100644 index 0000000..0bc4652 --- /dev/null +++ b/util/character.go @@ -0,0 +1,152 @@ +package util + +import ( + "bytes" + "encoding/hex" + "github.com/mozillazg/go-pinyin" + "golang.org/x/text/encoding/simplifiedchinese" + "golang.org/x/text/transform" + "io/ioutil" + "strconv" + "strings" + "unsafe" +) + +// 获取中文字符串第一个首字母 +func GetChineseFirstLetter(chinese string) string { + + // 获取中文字符串第一个字符 + firstChar := string([]rune(chinese)[:1]) + + // Utf8 转 GBK2312 + firstCharGbk, err := Utf8ToGbk([]byte(firstChar)) + if err != nil { + return "" + } + + // 获取第一个字符的16进制 + firstCharHex := hex.EncodeToString(firstCharGbk) + + // 16进制转十进制 + firstCharDec, err := strconv.ParseInt(firstCharHex, 16, 0) + if err != nil { + return "" + } + + // 十进制落在GB 2312的某个拼音区间即为某个字母 + firstCharDecimalRelative := firstCharDec - 65536 + if firstCharDecimalRelative >= -20319 && firstCharDecimalRelative <= -20284 { + return "A" + } + if firstCharDecimalRelative >= -20283 && firstCharDecimalRelative <= -19776 { + return "B" + } + if firstCharDecimalRelative >= -19775 && firstCharDecimalRelative <= -19219 { + return "C" + } + if firstCharDecimalRelative >= -19218 && firstCharDecimalRelative <= -18711 { + return "D" + } + if firstCharDecimalRelative >= -18710 && firstCharDecimalRelative <= -18527 { + return "E" + } + if firstCharDecimalRelative >= -18526 && firstCharDecimalRelative <= -18240 { + return "F" + } + if firstCharDecimalRelative >= -18239 && firstCharDecimalRelative <= -17923 { + return "G" + } + if firstCharDecimalRelative >= -17922 && firstCharDecimalRelative <= -17418 { + return "H" + } + if firstCharDecimalRelative >= -17417 && firstCharDecimalRelative <= -16475 { + return "J" + } + if firstCharDecimalRelative >= -16474 && firstCharDecimalRelative <= -16213 { + return "K" + } + if firstCharDecimalRelative >= -16212 && firstCharDecimalRelative <= -15641 { + return "L" + } + if firstCharDecimalRelative >= -15640 && firstCharDecimalRelative <= -15166 { + return "M" + } + if firstCharDecimalRelative >= -15165 && firstCharDecimalRelative <= -14923 { + return "N" + } + if firstCharDecimalRelative >= -14922 && firstCharDecimalRelative <= -14915 { + return "O" + } + if firstCharDecimalRelative >= -14914 && firstCharDecimalRelative <= -14631 { + return "P" + } + if firstCharDecimalRelative >= -14630 && firstCharDecimalRelative <= -14150 { + return "Q" + } + if firstCharDecimalRelative >= -14149 && firstCharDecimalRelative <= -14091 { + return "R" + } + if firstCharDecimalRelative >= -14090 && firstCharDecimalRelative <= -13319 { + return "S" + } + if firstCharDecimalRelative >= -13318 && firstCharDecimalRelative <= -12839 { + return "T" + } + if firstCharDecimalRelative >= -12838 && firstCharDecimalRelative <= -12557 { + return "W" + } + if firstCharDecimalRelative >= -12556 && firstCharDecimalRelative <= -11848 { + return "X" + } + if firstCharDecimalRelative >= -11847 && firstCharDecimalRelative <= -11056 { + return "Y" + } + if firstCharDecimalRelative >= -11055 && firstCharDecimalRelative <= -10247 { + return "Z" + } + return "" +} + +// Utf8ToGbk +func Utf8ToGbk(s []byte) ([]byte, error) { + reader := transform.NewReader(bytes.NewReader(s), simplifiedchinese.GBK.NewEncoder()) + d, e := ioutil.ReadAll(reader) + if e != nil { + return nil, e + } + return d, nil +} + +func CharacterUpper(character string) (ch string) { + anyCharacter := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + if len(character) > 0 { + if strings.ContainsAny(character, anyCharacter) { + ch = character[0:1] + ch = strings.ToUpper(ch) + return + } + } + return +} + +func HanZi2UpperCapital(name string) string { + a := pinyin.NewArgs() + list := pinyin.Pinyin(name, a) + upStrs := "" + for i := 0; i < len(list); i++ { + character := str2bytes(list[i][0])[0] + str := string(character) + upStrs += str + } + return strings.ToUpper(upStrs) +} + +func str2bytes(s string) []byte { + x := (*[2]uintptr)(unsafe.Pointer(&s)) + h := [3]uintptr{x[0], x[1], x[1]} + return *(*[]byte)(unsafe.Pointer(&h)) +} + +func bytes2str(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} diff --git a/util/common.go b/util/common.go new file mode 100644 index 0000000..174cbe0 --- /dev/null +++ b/util/common.go @@ -0,0 +1,174 @@ +package util + +import ( + "crypto/md5" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "log" + "math/rand" + "net/http" + "os" + "reflect" + "regexp" + "strconv" + "strings" + "time" + + "golang.org/x/crypto/bcrypt" +) + +// 生成邀请码 +func GenerateInviteCode() string { + alphabet := []byte("123456789ABCDEFGHIJKLMNPQRSTUVWXYZ") + codes := make([]byte, 0) + for i := 0; i < 6; i++ { + s := rand.NewSource(time.Now().UnixNano()) + r := rand.New(s) + index := r.Intn(len(alphabet)) + codes = append(codes, alphabet[index]) + } + + return string(codes) +} + +// 获取环境变量 +func GetEnv(key, defaultValue string) string { + value := os.Getenv(key) + if value == "" { + return defaultValue + } + return value +} + +// 生成密码 +func GeneratePwd(pwd string) string { + hash, _ := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.DefaultCost) + return string(hash) +} + +// 校验密码 +func ValidatePwd(encodePwd, pwd string) bool { + err := bcrypt.CompareHashAndPassword([]byte(encodePwd), []byte(pwd)) + if err != nil { + return false + } else { + return true + } +} + +// 校验手机号 +func VerifyMobile(mobile string) bool { + pattern := "^((13[0-9])|(14[0-9])|(15[0-9])|(17[0-9])|(18[0-9])|(16[0-9])|198|199)\\d{8}$" + reg := regexp.MustCompile(pattern) + return reg.MatchString(mobile) +} + +// 校验邮箱 +func VerifyEmail(email string) bool { + pattern := `^[0-9a-z][_.0-9a-z-]{0,31}@([0-9a-z][0-9a-z-]{0,30}[0-9a-z]\.){1,4}[a-z]{2,4}$` + reg := regexp.MustCompile(pattern) + return reg.MatchString(email) +} + +// 获取机器码 +func GetMachineUUID() (uuid string, err error) { + var ( + url string + resp *http.Response + body []byte + data map[string]map[string]interface{} + ok bool + cliHost string + cliPort string + ) + + cliHost = GetEnv("CLI_HOST", "192.168.1.252") + cliPort = GetEnv("CLI_PORT", "8686") + + url = fmt.Sprintf("http://%s:%s", cliHost, cliPort) + log.Printf("获取机器特征码 url: %s", url) + + resp, err = http.Get(url) + + if err != nil { + log.Printf("http.Get: %v", err) + err = errors.New("获取服务器特征码失败") + return + } + + defer resp.Body.Close() + + if resp.StatusCode == 200 { + body, err = ioutil.ReadAll(resp.Body) + err = json.Unmarshal(body, &data) + if err != nil { + log.Printf("json.Unmarshal: %v", err) + err = errors.New("获取服务器特征码失败") + return + } + + uuid, ok = data["machine"]["uuid"].(string) + if !ok { + log.Printf("assert err: %v", err) + err = errors.New("获取服务器特征码失败") + return + } + } + + return +} + +func Md5(str string) string { + hash := md5.New() + hash.Write([]byte(str)) + return hex.EncodeToString(hash.Sum(nil)) +} + +func InArray(needle interface{}, haystack interface{}) bool { + val := reflect.ValueOf(haystack) + switch val.Kind() { + case reflect.Slice, reflect.Array: + for i := 0; i < val.Len(); i++ { + if reflect.DeepEqual(needle, val.Index(i).Interface()) { + return true + } + } + case reflect.Map: + for _, k := range val.MapKeys() { + if reflect.DeepEqual(needle, val.MapIndex(k).Interface()) { + return true + } + } + } + + return false +} + +func ArrayIntersect(array1, array2 []string) []string { + var res []string + for _, v := range array1 { + if InArray(v, array2) { + res = append(res, v) + } + } + return res +} + +// +func RegNumberInString(str string) (float64, error) { + reg, _ := regexp.Compile(`^\d+`) + if reg != nil { + s := reg.FindAllString(str, -1) + if len(s) == 0 { + return 0, nil + } + info := strings.TrimSpace(s[0]) + // + f, e := strconv.ParseFloat(info, 64) + return f, e + } + return 0, errors.New("unknown param") +} diff --git a/util/decode.go b/util/decode.go new file mode 100644 index 0000000..22bc3b9 --- /dev/null +++ b/util/decode.go @@ -0,0 +1,75 @@ +package util + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "encoding/base64" + "strings" +) + +var aesKey []byte + +func init() { + aesKey = []byte("11e90a62f2fa07ce9e600242ac110007") +} + +func pkcs7Padding(src []byte, blockSize int) []byte { + padding := blockSize - len(src)%blockSize + padText := bytes.Repeat([]byte{byte(padding)}, padding) + return append(src, padText...) +} + +func aesEncrypt(src, key []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + blockSize := block.BlockSize() + src = pkcs7Padding(src, blockSize) + blockMode := cipher.NewCBCEncrypter(block, key[:blockSize]) + encrypted := make([]byte, len(src)) + blockMode.CryptBlocks(encrypted, src) + return encrypted, nil +} + +func aesDecrypt(encrypted, key []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + blockSize := block.BlockSize() + blockMode := cipher.NewCBCDecrypter(block, key[:blockSize]) + src := make([]byte, len(encrypted)) + blockMode.CryptBlocks(src, encrypted) + src = pkcs7UnPadding(src) + return src, nil +} + +func pkcs7UnPadding(src []byte) []byte { + length := len(src) + unPadding := int(src[length-1]) + return src[:(length - unPadding)] +} + +func AesEncrypt(src string) (string, error) { + res, err := aesEncrypt([]byte(src), aesKey) + if err != nil { + r := base64.StdEncoding.EncodeToString(res) + return r, nil + } else { + return "", err + } +} + +func AesDecrypt(src string) (string, error) { + if len(src) == 0 || strings.TrimSpace(src) == "" { + return "", nil + } + s, e := base64.StdEncoding.DecodeString(src) + if e != nil { + return "", e + } + res, err := aesDecrypt(s, aesKey) + return string(res), err +} diff --git a/util/decode_test.go b/util/decode_test.go new file mode 100644 index 0000000..5830e1a --- /dev/null +++ b/util/decode_test.go @@ -0,0 +1,10 @@ +package util + +import ( + "testing" +) + +func TestAesEncrypt(t *testing.T) { + r, _ := AesEncrypt("18611896226") + t.Log(r) +} diff --git a/util/enum.go b/util/enum.go new file mode 100644 index 0000000..a70cd79 --- /dev/null +++ b/util/enum.go @@ -0,0 +1,40 @@ +package util + +import "database/sql/driver" + +type Enumer interface { + // json 接口 + MarshalJSON() (data []byte, err error) + UnmarshalJSON(data []byte) (err error) + // 数据库接口 + Scan(value interface{}) error + Value() (driver.Value, error) + // 字符串接口 + String() string + // 描述接口 + Desc() string +} + +func EnumName(m map[int8]string, v int8) string { + s, ok := m[v] + if ok { + return s + } + return m[0] +} + +func EnumValue(m map[string]int8, v string) int8 { + i, ok := m[v] + if ok { + return i + } + return 0 +} + +func EnumDesc(m map[int8]string, v int8) string { + s, ok := m[v] + if ok { + return s + } + return m[0] +} diff --git a/util/export.go b/util/export.go new file mode 100644 index 0000000..3244e65 --- /dev/null +++ b/util/export.go @@ -0,0 +1,51 @@ +package util + +import "os" + +//import "github.com/EDDYCJY/go-gin-example/pkg/setting" + +const EXT = ".xlsx" + +// GetExcelFullUrl get the full access path of the Excel file +func GetExcelFullUrl(name string) string { + return "." + "/" + name +} + +// GetExcelPath get the relative save path of the Excel file +func GetExcelPath() string { + //return setting.AppSetting.ExportSavePath + return "excel/" +} + +// GetExcelFullPath Get the full save path of the Excel file +func GetExcelFullPath() string { + return "./" + GetExcelPath() +} + +// IsNotExistMkDir create a directory if it does not exist +func IsNotExistMkDir(src string) error { + if notExist := CheckNotExist(src); notExist == true { + if err := MkDir(src); err != nil { + return err + } + } + + return nil +} + +// CheckNotExist check if the file exists +func CheckNotExist(src string) bool { + _, err := os.Stat(src) + + return os.IsNotExist(err) +} + +// MkDir create a directory +func MkDir(src string) error { + err := os.MkdirAll(src, os.ModePerm) + if err != nil { + return err + } + + return nil +} diff --git a/util/file.go b/util/file.go new file mode 100644 index 0000000..c4acc66 --- /dev/null +++ b/util/file.go @@ -0,0 +1,233 @@ +package util + +import ( + "bufio" + "fmt" + "io" + "log" + "os" + "path" + "path/filepath" + "runtime" + "strings" +) + +// 判断所给路径文件/文件夹是否存在 +func Exists(path string) bool { + _, err := os.Stat(path) + + if err == nil { + return true + } + + if os.IsExist(err) { + return true + } + + if os.IsNotExist(err) { + return false + } + + return false +} + +// FindFile 查找指定名称的文件 +// 从构建后可执行文件所在目录或源码所在目录查找 +func FindFile(filename string) (string, error) { + if Exists(filename) { + return filename, nil + } + + // 构建后的可执行文件所在目录 + execDir, err := filepath.Abs(filepath.Dir(os.Args[0])) + if err != nil { + return "", err + } + + if file := recursiveFind(execDir, filename); len(file) > 0 { + return file, nil + } + + // 源代码运行时当前文件所在目录或项目根目录 + srcDir, err := os.Getwd() + if err != nil { + return "", err + } + + if file := recursiveFind(srcDir, filename); len(file) > 0 { + return file, nil + } + + var i int + for { + //当前行所在文件路径(从当前 util 文件开始逐层递归调用栈查找) + if _, fn, _, ok := runtime.Caller(i); ok { + if file := recursiveFind(path.Dir(fn), filename); len(file) > 0 { + return file, nil + } + } else { + break + } + i++ + } + + return "", nil +} + +func CreateFilePath(filePath string) error { + fi, err := os.Stat(filePath) + + if err == nil && fi.IsDir() { + return fmt.Errorf("%s is not file", filePath) + } + + if err != nil { + if os.IsNotExist(err) { + dir := filepath.Dir(filePath) + if err := os.MkdirAll(dir, os.ModePerm); err != nil { + return err + } + } else { + return err + } + } + + return nil +} + +// 从指定目录查找文件,若指定目录未找到对应文件,则递归从上级目录继续查找。 +func recursiveFind(dir, filename string) string { + file := path.Join(dir, filename) + + if Exists(file) { + return file + } + + // 已经递归到根目录了,且未找到对应文件,则返回空 + if dir == filepath.Base(dir) || + dir == filepath.Join(filepath.VolumeName(dir), filepath.Base(dir)) { + return "" + } + + // 未到根目录,继续从上级目录查找 + return recursiveFind(filepath.Dir(dir), filename) +} + +// 判断所给路径是否为文件夹 +func IsDir(path string) bool { + s, err := os.Stat(path) + if err != nil { + return false + } + return s.IsDir() +} + +// 判断所给路径是否为文件 +func IsFile(path string) bool { + return !IsDir(path) +} + +func JoinFilePath(path ...string) string { + s := "" + for _, p := range path { + if strings.TrimSpace(p) == "" { + continue + } + if strings.HasSuffix(p, "/") { + s += p + } else { + s += p + "/" + } + } + + s = strings.Replace(strings.TrimSuffix(s, "/"), "/", string(os.PathSeparator), -1) + s = strings.Replace(s, "\\", string(os.PathSeparator), -1) + + return s +} + +func CopyFile(dstName, srcName string) (written int64, err error) { + src, err := os.Open(srcName) + if err != nil { + return + } + + defer func() { + if err := src.Close(); err != nil { + fmt.Println(err) + } + }() + + dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644) + if err != nil { + return + } + + defer func() { + if err := dst.Close(); err != nil { + fmt.Println(err) + } + }() + + return io.Copy(dst, src) +} + +func WriteString(filename string, data string, append, newLine bool) error { + return WriteByte(filename, []byte(data), append, newLine) +} + +func WriteByte(filename string, data []byte, append, newLine bool) error { + flag := os.O_RDWR | os.O_CREATE | os.O_SYNC + perm := os.ModePerm + + if append { + flag = flag | os.O_APPEND + perm = os.ModeAppend + } else { + flag = flag | os.O_TRUNC + } + + f, err := os.OpenFile(filename, flag, perm) + if err != nil { + return err + } + + defer func() { + if err := f.Close(); err != nil { + log.Println(err) + } + }() + + //return writeFile(f, data, append, newLine) + return writeBufIO(f, data, append, newLine) +} + +// 性能较低 +func writeFile(file *os.File, data []byte, append, newLine bool) error { + if append && newLine { + if _, err := file.WriteString("\n"); err != nil { + return err + } + } + if _, err := file.Write(data); err != nil { + return err + } + + return nil +} + +func writeBufIO(file *os.File, data []byte, append, newLine bool) error { + writer := bufio.NewWriter(file) + + if append && newLine { + if _, err := writer.WriteString("\n"); err != nil { + return err + } + } + + if _, err := writer.Write(data); err != nil { + return err + } + + return writer.Flush() +} diff --git a/util/http.go b/util/http.go new file mode 100644 index 0000000..303b320 --- /dev/null +++ b/util/http.go @@ -0,0 +1,226 @@ +package util + +import ( + "bytes" + "crypto/tls" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "time" +) + +type RequestMethod string +type ContentType string +type RequestHeader map[string][]string + +const ( + GET RequestMethod = "GET" + POST RequestMethod = "POST" + PUT RequestMethod = "PUT" + DELETE RequestMethod = "DELETE" +) +const ( + ContentTypePlain ContentType = "text/plain;charset=utf-8" + ContentTypeHtml ContentType = "text/html;charset=utf-8" + ContentTypeXml ContentType = "text/xml;charset=utf-8" + ContentTypeJson ContentType = "application/json;charset=utf-8" + ContentTypeForm ContentType = "application/x-www-form-urlencoded;charset=utf-8" + ContentTypeFile ContentType = "multipart/form-data;charset=utf-8" +) + +func Get(url string) ([]byte, error) { + return Request(url, GET, ContentTypePlain, nil, nil) +} + +func Post(url string, contentType ContentType, v interface{}) ([]byte, error) { + return Request(url, POST, contentType, nil, v) +} + +func Put(url string, contentType ContentType, v interface{}) ([]byte, error) { + return Request(url, PUT, contentType, nil, v) +} + +func Del(url string) ([]byte, error) { + return Request(url, DELETE, ContentTypePlain, nil, nil) +} + +func GetByHeader(url string, header RequestHeader) ([]byte, error) { + return Request(url, GET, ContentTypePlain, header, nil) +} + +func PostByHeader(url string, contentType ContentType, header RequestHeader, v interface{}) ([]byte, error) { + return Request(url, POST, contentType, header, v) +} + +func PutByHeader(url string, contentType ContentType, header RequestHeader, v interface{}) ([]byte, error) { + return Request(url, PUT, contentType, header, v) +} + +func DelByHeader(url string, header RequestHeader) ([]byte, error) { + return Request(url, DELETE, ContentTypePlain, header, nil) +} + +func GetJson(url string, v interface{}) ([]byte, error) { + return Request(url, GET, ContentTypeJson, nil, v) +} + +func PostJson(url string, v interface{}) ([]byte, error) { + return Request(url, POST, ContentTypeJson, nil, v) +} + +func PutJson(url string, v interface{}) ([]byte, error) { + return Request(url, PUT, ContentTypeJson, nil, v) +} + +func DelJson(url string, v interface{}) ([]byte, error) { + return Request(url, DELETE, ContentTypeJson, nil, v) +} + +func PostJsonByHeader(url string, header RequestHeader, v interface{}) ([]byte, error) { + return Request(url, POST, ContentTypeJson, header, v) +} + +func PutJsonByHeader(url string, header RequestHeader, v interface{}) ([]byte, error) { + return Request(url, PUT, ContentTypeJson, header, v) +} + +func Request(url string, method RequestMethod, contentType ContentType, header RequestHeader, v interface{}) ([]byte, error) { + var body io.Reader + var err error + + //PrintInfo("response URL:") + //PrintInfo(url) + + switch contentType { + case ContentTypePlain: + //return nil, fmt.Errorf("unsupported content-type:%s", contentType) + case ContentTypeHtml: + return nil, fmt.Errorf("unsupported content-type:%s", contentType) + case ContentTypeXml: + return nil, fmt.Errorf("unsupported content-type:%s", contentType) + case ContentTypeForm: + return nil, fmt.Errorf("unsupported content-type:%s", contentType) + case ContentTypeJson: + body, err = toJson(v) + case ContentTypeFile: + return nil, fmt.Errorf("unsupported content-type:%s", contentType) + default: + return nil, fmt.Errorf("invalid content-type:%s", contentType) + } + + if err != nil { + return nil, err + } + + tran := &http.Transport{ + //TLSClientConfig: loadTlsConfig(), + } + + client := &http.Client{Transport: tran, Timeout: time.Second * 180} + req, err := http.NewRequest(string(method), url, body) + + if err != nil { + return nil, err + } + + req.Header.Set("Connection", "keep-alive") + + if len(contentType) == 0 { + contentType = ContentTypePlain + } + req.Header.Set("Content-Type", string(contentType)) + + if len(header) > 0 { + for k, vs := range header { + req.Header.Set(k, vs[0]) + for i := 1; i < len(vs); i++ { + req.Header.Add(k, vs[i]) + } + } + } + + rsp, err := client.Do(req) + + if err != nil { + closeBody(rsp) + return nil, err + } + + return readRsp(rsp) +} + +func loadTlsConfig() *tls.Config { + pemFile, err := FindFile("cert/2990195__241210.com.pem") + if err != nil { + panic(err) + } + + keyFile, err := FindFile("cert/2990195__241210.com.key") + if err != nil { + panic(err) + } + + PrintInfo(pemFile) + PrintInfo(keyFile) + + cert, err := tls.LoadX509KeyPair(pemFile, keyFile) + if err != nil { + panic(err) + } + + /*caFile, err := util.FindFile("cert/ca.pem") + if err != nil { + log.Fatalf("load CA cert err: %v", err) + } + + certPool := x509.NewCertPool() + ca, err := ioutil.ReadFile(caFile) + if err != nil { + log.Fatalf("ioutil.ReadFile err: %v", err) + } + + if ok := certPool.AppendCertsFromPEM(ca); !ok { + log.Fatalf("certPool.AppendCertsFromPEM err") + }*/ + + tlsCfg := &tls.Config{ + Certificates: []tls.Certificate{cert}, + //ClientAuth: tls.RequireAndVerifyClientCert, + //ClientCAs: certPool, + InsecureSkipVerify: true, + } + + return tlsCfg +} + +func toJson(v interface{}) (*bytes.Buffer, error) { + if v == nil { + return nil, nil + } + + b, err := json.Marshal(v) + if err != nil { + return nil, err + } + + //PrintInfo("response data:") + //PrintJSON(v) + + return bytes.NewBuffer(b), nil +} + +func readRsp(resp *http.Response) ([]byte, error) { + defer closeBody(resp) + return ioutil.ReadAll(resp.Body) +} + +func closeBody(resp *http.Response) { + if resp != nil && resp.Body != nil { + err := resp.Body.Close() + if err != nil { + PrintErr(err) + } + } +} diff --git a/util/log.go b/util/log.go new file mode 100644 index 0000000..3931e35 --- /dev/null +++ b/util/log.go @@ -0,0 +1,22 @@ +package util + +import ( + "encoding/json" + "fmt" +) + +func PrintInfo(v interface{}) { + fmt.Printf("\x1b[36m%v\x1b[0m\n", v) +} + +func PrintErr(v interface{}) { + fmt.Printf("\x1b[31m%v\x1b[0m\n", v) +} + +func PrintJSON(v interface{}) { + if b, err := json.Marshal(v); err != nil { + PrintErr(fmt.Sprintf("JSON marshal error: %v", err)) + } else { + PrintInfo(string(b)) + } +} diff --git a/util/math.go b/util/math.go new file mode 100644 index 0000000..cdf8c5a --- /dev/null +++ b/util/math.go @@ -0,0 +1,43 @@ +package util + +import ( + "fmt" + "strconv" +) + +//四舍五入,默认保留2位小数位 +func Round(f float64) float64 { + return RoundDecimal(f, 2) +} + +func RoundDecimal(f float64, d int64) float64 { + res, err := strconv.ParseFloat(fmt.Sprintf("%."+strconv.FormatInt(d, 32)+"f", f), 64) + if err != nil { + panic(err) + } + return res +} + +//0.01412 --> 141.2 --> 141.2000 --> 141 +//1.01412 --> 10141.2 --> 10141.2000 --> 10141 +//9.99999 --> 99999.9 --> 99999.9000 --> 99999 + +//0.014199999 --> 141.99999 --> 142.0000 --> 142 +//1.014199999 --> 10141.99999 --> 10142.0000 --> 10142 +//9.999999999 --> 99999.99999 --> 100000.0000 --> 100000 +//9.999999999 --> 9999999.999 --> 10000000.00 --> 10000000 +func GetIntPrice(v float64) int64 { + //6位小数的价格,如:0.034875,四舍五入后向上取整转换为整数保存 + return int64(RoundDecimal(v*1000000, 0)) //价格存储的为4位小数的值 +} + +//1412 --> 0.1412 --> 0.1412 +//101412 --> 10.1412 --> 10.1412 +//999999 --> 99.9999 --> 99.9999 + +//1419999 --> 141.9999 --> 141.9999 +//1014199999 --> 101419.9999 --> 101419.9999 +//999999999 --> 99999.9999 --> 99999.9999 +func GetFloatPrice(v int64) float64 { + return float64(v) / 1000000.00 +} diff --git a/util/order_data.go b/util/order_data.go new file mode 100644 index 0000000..77a2005 --- /dev/null +++ b/util/order_data.go @@ -0,0 +1,107 @@ +package util + +import ( + "regexp" + "strings" + "time" +) + +func substr2(str string, start int, end int) string { + rs := []rune(str) + return string(rs[start:end]) +} + +func HideStar(str string) (result string) { + if str == "" { + return "" + } + if strings.Contains(str, "@") { + res := strings.Split(str, "@") + if len(res[0]) < 3 { + resString := "***" + result = resString + "@" + res[1] + } else { + res2 := substr2(str, 0, 3) + resString := res2 + "***" + result = resString + "@" + res[1] + } + return result + } else { + reg := `^1[0-9]\d{9}$` + rgx := regexp.MustCompile(reg) + mobileMatch := rgx.MatchString(str) + if mobileMatch { + result = substr2(str, 0, 3) + "****" + substr2(str, 7, 11) + } else { + nameRune := []rune(str) + lens := len(nameRune) + + if lens <= 1 { + result = "***" + } else if lens == 2 { + result = string(nameRune[:1]) + "*" + } else if lens == 3 { + result = string(nameRune[:1]) + "*" + string(nameRune[2:3]) + } else if lens == 4 { + result = string(nameRune[:1]) + "**" + string(nameRune[lens-1:lens]) + } else if lens > 4 { + result = string(nameRune[:2]) + "***" + string(nameRune[lens-2:lens]) + } + } + return + } +} + +func FTime(fTime string) (sTime string) { + if len(fTime) == 0 { + return `` + } + t, _ := time.Parse(time.RFC3339, fTime) + sTime = t.Format("2006-01-02 15:04:05") + return +} + +func GetStatus(status int) (statusInfo string) { + var data = map[int]string{ + 1: "未支付", + 2: "已取消", + 3: "已支付", + 4: "调剂中", + 5: "待收药", + 6: "待自提", + 7: "待配送", + 8: "配送中", + 9: "已通知", + 10: "已完成", + 11: "已删除", + 12: "支付失败", + 13: "有退款", + } + statusInfo = data[status] + + return +} + +func SexToString(sex int) (s string) { + switch sex { + case 1: + s = "男" + case 2: + s = "女" + default: + s = "未知" + } + return +} + +func PayTypeString(p string) (t string) { + switch p { + case "online": + t = "线上收款" + case "offline": + t = "系统外收款" + default: + t = "" + } + return +} diff --git a/util/os.go b/util/os.go new file mode 100644 index 0000000..1abb000 --- /dev/null +++ b/util/os.go @@ -0,0 +1,9 @@ +package util + +import "os" + +func SetEnv(key, value string) { + if err := os.Setenv(key, value); err != nil { + panic(err) + } +} diff --git a/util/pinyin.go b/util/pinyin.go new file mode 100644 index 0000000..3cdb7a9 --- /dev/null +++ b/util/pinyin.go @@ -0,0 +1,90 @@ +package util + +import ( + "bytes" + "strings" + "unicode" + + "github.com/mozillazg/go-pinyin" +) + +func PinyinFirstLetterUpper(hans string) string { + if hans == "" { + return "" + } + + py := getPinyin(hans) + return processPolyphones(hans, py) +} + +func getPinyin(hans string) string { + a := pinyin.NewArgs() + a.Style = pinyin.FIRST_LETTER + a.Heteronym = true + + pys := pinyin.Pinyin(hans, a) + + var buffer bytes.Buffer + + for _, py := range pys { + buffer.WriteString(strings.ToUpper(py[0])) + } + + return buffer.String() +} + +var polyphoneDict = map[string][2]rune{ + "阿": [2]rune{'A', 'E'}, + "参": [2]rune{'C', 'S'}, + "长": [2]rune{'C', 'Z'}, + "术": [2]rune{'S', 'Z'}, +} + +// 处理多音字,目前只支持一个汉字两个多音字的处理 +func processPolyphones(src, py string) string { + srcRune := []rune(src) + keywordIndex := map[int][2]rune{} + + for i, r := range srcRune { + if _, ok := polyphoneDict[string(r)]; ok { + keywordIndex[i] = polyphoneDict[string(r)] + } + } + + if len(keywordIndex) == 0 { + return py + } + + pyRune := []rune(py) + pyRuneReplaced := make([]rune, len(pyRune)) + + for i, r := range pyRune { + pyRuneReplaced[i] = r + + if rs, ok := keywordIndex[i]; ok { + for _, pr := range rs { + if r != pr { + pyRuneReplaced[i] = pr + break + } + } + } + } + + if len(pyRuneReplaced) > 0 { + pyRune = append(pyRune, ',') + pyRune = append(pyRune, pyRuneReplaced...) + } + + return string(pyRune) +} + +//是否是字母字符串 +func IsLetter(s string) bool { + for _, r := range s { + if !unicode.IsLetter(r) { + return false + } + } + return true +} diff --git a/util/slice.go b/util/slice.go new file mode 100644 index 0000000..6e3970c --- /dev/null +++ b/util/slice.go @@ -0,0 +1,19 @@ +package util + +func IsIntValueInList(value int, list []int) bool { + for _, v := range list { + if v == value { + return true + } + } + return false +} + +func IsStringValueInList(value string, list []string) bool { + for _, v := range list { + if v == value { + return true + } + } + return false +} diff --git a/util/snowflake.go b/util/snowflake.go new file mode 100644 index 0000000..fd4c332 --- /dev/null +++ b/util/snowflake.go @@ -0,0 +1,25 @@ +package util + +import ( + "fmt" + "github.com/bwmarrin/snowflake" +) + +var node *snowflake.Node + +func init() { + n, err := snowflake.NewNode(1) + if err != nil { + fmt.Println(err) + return + } + node = n +} + +func GenCodeInt() int64 { + return node.Generate().Int64() +} + +func GenCodeStr() string { + return node.Generate().String() +} diff --git a/util/string.go b/util/string.go new file mode 100644 index 0000000..fe9c060 --- /dev/null +++ b/util/string.go @@ -0,0 +1,70 @@ +package util + +import ( + "fmt" + "math/rand" + "regexp" + "strings" + "time" +) + +// 生成随机数字字符串 +func RandomNumberStr(length int) string { + nums := [10]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + r := len(nums) + rand.Seed(time.Now().UnixNano()) + var sb strings.Builder + for i := 0; i < length; i++ { + // 短信验证码第一位不能是0 + if i == 0 { + fmt.Fprintf(&sb, "%d", nums[1:r][rand.Intn(r-1)]) + } else { + fmt.Fprintf(&sb, "%d", nums[rand.Intn(r)]) + } + } + return sb.String() +} + +func RandStr(size int) string { + src := []string{"1", "2", "3", "4", "5", "6", "7", "8", "8", "0", + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", + "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", + "y", "v", "w", "x", "y", "z", + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", + "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", + "Y", "V", "W", "X", "Y", "Z"} + var res []string + for i := 0; i < size; i++ { + res = append(res, src[rand.Int31n(62)]) + } + return strings.Join(res, "") +} + +func NotEmpty(v interface{}) bool { + return v != nil && v != "" +} + +func CompressStr(str string) string { + if str == "" { + return "" + } + //匹配一个或多个空白符的正则表达式 + reg := regexp.MustCompile("\\s+") + return reg.ReplaceAllString(str, "") +} + +// 通过map主键唯一的特性过滤重复元素 +func RemoveRepByMap(slc []string) []string { + result := []string{} + tempMap := map[string]byte{} // 存放不重复主键 + for _, e := range slc { + if e != "" { + l := len(tempMap) + tempMap[e] = 0 + if len(tempMap) != l { // 加入map后,map长度变化,则元素不重复 + result = append(result, e) + } + } + } + return result +} diff --git a/util/structToMap.go b/util/structToMap.go new file mode 100644 index 0000000..d4855ae --- /dev/null +++ b/util/structToMap.go @@ -0,0 +1,21 @@ +package util + +import "reflect" + +func Struct2Map(obj interface{}) map[string]interface{} { + t := reflect.TypeOf(obj) // 获取 obj 的类型信息 + v := reflect.ValueOf(obj) + if t.Kind() == reflect.Ptr { // 如果是指针,则获取其所指向的元素 + t = t.Elem() + v = v.Elem() + } + + var data = make(map[string]interface{}) + if t.Kind() == reflect.Struct { // 只有结构体可以获取其字段信息 + for i := 0; i < t.NumField(); i++ { + data[t.Field(i).Name] = v.Field(i).Interface() + } + + } + return data +} diff --git a/util/time.go b/util/time.go new file mode 100644 index 0000000..1d8faf0 --- /dev/null +++ b/util/time.go @@ -0,0 +1,377 @@ +package util + +import ( + "fmt" + "math" + "strings" + "time" + + gptypes "github.com/golang/protobuf/ptypes" + gptime "github.com/golang/protobuf/ptypes/timestamp" + "github.com/shopspring/decimal" + "github.com/sirupsen/logrus" +) + +const ( + DEFAULT_LAYOUT = "2006-01-02 15:04:05" + DATE_LAYOUT = "2006-01-02" + TIME_LAYOUT = "15:04:05" + DEFAULT_TIME = "1900-01-01 00:00:00" //0000-00-00 00:00:00 0001-01-01 00:00:00 + STR_LAYOUT = "2006-01-02T15:04:05Z07:00" +) + +func Now() time.Time { + return time.Now().UTC() +} + +func NowPtr() *time.Time { + now := Now() + return &now +} + +func Format(layout string, t time.Time) string { + return t.Format(layout) +} + +func FormatByDefLay(t time.Time) string { + return Format(DEFAULT_LAYOUT, t) +} + +func Parse(layout string, s string) *time.Time { + t, err := time.Parse(layout, s) + if err != nil { + panic(err) + } + return &t +} + +func ParseByDefLay(s string) *time.Time { + return Parse(DEFAULT_LAYOUT, s) +} + +func IsDefaultTime(t time.Time) bool { + defTime := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC) + return defTime.Equal(t.UTC()) +} + +//检查日期 t 是否为日期时间零值:0001-01-01 00:00:00 +0000 UTC +func IsTimeZero(t time.Time) bool { + timeZero := time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC) + return timeZero.Equal(t.UTC()) +} + +func Time2Ts(t time.Time) *gptime.Timestamp { + if IsTimeZero(t) { + return nil + } + ts, err := gptypes.TimestampProto(t) + if err != nil { + return nil + } + return ts +} + +func Uint8ToTs(b *[]uint8) *gptime.Timestamp { + if b == nil || len(*b) == 0 { + return nil + } + s := string(*b) + return Str2TsByDefLay(s) +} + +func Ts2Time(ts *gptime.Timestamp) *time.Time { + if ts == nil { + return nil + } + t, err := gptypes.Timestamp(ts) + + if err != nil { + logrus.Error(err) + return nil + } + + if IsTimeZero(t) { + return nil + } + + return &t +} + +func Str2TsByDefLay(s string) *gptime.Timestamp { + if s == "" { + return nil + } + return Str2Ts("2006-01-02 15:04:05", s) +} + +func Str2Ts(layout, s string) *gptime.Timestamp { + if s == "" { + return nil + } + if layout == "" { + return Str2TsByDefLay(s) + } + + t := Parse(layout, s) + + return Time2Ts(*t) +} + +func Ts2StrByDefLay(ts *gptime.Timestamp) string { + return Ts2Str("2006-01-02 15:04:05", ts) +} + +func Ts2Str(layout string, ts *gptime.Timestamp) string { + t := Ts2Time(ts) + + if t == nil { + return "" + } + + return Format(layout, *t) +} + +//计算截止到当前时间,指定出生日期对应的年龄描述,如:不足1小时、1小时、1天、1个月、1 岁、1岁1个月、1岁1个月5天 +// +func CovAgeCnAtNow(birth time.Time) (day int, ageCn string) { + now := time.Now() + + if !Before(birth, now) { + return 0, "" + } + + since := now.Sub(birth) + hoursSince := int(RoundDecimal(since.Hours(), 0)) + daySince := hoursSince / 24 + + if hoursSince < 1.0 { + return daySince, "不足一小时" + } + if hoursSince < 24 { + return daySince, fmt.Sprintf("%d 小时", hoursSince) + } + + yearSince := now.Year() - birth.Year() + monthSince := now.Month() - birth.Month() + //dayDiff := now.Day() - birth.Day() + + if yearSince == 0 { //同一年 + if monthSince == 0 { //同一月 + if daySince == 0 { //同一天 + return 0, "不足一天" + } else if daySince > 0 { + return daySince, fmt.Sprintf("%d 天", daySince) + } else { + return 0, "" + } + } else if monthSince > 0 { + if daySince == 0 { //同一天 + return hoursSince / 24, fmt.Sprintf("%d 个月", monthSince) + } else if daySince > 0 { + return daySince, fmt.Sprintf("%d 天", daySince) + } else { + return 0, "" + } + } else { + + } + } else if yearSince > 0 { + + } else { + + } + + return 0, "" +} + +//根据结束日期和开始日期,计算年龄,返回包含年龄单位(岁、月、天)的字符串 +//开始日期一般为用户生日,结束日期一般为当前时间 +func CovAgeChinese(start time.Time, end time.Time) (float32, string) { + if IsDefaultTime(start) { + return 0, "" + } + + //start = start.UTC() + //end = end.UTC() + + diff := end.Unix() - start.Unix() + if diff < 0 { + return 0, "" + } + + visitAge := decimal.NewFromFloat(float64(diff)).Div(decimal.NewFromFloat(float64(3600 * 365 * 24))) + f64, _ := visitAge.Float64() + + y := decimal.NewFromFloat(float64(diff)).Div(decimal.NewFromFloat(float64(3600 * 365 * 24))) + yf, _ := y.Float64() + + duration := end.Sub(start) + //三个月以下 + if yf*12 < 3 { + days := duration.Hours() / 24 + + return float32(f64), fmt.Sprintf("%.0f天", math.Ceil(days)) + } + + //三个月以上三岁以下 + if yf*12 > 3 && yf < 3 { + year := duration.Hours() / (24 * 365) + + years := int(year) + months := (year - float64(years)) * 12 + months = math.Floor(months + 0.5) + + imonths := int(RoundDecimal(months, 0)) + + sAge := fmt.Sprintf("%d岁", int(years)) + if imonths == 12 { + sAge = fmt.Sprintf("%d岁", int(years+1)) + } else if imonths > 12 { + sAge = fmt.Sprintf("%d岁%d个月", int(years+1), imonths-12) + } else if imonths < 12 && imonths > 0 { + if years == 0 { + sAge = fmt.Sprintf("%d个月", imonths) + } else { + sAge = fmt.Sprintf("%d岁%d个月", int(years), imonths) + } + } + + return float32(f64), sAge + } + + //三岁以上 + if yf > 3 { + years := duration.Hours() / (24 * 365) + years = RoundDecimal(years, 0) + + return float32(f64), fmt.Sprintf("%d岁", int(years)) + } + + return 0, "" + /*age, ageUnit := CovAgeInt(start, end) + + if age <= 0 { + return "未知" + } + + return GetChineseAge(age, ageUnit)*/ +} + +func GetChineseAge(age int, ageUnit string) string { + if age <= 0 { + return "" + } + switch ageUnit { + case "Y": + return fmt.Sprintf("%d %s", age, "岁") + case "M": + return fmt.Sprintf("%d %s", age, "个月") + case "D": + return fmt.Sprintf("%d %s", age, "天") + case "H": + return "1 天" //fmt.Sprintf( "%d %s", num, "小时") + case "m": + return "1 天" //fmt.Sprintf( "%d %s", num, "分钟") + case "S": + return "1 天" //fmt.Sprintf( "%d %s", num, "秒") + case "N": + return "1 天" //fmt.Sprintf( "%d %s", num, "纳秒") + default: + return "1 天" + } +} + +func CovAgeInt(start time.Time, end time.Time) (int, string) { + start = start.UTC() + end = end.UTC() + + if !Before(start, end) { + return 0, "" + } + + if end.Year() > start.Year() { //不同年 + return end.Year() - start.Year(), "Y" + } else { //同一年 + if end.Month() > start.Month() { //不同月 + return int(end.Month()) - int(start.Month()), "M" + } else { //同一月 + if end.Day() > start.Day() { //不同天 + return end.Day() - start.Day(), "D" + } else { //同一天 + if end.Hour() > start.Hour() { //不同小时 + return end.Hour() - start.Hour(), "H" + } else { //同一小时 + if end.Minute() > start.Minute() { //不同分钟 + return end.Minute() - start.Minute(), "m" + } else { //同一分钟 + if end.Second() > start.Second() { //不同秒 + return end.Second() - start.Second(), "S" + } + } + } + } + } + } + + return end.Nanosecond() - start.Nanosecond(), "N" +} + +//判断是否start为早于end的时间,只判断年月日 +func Before(start time.Time, end time.Time) bool { + if start.Year() < end.Year() { + return true + } + if start.Year() > end.Year() { + return false + } + if start.Year() == end.Year() { //同一年 + if start.Month() < end.Month() { + return true + } + if start.Month() > end.Month() { + return false + } + if start.Month() == end.Month() { //同一月 + if start.Day() < end.Day() { + return true + } + if start.Day() > end.Day() { + return false + } + if start.Day() == end.Day() { + return true //同一天,暂时返回true + } + } + } + + return end.Nanosecond() >= start.Nanosecond() +} + +func StartTime(t time.Time) time.Time { + return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) +} + +func EndTime(t time.Time) time.Time { + return time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 0, t.Location()) +} + +func Strisemptyorzerotime(str string) (res *time.Time) { + if strings.TrimSpace(str) == "" { + return nil + } + t1, e1 := time.Parse(DEFAULT_LAYOUT, str) + if e1 != nil { + t2, e2 := time.Parse(STR_LAYOUT, str) + if e2 != nil { + // + t3, e3 := time.Parse(DATE_LAYOUT, str) + if e3 != nil { + // + return nil + } + return &t3 + } + return &t2 + } + return &t1 +} diff --git a/util/uuid.go b/util/uuid.go new file mode 100644 index 0000000..a993199 --- /dev/null +++ b/util/uuid.go @@ -0,0 +1,124 @@ +package util + +import ( + "encoding/hex" + "fmt" + "regexp" + "sort" + "strings" + + uuid "github.com/satori/go.uuid" +) + +var GUUID *UUIDFactory = new(UUIDFactory) +var EmptyUUID = "00000000-0000-0000-0000-000000000000" + +type UUIDFactory struct { + uid uuid.UUID +} + +func (nu *UUIDFactory) NewV1() *UUIDFactory { + uid := uuid.NewV1() + nu.uid = uid + return nu +} + +func (nu *UUIDFactory) Sort() []byte { + return UUIDToBytes(nu.String()) +} + +func (nu *UUIDFactory) String() string { + return Sort(nu.uid.String()) //strings.Replace(Sort(nu.uid.String()), "-", "", -1) +} + +func BytesToUUID(b []byte) string { + hs := hex.EncodeToString(b) + return hs[0:8] + "-" + hs[8:12] + "-" + hs[12:16] + "-" + hs[16:20] + "-" + hs[20:32] +} + +func UUIDToBytes(s string) []byte { + if s == "" { + fmt.Println("空uid") + return []byte("00000000-0000-0000-0000-000000000000") + } + + if !IsUUID(s) { + fmt.Errorf("非法UUID:%s", s) + } + if strings.Contains(s, "-") { + s = strings.Replace(s, "-", "", -1) + } + + b, err := hex.DecodeString(s) + + if err != nil { + //CheckError(err) + } + + return b +} + +//校验是否为合法的UUID,合法UUID格式为16进制字符和“-”组成,类似如下的格式: +//(1)11e90a62-f2fa-07ce-9e60-0242ac110007 +//(2)11E90A62-F2fa-07ce-9e60-0242ac11000A +//(3)11e90a62f2fa07ce9e600242ac110007 +//(4)11E90A62F2fa07ce9e600242ac11000A +//以下格式字符串为非法UUID: +//(1)11e90a62-f2fa-07ce-9e60-0242ac11000x(包含16进制字符之外的字符“x”,非法) +//(2)11e90a62-f2fa-07ce-9e60-0242ac11000X(包含16进制字符之外的字符“X”,非法) +//(3)11e90a62f2fa07ce9e600242ac11000x(包含16进制字符之外的字符“x”,非法) +//(4)11e90a62f2fa07ce9e600242ac11000X(包含16进制字符之外的字符“X”,非法) +//(5)11e90a62f2fa07ce9e600242ac11000(不包含“-”27位,非法) +//(6)11e90a62-f2fa-07ce-9e60-0242ac11000(31位,非法) +//(7)11e90a62-f2fa-07ce-9e600242ac110007(缺少“-”的31位字符串,非法) +func IsUUID(s string) bool { + const pattern = `[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}|[0-9a-fA-F]{32}` + if b, err := regexp.MatchString(pattern, s); b && err == nil { + return true + } + return false +} + +func Sort(uid string) string { + us := strings.Split(uid, "-") + + var res []string + + res = append(res, us[1]+us[2]) + res = append(res, string([]rune(us[0])[4:8])) + res = append(res, string([]rune(us[0])[:4])) + res = append(res, us[3]) + res = append(res, us[4]) + + return strings.Join(res, "-") +} + +func IsEmptyUUID(uid string) bool { + return len(uid) == 0 || + len(strings.TrimSpace(uid)) == 0 || + uid == "00000000-0000-0000-0000-000000000000" || + uid == "00000000000000000000000000000000" || + uid == "30780000-0000-0000-0000-000000000000" +} + +func IsValidUUID(uid string) bool { + return !IsEmptyUUID(uid) && IsUUID(uid) +} + +// 数组切片去重 +func SliceRemoveDuplicates(slice []string) []string { + sort.Strings(slice) + i := 0 + var j int + for { + if i >= len(slice)-1 { + break + } + + for j = i + 1; j < len(slice) && slice[i] == slice[j]; j++ { + } + slice = append(slice[:i+1], slice[j:]...) + i++ + } + return slice +} diff --git a/web/Dockerfile b/web/Dockerfile new file mode 100644 index 0000000..a6a4cce --- /dev/null +++ b/web/Dockerfile @@ -0,0 +1,18 @@ +FROM repository.241210.com/repository/base/alpine:3.9 + +MAINTAINER mencius + +ENV LANG C.UTF-8 +ENV LANGUAGE C.UTF-8 + +COPY web/conf.yaml /usr/local/bin/conf.yaml +COPY web/gy-uuos-web /usr/local/bin/ + +RUN chmod a+x /usr/local/bin/gy-uuos-web +RUN apk add --no-cache tzdata + +EXPOSE 8080 + +WORKDIR /usr/local/bin/ + +ENTRYPOINT ["gy-uuos-web"] diff --git a/web/conf.yaml b/web/conf.yaml new file mode 100644 index 0000000..500ef47 --- /dev/null +++ b/web/conf.yaml @@ -0,0 +1,113 @@ +version: 3.1.0 +serviceName: gy.micro.web.uuos +address: 8080 +singlepoint: false +domain: test_operate.241210.com + +# jwt 配置 +Jwt: + SigningKey: 'gy_uuos_jwt_signing-key' + #192.168.1.112:31505@dev/123(mysql) + #192.168.1.112:31543@postgres/mzq81lPMl39fdBU(postgres) + #123.56.226.110:31943@dev/123(mysql) +db: + # host: 192.168.1.112 + # port: 31543 + # user: postgres + # password: mzq81lPMl39fdBU + # dbname: gy_uums +# host: 192.168.1.113 +# port: 30543 +# user: postgres +# password: TDps8twpvSjuV7My2xH7favwd8FNG99 + host: 192.168.1.113 + port: 30543 + user: postgres + password: TDps8twpvSjuV7My2xH7favwd8FNG99 + dbname: gy_uums + +db2: + host: 192.168.1.113 + port: 30543 + user: postgres + password: TDps8twpvSjuV7My2xH7favwd8FNG99 + dbname: gy_order +db3: + host: 192.168.1.113 + port: 30543 + user: postgres + password: TDps8twpvSjuV7My2xH7favwd8FNG99 + dbname: gy_cloud + +mail: + username: noreply.service@henganpros.com + password: ABcd1234 + host: smtp.mxhichina.com + port: 465 #465/994/25(usingTls 的值不同,port可能会不一样。) + usingTls: true #true/false + +Gather: + Domain: https://test_bridgeapi.241210.com/bridge + Userid: /orgwx/get_user_id + #secondary 应用参数id + Orgid: a40d11eb-2f81-f672-97fb-d29f0db767e3 + +CompanyWxSync: + #main 企业微信参数id + Id: a40d11eb-2f81-f672-97fb-d29f0db767e3 + PartyId: "7" + +Gyys: + Domain: https://gyys.241210.com + +Redis: + Addr: 192.168.1.113:30637 + +Nats: + Addr: nats://192.168.1.112:4222 + Subject: + disturb: gyys.uuos.need_reg + +Micro: + Registry: + Name: nats + Addrs: nats://192.168.1.113:30422 + Service: + Cipher: gy.micro.service.cipher + +#Minio: +# Addr: upload.241210.com:30006 +# AccessKeyID: hPmDjnka0AAJM9DM +# SecretAccessKey: UN08jvQ00z54xInRGpH7IQmdvspHLXZK +# Ssl: true +# DefaultBucketName: default +Minio: + Addr: 192.168.1.112:30006 + AccessKeyID: tbwGF5jRUHGGamu + SecretAccessKey: TEJzvVcNYNn4DMc + Ssl: false + DefaultBucketName: default + +log: + out: std + formatter: text + jsonPrettyPrint: false + outColor: true + minLevel: debug + reportCaller: true + maxFileSize: 10240 + withLinkFile: true + filePath: logs + fileName: gy_uuos_log.log + rotationTime: 6h + maxAge: 240h + maxRemainCount: 100 + timestampFormat: 2006-01-02 15:04:05 + disableSorting: true + +LogrusHttp: + Url: "https://test_gyys.241210.com/collect" + LogLvl: "info" + +apiAddr: + warningQuery: https://test_operate.241210.com/mss/stock_warning/warning/query diff --git a/web/deployment.yaml b/web/deployment.yaml new file mode 100644 index 0000000..7f32d6a --- /dev/null +++ b/web/deployment.yaml @@ -0,0 +1,46 @@ +apiVersion: v1 +kind: Service +metadata: + name: gy-uuos-web +spec: + ports: + - name: gu + port: 8080 + targetPort: 8080 + selector: + app: gy-uuos-web +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: gy-uuos-web +spec: + replicas: 1 + selector: + matchLabels: + app: gy-uuos-web + strategy: + type: RollingUpdate + template: + metadata: + labels: + app: gy-uuos-web + spec: + serviceAccountName: micro-account + containers: + - name: gpw + image: IMAGE_PATH:IMAGE_TAG + ports: + - name: gpww + containerPort: 8080 + volumeMounts: + - name: configfile + mountPath: /usr/local/bin/conf.yaml + subPath: gy-uuos.yaml + volumes: + - name: configfile + configMap: + name: config-center + items: + - key: gy-uuos.yaml + path: gy-uuos.yaml \ No newline at end of file diff --git a/web/handler/helloworld.go b/web/handler/helloworld.go new file mode 100644 index 0000000..902731f --- /dev/null +++ b/web/handler/helloworld.go @@ -0,0 +1,9 @@ +package handler + +import ( + "github.com/gin-gonic/gin" +) + +func Hello(c *gin.Context) { + c.String(200, "hello world") +} diff --git a/web/main.go b/web/main.go new file mode 100644 index 0000000..dd3a22f --- /dev/null +++ b/web/main.go @@ -0,0 +1,60 @@ +package main + +import ( + "fmt" + "gitea.baoapi.com/root/stu_uuos/lib/logruspan" + "log" + "time" + + "gitea.baoapi.com/root/stu_uuos/lib/nats" + "gitea.baoapi.com/root/stu_uuos/lib/redis" + + "gitea.baoapi.com/root/stu_uuos/micro" + + "gitea.baoapi.com/root/stu_uuos/web/router" + "github.com/micro/go-micro/v2/web" + + "gitea.baoapi.com/root/stu_uuos/config" + "gitea.baoapi.com/root/stu_uuos/lib/db" + "gitea.baoapi.com/root/stu_uuos/logger" + _ "github.com/micro/go-plugins/registry/kubernetes/v2" +) + +func init() { + config.Init() + logger.Init() + logruspan.LogInitHttp() + db.Init() + db.InitTable() + redis.Init() + nats.Init() + micro.InitMicro() + //监听同步任务 +} + +func main() { + + service := web.NewService( + web.Name(config.GetConfig().ServiceName), + web.Version(config.GetConfig().Version), + web.Address(fmt.Sprintf(":%d", config.GetConfig().Address)), + web.RegisterTTL(time.Second*30), + web.RegisterInterval(time.Second*15), + web.Handler(router.Init()), + web.AfterStop(func() error { + return db.Close() + }), + //web.Secure(true), + //web.TLSConfig(gomicro.LoadTlsConfig()), + ) + //handler.InitDatab() + if err := service.Init(); err != nil { + log.Fatal(err) + } + + if err := service.Run(); err != nil { + log.Fatal(err) + } +} + +// t1 diff --git a/web/router/router.go b/web/router/router.go new file mode 100644 index 0000000..3f72dce --- /dev/null +++ b/web/router/router.go @@ -0,0 +1,33 @@ +package router + +import ( + "gitea.baoapi.com/root/stu_uuos/web/handler" + "github.com/gin-gonic/gin" + "net/http" + /* + "gitea.241210.com/operate/uuos/web/handler" + ginmw "gitea.241210.com/operate/uuos/web/middleware" + */) + +func Init() *gin.Engine { + gin.SetMode(gin.ReleaseMode) + router := gin.New() + router.Use(gin.Recovery()) + /* + router.Use(ginmw.LoggerWithMico()) + router.Use(ginmw.Cors()) + router.NoMethod(handler.NoMethod) + router.NoRoute(handler.NoRoute) + router.Any("/", handler.Home) + */ + router.StaticFS("/export", http.Dir("./export/")) + + rb := router.Group("/") + { + rb.GET("", handler.Hello) + } + //获取企业微信人员 + router.POST("/hello", handler.Hello) //新建群聊 + + return router +}