Compare commits

...

No commits in common. "f7b6277f0031d2a39fd3fc88ea3a986034737d58" and "577bd31a25599ced52b7d70e43afd7da60839469" have entirely different histories.

186 changed files with 19185 additions and 22773 deletions

2
.gitattributes vendored
View File

@ -1,2 +0,0 @@
*.go linguist-detectable=true
*.js linguist-detectable=false

View File

@ -1,19 +0,0 @@
name: Build
on: [push, pull_request]
jobs:
frontend-linter:
name: Frontend Linter
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 16
# cache
- uses: c-hive/gha-yarn-cache@v2
with:
directory: ./web
- run: yarn install && yarn run lint
working-directory: ./web

View File

@ -1,84 +1 @@
<h1 align="center" style="border-bottom: none;">📦⚡️ CasBase</h1>
<h3 align="center">An open-source AI knowledge base platform developed by Go and React.</h3>
<p align="center">
<a href="#badge">
<img alt="semantic-release" src="https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg">
</a>
<a href="https://hub.docker.com/r/casbin/casnode">
<img alt="docker pull casbin/casnode" src="https://img.shields.io/docker/pulls/casbin/casnode.svg">
</a>
<a href="https://github.com/casbin/casnode/actions/workflows/build.yml">
<img alt="GitHub Workflow Status (branch)" src="https://github.com/casbin/jcasbin/workflows/build/badge.svg?style=flat-square">
</a>
<a href="https://github.com/casbin/casnode/releases/latest">
<img alt="GitHub Release" src="https://img.shields.io/github/v/release/casbin/casnode.svg">
</a>
<a href="https://hub.docker.com/repository/docker/casbin/casnode">
<img alt="Docker Image Version (latest semver)" src="https://img.shields.io/badge/Docker%20Hub-latest-brightgreen">
</a>
</p>
<p align="center">
<a href="https://goreportcard.com/report/github.com/casbin/casnode">
<img alt="Go Report Card" src="https://goreportcard.com/badge/github.com/casbin/casnode?style=flat-square">
</a>
<a href="https://github.com/casbin/casnode/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/casbin/casnode?style=flat-square" alt="license">
</a>
<a href="https://github.com/casbin/casnode/issues">
<img alt="GitHub issues" src="https://img.shields.io/github/issues/casbin/casnode?style=flat-square">
</a>
<a href="#">
<img alt="GitHub stars" src="https://img.shields.io/github/stars/casbin/casnode?style=flat-square">
</a>
<a href="https://github.com/casbin/casnode/network">
<img alt="GitHub forks" src="https://img.shields.io/github/forks/casbin/casnode?style=flat-square">
</a>
<a href="https://crowdin.com/project/casnode">
<img alt="Crowdin" src="https://badges.crowdin.net/casnode/localized.svg">
</a>
</p>
## Architecture
CasBase contains 2 parts:
| Name | Description | Language |
|----------|--------------------------------|------------------------|
| Frontend | Web frontend UI for CasBase | Javascript + React |
| Backend | RESTful API backend for CasBase | Golang + Beego + MySQL |
## Installation
CasBase uses Casdoor to manage members. So you need to create an organization and an application for CasBase in a Casdoor instance.
### Necessary configuration
#### Setup database
CasBase will store its users, nodes and topics informations in a MySQL database named: `casbase`, will create it if not existed. The DB connection string can be specified at: https://github.com/casbin/casbase/blob/master/conf/app.conf
```ini
dataSourceName = root:123@tcp(localhost:3306)/
```
CasBase uses XORM to connect to DB, so all DBs supported by XORM can also be used.
#### Run casbase
- Configure and run casbase by yourself. If you want to learn more about casbase, you see [casbase installation](https://casbase.org/docs/installation).
- Install casbase using docker. you see [installation by docker](https://casbase.org/docs/Docker).
- Install casbase using BTpanel. you see [installation by BTpanel](https://casbase.org/docs/BTpanel).
- Open browser:
http://localhost:3000/
### Optional configuration
#### Setup your platform to enable some third-party login platform
CasBase uses Casdoor to manage members. If you want to log in with oauth, you should see [casdoor oauth configuration](https://casdoor.org/docs/provider/OAuth).
#### OSS, Mail, and SMS services
CasBase uses Casdoor to upload files to cloud storage, send Emails and send SMSs. See Casdoor for more details.
# casbase

View File

@ -1,17 +1,3 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package casdoor
import (

View File

@ -0,0 +1,95 @@
package casdoor
import (
"github.com/casbin/casbase/util"
"xorm.io/core"
)
type Permission struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
Users []string `xorm:"mediumtext" json:"users"`
Roles []string `xorm:"mediumtext" json:"roles"`
Domains []string `xorm:"mediumtext" json:"domains"`
Model string `xorm:"varchar(100)" json:"model"`
ResourceType string `xorm:"varchar(100)" json:"resourceType"`
Resources []string `xorm:"mediumtext" json:"resources"`
Actions []string `xorm:"mediumtext" json:"actions"`
Effect string `xorm:"varchar(100)" json:"effect"`
IsEnabled bool `json:"isEnabled"`
Submitter string `xorm:"varchar(100)" json:"submitter"`
Approver string `xorm:"varchar(100)" json:"approver"`
ApproveTime string `xorm:"varchar(100)" json:"approveTime"`
State string `xorm:"varchar(100)" json:"state"`
}
func GetPermissions(owner string) []*Permission {
permissions := []*Permission{}
err := adapter.Engine.Desc("created_time").Find(&permissions, &Permission{Owner: owner})
if err != nil {
panic(err)
}
return permissions
}
func getPermission(owner string, name string) *Permission {
if owner == "" || name == "" {
return nil
}
permission := Permission{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&permission)
if err != nil {
panic(err)
}
if existed {
return &permission
} else {
return nil
}
}
func GetPermission(id string) *Permission {
owner, name := util.GetOwnerAndNameFromId(id)
return getPermission(owner, name)
}
func UpdatePermission(id string, permission *Permission) bool {
owner, name := util.GetOwnerAndNameFromId(id)
oldPermission := getPermission(owner, name)
if oldPermission == nil {
return false
}
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(permission)
if err != nil {
panic(err)
}
return affected != 0
}
func AddPermission(permission *Permission) bool {
affected, err := adapter.Engine.Insert(permission)
if err != nil {
panic(err)
}
return affected != 0
}
func DeletePermission(permission *Permission) bool {
affected, err := adapter.Engine.ID(core.PK{permission.Owner, permission.Name}).Delete(&Permission{})
if err != nil {
panic(err)
}
return affected != 0
}

View File

@ -1,73 +0,0 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package casdoor
import "github.com/casdoor/casdoor-go-sdk/auth"
func GetUsers() []*auth.User {
owner := CasdoorOrganization
if adapter == nil {
panic("casdoor adapter is nil")
}
users := []*auth.User{}
err := adapter.Engine.Desc("created_time").Find(&users, &auth.User{Owner: owner})
if err != nil {
panic(err)
}
return users
}
func GetSortedUsers(sorter string, limit int) []*auth.User {
owner := CasdoorOrganization
if adapter == nil {
panic("casdoor adapter is nil")
}
users := []*auth.User{}
err := adapter.Engine.Desc(sorter).Limit(limit, 0).Find(&users, &auth.User{Owner: owner})
if err != nil {
panic(err)
}
return users
}
func GetUser(name string) *auth.User {
owner := CasdoorOrganization
if adapter == nil {
panic("casdoor adapter is nil")
}
if owner == "" || name == "" {
return nil
}
user := auth.User{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&user)
if err != nil {
panic(err)
}
if existed {
return &user
} else {
return nil
}
}

View File

@ -1,19 +1,18 @@
appname = confita
httpport = 12000
runmode = dev
SessionOn = true
redisEndpoint =
copyrequestbody = true
socks5Proxy = "127.0.0.1:10808"
driverName = mysql
dataSourceName = root:123@tcp(localhost:3306)/
dbName = confita
casdoorEndpoint = http://localhost:8000
clientId = 4204b22726f5ff8c9efe
clientSecret = xxx
jwtSecret = CasdoorSecret
casdoorOrganization = "casbin"
casdoorApplication = "app-confita"
casdoorDbName =
cacheExpireSeconds = 60
chromeCtxNum = 1
appname = casbase
httpport = 14000
runmode = dev
SessionOn = true
copyrequestbody = true
driverName = mysql
dataSourceName = root:123@tcp(localhost:3306)/
dbName = casbase
redisEndpoint =
landingFolder = casbase-landing
casdoorEndpoint = http://localhost:8000
clientId = af6b5aa958822fb9dc33
clientSecret = 8bc3010c1c951c8d876b1f311a901ff8deeb93bc
casdoorDbName = casdoor
casdoorOrganization = "casbin"
casdoorApplication = "app-casbase"
cacheDir = "C:/casbase_cache"
appDir = ""

View File

@ -1,28 +0,0 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package conf
import (
"os"
"github.com/astaxie/beego"
)
func GetConfigString(key string) string {
if value, ok := os.LookupEnv(key); ok {
return value
}
return beego.AppConfig.String(key)
}

View File

@ -1,24 +1,10 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
_ "embed"
"github.com/astaxie/beego"
"github.com/casdoor/casdoor-go-sdk/auth"
"github.com/casdoor/casdoor-go-sdk/casdoorsdk"
)
//go:embed token_jwt_key.pem
@ -35,20 +21,20 @@ func InitAuthConfig() {
casdoorOrganization := beego.AppConfig.String("casdoorOrganization")
casdoorApplication := beego.AppConfig.String("casdoorApplication")
auth.InitConfig(casdoorEndpoint, clientId, clientSecret, JwtPublicKey, casdoorOrganization, casdoorApplication)
casdoorsdk.InitConfig(casdoorEndpoint, clientId, clientSecret, JwtPublicKey, casdoorOrganization, casdoorApplication)
}
func (c *ApiController) Signin() {
code := c.Input().Get("code")
state := c.Input().Get("state")
token, err := auth.GetOAuthToken(code, state)
token, err := casdoorsdk.GetOAuthToken(code, state)
if err != nil {
c.ResponseError(err.Error())
return
}
claims, err := auth.ParseJwtToken(token.AccessToken)
claims, err := casdoorsdk.ParseJwtToken(token.AccessToken)
if err != nil {
c.ResponseError(err.Error())
return
@ -61,29 +47,18 @@ func (c *ApiController) Signin() {
}
func (c *ApiController) Signout() {
claims := c.GetSessionClaims()
if claims != nil {
clearUserDuplicated(claims)
}
c.SetSessionClaims(nil)
c.ResponseOk()
}
func (c *ApiController) GetAccount() {
if c.RequireSignedIn() {
_, ok := c.RequireSignedIn()
if !ok {
return
}
claims := c.GetSessionClaims()
if isUserDuplicated(claims) {
if !claims.IsAdmin {
c.ResponseError("you have signed in from another place, this session has been ended")
return
}
}
c.ResponseOk(claims)
}

View File

@ -1,24 +1,10 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"encoding/gob"
"github.com/astaxie/beego"
"github.com/casdoor/casdoor-go-sdk/auth"
"github.com/casdoor/casdoor-go-sdk/casdoorsdk"
)
type ApiController struct {
@ -26,10 +12,10 @@ type ApiController struct {
}
func init() {
gob.Register(auth.Claims{})
gob.Register(casdoorsdk.Claims{})
}
func GetUserName(user *auth.User) string {
func GetUserName(user *casdoorsdk.User) string {
if user == nil {
return ""
}
@ -37,17 +23,17 @@ func GetUserName(user *auth.User) string {
return user.Name
}
func (c *ApiController) GetSessionClaims() *auth.Claims {
func (c *ApiController) GetSessionClaims() *casdoorsdk.Claims {
s := c.GetSession("user")
if s == nil {
return nil
}
claims := s.(auth.Claims)
claims := s.(casdoorsdk.Claims)
return &claims
}
func (c *ApiController) SetSessionClaims(claims *auth.Claims) {
func (c *ApiController) SetSessionClaims(claims *casdoorsdk.Claims) {
if claims == nil {
c.DelSession("user")
return
@ -56,7 +42,7 @@ func (c *ApiController) SetSessionClaims(claims *auth.Claims) {
c.SetSession("user", *claims)
}
func (c *ApiController) GetSessionUser() *auth.User {
func (c *ApiController) GetSessionUser() *casdoorsdk.User {
claims := c.GetSessionClaims()
if claims == nil {
return nil
@ -65,7 +51,7 @@ func (c *ApiController) GetSessionUser() *auth.User {
return &claims.User
}
func (c *ApiController) SetSessionUser(user *auth.User) {
func (c *ApiController) SetSessionUser(user *casdoorsdk.User) {
if user == nil {
c.DelSession("user")
return

View File

@ -1,75 +0,0 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"encoding/json"
"github.com/casbin/confita/object"
)
func (c *ApiController) GetGlobalCodes() {
c.Data["json"] = object.GetGlobalCodes()
c.ServeJSON()
}
func (c *ApiController) GetCodes() {
owner := c.Input().Get("owner")
c.Data["json"] = object.GetCodes(owner)
c.ServeJSON()
}
func (c *ApiController) GetCode() {
id := c.Input().Get("id")
c.Data["json"] = object.GetCode(id)
c.ServeJSON()
}
func (c *ApiController) UpdateCode() {
id := c.Input().Get("id")
var code object.Code
err := json.Unmarshal(c.Ctx.Input.RequestBody, &code)
if err != nil {
panic(err)
}
c.Data["json"] = object.UpdateCode(id, &code)
c.ServeJSON()
}
func (c *ApiController) AddCode() {
var code object.Code
err := json.Unmarshal(c.Ctx.Input.RequestBody, &code)
if err != nil {
panic(err)
}
c.Data["json"] = object.AddCode(&code)
c.ServeJSON()
}
func (c *ApiController) DeleteCode() {
var code object.Code
err := json.Unmarshal(c.Ctx.Input.RequestBody, &code)
if err != nil {
panic(err)
}
c.Data["json"] = object.DeleteCode(&code)
c.ServeJSON()
}

View File

@ -1,75 +0,0 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"encoding/json"
"github.com/casbin/confita/object"
)
func (c *ApiController) GetGlobalConferences() {
c.Data["json"] = object.GetGlobalConferences()
c.ServeJSON()
}
func (c *ApiController) GetConferences() {
owner := c.Input().Get("owner")
c.Data["json"] = object.GetConferences(owner)
c.ServeJSON()
}
func (c *ApiController) GetConference() {
id := c.Input().Get("id")
c.Data["json"] = object.GetConference(id)
c.ServeJSON()
}
func (c *ApiController) UpdateConference() {
id := c.Input().Get("id")
var conference object.Conference
err := json.Unmarshal(c.Ctx.Input.RequestBody, &conference)
if err != nil {
panic(err)
}
c.Data["json"] = object.UpdateConference(id, &conference)
c.ServeJSON()
}
func (c *ApiController) AddConference() {
var conference object.Conference
err := json.Unmarshal(c.Ctx.Input.RequestBody, &conference)
if err != nil {
panic(err)
}
c.Data["json"] = object.AddConference(&conference)
c.ServeJSON()
}
func (c *ApiController) DeleteConference() {
var conference object.Conference
err := json.Unmarshal(c.Ctx.Input.RequestBody, &conference)
if err != nil {
panic(err)
}
c.Data["json"] = object.DeleteConference(&conference)
c.ServeJSON()
}

83
controllers/file.go Normal file
View File

@ -0,0 +1,83 @@
package controllers
import (
"encoding/json"
"mime/multipart"
"github.com/casbin/casbase/object"
)
func (c *ApiController) UpdateFile() {
userName, ok := c.RequireSignedIn()
if !ok {
return
}
storeId := c.Input().Get("store")
key := c.Input().Get("key")
var file object.File
err := json.Unmarshal(c.Ctx.Input.RequestBody, &file)
if err != nil {
panic(err)
}
res := object.UpdateFile(storeId, key, &file)
if res {
addRecordForFile(c, userName, "Update", storeId, key, "", true)
}
c.Data["json"] = res
c.ServeJSON()
}
func (c *ApiController) AddFile() {
userName, ok := c.RequireSignedIn()
if !ok {
return
}
storeId := c.Input().Get("store")
key := c.Input().Get("key")
isLeaf := c.Input().Get("isLeaf") == "1"
filename := c.Input().Get("filename")
var file multipart.File
if isLeaf {
var err error
file, _, err = c.GetFile("file")
if err != nil {
c.ResponseError(err.Error())
return
}
defer file.Close()
}
res, bs := object.AddFile(storeId, key, isLeaf, filename, file)
if res {
addFileToCache(key, filename, bs)
addRecordForFile(c, userName, "Add", storeId, key, filename, isLeaf)
}
c.Data["json"] = res
c.ServeJSON()
}
func (c *ApiController) DeleteFile() {
userName, ok := c.RequireSignedIn()
if !ok {
return
}
storeId := c.Input().Get("store")
key := c.Input().Get("key")
isLeaf := c.Input().Get("isLeaf") == "1"
res := object.DeleteFile(storeId, key, isLeaf)
if res {
addRecordForFile(c, userName, "Delete", storeId, key, "", isLeaf)
}
c.Data["json"] = res
c.ServeJSON()
}

83
controllers/file_cache.go Normal file
View File

@ -0,0 +1,83 @@
package controllers
import (
"fmt"
"strings"
"github.com/astaxie/beego"
"github.com/casbin/casbase/util"
)
var cacheDir string
var appDir string
var cacheMap = map[string]string{}
func init() {
cacheDir = beego.AppConfig.String("cacheDir")
appDir = beego.AppConfig.String("appDir")
}
func getAppPath(filename string) string {
return fmt.Sprintf("%s/%s.ctf", appDir, filename)
}
func getCachePrefix(filename string) string {
if !strings.HasPrefix(filename, "ECG_") && !strings.HasPrefix(filename, "EEG_") && !strings.HasPrefix(filename, "Impedance_") {
return ""
}
tokens := strings.SplitN(filename, "_", 2)
res := tokens[0]
return res
}
func addFileToCache(key string, filename string, bs []byte) {
prefix := getCachePrefix(filename)
if prefix == "" {
return
}
path := fmt.Sprintf("%s/%s/%s", cacheDir, key, filename)
util.EnsureFileFolderExists(path)
util.WriteBytesToPath(bs, path)
}
func (c *ApiController) ActivateFile() {
_, ok := c.RequireSignedIn()
if !ok {
return
}
key := c.Input().Get("key")
filename := c.Input().Get("filename")
prefix := getCachePrefix(filename)
if prefix == "" {
c.Data["json"] = false
c.ServeJSON()
return
}
path := fmt.Sprintf("%s/%s", cacheDir, key)
cacheMap[prefix] = path
fmt.Printf("%v\n", cacheMap)
if !util.FileExist(getAppPath(filename)) {
util.CopyFile(getAppPath(filename), getAppPath(prefix))
}
c.Data["json"] = true
c.ServeJSON()
}
func (c *ApiController) GetActiveFile() {
prefix := c.Input().Get("prefix")
res := ""
if v, ok := cacheMap[prefix]; ok {
res = v
}
c.Data["json"] = res
c.ServeJSON()
}

View File

@ -1,39 +0,0 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import "github.com/casbin/confita/service"
func (c *ApiController) GetGlobalPayments() {
payments, err := service.GetGlobalPayments()
if err != nil {
panic(err)
}
c.Data["json"] = payments
c.ServeJSON()
}
func (c *ApiController) GetPayments() {
owner := c.Input().Get("owner")
payments, err := service.GetPayments(owner)
if err != nil {
panic(err)
}
c.Data["json"] = payments
c.ServeJSON()
}

56
controllers/permission.go Normal file
View File

@ -0,0 +1,56 @@
package controllers
import (
"encoding/json"
"github.com/casbin/casbase/casdoor"
)
func (c *ApiController) GetPermissions() {
owner := c.Input().Get("owner")
c.Data["json"] = casdoor.GetPermissions(owner)
c.ServeJSON()
}
func (c *ApiController) GetPermission() {
id := c.Input().Get("id")
c.Data["json"] = casdoor.GetPermission(id)
c.ServeJSON()
}
func (c *ApiController) UpdatePermission() {
id := c.Input().Get("id")
var permission casdoor.Permission
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)
if err != nil {
panic(err)
}
c.Data["json"] = casdoor.UpdatePermission(id, &permission)
c.ServeJSON()
}
func (c *ApiController) AddPermission() {
var permission casdoor.Permission
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)
if err != nil {
panic(err)
}
c.Data["json"] = casdoor.AddPermission(&permission)
c.ServeJSON()
}
func (c *ApiController) DeletePermission() {
var permission casdoor.Permission
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)
if err != nil {
panic(err)
}
c.Data["json"] = casdoor.DeletePermission(&permission)
c.ServeJSON()
}

View File

@ -1,27 +0,0 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import "github.com/casbin/confita/service"
func (c *ApiController) GetProducts() {
products, err := service.GetProducts()
if err != nil {
panic(err)
}
c.Data["json"] = products
c.ServeJSON()
}

View File

@ -1,144 +0,0 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"encoding/json"
"github.com/casbin/confita/object"
"github.com/casdoor/casdoor-go-sdk/auth"
)
func (c *ApiController) GetGlobalRooms() {
isPublic := c.Input().Get("isPublic")
if isPublic != "1" {
if c.RequireSignedIn() {
return
}
}
rooms := object.GetGlobalRooms()
if isPublic == "1" {
rooms = object.GetPublicRooms(rooms)
}
user := c.GetSessionUser()
if isPublic == "1" && (user == nil || !user.IsAdmin) {
if user == nil {
user = &auth.User{Name: ""}
}
rooms = object.GetMaskedRooms(rooms, user.Name)
}
rooms = object.GetRoomsWithLive(rooms)
c.Data["json"] = rooms
c.ServeJSON()
}
func (c *ApiController) GetRooms() {
if c.RequireSignedIn() {
return
}
owner := c.Input().Get("owner")
rooms := object.GetRooms(owner)
user := c.GetSessionUser()
if !user.IsAdmin {
rooms = object.GetMaskedRooms(rooms, user.Name)
}
rooms = object.GetRoomsWithLive(rooms)
c.Data["json"] = rooms
c.ServeJSON()
}
func (c *ApiController) GetRoom() {
//if c.RequireSignedIn() {
// return
//}
id := c.Input().Get("id")
room := object.GetRoom(id)
user := c.GetSessionUser()
if user == nil {
user = &auth.User{Name: ""}
}
if !user.IsAdmin {
room = object.GetMaskedRoom(room, user.Name)
}
room = object.GetRoomWithLive(room)
c.Data["json"] = room
c.ServeJSON()
}
func (c *ApiController) UpdateRoom() {
id := c.Input().Get("id")
var room object.Room
err := json.Unmarshal(c.Ctx.Input.RequestBody, &room)
if err != nil {
panic(err)
}
c.Data["json"] = object.UpdateRoom(id, &room)
c.ServeJSON()
}
func (c *ApiController) IncrementRoomViewer() {
id := c.Input().Get("id")
c.Data["json"] = object.IncrementRoomViewer(id)
c.ServeJSON()
}
func (c *ApiController) AddRoom() {
var room object.Room
err := json.Unmarshal(c.Ctx.Input.RequestBody, &room)
if err != nil {
panic(err)
}
c.Data["json"] = object.AddRoom(&room)
c.ServeJSON()
}
func (c *ApiController) DeleteRoom() {
var room object.Room
err := json.Unmarshal(c.Ctx.Input.RequestBody, &room)
if err != nil {
panic(err)
}
c.Data["json"] = object.DeleteRoom(&room)
c.ServeJSON()
}
func (c *ApiController) RegisterRoom() {
if c.RequireSignedIn() {
return
}
id := c.Input().Get("id")
username := c.GetSessionUsername()
c.Data["json"] = object.RegisterRoom(id, username)
c.ServeJSON()
}

View File

@ -1,73 +0,0 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"encoding/json"
"time"
"github.com/casbin/confita/object"
)
type MeetingEvent struct {
Event string `json:"event"`
Payload struct {
AccountId string `json:"account_id"`
Object struct {
Duration int `json:"duration"`
StartTime time.Time `json:"start_time"`
Timezone string `json:"timezone"`
EndTime time.Time `json:"end_time"`
Topic string `json:"topic"`
Id string `json:"id"`
Type int `json:"type"`
Uuid string `json:"uuid"`
HostId string `json:"host_id"`
} `json:"object"`
} `json:"payload"`
EventTs int64 `json:"event_ts"`
}
var messageMap map[string]int
func init() {
messageMap = map[string]int{}
}
func (c *ApiController) WebhookRoom() {
// https://marketplace.zoom.us/docs/guides/build/webhook-only-app/
var event MeetingEvent
err := json.Unmarshal(c.Ctx.Input.RequestBody, &event)
if err != nil {
panic(err)
}
status := ""
if event.Event == "webinar.started" {
status = "Started"
} else if event.Event == "webinar.ended" {
status = "Ended"
} else {
c.Data["json"] = true
c.ServeJSON()
return
}
meetingNumber := event.Payload.Object.Id
object.UpdateRoomStatus(meetingNumber, status)
c.Data["json"] = true
c.ServeJSON()
}

View File

@ -1,45 +0,0 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"fmt"
"github.com/casdoor/casdoor-go-sdk/auth"
)
var sessionMap = map[string]int64{}
func clearUserDuplicated(claims *auth.Claims) {
userId := fmt.Sprintf("%s/%s", claims.Owner, claims.Name)
delete(sessionMap, userId)
}
func isUserDuplicated(claims *auth.Claims) bool {
userId := fmt.Sprintf("%s/%s", claims.Owner, claims.Name)
unixTimestamp := claims.IssuedAt.Unix()
sessionUnixTimestamp, ok := sessionMap[userId]
if !ok {
sessionMap[userId] = unixTimestamp
return false
} else {
if unixTimestamp == sessionUnixTimestamp {
return false
} else {
return true
}
}
}

69
controllers/store.go Normal file
View File

@ -0,0 +1,69 @@
package controllers
import (
"encoding/json"
"github.com/casbin/casbase/object"
)
func (c *ApiController) GetGlobalStores() {
c.Data["json"] = object.GetGlobalStores()
c.ServeJSON()
}
func (c *ApiController) GetStores() {
owner := c.Input().Get("owner")
c.Data["json"] = object.GetStores(owner)
c.ServeJSON()
}
func (c *ApiController) GetStore() {
id := c.Input().Get("id")
store := object.GetStore(id)
if store == nil {
c.ResponseError("store is empty")
return
}
store.Populate()
c.Data["json"] = store
c.ServeJSON()
}
func (c *ApiController) UpdateStore() {
id := c.Input().Get("id")
var store object.Store
err := json.Unmarshal(c.Ctx.Input.RequestBody, &store)
if err != nil {
panic(err)
}
c.Data["json"] = object.UpdateStore(id, &store)
c.ServeJSON()
}
func (c *ApiController) AddStore() {
var store object.Store
err := json.Unmarshal(c.Ctx.Input.RequestBody, &store)
if err != nil {
panic(err)
}
c.Data["json"] = object.AddStore(&store)
c.ServeJSON()
}
func (c *ApiController) DeleteStore() {
var store object.Store
err := json.Unmarshal(c.Ctx.Input.RequestBody, &store)
if err != nil {
panic(err)
}
c.Data["json"] = object.DeleteStore(&store)
c.ServeJSON()
}

View File

@ -1,75 +0,0 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"encoding/json"
"github.com/casbin/confita/object"
)
func (c *ApiController) GetGlobalSubmissions() {
c.Data["json"] = object.GetGlobalSubmissions()
c.ServeJSON()
}
func (c *ApiController) GetSubmissions() {
owner := c.Input().Get("owner")
c.Data["json"] = object.GetSubmissions(owner)
c.ServeJSON()
}
func (c *ApiController) GetSubmission() {
id := c.Input().Get("id")
c.Data["json"] = object.GetSubmission(id)
c.ServeJSON()
}
func (c *ApiController) UpdateSubmission() {
id := c.Input().Get("id")
var submission object.Submission
err := json.Unmarshal(c.Ctx.Input.RequestBody, &submission)
if err != nil {
panic(err)
}
c.Data["json"] = object.UpdateSubmission(id, &submission)
c.ServeJSON()
}
func (c *ApiController) AddSubmission() {
var submission object.Submission
err := json.Unmarshal(c.Ctx.Input.RequestBody, &submission)
if err != nil {
panic(err)
}
c.Data["json"] = object.AddSubmission(&submission)
c.ServeJSON()
}
func (c *ApiController) DeleteSubmission() {
var submission object.Submission
err := json.Unmarshal(c.Ctx.Input.RequestBody, &submission)
if err != nil {
panic(err)
}
c.Data["json"] = object.DeleteSubmission(&submission)
c.ServeJSON()
}

View File

@ -1,55 +0,0 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"bytes"
"fmt"
"io"
"mime/multipart"
"net/url"
"github.com/casbin/confita/service"
)
func getFileBytes(file *multipart.File) []byte {
buf := bytes.NewBuffer(nil)
if _, err := io.Copy(buf, *file); err != nil {
panic(err)
}
return buf.Bytes()
}
func (c *ApiController) UploadSubmissionFile() {
var resp Response
owner := c.GetSessionUsername()
file, header, err := c.Ctx.Request.FormFile("file")
if err != nil {
panic(err)
}
filename := header.Filename
filename = url.QueryEscape(filename)
fileBytes := getFileBytes(&file)
fileUrl, objectKey := service.UploadFileToStorage(owner, "file", "UploadSubmissionFile", fmt.Sprintf("confita/file/%s/%s/%s", owner, "submissions", filename), fileBytes)
resp = Response{Status: "ok", Msg: fileUrl, Data: len(fileBytes), Data2: objectKey}
c.Data["json"] = resp
c.ServeJSON()
}

View File

@ -1,22 +0,0 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import "github.com/casbin/confita/casdoor"
func (c *ApiController) GetUsers() {
c.Data["json"] = casdoor.GetUsers()
c.ServeJSON()
}

View File

@ -1,17 +1,3 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
type Response struct {
@ -47,13 +33,13 @@ func (c *ApiController) ResponseError(error string, data ...interface{}) {
c.ServeJSON()
}
func (c *ApiController) RequireSignedIn() bool {
if c.GetSessionUser() == nil {
c.ResponseError("please sign in first")
return true
func (c *ApiController) RequireSignedIn() (string, bool) {
userId := c.GetSessionUsername()
if userId == "" {
c.ResponseError("Please sign in first")
return "", false
}
return false
return userId, true
}
func (c *ApiController) RequireAdmin() bool {
@ -65,4 +51,3 @@ func (c *ApiController) RequireAdmin() bool {
return false
}

View File

@ -0,0 +1,58 @@
package controllers
import (
"fmt"
"strings"
"github.com/astaxie/beego/context"
"github.com/casbin/casbase/util"
"github.com/casdoor/casdoor-go-sdk/casdoorsdk"
)
func NewRecord(ctx *context.Context) *casdoorsdk.Record {
ip := strings.Replace(util.GetIPFromRequest(ctx.Request), ": ", "", -1)
action := strings.Replace(ctx.Request.URL.Path, "/api/", "", -1)
requestUri := util.FilterQuery(ctx.Request.RequestURI, []string{"accessToken"})
if len(requestUri) > 1000 {
requestUri = requestUri[0:1000]
}
record := casdoorsdk.Record{
Name: util.GenerateId(),
CreatedTime: util.GetCurrentTime(),
ClientIp: ip,
User: "",
Method: ctx.Request.Method,
RequestUri: requestUri,
Action: action,
IsTriggered: false,
}
return &record
}
func addRecord(c *ApiController, userName string, requestUri string) {
record := NewRecord(c.Ctx)
record.User = userName
if requestUri != "" {
record.RequestUri = requestUri
}
util.SafeGoroutine(func() { casdoorsdk.AddRecord(record) })
}
func addRecordForFile(c *ApiController, userName string, action string, storeId string, key string, filename string, isLeaf bool) {
typ := "Folder"
if isLeaf {
typ = "File"
}
_, storeName := util.GetOwnerAndNameFromId(storeId)
path := fmt.Sprintf("/%s/%s", key, filename)
if filename == "" {
path = key
}
text := fmt.Sprintf("%s%s, Store: %s, Path: %s", action, typ, storeName, path)
addRecord(c, userName, text)
}

61
controllers/vectorset.go Normal file
View File

@ -0,0 +1,61 @@
package controllers
import (
"encoding/json"
"github.com/casbin/casbase/object"
)
func (c *ApiController) GetGlobalVectorsets() {
c.Data["json"] = object.GetGlobalVectorsets()
c.ServeJSON()
}
func (c *ApiController) GetVectorsets() {
owner := c.Input().Get("owner")
c.Data["json"] = object.GetVectorsets(owner)
c.ServeJSON()
}
func (c *ApiController) GetVectorset() {
id := c.Input().Get("id")
c.Data["json"] = object.GetVectorset(id)
c.ServeJSON()
}
func (c *ApiController) UpdateVectorset() {
id := c.Input().Get("id")
var vectorset object.Vectorset
err := json.Unmarshal(c.Ctx.Input.RequestBody, &vectorset)
if err != nil {
panic(err)
}
c.Data["json"] = object.UpdateVectorset(id, &vectorset)
c.ServeJSON()
}
func (c *ApiController) AddVectorset() {
var vectorset object.Vectorset
err := json.Unmarshal(c.Ctx.Input.RequestBody, &vectorset)
if err != nil {
panic(err)
}
c.Data["json"] = object.AddVectorset(&vectorset)
c.ServeJSON()
}
func (c *ApiController) DeleteVectorset() {
var vectorset object.Vectorset
err := json.Unmarshal(c.Ctx.Input.RequestBody, &vectorset)
if err != nil {
panic(err)
}
c.Data["json"] = object.DeleteVectorset(&vectorset)
c.ServeJSON()
}

137
controllers/video.go Normal file
View File

@ -0,0 +1,137 @@
package controllers
import (
"bytes"
"encoding/json"
"fmt"
"io"
"time"
"github.com/casbin/casbase/object"
"github.com/casbin/casbase/util"
"github.com/casbin/casbase/video"
)
func (c *ApiController) GetGlobalVideos() {
c.Data["json"] = object.GetGlobalVideos()
c.ServeJSON()
}
func (c *ApiController) GetVideos() {
owner := c.Input().Get("owner")
c.Data["json"] = object.GetVideos(owner)
c.ServeJSON()
}
func (c *ApiController) GetVideo() {
id := c.Input().Get("id")
video := object.GetVideo(id)
video.Populate()
c.Data["json"] = video
c.ServeJSON()
}
func (c *ApiController) UpdateVideo() {
id := c.Input().Get("id")
var video object.Video
err := json.Unmarshal(c.Ctx.Input.RequestBody, &video)
if err != nil {
panic(err)
}
c.Data["json"] = object.UpdateVideo(id, &video)
c.ServeJSON()
}
func (c *ApiController) AddVideo() {
var video object.Video
err := json.Unmarshal(c.Ctx.Input.RequestBody, &video)
if err != nil {
panic(err)
}
c.Data["json"] = object.AddVideo(&video)
c.ServeJSON()
}
func (c *ApiController) DeleteVideo() {
var video object.Video
err := json.Unmarshal(c.Ctx.Input.RequestBody, &video)
if err != nil {
panic(err)
}
c.Data["json"] = object.DeleteVideo(&video)
c.ServeJSON()
}
func startCoverUrlJob(owner string, name string, videoId string) {
go func(owner string, name string, videoId string) {
for i := 0; i < 20; i++ {
coverUrl := video.GetVideoCoverUrl(videoId)
if coverUrl != "" {
video := object.GetVideo(util.GetIdFromOwnerAndName(owner, name))
if video.CoverUrl != "" {
break
}
video.CoverUrl = coverUrl
object.UpdateVideo(util.GetIdFromOwnerAndName(owner, name), video)
break
}
time.Sleep(time.Second * 5)
}
}(owner, name, videoId)
}
func (c *ApiController) UploadVideo() {
owner := c.GetSessionUsername()
file, header, err := c.GetFile("file")
if err != nil {
panic(err)
}
defer file.Close()
filename := header.Filename
fileId := util.RemoveExt(filename)
fileBuffer := bytes.NewBuffer(nil)
if _, err = io.Copy(fileBuffer, file); err != nil {
c.ResponseError(err.Error())
return
}
fileType := "unknown"
contentType := header.Header.Get("Content-Type")
fileType, _ = util.GetOwnerAndNameFromId(contentType)
if fileType != "video" {
c.ResponseError(fmt.Sprintf("contentType: %s is not video", contentType))
return
}
videoId := video.UploadVideo(fileId, filename, fileBuffer)
if videoId != "" {
startCoverUrlJob(owner, fileId, videoId)
video := &object.Video{
Owner: owner,
Name: fileId,
CreatedTime: util.GetCurrentTime(),
DisplayName: fileId,
VideoId: videoId,
Labels: []*object.Label{},
DataUrls: []string{},
}
object.AddVideo(video)
c.ResponseOk(fileId)
} else {
c.ResponseError("videoId is empty")
}
}

78
controllers/wordset.go Normal file
View File

@ -0,0 +1,78 @@
package controllers
import (
"encoding/json"
"github.com/casbin/casbase/object"
"github.com/casbin/casbase/util"
)
func (c *ApiController) GetGlobalWordsets() {
c.Data["json"] = object.GetGlobalWordsets()
c.ServeJSON()
}
func (c *ApiController) GetWordsets() {
owner := c.Input().Get("owner")
c.Data["json"] = object.GetWordsets(owner)
c.ServeJSON()
}
func (c *ApiController) GetWordset() {
id := c.Input().Get("id")
c.Data["json"] = object.GetWordset(id)
c.ServeJSON()
}
func (c *ApiController) GetWordsetGraph() {
id := c.Input().Get("id")
clusterNumber := util.ParseInt(c.Input().Get("clusterNumber"))
distanceLimit := util.ParseInt(c.Input().Get("distanceLimit"))
c.Data["json"] = object.GetWordsetGraph(id, clusterNumber, distanceLimit)
c.ServeJSON()
}
func (c *ApiController) GetWordsetMatch() {
id := c.Input().Get("id")
c.Data["json"] = object.GetWordsetMatch(id)
c.ServeJSON()
}
func (c *ApiController) UpdateWordset() {
id := c.Input().Get("id")
var wordset object.Wordset
err := json.Unmarshal(c.Ctx.Input.RequestBody, &wordset)
if err != nil {
panic(err)
}
c.Data["json"] = object.UpdateWordset(id, &wordset)
c.ServeJSON()
}
func (c *ApiController) AddWordset() {
var wordset object.Wordset
err := json.Unmarshal(c.Ctx.Input.RequestBody, &wordset)
if err != nil {
panic(err)
}
c.Data["json"] = object.AddWordset(&wordset)
c.ServeJSON()
}
func (c *ApiController) DeleteWordset() {
var wordset object.Wordset
err := json.Unmarshal(c.Ctx.Input.RequestBody, &wordset)
if err != nil {
panic(err)
}
c.Data["json"] = object.DeleteWordset(&wordset)
c.ServeJSON()
}

45
go.mod
View File

@ -1,30 +1,31 @@
module github.com/casbin/confita
module github.com/casbin/casbase
go 1.16
require (
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1790
github.com/aliyun/aliyun-oss-go-sdk v2.1.9+incompatible
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1585
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible
github.com/astaxie/beego v1.12.3
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
github.com/casdoor/casdoor-go-sdk v0.3.3
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/chromedp/chromedp v0.8.6
github.com/cristalhq/jwt/v4 v4.0.0
github.com/go-sql-driver/mysql v1.5.0
github.com/google/go-cmp v0.5.6 // indirect
github.com/google/uuid v1.3.0
github.com/nomeguy/zoom-go v0.0.6
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/onsi/gomega v1.18.1 // indirect
github.com/prometheus/client_golang v1.11.0 // indirect
github.com/satori/go.uuid v1.2.0 // indirect
github.com/stretchr/testify v1.7.1 // indirect
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f // indirect
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
golang.org/x/tools v0.1.5 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
github.com/casdoor/casdoor-go-sdk v0.9.1
github.com/danaugrs/go-tsne/tsne v0.0.0-20220306155740-2250969e057f
github.com/go-sql-driver/mysql v1.6.0
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
github.com/golang/protobuf v1.4.3 // indirect
github.com/google/uuid v1.2.0
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/muesli/clusters v0.0.0-20200529215643-2700303c1762
github.com/muesli/kmeans v0.3.0
github.com/rogpeppe/go-internal v1.8.0 // indirect
github.com/tealeg/xlsx v1.0.5
golang.org/x/crypto v0.0.0-20220208233918-bba287dce954 // indirect
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 // indirect
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
gonum.org/v1/gonum v0.9.3
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v2 v2.3.0 // indirect
xorm.io/core v0.7.3
xorm.io/xorm v1.1.2
xorm.io/xorm v1.2.5
)

552
go.sum
View File

@ -31,24 +31,41 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
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/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
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/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
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/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1790 h1:PRZ7Qund25h+MxuC0WLeX6pdMkag5fb+rLrXe856LZo=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1790/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
github.com/aliyun/aliyun-oss-go-sdk v2.1.9+incompatible h1:mO8fA9l5cQ7r0D2v3WribTT1GGbNVtnVviKM51jH6lI=
github.com/aliyun/aliyun-oss-go-sdk v2.1.9+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1585 h1:ECnkjykkSn3Gsibjd8FrcC+8SMDJcUbJOP4iT2hItrw=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1585/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible h1:9gWa46nstkJ9miBReJcN8Gq34cBFbzSpQZVVT9N09TM=
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.13.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/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/astaxie/beego v1.12.3 h1:SAQkdD2ePye+v8Gn1r4X6IKZM1wd28EyUOVQ3PDSOOQ=
github.com/astaxie/beego v1.12.3/go.mod h1:p3qIm0Ryx7zeBHLljmd7omloyca1s4yu1a8kM1FkpIA=
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA=
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
@ -57,76 +74,106 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
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/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
github.com/casdoor/casdoor-go-sdk v0.3.3 h1:oyUNjpkC6zOEwBtY96qzqIQliQLsHZguOdrwItcGWnY=
github.com/casdoor/casdoor-go-sdk v0.3.3/go.mod h1:MBed3ISHQfXTtoOCAk5T8l5lt4wFvsyynrw0awggydY=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/casdoor/casdoor-go-sdk v0.9.1 h1:z+5nJ4IvP9cNUodLf8wS42AYtDoUCvN6McRB5M+1SAQ=
github.com/casdoor/casdoor-go-sdk v0.9.1/go.mod h1:MBed3ISHQfXTtoOCAk5T8l5lt4wFvsyynrw0awggydY=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
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/chromedp/cdproto v0.0.0-20220924210414-0e3390be1777 h1:nEnjcdmVQjhtQm0RFJxRINMw7lsQ8gidtbpsidiDqpY=
github.com/chromedp/cdproto v0.0.0-20220924210414-0e3390be1777/go.mod h1:5Y4sD/eXpwrChIuxhSr/G20n9CdbCmoerOHnuAf0Zr0=
github.com/chromedp/chromedp v0.8.6 h1:KobeeqR2dpfKSG1prS3Y6+FbffMmGC6xmAobRXA9QEQ=
github.com/chromedp/chromedp v0.8.6/go.mod h1:nBYHoD6YSNzrr82cIeuOzhw1Jo/s2o0QQ+ifTeoCZ+c=
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U=
github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
github.com/cristalhq/jwt/v4 v4.0.0 h1:gy4qHXjr7U8aPn9G8onlLfnC2UpjTyOg9QvEK/sDqq4=
github.com/cristalhq/jwt/v4 v4.0.0/go.mod h1:HnYraSNKDRag1DZP92rYHyrjyQHnVEHPNqesmzs+miQ=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
github.com/danaugrs/go-tsne/tsne v0.0.0-20220306155740-2250969e057f h1:5M3/cWnsF9o5+7/PkKJXtZ0i5XZDnoxBzI8531mXJUM=
github.com/danaugrs/go-tsne/tsne v0.0.0-20220306155740-2250969e057f/go.mod h1:vQ+nFRPFDrDVbRneDNbXPObFFq4ZilZBhYdfNiqSr7k=
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.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
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/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI=
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw=
github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g=
github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks=
github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY=
github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY=
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-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U=
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-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
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-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
github.com/goccy/go-json v0.7.4 h1:B44qRUFwz/vxPKPISQ1KhvzRi9kZ28RAf6YtjriBZ5k=
github.com/goccy/go-json v0.7.4/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
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/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-jwt/jwt/v4 v4.1.0 h1:XUgk2Ex5veyVFVeLm0xhusUTQybEbexJXrvPNOKkSY0=
github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU=
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
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/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@ -150,10 +197,8 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
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-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
@ -168,11 +213,8 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3 h1:x95R7cp+rSeeqAMI2knLtQ0DKlaBhv2NrtrOvafPHRo=
github.com/google/go-cmp v0.5.3/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/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
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/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@ -183,179 +225,382 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
github.com/google/uuid v1.2.0/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/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/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 v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
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/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
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.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
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/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
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/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk=
github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
github.com/jackc/pgconn v1.8.1/go.mod h1:JV6m6b6jhjdmzchES0drzCcYcAHS1OPD5xu3OZ/lE2g=
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0=
github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po=
github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ=
github.com/jackc/pgtype v1.7.0/go.mod h1:ZnHF+rMePVqDKaOfJVI4Q8IVvAQMryDlDkZnKOI75BE=
github.com/jackc/pgtype v1.8.0/go.mod h1:PqDKcEBtllAtk/2p6z6SHdXW5UB+MhE75tUol2OKexE=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA=
github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o=
github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg=
github.com/jackc/pgx/v4 v4.11.0/go.mod h1:i62xJgdrtVDsnL3U8ekyrQXEwGNTRoG7/8r+CIdYfcc=
github.com/jackc/pgx/v4 v4.12.0/go.mod h1:fE547h6VulLPA3kySjfnSG/e2D861g/50JlVUa/ub60=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
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.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
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/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
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/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.3/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/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
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/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
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-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
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/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
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-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
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/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/muesli/clusters v0.0.0-20180605185049-a07a36e67d36/go.mod h1:mw5KDqUj0eLj/6DUNINLVJNoPTFkEuGMHtJsXLviLkY=
github.com/muesli/clusters v0.0.0-20200529215643-2700303c1762 h1:p4A2Jx7Lm3NV98VRMKlyWd3nqf8obft8NfXlAUmqd3I=
github.com/muesli/clusters v0.0.0-20200529215643-2700303c1762/go.mod h1:mw5KDqUj0eLj/6DUNINLVJNoPTFkEuGMHtJsXLviLkY=
github.com/muesli/kmeans v0.3.0 h1:cI2cpeS8m3pm+gTOdzl+7SlzZYSe+x0XoqXUyUvb1ro=
github.com/muesli/kmeans v0.3.0/go.mod h1:eNyybq0tX9/iBEP6EMU4Y7dpmGK0uEhODdZpnG1a/iQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nomeguy/zoom-go v0.0.6 h1:ryr5hY3dSHY5e+mAGSZQDQeX62FZrxinJ81OPqBxTjI=
github.com/nomeguy/zoom-go v0.0.6/go.mod h1:E1EuRYQp1u9xNUznZ3bwFCZSlDKRfY/JrPJ9S/CO23c=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/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.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY=
github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
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/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
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.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
github.com/prometheus/client_golang v1.7.0 h1:wCi7urQOGBsYcQROHqpUUX4ct84xp40t9R9JX0FuA/U=
github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
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/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/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.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
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.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
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/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
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/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s=
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
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.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
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.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/tealeg/xlsx v1.0.5 h1:+f8oFmvY8Gw1iUXzPk+kz+4GpbDZPK1FhPiQRd+ypgE=
github.com/tealeg/xlsx v1.0.5/go.mod h1:btRS8dz54TDnvKNosuAqxrM1QgN1udgk9O34bDCnORM=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/wcharczuk/go-chart/v2 v2.1.0/go.mod h1:yx7MvAVNcP/kN9lKXM/NTce4au4DFN99j6i1OwDclNA=
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
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.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
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/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
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-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-20190411191339-88737f569e3a/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-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f h1:OeJjE6G4dgCY4PIXvIRQbE8+RX+uXZyGhUy/ksMGJoc=
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220208233918-bba287dce954 h1:BkypuErRT9A9I/iljuaG3/zdMjd/J6m8tKKJQtGfSdA=
golang.org/x/crypto v0.0.0-20220208233918-bba287dce954/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-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE=
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/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
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/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20210216034530-4410531fe030/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=
@ -373,14 +618,17 @@ 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/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
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-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@ -391,6 +639,7 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/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-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -401,14 +650,12 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/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-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
@ -417,8 +664,9 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c h1:pkQiBZBvdos9qq4wBAHqlzuZHEXo07pqV06ef90u1WI=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 h1:3B43BWw0xEBsLZ/NO1VALz6fppU3481pik+2Ksv45z8=
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
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=
@ -428,14 +676,18 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/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=
@ -443,11 +695,13 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
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-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/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-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -464,22 +718,17 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -487,28 +736,42 @@ 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.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/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-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
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-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w=
golang.org/x/time v0.0.0-20220411224347-583f2d630306/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-20190425163242-31fd60d6bfdc/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-20190823170909-c4a336ef6a2f/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-20190927191325-030b2cf1153e/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-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@ -516,6 +779,7 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
@ -534,15 +798,24 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78 h1:M8tBwCtWD/cZV9DZpFYRUgaymAYAr+aIUTWzDaM3uPs=
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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/gonum v0.9.3 h1:DnoIG+QAMaF5NvxnGe/oKsgKcAc6PcUyl8q0VetfQ8s=
gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0=
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc=
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=
gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY=
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=
@ -560,6 +833,7 @@ google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
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.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@ -572,6 +846,7 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn
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-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
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=
@ -596,10 +871,15 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
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.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
@ -617,36 +897,40 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
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/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI=
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
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/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.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
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=
@ -654,36 +938,42 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
modernc.org/cc/v3 v3.31.5-0.20210308123301-7a3e9dab9009 h1:u0oCo5b9wyLr++HF3AN9JicGhkUxJhMz51+8TIZH9N0=
modernc.org/cc/v3 v3.31.5-0.20210308123301-7a3e9dab9009/go.mod h1:0R6jl1aZlIl2avnYfbfHBS1QB6/f+16mihBObaBC878=
modernc.org/ccgo/v3 v3.9.0 h1:JbcEIqjw4Agf+0g3Tc85YvfYqkkFOv6xBwS4zkfqSoA=
modernc.org/ccgo/v3 v3.9.0/go.mod h1:nQbgkn8mwzPdp4mm6BT6+p85ugQ7FrGgIcYaE7nSrpY=
lukechampine.com/uint128 v1.1.1 h1:pnxCASz787iMf+02ssImqk6OLt+Z5QHMoZyUXR4z6JU=
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.33.6 h1:r63dgSzVzRxUpAJFPQWHy1QeZeY1ydNENUDaBx1GqYc=
modernc.org/cc/v3 v3.33.6/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/ccgo/v3 v3.9.5 h1:dEuUSf8WN51rDkprFuAqjfchKEzN0WttP/Py3enBwjk=
modernc.org/ccgo/v3 v3.9.5/go.mod h1:umuo2EP2oDSBnD3ckjaVUXMrmeAw8C8OSICVa0iFf60=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v1.7.13-0.20210308123627-12f642a52bb8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/libc v1.8.0 h1:Pp4uv9g0csgBMpGPABKtkieF6O5MGhfGo6ZiOdlYfR8=
modernc.org/libc v1.8.0/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/libc v1.9.8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/libc v1.9.11 h1:QUxZMs48Ahg2F7SN41aERvMfGLY2HU/ADnB9DC4Yts8=
modernc.org/libc v1.9.11/go.mod h1:NyF3tsA5ArIjJ83XB0JlqhjTabTCHm9aX4XMPHyQn0Q=
modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.2.2 h1:+yFk8hBprV+4c0U9GjFtL+dV3N8hOJ8JCituQcMShFY=
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.4.0 h1:GCjoRaBew8ECCKINQA2nYjzvufFW9YiEuuB+rQ9bn2E=
modernc.org/mathutil v1.4.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.0.4 h1:utMBrFcpnQDdNsmM6asmyH/FM9TqLPS7XF7otpJmrwM=
modernc.org/memory v1.0.4/go.mod h1:nV2OApxradM3/OVbs2/0OsP6nPfakXpi50C7dcoHXlc=
modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A=
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84 h1:rgEUzE849tFlHSoeCrKyS9cZAljC+DY7MdMHKq6R6sY=
modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84/go.mod h1:PGzq6qlhyYjL6uVbSgS6WoF7ZopTW/sI7+7p+mb4ZVU=
modernc.org/strutil v1.1.0 h1:+1/yCzZxY2pZwwrsbH+4T7BQMoLQ9QiBshRC9eicYsc=
modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
modernc.org/tcl v1.5.0/go.mod h1:gb57hj4pO8fRrK54zveIfFXBaMHK3SKJNWcmRw1cRzc=
modernc.org/sqlite v1.11.2 h1:ShWQpeD3ag/bmx6TqidBlIWonWmQaSQKls3aenCbt+w=
modernc.org/sqlite v1.11.2/go.mod h1:+mhs/P1ONd+6G7hcAs6irwDi/bjTQ7nLW6LHRBsEa3A=
modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs=
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
modernc.org/tcl v1.5.5/go.mod h1:ADkaTUuwukkrlhqwERyq0SM8OvyXo7+TjFz7yAF56EI=
modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.0.1-0.20210308123920-1f282aa71362/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
xorm.io/builder v0.3.8 h1:P/wPgRqa9kX5uE0aA1/ukJ23u9KH0aSRpHLwDKXigSE=
xorm.io/builder v0.3.8/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
xorm.io/builder v0.3.9 h1:Sd65/LdWyO7LR8+Cbd+e7mm3sK/7U9k0jS3999IDHMc=
xorm.io/builder v0.3.9/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/core v0.7.3 h1:W8ws1PlrnkS1CZU1YWaYLMQcQilwAmQXU0BJDJon+H0=
xorm.io/core v0.7.3/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=
xorm.io/xorm v1.1.2 h1:bje+1KZvK3m5AHtZNfUDlKEEyuw/IRHT+an0CLIG5TU=
xorm.io/xorm v1.1.2/go.mod h1:Cb0DKYTHbyECMaSfgRnIZp5aiUgQozxcJJ0vzcLGJSg=
xorm.io/xorm v1.2.5 h1:tqN7OhN8P9xi52qBb76I8m5maAJMz/SSbgK2RGPCPbo=
xorm.io/xorm v1.2.5/go.mod h1:fTG8tSjk6O1BYxwuohZUK+S1glnRycsCF05L1qQyEU0=

View File

@ -1,17 +1,3 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package i18n
import (
@ -21,7 +7,7 @@ import (
"regexp"
"strings"
"github.com/casbin/confita/util"
"github.com/casbin/casbase/util"
)
type I18nData map[string]map[string]string

View File

@ -1,17 +1,3 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package i18n
import "testing"

View File

@ -1,23 +1,9 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package i18n
import (
"fmt"
"github.com/casbin/confita/util"
"github.com/casbin/casbase/util"
)
func getI18nFilePath(language string) string {

42
main.go
View File

@ -1,37 +1,17 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"github.com/astaxie/beego"
"github.com/astaxie/beego/context"
"github.com/astaxie/beego/plugins/cors"
_ "github.com/astaxie/beego/session/redis"
"github.com/casbin/confita/casdoor"
"github.com/casbin/confita/conf"
"github.com/casbin/confita/object"
"github.com/casbin/confita/proxy"
"github.com/casbin/confita/routers"
_ "github.com/casbin/confita/routers"
"github.com/casbin/casbase/casdoor"
"github.com/casbin/casbase/object"
"github.com/casbin/casbase/routers"
)
func main() {
object.InitAdapter()
casdoor.InitCasdoorAdapter()
proxy.InitHttpClient()
object.InitRoomClient()
beego.InsertFilter("*", beego.BeforeRouter, cors.Allow(&cors.Options{
AllowOrigins: []string{"*"},
@ -41,26 +21,18 @@ func main() {
AllowCredentials: true,
}))
// Cors Post method issue
// https://github.com/astaxie/beego/issues/1037
beego.InsertFilter("*", beego.BeforeRouter, func(ctx *context.Context) {
if ctx.Input.Method() == "OPTIONS" {
ctx.WriteString("ok")
}
})
//beego.DelStaticPath("/static")
beego.SetStaticPath("/static", "web/build/static")
// https://studygolang.com/articles/2303
beego.InsertFilter("*", beego.BeforeRouter, routers.BotFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.Static)
beego.InsertFilter("/", beego.BeforeRouter, routers.TransparentStatic) // must has this for default page
beego.InsertFilter("/*", beego.BeforeRouter, routers.TransparentStatic)
if conf.GetConfigString("redisEndpoint") == "" {
if beego.AppConfig.String("redisEndpoint") == "" {
beego.BConfig.WebConfig.Session.SessionProvider = "file"
beego.BConfig.WebConfig.Session.SessionProviderConfig = "./tmp"
} else {
beego.BConfig.WebConfig.Session.SessionProvider = "redis"
beego.BConfig.WebConfig.Session.SessionProviderConfig = conf.GetConfigString("redisEndpoint")
beego.BConfig.WebConfig.Session.SessionProviderConfig = beego.AppConfig.String("redisEndpoint")
}
beego.BConfig.WebConfig.Session.SessionGCMaxLifetime = 3600 * 24 * 365

View File

@ -1,17 +1,3 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
@ -99,22 +85,22 @@ func (a *Adapter) close() {
}
func (a *Adapter) createTable() {
err := a.engine.Sync2(new(Conference))
err := a.engine.Sync2(new(Wordset))
if err != nil {
panic(err)
}
err = a.engine.Sync2(new(Code))
err = a.engine.Sync2(new(Vectorset))
if err != nil {
panic(err)
}
err = a.engine.Sync2(new(Submission))
err = a.engine.Sync2(new(Video))
if err != nil {
panic(err)
}
err = a.engine.Sync2(new(Room))
err = a.engine.Sync2(new(Store))
if err != nil {
panic(err)
}

View File

@ -1,102 +0,0 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"github.com/casbin/confita/util"
"xorm.io/core"
)
type Code struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
Notebook string `xorm:"varchar(100)" json:"notebook"`
Tags []string `xorm:"varchar(100)" json:"tags"`
ImgUrl string `xorm:"varchar(100)" json:"imgUrl"`
}
func GetGlobalCodes() []*Code {
codes := []*Code{}
err := adapter.engine.Asc("owner").Desc("created_time").Find(&codes)
if err != nil {
panic(err)
}
return codes
}
func GetCodes(owner string) []*Code {
codes := []*Code{}
err := adapter.engine.Desc("created_time").Find(&codes, &Code{Owner: owner})
if err != nil {
panic(err)
}
return codes
}
func getCode(owner string, name string) *Code {
code := Code{Owner: owner, Name: name}
existed, err := adapter.engine.Get(&code)
if err != nil {
panic(err)
}
if existed {
return &code
} else {
return nil
}
}
func GetCode(id string) *Code {
owner, name := util.GetOwnerAndNameFromId(id)
return getCode(owner, name)
}
func UpdateCode(id string, code *Code) bool {
owner, name := util.GetOwnerAndNameFromId(id)
if getCode(owner, name) == nil {
return false
}
_, err := adapter.engine.ID(core.PK{owner, name}).AllCols().Update(code)
if err != nil {
panic(err)
}
//return affected != 0
return true
}
func AddCode(code *Code) bool {
affected, err := adapter.engine.Insert(code)
if err != nil {
panic(err)
}
return affected != 0
}
func DeleteCode(code *Code) bool {
affected, err := adapter.engine.ID(core.PK{code.Owner, code.Name}).Delete(&Code{})
if err != nil {
panic(err)
}
return affected != 0
}

View File

@ -1,133 +0,0 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"github.com/casbin/confita/util"
"xorm.io/core"
)
type TreeItem struct {
Key string `xorm:"varchar(100)" json:"key"`
Title string `xorm:"varchar(100)" json:"title"`
Content string `xorm:"mediumtext" json:"content"`
TitleEn string `xorm:"varchar(100)" json:"titleEn"`
ContentEn string `xorm:"mediumtext" json:"contentEn"`
Children []*TreeItem `xorm:"varchar(1000)" json:"children"`
}
type Conference struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
Type string `xorm:"varchar(100)" json:"type"`
Introduction string `xorm:"mediumtext" json:"introduction"`
StartDate string `xorm:"varchar(100)" json:"startDate"`
EndDate string `xorm:"varchar(100)" json:"endDate"`
Organizer string `xorm:"varchar(100)" json:"organizer"`
Carousels []string `xorm:"mediumtext" json:"carousels"`
CarouselHeight string `xorm:"varchar(100)" json:"carouselHeight"`
Tags []string `xorm:"mediumtext" json:"tags"`
DatasetUrl string `xorm:"varchar(100)" json:"datasetUrl"`
DatasetPreviewUrl string `xorm:"varchar(100)" json:"datasetPreviewUrl"`
PreviewData string `xorm:"mediumtext" json:"previewData"`
ResultUrl string `xorm:"varchar(100)" json:"resultUrl"`
Bonus int `json:"bonus"`
PersonCount int `json:"personCount"`
DisplayState string `xorm:"varchar(100)" json:"displayState"`
Status string `xorm:"varchar(100)" json:"status"`
Language string `xorm:"varchar(100)" json:"language"`
Location string `xorm:"varchar(100)" json:"location"`
Address string `xorm:"varchar(100)" json:"address"`
EnableSubmission bool `json:"enableSubmission"`
DefaultItem string `xorm:"mediumtext" json:"defaultItem"`
TreeItems []*TreeItem `xorm:"mediumtext" json:"treeItems"`
}
func GetGlobalConferences() []*Conference {
conferences := []*Conference{}
err := adapter.engine.Asc("owner").Desc("created_time").Find(&conferences)
if err != nil {
panic(err)
}
return conferences
}
func GetConferences(owner string) []*Conference {
conferences := []*Conference{}
err := adapter.engine.Desc("created_time").Find(&conferences, &Conference{Owner: owner})
if err != nil {
panic(err)
}
return conferences
}
func getConference(owner string, name string) *Conference {
conference := Conference{Owner: owner, Name: name}
existed, err := adapter.engine.Get(&conference)
if err != nil {
panic(err)
}
if existed {
return &conference
} else {
return nil
}
}
func GetConference(id string) *Conference {
owner, name := util.GetOwnerAndNameFromId(id)
return getConference(owner, name)
}
func UpdateConference(id string, conference *Conference) bool {
owner, name := util.GetOwnerAndNameFromId(id)
if getConference(owner, name) == nil {
return false
}
_, err := adapter.engine.ID(core.PK{owner, name}).AllCols().Update(conference)
if err != nil {
panic(err)
}
//return affected != 0
return true
}
func AddConference(conference *Conference) bool {
affected, err := adapter.engine.Insert(conference)
if err != nil {
panic(err)
}
return affected != 0
}
func DeleteConference(conference *Conference) bool {
affected, err := adapter.engine.ID(core.PK{conference.Owner, conference.Name}).Delete(&Conference{})
if err != nil {
panic(err)
}
return affected != 0
}

58
object/file.go Normal file
View File

@ -0,0 +1,58 @@
package object
import (
"bytes"
"fmt"
"io"
"mime/multipart"
"strings"
"github.com/casbin/casbase/storage"
)
func UpdateFile(storeId string, key string, file *File) bool {
return true
}
func AddFile(storeId string, key string, isLeaf bool, filename string, file multipart.File) (bool, []byte) {
store := GetStore(storeId)
if store == nil {
return false, nil
}
var objectKey string
var fileBuffer *bytes.Buffer
if isLeaf {
objectKey = fmt.Sprintf("%s/%s", key, filename)
objectKey = strings.TrimLeft(objectKey, "/")
fileBuffer = bytes.NewBuffer(nil)
if _, err := io.Copy(fileBuffer, file); err != nil {
panic(err)
}
} else {
objectKey = fmt.Sprintf("%s/%s/_hidden.ini", key, filename)
objectKey = strings.TrimLeft(objectKey, "/")
fileBuffer = bytes.NewBuffer(nil)
}
bs := fileBuffer.Bytes()
storage.PutObject(store.Bucket, objectKey, fileBuffer)
return true, bs
}
func DeleteFile(storeId string, key string, isLeaf bool) bool {
store := GetStore(storeId)
if store == nil {
return false
}
if isLeaf {
storage.DeleteObject(store.Bucket, key)
} else {
objects := storage.ListObjects(store.Bucket, key)
for _, object := range objects {
storage.DeleteObject(store.Bucket, object.Key)
}
}
return true
}

61
object/graph.go Normal file
View File

@ -0,0 +1,61 @@
package object
type Node struct {
Id string `json:"id"`
Name string `json:"name"`
Value int `json:"val"`
Color string `json:"color"`
Tag string `json:"tag"`
Weight int `json:"weight"`
}
func newNode(id string, name string, value int, color string, tag string, weight int) *Node {
n := Node{}
n.Id = id
n.Name = name
n.Value = value
n.Color = color
n.Tag = tag
n.Weight = weight
return &n
}
type Link struct {
Name string `json:"name"`
Source string `json:"source"`
Target string `json:"target"`
Value int `json:"value"`
Color string `json:"color"`
Tag string `json:"tag"`
}
func newLink(name string, source string, target string, value int, color string, tag string) *Link {
l := Link{}
l.Name = name
l.Source = source
l.Target = target
l.Value = value
l.Color = color
l.Tag = tag
return &l
}
type Graph struct {
Nodes []*Node `json:"nodes"`
Links []*Link `json:"links"`
}
func newGraph() *Graph {
g := Graph{}
return &g
}
func (g *Graph) addNode(id string, name string, value int, color string, tag string, weight int) {
n := newNode(id, name, value, color, tag, weight)
g.Nodes = append(g.Nodes, n)
}
func (g *Graph) addLink(name string, source string, target string, value int, color string, tag string) {
l := newLink(name, source, target, value, color, tag)
g.Links = append(g.Links, l)
}

67
object/kmeans.go Normal file
View File

@ -0,0 +1,67 @@
package object
import (
"fmt"
"strconv"
"strings"
"github.com/casbin/casbase/util"
"github.com/muesli/clusters"
"github.com/muesli/kmeans"
)
func fa2Str(floatArray []float64) string {
sData := []string{}
for _, f := range floatArray {
sData = append(sData, fmt.Sprintf("%f", f))
}
return strings.Join(sData, "|")
}
func runKmeans(vectors []*Vector, clusterNumber int) {
vectorMap := map[string]*Vector{}
var d clusters.Observations
for _, vector := range vectors {
if len(vector.Data) == 0 {
continue
}
dataKey := vector.GetDataKey()
vectorMap[dataKey] = vector
d = append(d, clusters.Coordinates(vector.Data))
}
km := kmeans.New()
cs, err := km.Partition(d, clusterNumber)
if err != nil {
panic(err)
}
for i, c := range cs {
fmt.Printf("Centered at x: %.2f y: %.2f\n", c.Center[0], c.Center[1])
fmt.Printf("Matching data points: %+v\n\n", c.Observations)
color := util.GetRandomColor()
for _, observation := range c.Observations {
floatArray := observation.Coordinates()
dataKey := fa2Str(floatArray)
vector, ok := vectorMap[dataKey]
if !ok {
panic(fmt.Errorf("vectorMap vector not found, dataKey = %s", dataKey))
}
vector.Category = strconv.Itoa(i)
vector.Color = color
}
}
}
func updateWordsetVectorCategories(owner string, wordsetName string) {
wordset := getWordset(owner, wordsetName)
runKmeans(wordset.Vectors, 100)
UpdateWordset(wordset.GetId(), wordset)
}

9
object/kmeans_test.go Normal file
View File

@ -0,0 +1,9 @@
package object
import "testing"
func TestUpdateWordsetVectorCategories(t *testing.T) {
InitConfig()
updateWordsetVectorCategories("admin", "word")
}

View File

@ -1,155 +0,0 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"strings"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
"github.com/aliyun/alibaba-cloud-sdk-go/services/live"
)
var LiveClient *live.Client
func init() {
LiveClient = getLiveClient()
}
func getLiveClient() *live.Client {
config := sdk.NewConfig()
credential := credentials.NewAccessKeyCredential(clientId, clientSecret)
client, err := live.NewClientWithOptions("cn-beijing", config, credential)
if err != nil {
panic(err)
}
return client
}
func getLiveDomainOnlineCount(room *Room) map[string]int {
if room.StreamingDomain == "" {
return nil
}
request := live.CreateDescribeLiveDomainOnlineUserNumRequest()
request.Scheme = "https"
request.DomainName = room.StreamingDomain
response, err := LiveClient.DescribeLiveDomainOnlineUserNum(request)
if err != nil {
fmt.Println(err)
return nil
}
res := map[string]int{}
for _, streamInfo := range response.OnlineUserInfo.LiveStreamOnlineUserNumInfo {
tokens := strings.Split(streamInfo.StreamName, "/")
streamName := tokens[len(tokens)-1]
res[streamName] = 0
for _, subStreamInfo := range streamInfo.Infos.Info {
res[streamName] += int(subStreamInfo.UserNumber)
}
}
return res
}
func getLiveStreamOnlineMap(room *Room) map[string]int {
if room.IngestDomain == "" {
return nil
}
request := live.CreateDescribeLiveStreamsOnlineListRequest()
request.Scheme = "https"
request.DomainName = room.IngestDomain
request.AppName = room.Conference
request.StreamName = room.Name
response, err := LiveClient.DescribeLiveStreamsOnlineList(request)
if err != nil {
panic(err)
}
res := map[string]int{}
for _, info := range response.OnlineInfo.LiveStreamOnlineInfo {
res[info.StreamName] = 1
}
return res
}
func GetRoomWithLive(room *Room) *Room {
if room.IngestDomain == "" {
return room
}
domainOnlineCountMap := getLiveDomainOnlineCount(room)
streamOnlineMap := getLiveStreamOnlineMap(room)
_, isLive := streamOnlineMap[room.Name]
room.IsLive = isLive
if isLive {
if domainOnlineCountMap != nil {
room.LiveUserCount = domainOnlineCountMap[room.Name]
}
}
return room
}
func GetRoomsWithLive(rooms []*Room) []*Room {
if len(rooms) == 0 {
return rooms
}
isEnded := true
for _, room := range rooms {
if room.MeetingNumber != "" && room.MeetingNumber != "123456789" {
isEnded = false
}
}
if isEnded {
return rooms
}
var roomWithDomain *Room = nil
for _, room := range rooms {
if room.StreamingDomain != "" {
roomWithDomain = room
break
}
}
domainOnlineCountMap := getLiveDomainOnlineCount(roomWithDomain)
for _, room := range rooms {
if room.IngestDomain == "" {
continue
}
streamOnlineMap := getLiveStreamOnlineMap(room)
_, isLive := streamOnlineMap[room.Name]
room.IsLive = isLive
if isLive {
if domainOnlineCountMap != nil {
room.LiveUserCount = domainOnlineCountMap[room.Name]
}
}
}
return rooms
}

View File

@ -1,4 +0,0 @@
package object
var clientId = "xxx"
var clientSecret = "xxx"

View File

@ -1,32 +0,0 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"testing"
"time"
)
func TestGetLive(t *testing.T) {
InitConfig()
for {
room := getRoom("admin", "seminar_1")
fmt.Printf("%v, %v\n", getLiveStreamOnlineMap(room), getLiveDomainOnlineCount(room))
time.Sleep(time.Second)
}
}

View File

@ -1,338 +0,0 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"strings"
"time"
"github.com/casbin/confita/casdoor"
"github.com/casbin/confita/util"
"xorm.io/core"
)
type Participant struct {
Name string `xorm:"varchar(100)" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
Email string `xorm:"varchar(100)" json:"email"`
Affiliation string `xorm:"varchar(100)" json:"affiliation"`
Tag string `xorm:"varchar(100)" json:"tag"`
Role string `xorm:"varchar(100)" json:"role"`
JoinUrl string `xorm:"varchar(500)" json:"joinUrl"`
}
type Slot struct {
Type string `xorm:"varchar(100)" json:"type"`
Date string `xorm:"varchar(100)" json:"date"`
StartTime string `xorm:"varchar(100)" json:"startTime"`
EndTime string `xorm:"varchar(100)" json:"endTime"`
Title string `xorm:"varchar(100)" json:"title"`
Speaker string `xorm:"varchar(100)" json:"speaker"`
Location string `xorm:"varchar(100)" json:"location"`
VideoUrl string `xorm:"varchar(255)" json:"videoUrl"`
}
type Room struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
Conference string `xorm:"varchar(100)" json:"conference"`
Speaker string `xorm:"varchar(100)" json:"speaker"`
Date string `xorm:"varchar(100)" json:"date"`
StartTime string `xorm:"varchar(100)" json:"startTime"`
EndTime string `xorm:"varchar(100)" json:"endTime"`
Location string `xorm:"varchar(100)" json:"location"`
ImageUrl string `xorm:"varchar(100)" json:"imageUrl"`
SdkKey string `xorm:"varchar(100)" json:"sdkKey"`
Signature string `xorm:"varchar(1000)" json:"signature"`
MeetingNumber string `xorm:"varchar(100)" json:"meetingNumber"`
Passcode string `xorm:"varchar(100)" json:"passcode"`
InviteLink string `xorm:"varchar(100)" json:"inviteLink"`
StartUrl string `xorm:"varchar(500)" json:"startUrl"`
Participants []*Participant `xorm:"mediumtext" json:"participants"`
Slots []*Slot `xorm:"mediumtext" json:"slots"`
Status string `xorm:"varchar(100)" json:"status"`
IsPublic bool `json:"isPublic"`
IngestDomain string `xorm:"varchar(100)" json:"ingestDomain"`
IngestAuthKey string `xorm:"varchar(100)" json:"ingestAuthKey"`
StreamingDomain string `xorm:"varchar(100)" json:"streamingDomain"`
StreamingAuthKey string `xorm:"varchar(100)" json:"streamingAuthKey"`
MobileStreamingAuthKey string `xorm:"varchar(100)" json:"mobileStreamingAuthKey"`
VideoWidth int `json:"videoWidth"`
VideoHeight int `json:"videoHeight"`
IsLive bool `json:"isLive"`
LiveUserCount int `json:"liveUserCount"`
ViewerCount int `json:"viewerCount"`
VideoUrl string `xorm:"varchar(255)" json:"videoUrl"`
}
func GetGlobalRooms() []*Room {
rooms := []*Room{}
err := adapter.engine.Desc("created_time").Find(&rooms, &Room{})
if err != nil {
panic(err)
}
for _, room := range rooms {
room.updateRoomStartUrl()
}
return rooms
}
func GetRooms(owner string) []*Room {
rooms := []*Room{}
err := adapter.engine.Desc("created_time").Find(&rooms, &Room{Owner: owner})
if err != nil {
panic(err)
}
for _, room := range rooms {
room.updateRoomStartUrl()
}
return rooms
}
func GetMaskedRoom(room *Room, username string) *Room {
if room == nil {
return nil
}
if room.SdkKey != "" {
room.SdkKey = "***"
}
if room.Signature != "" {
room.Signature = "***"
}
if room.MeetingNumber != "" {
room.MeetingNumber = "***"
}
if room.Passcode != "" {
room.Passcode = "***"
}
if room.InviteLink != "" {
room.InviteLink = "***"
}
if room.StartUrl != "" {
room.StartUrl = "***"
}
for _, participant := range room.Participants {
if participant.Name != username {
if participant.JoinUrl != "" {
participant.JoinUrl = "***"
}
}
}
return room
}
func GetMaskedRooms(rooms []*Room, username string) []*Room {
for _, room := range rooms {
room = GetMaskedRoom(room, username)
}
return rooms
}
func GetPublicRooms(rooms []*Room) []*Room {
res := []*Room{}
for _, room := range rooms {
if room.IsPublic {
res = append(res, room)
}
}
return res
}
func getRoom(owner string, name string) *Room {
room := Room{Owner: owner, Name: name}
existed, err := adapter.engine.Get(&room)
if err != nil {
panic(err)
}
if existed {
return &room
} else {
return nil
}
}
func GetRoom(id string) *Room {
owner, name := util.GetOwnerAndNameFromId(id)
room := getRoom(owner, name)
if room != nil && room.MeetingNumber != "" {
room.Signature = generateSignature(room.MeetingNumber, "1")
room.updateRoomStartUrl()
}
return room
}
func UpdateRoom(id string, room *Room) bool {
owner, name := util.GetOwnerAndNameFromId(id)
if getRoom(owner, name) == nil {
return false
}
if room.MeetingNumber != "" {
room.updateRoomRegistrants()
}
_, err := adapter.engine.ID(core.PK{owner, name}).AllCols().Update(room)
if err != nil {
panic(err)
}
//return affected != 0
return true
}
func IncrementRoomViewer(id string) bool {
room := Room{}
owner, name := util.GetOwnerAndNameFromId(id)
_, err := adapter.engine.ID(core.PK{owner, name}).Incr("viewer_count").Update(room)
if err != nil {
panic(err)
}
//return affected != 0
return true
}
func (p *Room) GetId() string {
return fmt.Sprintf("%s/%s", p.Owner, p.Name)
}
func AddRoom(room *Room) bool {
affected, err := adapter.engine.Insert(room)
if err != nil {
panic(err)
}
return affected != 0
}
func DeleteRoom(room *Room) bool {
affected, err := adapter.engine.ID(core.PK{room.Owner, room.Name}).Delete(&Room{})
if err != nil {
panic(err)
}
return affected != 0
}
func (room *Room) updateRoomRegistrants() {
for i, participant := range room.Participants {
if participant.JoinUrl == "" {
isPanelist := i < 99
joinUrl := addMeetingRegistrant(room.MeetingNumber, participant.Name, participant.DisplayName, participant.Email, participant.Affiliation, isPanelist)
participant.JoinUrl = joinUrl
}
}
}
func RegisterRoom(id string, username string) *Room {
room := GetRoom(id)
if room == nil {
return nil
}
for i, participant := range room.Participants {
if participant.Name == username {
if participant.JoinUrl == "" {
isPanelist := i < 99
joinUrl := addMeetingRegistrant(room.MeetingNumber, participant.Name, participant.DisplayName, participant.Email, participant.Affiliation, isPanelist)
participant.JoinUrl = joinUrl
UpdateRoom(room.GetId(), room)
return room
}
}
}
user := casdoor.GetUser(username)
participant := &Participant{
Name: username,
CreatedTime: util.GetCurrentTime(),
DisplayName: user.DisplayName,
Email: user.Email,
Affiliation: user.Affiliation,
Tag: user.Tag,
Role: "Panelist",
JoinUrl: "",
}
isPanelist := len(room.Participants) < 99
joinUrl := addMeetingRegistrant(room.MeetingNumber, participant.Name, participant.DisplayName, participant.Email, participant.Affiliation, isPanelist)
participant.JoinUrl = joinUrl
room.Participants = append(room.Participants, participant)
UpdateRoom(room.GetId(), room)
return room
}
func (room *Room) updateRoomStartUrl() {
if room.MeetingNumber == "" || room.MeetingNumber == "123456789" {
return
}
if room.StartUrl == "" {
startUrl := getMeetingStartUrl(room.MeetingNumber)
room.StartUrl = startUrl
UpdateRoom(room.GetId(), room)
return
}
tokens := strings.SplitN(room.StartUrl, "?zak=", 2)
if len(tokens) < 2 {
startUrl := getMeetingStartUrl(room.MeetingNumber)
room.StartUrl = startUrl
UpdateRoom(room.GetId(), room)
return
}
zakToken := tokens[1]
zakTokenExpireTime := getZakExpireTime(zakToken)
if zakTokenExpireTime.Before(time.Now()) {
startUrl := getMeetingStartUrl(room.MeetingNumber)
room.StartUrl = startUrl
UpdateRoom(room.GetId(), room)
}
}
func UpdateRoomStatus(meetingNumber string, status string) {
room := Room{Owner: "admin", MeetingNumber: meetingNumber}
_, err := adapter.engine.Get(&room)
if err != nil {
panic(err)
}
room.Status = status
UpdateRoom(room.GetId(), &room)
}

View File

@ -1,98 +0,0 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"encoding/json"
"time"
"github.com/casbin/confita/util"
"github.com/cristalhq/jwt/v4"
)
type JwtPayload struct {
SdkKey string `json:"sdkKey"`
Mn string `json:"mn"`
Role string `json:"role"`
Iat int64 `json:"iat"`
Exp int64 `json:"exp"`
AppKey string `json:"appKey"`
TokenExp int64 `json:"tokenExp"`
}
type ZakClaims struct {
Aud string `json:"aud"`
Uid string `json:"uid"`
Iss string `json:"iss"`
Sk string `json:"sk"`
Sty int `json:"sty"`
Wcd string `json:"wcd"`
Clt int `json:"clt"`
Mnum string `json:"mnum"`
Exp int `json:"exp"`
Iat int `json:"iat"`
Aid string `json:"aid"`
Cid string `json:"cid"`
}
func generateJwtPayload(meetingNumber string, role string) string {
iat := time.Now().Unix() - 30
exp := iat + 60*60*2
payload := JwtPayload{
SdkKey: zoomSdkKey,
Mn: meetingNumber,
Role: role,
Iat: iat,
Exp: exp,
AppKey: zoomSdkKey,
TokenExp: exp,
}
res := util.StructToJsonCompact(payload)
return res
}
func generateSignature(meetingNumber string, role string) string {
examplePayload := generateJwtPayload(meetingNumber, role)
signer, err := jwt.NewSignerHS(jwt.HS256, []byte(zoomSdkSecret))
if err != nil {
panic(err)
}
token, err := jwt.NewBuilder(signer).Build(examplePayload)
if err != nil {
panic(err)
}
return token.String()
}
func getZakExpireTime(token string) time.Time {
tokenBytes := []byte(token)
newToken, err := jwt.ParseNoVerify(tokenBytes)
if err != nil {
panic(err)
}
data := &ZakClaims{}
err = json.Unmarshal(newToken.Claims(), data)
if err != nil {
panic(err)
}
tm := time.Unix(int64(data.Exp), 0)
return tm
}

View File

@ -1,34 +0,0 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"testing"
"time"
)
func TestGenerateSignature(t *testing.T) {
println(generateSignature("123456789", "1"))
}
func TestAddMeetingRegistrant(t *testing.T) {
println(addMeetingRegistrant("123456789", "alice", "Alice", "alice@example.com", "Example Inc.", true))
}
func TestGetZakExpireTime(t *testing.T) {
token := ""
tm := getZakExpireTime(token)
println(tm.Format(time.RFC3339))
}

View File

@ -1,21 +0,0 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
var zoomSdkKey = ""
var zoomSdkSecret = ""
var zoomApiEndpoint = ""
var zoomJwtToken = ""

View File

@ -1,129 +0,0 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"github.com/casbin/confita/proxy"
"github.com/casbin/confita/util"
"github.com/nomeguy/zoom-go/zoomAPI"
)
var zoomClient zoomAPI.Client
func InitRoomClient() {
zoomClient = zoomAPI.NewClient(zoomApiEndpoint, zoomJwtToken, proxy.ProxyHttpClient)
zoomClient.IsWebinar = true
}
func getMeetingStartUrl(meetingNumber string) string {
meetingId := util.ParseInt(meetingNumber)
resp, err := zoomClient.GetMeeting(meetingId)
if err != nil {
panic(err)
}
return resp.StartUrl
}
func getMeetingRegistrantId(meetingNumber string, email string) string {
meetingId := util.ParseInt(meetingNumber)
resp, err := zoomClient.ListMeetingRegistrants(meetingId, "pending")
if err != nil {
panic(err)
}
for _, registrant := range resp.Registrants {
if email == registrant.Email {
return registrant.Id
}
}
return ""
}
func approveMeetingRegistrant(meetingNumber string, email string) {
id := getMeetingRegistrantId(meetingNumber, email)
if id == "" {
fmt.Printf("getMeetingRegistrantId() is empty, meetingNumber = %s, email = %s, may be it is panelist\n", meetingNumber, email)
return
}
meetingId := util.ParseInt(meetingNumber)
registrants := []zoomAPI.Registrant{{email, id}}
err := zoomClient.UpdateMeetingRegistrantStatus(meetingId, "approve", registrants)
if err != nil {
panic(err)
}
}
func addMeetingRegistrant(meetingNumber string, name string, displayName string, email string, affiliation string, isPanelist bool) string {
var resp zoomAPI.AddMeetingRegistrantResponse
var err error
email = fmt.Sprintf("%s%s@example-nowhere.com", util.GenerateId()[:8], util.GenerateId()[:8])
phone := fmt.Sprintf("186%s", util.GenerateNumber(10000000, 99999999))
if displayName == "" {
displayName = name
}
meetingId := util.ParseInt(meetingNumber)
resp, err = zoomClient.AddMeetingRegistrant(meetingId,
email,
displayName,
fmt.Sprintf("(%s)", name),
"",
"",
"",
"",
"",
phone,
"",
affiliation,
"",
"",
"",
"",
"",
nil)
if err != nil {
panic(err)
}
approveMeetingRegistrant(meetingNumber, email)
if isPanelist {
addWebinarPanelist(meetingNumber, displayName, email)
}
return resp.JoinUrl
}
func addWebinarPanelist(meetingNumber string, displayName string, email string) {
panelist := zoomAPI.Panelist{
Email: email,
Name: displayName,
}
panelists := []zoomAPI.Panelist{panelist}
meetingId := util.ParseInt(meetingNumber)
err := zoomClient.AddWebinarPanelists(meetingId, panelists)
if err != nil {
panic(err)
}
}

113
object/store.go Normal file
View File

@ -0,0 +1,113 @@
package object
import (
"fmt"
"github.com/casbin/casbase/util"
"xorm.io/core"
)
type File struct {
Key string `xorm:"varchar(100)" json:"key"`
Title string `xorm:"varchar(100)" json:"title"`
Size int64 `json:"size"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
IsLeaf bool `json:"isLeaf"`
Children []*File `xorm:"varchar(1000)" json:"children"`
ChildrenMap map[string]*File `xorm:"-" json:"-"`
}
type Properties struct {
CollectedTime string `xorm:"varchar(100)" json:"collectedTime"`
Subject string `xorm:"varchar(100)" json:"subject"`
}
type Store struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
Bucket string `xorm:"varchar(100)" json:"bucket"`
Domain string `xorm:"varchar(100)" json:"domain"`
FileTree *File `xorm:"mediumtext" json:"fileTree"`
PropertiesMap map[string]*Properties `xorm:"mediumtext" json:"propertiesMap"`
}
func GetGlobalStores() []*Store {
stores := []*Store{}
err := adapter.engine.Asc("owner").Desc("created_time").Find(&stores)
if err != nil {
panic(err)
}
return stores
}
func GetStores(owner string) []*Store {
stores := []*Store{}
err := adapter.engine.Desc("created_time").Find(&stores, &Store{Owner: owner})
if err != nil {
panic(err)
}
return stores
}
func getStore(owner string, name string) *Store {
store := Store{Owner: owner, Name: name}
existed, err := adapter.engine.Get(&store)
if err != nil {
panic(err)
}
if existed {
return &store
} else {
return nil
}
}
func GetStore(id string) *Store {
owner, name := util.GetOwnerAndNameFromId(id)
return getStore(owner, name)
}
func UpdateStore(id string, store *Store) bool {
owner, name := util.GetOwnerAndNameFromId(id)
if getStore(owner, name) == nil {
return false
}
_, err := adapter.engine.ID(core.PK{owner, name}).AllCols().Update(store)
if err != nil {
panic(err)
}
//return affected != 0
return true
}
func AddStore(store *Store) bool {
affected, err := adapter.engine.Insert(store)
if err != nil {
panic(err)
}
return affected != 0
}
func DeleteStore(store *Store) bool {
affected, err := adapter.engine.ID(core.PK{store.Owner, store.Name}).Delete(&Store{})
if err != nil {
panic(err)
}
return affected != 0
}
func (store *Store) GetId() string {
return fmt.Sprintf("%s/%s", store.Owner, store.Name)
}

121
object/store_provider.go Normal file
View File

@ -0,0 +1,121 @@
package object
import (
"fmt"
"strings"
"time"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/casbin/casbase/storage"
)
func (store *Store) createPathIfNotExisted(tokens []string, size int64, lastModifiedTime string, isLeaf bool) {
currentFile := store.FileTree
for i, token := range tokens {
if currentFile.Children == nil {
currentFile.Children = []*File{}
}
if currentFile.ChildrenMap == nil {
currentFile.ChildrenMap = map[string]*File{}
}
tmpFile, ok := currentFile.ChildrenMap[token]
if ok {
currentFile = tmpFile
continue
}
isLeafTmp := false
if i == len(tokens)-1 {
isLeafTmp = isLeaf
}
key := strings.Join(tokens[:i+1], "/")
newFile := &File{
Key: key,
Title: token,
IsLeaf: isLeafTmp,
Children: []*File{},
ChildrenMap: map[string]*File{},
}
if i == len(tokens)-1 {
newFile.Size = size
newFile.CreatedTime = lastModifiedTime
if token == "_hidden.ini" {
continue
}
} else if i == len(tokens)-2 {
if tokens[len(tokens)-1] == "_hidden.ini" {
newFile.CreatedTime = lastModifiedTime
}
}
currentFile.Children = append(currentFile.Children, newFile)
currentFile.ChildrenMap[token] = newFile
currentFile = newFile
}
}
func isObjectLeaf(object *oss.ObjectProperties) bool {
isLeaf := true
if object.Key[len(object.Key)-1] == '/' {
isLeaf = false
}
return isLeaf
}
func (store *Store) Populate() {
objects := storage.ListObjects(store.Bucket, "")
if store.FileTree == nil {
store.FileTree = &File{
Key: "/",
Title: store.DisplayName,
CreatedTime: store.CreatedTime,
IsLeaf: false,
Children: []*File{},
ChildrenMap: map[string]*File{},
}
}
sortedObjects := []oss.ObjectProperties{}
for _, object := range objects {
if strings.HasSuffix(object.Key, "/_hidden.ini") {
sortedObjects = append(sortedObjects, object)
}
}
for _, object := range objects {
if !strings.HasSuffix(object.Key, "/_hidden.ini") {
sortedObjects = append(sortedObjects, object)
}
}
for _, object := range sortedObjects {
lastModifiedTime := object.LastModified.Local().Format(time.RFC3339)
isLeaf := isObjectLeaf(&object)
size := object.Size
tokens := strings.Split(strings.Trim(object.Key, "/"), "/")
store.createPathIfNotExisted(tokens, size, lastModifiedTime, isLeaf)
//fmt.Printf("%s, %d, %v\n", object.Key, object.Size, object.LastModified)
}
}
func (store *Store) GetVideoData() []string {
objects := storage.ListObjects(store.Bucket, "2023/视频附件")
res := []string{}
for _, object := range objects {
if strings.HasSuffix(object.Key, "/_hidden.ini") {
continue
}
url := fmt.Sprintf("%s/%s", store.Domain, object.Key)
res = append(res, url)
}
return res
}

11
object/store_test.go Normal file
View File

@ -0,0 +1,11 @@
package object
import "testing"
func TestUpdateStoreFolders(t *testing.T) {
InitConfig()
store := getStore("admin", "default")
//store.Populate()
store.GetVideoData()
}

View File

@ -1,121 +0,0 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"github.com/casbin/confita/util"
"xorm.io/core"
)
type AuthorItem struct {
Name string `xorm:"varchar(100)" json:"name"`
Affiliation string `xorm:"varchar(100)" json:"affiliation"`
Email string `xorm:"varchar(100)" json:"email"`
IsNotified bool `json:"isNotified"`
IsCorresponding bool `json:"isCorresponding"`
}
type Submission struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
Conference string `xorm:"varchar(100)" json:"conference"`
Title string `xorm:"varchar(100)" json:"title"`
Authors []*AuthorItem `xorm:"varchar(2000)" json:"authors"`
Type string `xorm:"varchar(100)" json:"type"`
SubType string `xorm:"varchar(100)" json:"subType"`
AbsWordFileUrl string `xorm:"varchar(500)" json:"absWordFileUrl"`
AbsPdfFileUrl string `xorm:"varchar(500)" json:"absPdfFileUrl"`
FullWordFileUrl string `xorm:"varchar(500)" json:"fullWordFileUrl"`
FullPdfFileUrl string `xorm:"varchar(500)" json:"fullPdfFileUrl"`
FinalWordFileUrl string `xorm:"varchar(500)" json:"finalWordFileUrl"`
FinalPdfFileUrl string `xorm:"varchar(500)" json:"finalPdfFileUrl"`
Status string `xorm:"varchar(100)" json:"status"`
Code string `xorm:"mediumtext" json:"code"`
}
func GetGlobalSubmissions() []*Submission {
submissions := []*Submission{}
err := adapter.engine.Desc("created_time").Find(&submissions, &Submission{})
if err != nil {
panic(err)
}
return submissions
}
func GetSubmissions(owner string) []*Submission {
submissions := []*Submission{}
err := adapter.engine.Desc("created_time").Find(&submissions, &Submission{Owner: owner})
if err != nil {
panic(err)
}
return submissions
}
func getSubmission(owner string, name string) *Submission {
submission := Submission{Owner: owner, Name: name}
existed, err := adapter.engine.Get(&submission)
if err != nil {
panic(err)
}
if existed {
return &submission
} else {
return nil
}
}
func GetSubmission(id string) *Submission {
owner, name := util.GetOwnerAndNameFromId(id)
return getSubmission(owner, name)
}
func UpdateSubmission(id string, submission *Submission) bool {
owner, name := util.GetOwnerAndNameFromId(id)
if getSubmission(owner, name) == nil {
return false
}
_, err := adapter.engine.ID(core.PK{owner, name}).AllCols().Update(submission)
if err != nil {
panic(err)
}
//return affected != 0
return true
}
func AddSubmission(submission *Submission) bool {
affected, err := adapter.engine.Insert(submission)
if err != nil {
panic(err)
}
return affected != 0
}
func DeleteSubmission(submission *Submission) bool {
affected, err := adapter.engine.ID(core.PK{submission.Owner, submission.Name}).Delete(&Submission{})
if err != nil {
panic(err)
}
return affected != 0
}

21
object/vector.go Normal file
View File

@ -0,0 +1,21 @@
package object
import (
"fmt"
"strings"
)
type Vector struct {
Name string `xorm:"varchar(100)" json:"name"`
Category string `xorm:"varchar(100)" json:"category"`
Color string `xorm:"varchar(100)" json:"color"`
Data []float64 `xorm:"varchar(1000)" json:"data"`
}
func (vector *Vector) GetDataKey() string {
sData := []string{}
for _, f := range vector.Data {
sData = append(sData, fmt.Sprintf("%f", f))
}
return strings.Join(sData, "|")
}

101
object/vectorset.go Normal file
View File

@ -0,0 +1,101 @@
package object
import (
"fmt"
"github.com/casbin/casbase/util"
"xorm.io/core"
)
type Vectorset struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
DisplayName string `xorm:"varchar(500)" json:"displayName"`
Url string `xorm:"varchar(100)" json:"url"`
FileName string `xorm:"varchar(100)" json:"fileName"`
FileSize string `xorm:"varchar(100)" json:"fileSize"`
Dimension int `json:"dimension"`
Count int `json:"count"`
Vectors []*Vector `xorm:"mediumtext" json:"vectors"`
AllVectors []*Vector `xorm:"-" json:"allVectors"`
VectorMap map[string]*Vector `xorm:"-" json:"vectorMap"`
}
func GetGlobalVectorsets() []*Vectorset {
vectorsets := []*Vectorset{}
err := adapter.engine.Asc("owner").Desc("created_time").Find(&vectorsets)
if err != nil {
panic(err)
}
return vectorsets
}
func GetVectorsets(owner string) []*Vectorset {
vectorsets := []*Vectorset{}
err := adapter.engine.Desc("created_time").Find(&vectorsets, &Vectorset{Owner: owner})
if err != nil {
panic(err)
}
return vectorsets
}
func getVectorset(owner string, name string) *Vectorset {
vectorset := Vectorset{Owner: owner, Name: name}
existed, err := adapter.engine.Get(&vectorset)
if err != nil {
panic(err)
}
if existed {
return &vectorset
} else {
return nil
}
}
func GetVectorset(id string) *Vectorset {
owner, name := util.GetOwnerAndNameFromId(id)
return getVectorset(owner, name)
}
func UpdateVectorset(id string, vectorset *Vectorset) bool {
owner, name := util.GetOwnerAndNameFromId(id)
if getVectorset(owner, name) == nil {
return false
}
_, err := adapter.engine.ID(core.PK{owner, name}).AllCols().Update(vectorset)
if err != nil {
panic(err)
}
//return affected != 0
return true
}
func AddVectorset(vectorset *Vectorset) bool {
affected, err := adapter.engine.Insert(vectorset)
if err != nil {
panic(err)
}
return affected != 0
}
func DeleteVectorset(vectorset *Vectorset) bool {
affected, err := adapter.engine.ID(core.PK{vectorset.Owner, vectorset.Name}).Delete(&Vectorset{})
if err != nil {
panic(err)
}
return affected != 0
}
func (vectorset *Vectorset) GetId() string {
return fmt.Sprintf("%s/%s", vectorset.Owner, vectorset.Name)
}

59
object/vectorset_tsne.go Normal file
View File

@ -0,0 +1,59 @@
package object
import (
"fmt"
"github.com/danaugrs/go-tsne/tsne"
"gonum.org/v1/gonum/mat"
)
func testTsne() {
b := mat.NewDense(5, 3, []float64{
0.1, 0.1, 0.1,
0.7, 0.7, 0.7,
0.1, 0.7, 0.5,
0.7, 0.1, 0.2,
0.1, 0.7, 0.5,
})
t := tsne.NewTSNE(2, 300, 100, 300, true)
Y := t.EmbedData(b, func(iter int, divergence float64, embedding mat.Matrix) bool {
fmt.Printf("Iteration %d: divergence is %v\n", iter, divergence)
return false
})
println(Y)
}
func (vectorset *Vectorset) DoTsne(dimension int) {
floatArray := []float64{}
for _, vector := range vectorset.AllVectors {
floatArray = append(floatArray, vector.Data...)
}
X := mat.NewDense(len(vectorset.AllVectors), vectorset.Dimension, floatArray)
t := tsne.NewTSNE(dimension, 300, 100, 300, true)
Y := t.EmbedData(X, func(iter int, divergence float64, embedding mat.Matrix) bool {
fmt.Printf("Iteration %d: divergence is %v\n", iter, divergence)
return false
})
rowCount, columnCount := Y.Dims()
if rowCount != len(vectorset.AllVectors) {
panic("rowCount != len(vectorset.AllVectors)")
}
if columnCount != dimension {
panic("columnCount != dimension")
}
for i, vector := range vectorset.AllVectors {
arr := []float64{}
for j := 0; j < dimension; j++ {
arr = append(arr, Y.At(i, j))
}
vector.Data = arr
}
}

View File

@ -0,0 +1,24 @@
package object
import (
"fmt"
"testing"
)
func TestDoVectorsetTsne(t *testing.T) {
InitConfig()
dimension := 50
//vectorset := getVectorset("admin", "wikipedia")
vectorset := getVectorset("admin", "wordVector_utf-8")
vectorset.LoadVectors("../../tmpFiles/")
vectorset.DoTsne(dimension)
vectorset.Name = fmt.Sprintf("%s_Dim_%d", vectorset.Name, dimension)
vectorset.FileName = fmt.Sprintf("%s_Dim_%d.csv", vectorset.FileName, dimension)
vectorset.FileSize = ""
vectorset.Dimension = dimension
vectorset.WriteVectors("../../tmpFiles/")
AddVectorset(vectorset)
}

View File

@ -0,0 +1,57 @@
package object
import (
"fmt"
"strings"
"github.com/casbin/casbase/util"
)
func (vectorset *Vectorset) LoadVectors(pathPrefix string) {
path := util.GetUploadFilePath(fmt.Sprintf("%s%s", pathPrefix, vectorset.FileName))
var nameArray []string
var dataArray [][]float64
if strings.HasSuffix(vectorset.FileName, ".csv") {
if strings.Contains(vectorset.FileName, "_Dim_") {
nameArray, dataArray = util.LoadVectorFileByCsv2(path)
} else {
nameArray, dataArray = util.LoadVectorFileByCsv(path)
}
} else {
nameArray, dataArray = util.LoadVectorFileBySpace(path)
}
exampleVectors := []*Vector{}
vectors := []*Vector{}
vectorMap := map[string]*Vector{}
for i := 0; i < len(nameArray); i++ {
vector := &Vector{
Name: nameArray[i],
Data: dataArray[i],
}
if i < 100 {
exampleVectors = append(exampleVectors, vector)
}
vectors = append(vectors, vector)
vectorMap[vector.Name] = vector
}
vectorset.Vectors = exampleVectors
vectorset.AllVectors = vectors
vectorset.VectorMap = vectorMap
}
func (vectorset *Vectorset) WriteVectors(pathPrefix string) {
path := util.GetUploadFilePath(fmt.Sprintf("%s%s", pathPrefix, vectorset.FileName))
rows := [][]string{}
for _, vector := range vectorset.AllVectors {
row := util.FloatsToStrings(vector.Data)
row = append([]string{vector.Name}, row...)
rows = append(rows, row)
}
util.WriteCsvFile(path, &rows)
}

View File

@ -0,0 +1,12 @@
package object
import "testing"
func TestUpdateVectorsetVectors(t *testing.T) {
InitConfig()
//vectorset := getVectorset("admin", "wikipedia")
vectorset := getVectorset("admin", "wordVector_utf-8")
vectorset.LoadVectors("../../tmpFiles/")
UpdateVectorset(vectorset.GetId(), vectorset)
}

116
object/video.go Normal file
View File

@ -0,0 +1,116 @@
package object
import (
"fmt"
"github.com/casbin/casbase/util"
"github.com/casbin/casbase/video"
"xorm.io/core"
)
type Label struct {
Id string `xorm:"varchar(100)" json:"id"`
StartTime float64 `json:"startTime"`
EndTime float64 `json:"endTime"`
Text string `xorm:"varchar(100)" json:"text"`
}
type Video struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
DisplayName string `xorm:"varchar(500)" json:"displayName"`
VideoId string `xorm:"varchar(100)" json:"videoId"`
CoverUrl string `xorm:"varchar(200)" json:"coverUrl"`
Labels []*Label `xorm:"mediumtext" json:"labels"`
DataUrls []string `xorm:"mediumtext" json:"dataUrls"`
DataUrl string `xorm:"varchar(200)" json:"dataUrl"`
TagOnPause bool `json:"tagOnPause"`
PlayAuth string `xorm:"-" json:"playAuth"`
}
func GetGlobalVideos() []*Video {
videos := []*Video{}
err := adapter.engine.Asc("owner").Desc("created_time").Find(&videos)
if err != nil {
panic(err)
}
return videos
}
func GetVideos(owner string) []*Video {
videos := []*Video{}
err := adapter.engine.Desc("created_time").Find(&videos, &Video{Owner: owner})
if err != nil {
panic(err)
}
return videos
}
func getVideo(owner string, name string) *Video {
v := Video{Owner: owner, Name: name}
existed, err := adapter.engine.Get(&v)
if err != nil {
panic(err)
}
if existed {
if v.VideoId != "" {
v.PlayAuth = video.GetVideoPlayAuth(v.VideoId)
}
return &v
} else {
return nil
}
}
func GetVideo(id string) *Video {
owner, name := util.GetOwnerAndNameFromId(id)
return getVideo(owner, name)
}
func UpdateVideo(id string, video *Video) bool {
owner, name := util.GetOwnerAndNameFromId(id)
if getVideo(owner, name) == nil {
return false
}
_, err := adapter.engine.ID(core.PK{owner, name}).AllCols().Update(video)
if err != nil {
panic(err)
}
//return affected != 0
return true
}
func AddVideo(video *Video) bool {
affected, err := adapter.engine.Insert(video)
if err != nil {
panic(err)
}
return affected != 0
}
func DeleteVideo(video *Video) bool {
affected, err := adapter.engine.ID(core.PK{video.Owner, video.Name}).Delete(&Video{})
if err != nil {
panic(err)
}
return affected != 0
}
func (video *Video) GetId() string {
return fmt.Sprintf("%s/%s", video.Owner, video.Name)
}
func (video *Video) Populate() {
store := getStore("admin", "default")
video.DataUrls = store.GetVideoData()
}

96
object/wordset.go Normal file
View File

@ -0,0 +1,96 @@
package object
import (
"fmt"
"github.com/casbin/casbase/util"
"xorm.io/core"
)
type Wordset struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
DistanceLimit int `json:"distanceLimit"`
Vectorset string `xorm:"varchar(100)" json:"vectorset"`
Vectors []*Vector `xorm:"mediumtext" json:"vectors"`
}
func GetGlobalWordsets() []*Wordset {
wordsets := []*Wordset{}
err := adapter.engine.Asc("owner").Desc("created_time").Find(&wordsets)
if err != nil {
panic(err)
}
return wordsets
}
func GetWordsets(owner string) []*Wordset {
wordsets := []*Wordset{}
err := adapter.engine.Desc("created_time").Find(&wordsets, &Wordset{Owner: owner})
if err != nil {
panic(err)
}
return wordsets
}
func getWordset(owner string, name string) *Wordset {
wordset := Wordset{Owner: owner, Name: name}
existed, err := adapter.engine.Get(&wordset)
if err != nil {
panic(err)
}
if existed {
return &wordset
} else {
return nil
}
}
func GetWordset(id string) *Wordset {
owner, name := util.GetOwnerAndNameFromId(id)
return getWordset(owner, name)
}
func UpdateWordset(id string, wordset *Wordset) bool {
owner, name := util.GetOwnerAndNameFromId(id)
if getWordset(owner, name) == nil {
return false
}
_, err := adapter.engine.ID(core.PK{owner, name}).AllCols().Update(wordset)
if err != nil {
panic(err)
}
//return affected != 0
return true
}
func AddWordset(wordset *Wordset) bool {
affected, err := adapter.engine.Insert(wordset)
if err != nil {
panic(err)
}
return affected != 0
}
func DeleteWordset(wordset *Wordset) bool {
affected, err := adapter.engine.ID(core.PK{wordset.Owner, wordset.Name}).Delete(&Wordset{})
if err != nil {
panic(err)
}
return affected != 0
}
func (wordset *Wordset) GetId() string {
return fmt.Sprintf("%s/%s", wordset.Owner, wordset.Name)
}

134
object/wordset_graph.go Normal file
View File

@ -0,0 +1,134 @@
package object
import (
"fmt"
"image/color"
"math"
"strconv"
"github.com/casbin/casbase/util"
)
var graphCache map[string]*Graph
func init() {
graphCache = map[string]*Graph{}
}
func GetWordsetGraph(id string, clusterNumber int, distanceLimit int) *Graph {
cacheId := fmt.Sprintf("%s|%d|%d", id, clusterNumber, distanceLimit)
g, ok := graphCache[cacheId]
if ok {
return g
}
wordset := GetWordset(id)
if wordset == nil {
return nil
}
if len(wordset.Vectors) == 0 {
return nil
}
allZero := true
for _, vector := range wordset.Vectors {
if len(vector.Data) != 0 {
allZero = false
break
}
}
if allZero {
return nil
}
runKmeans(wordset.Vectors, clusterNumber)
g = generateGraph(wordset.Vectors, distanceLimit)
//graphCache[cacheId] = g
return g
}
func getDistance(v1 *Vector, v2 *Vector) float64 {
res := 0.0
for i := range v1.Data {
res += (v1.Data[i] - v2.Data[i]) * (v1.Data[i] - v2.Data[i])
}
return math.Sqrt(res)
}
func refineVectors(vectors []*Vector) []*Vector {
res := []*Vector{}
for _, vector := range vectors {
if len(vector.Data) > 0 {
res = append(res, vector)
}
}
return res
}
func getNodeColor(weight int) string {
if weight > 10 {
weight = 10
}
f := (10.0 - float64(weight)) / 10.0
color1 := color.RGBA{R: 232, G: 67, B: 62}
color2 := color.RGBA{R: 24, G: 144, B: 255}
myColor := util.MixColor(color1, color2, f)
return fmt.Sprintf("rgb(%d,%d,%d)", myColor.R, myColor.G, myColor.B)
}
func generateGraph(vectors []*Vector, distanceLimit int) *Graph {
vectors = refineVectors(vectors)
//vectors = vectors[:100]
g := newGraph()
g.Nodes = []*Node{}
g.Links = []*Link{}
nodeWeightMap := map[string]int{}
for i := 0; i < len(vectors); i++ {
for j := i + 1; j < len(vectors); j++ {
v1 := vectors[i]
v2 := vectors[j]
distance := int(getDistance(v1, v2))
if distance >= distanceLimit {
continue
}
if v, ok := nodeWeightMap[v1.Name]; !ok {
nodeWeightMap[v1.Name] = 1
} else {
nodeWeightMap[v1.Name] = v + 1
}
if v, ok := nodeWeightMap[v2.Name]; !ok {
nodeWeightMap[v2.Name] = 1
} else {
nodeWeightMap[v2.Name] = v + 1
}
linkValue := (1*(distance-7) + 10*(distanceLimit-1-distance)) / (distanceLimit - 8)
linkColor := "rgb(44,160,44,0.6)"
linkName := fmt.Sprintf("Edge [%s] - [%s]: distance = %d, linkValue = %d", v1.Name, v2.Name, distance, linkValue)
fmt.Println(linkName)
g.addLink(linkName, v1.Name, v2.Name, linkValue, linkColor, strconv.Itoa(distance))
}
}
for _, vector := range vectors {
//value := 5
value := int(math.Sqrt(float64(nodeWeightMap[vector.Name]))) + 3
weight := nodeWeightMap[vector.Name]
//nodeColor := "rgb(232,67,62)"
//nodeColor := getNodeColor(value)
nodeColor := vector.Color
fmt.Printf("Node [%s]: weight = %d, nodeValue = %d\n", vector.Name, nodeWeightMap[vector.Name], value)
g.addNode(vector.Name, vector.Name, value, nodeColor, vector.Category, weight)
}
return g
}

26
object/wordset_match.go Normal file
View File

@ -0,0 +1,26 @@
package object
func GetWordsetMatch(id string) *Wordset {
wordset := GetWordset(id)
if wordset == nil {
return nil
}
vectorset := getVectorset(wordset.Owner, wordset.Vectorset)
if vectorset == nil {
return nil
}
vectorset.LoadVectors("")
for _, vector := range wordset.Vectors {
if trueVector, ok := vectorset.VectorMap[vector.Name]; ok {
vector.Data = trueVector.Data
} else {
vector.Data = []float64{}
}
}
UpdateWordset(wordset.GetId(), wordset)
return wordset
}

36
object/wordset_upload.go Normal file
View File

@ -0,0 +1,36 @@
package object
import (
"github.com/casbin/casbase/util"
"github.com/casbin/casbase/xlsx"
)
func uploadVectorNames(owner string, fileId string) bool {
table := xlsx.ReadXlsxFile(fileId)
vectorMap := map[string]int{}
vectors := []*Vector{}
for _, line := range table {
if _, ok := vectorMap[line[0]]; ok {
continue
} else {
vectorMap[line[0]] = 1
}
vector := &Vector{
Name: line[0],
Data: []float64{},
}
vectors = append(vectors, vector)
}
wordset := &Wordset{
Owner: owner,
Name: "word",
CreatedTime: util.GetCurrentTime(),
DisplayName: "word",
DistanceLimit: 14,
Vectors: vectors,
}
return AddWordset(wordset)
}

View File

@ -0,0 +1,9 @@
package object
import "testing"
func TestUploadVectorNames(t *testing.T) {
InitConfig()
uploadVectorNames("admin", "../../tmpFiles/filename")
}

View File

@ -1,8 +0,0 @@
package oss
var endpoint = "xxx"
var accessKeyId = "xxx"
var accessKeySecret = "xxx"
var domain = "xxx"
var bucketName = "xxx"

View File

@ -1,40 +0,0 @@
package oss
import (
"fmt"
"os"
"strings"
"github.com/casbin/confita/util"
)
func uploadFolder(folder string) {
path := fmt.Sprintf("../web/build/static/%s/", folder)
filenames := util.ListFiles(path)
bucket := getBucket()
for _, filename := range filenames {
file, err := os.Open(path + filename)
if err != nil {
panic(err)
}
objectKey := fmt.Sprintf("confita/static/%s/%s", folder, filename)
err = bucket.PutObject(objectKey, file)
if err != nil {
panic(err)
}
fmt.Printf("Uploaded [%s] to [%s]\n", path, objectKey)
}
}
func updateHtml() {
htmlPath := "../web/build/index.html"
html := util.ReadStringFromPath(htmlPath)
html = strings.Replace(html, "\"/static/", fmt.Sprintf("\"https://%s/confita/static/", domain), -1)
util.WriteStringToPath(html, htmlPath)
fmt.Printf("Updated HTML to [%s]\n", html)
}

View File

@ -1,10 +0,0 @@
package oss
import "testing"
func TestDeploy(t *testing.T) {
uploadFolder("js")
uploadFolder("css")
updateHtml()
}

View File

@ -1,63 +0,0 @@
package oss
import (
"bytes"
"fmt"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
func getBucket() *oss.Bucket {
client, err := oss.New(endpoint, accessKeyId, accessKeySecret)
if err != nil {
panic(err)
}
bucket, err := client.Bucket(bucketName)
if err != nil {
panic(err)
}
return bucket
}
func UploadFileAndGetLink(folder string, owner string, filename string, fileBytes []byte) (string, string) {
reader := bytes.NewReader(fileBytes)
bucket := getBucket()
objectKey := fmt.Sprintf("%s/%s/%s", folder, owner, filename)
err := bucket.PutObject(objectKey, reader)
if err != nil {
panic(err)
}
url := fmt.Sprintf("https://%s/%s/%s/%s", domain, folder, owner, filename)
return url, objectKey
}
func GetFile(folder string, owner string, filename string) (string, string) {
bucket := getBucket()
objectKey := fmt.Sprintf("%s/%s/%s", folder, owner, filename)
existed, err := bucket.IsObjectExist(objectKey)
if err != nil {
panic(err)
}
if existed {
url := fmt.Sprintf("https://%s/%s/%s/%s", domain, folder, owner, filename)
return url, objectKey
} else {
return "", objectKey
}
}
func DeleteFile(objectKey string) {
bucket := getBucket()
err := bucket.DeleteObject(objectKey)
if err != nil {
panic(err)
}
}

View File

@ -1,86 +0,0 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package proxy
import (
"fmt"
"net"
"net/http"
"strings"
"time"
"github.com/astaxie/beego"
"golang.org/x/net/proxy"
)
var (
DefaultHttpClient *http.Client
ProxyHttpClient *http.Client
)
func InitHttpClient() {
// not use proxy
DefaultHttpClient = http.DefaultClient
// use proxy
ProxyHttpClient = getProxyHttpClient()
}
func isAddressOpen(address string) bool {
timeout := time.Millisecond * 100
conn, err := net.DialTimeout("tcp", address, timeout)
if err != nil {
// cannot connect to address, proxy is not active
return false
}
if conn != nil {
defer conn.Close()
fmt.Printf("Socks5 proxy enabled: %s\n", address)
return true
}
return false
}
func getProxyHttpClient() *http.Client {
socks5Proxy := beego.AppConfig.String("socks5Proxy")
if socks5Proxy == "" {
return &http.Client{}
}
if !isAddressOpen(socks5Proxy) {
return &http.Client{}
}
// https://stackoverflow.com/questions/33585587/creating-a-go-socks5-client
dialer, err := proxy.SOCKS5("tcp", socks5Proxy, nil, proxy.Direct)
if err != nil {
panic(err)
}
tr := &http.Transport{Dial: dialer.Dial}
return &http.Client{
Transport: tr,
}
}
func GetHttpClient(url string) *http.Client {
if strings.Contains(url, "githubusercontent.com") || strings.Contains(url, "googleusercontent.com") {
return ProxyHttpClient
} else {
return DefaultHttpClient
}
}

View File

@ -1,33 +1,35 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package routers
import (
"fmt"
"net/http"
"strings"
"github.com/astaxie/beego"
"github.com/astaxie/beego/context"
"github.com/casbin/confita/util"
"github.com/casbin/casbase/util"
)
func Static(ctx *context.Context) {
func TransparentStatic(ctx *context.Context) {
urlPath := ctx.Request.URL.Path
if strings.HasPrefix(urlPath, "/api/") {
return
}
landingFolder := beego.AppConfig.String("landingFolder")
if landingFolder != "" {
if urlPath == "" || urlPath == "/" || urlPath == "/about" {
http.ServeFile(ctx.ResponseWriter, ctx.Request, fmt.Sprintf("../%s/web/build/index.html", landingFolder))
return
}
landingPath := fmt.Sprintf("../%s/web/build%s", landingFolder, urlPath)
if util.FileExist(landingPath) {
http.ServeFile(ctx.ResponseWriter, ctx.Request, landingPath)
return
}
}
path := "web/build"
if urlPath == "/" {
path += "/index.html"

View File

@ -1,130 +0,0 @@
package routers
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"sync"
"time"
"github.com/astaxie/beego"
"github.com/astaxie/beego/context"
)
// var chromeCtx ctx.Context
var chromeCtxPool *SsrPool
var (
isChromeInstalled bool
isChromeInit bool
)
type PageCache struct {
time time.Time
html string
}
var renderCache = make(map[string]PageCache)
// modified from https://github.com/chromedp/chromedp/blob/master/allocate.go#L331
func isChromeFound() bool {
for _, path := range [...]string{
// Unix-like
"headless_shell",
"headless-shell",
"chromium",
"chromium-browser",
"google-chrome",
"google-chrome-stable",
"google-chrome-beta",
"google-chrome-unstable",
"/usr/bin/google-chrome",
// Windows
"chrome",
"chrome.exe", // in case PATHEXT is misconfigured
`C:\Program Files (x86)\Google\Chrome\Application\chrome.exe`,
`C:\Program Files\Google\Chrome\Application\chrome.exe`,
filepath.Join(os.Getenv("USERPROFILE"), `AppData\Local\Google\Chrome\Application\chrome.exe`),
// Mac
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
} {
_, err := exec.LookPath(path)
if err == nil {
// return found -> return true
// modified by Kininaru<shiftregister233@outlook.com>
return true
}
}
// return "google-chrome" -> return false
// modified by Kininaru<shiftregister233@outlook.com>
return false
}
func InitChromeDp() {
isChromeInit = true
isChromeInstalled = isChromeFound()
if isChromeInstalled {
chromeCtxNum, _ := beego.AppConfig.Int("chromeCtxNum")
if chromeCtxNum <= 0 {
chromeCtxNum = 1 // default
}
chromeCtxPool = NewSsrPool(chromeCtxNum)
}
go chromeCtxPool.Run() // start ssr_pool
}
func cacheSave(urlString string, res string) {
renderCache[urlString] = PageCache{time.Now(), res}
}
func cacheRestore(urlString string, cacheExpireSeconds int64) (string, bool) {
if _, ok := renderCache[urlString]; ok {
if time.Now().Sub(renderCache[urlString].time) < time.Duration(cacheExpireSeconds)*time.Second {
return renderCache[urlString].html, true
}
}
return "", false
}
var botRegex *regexp.Regexp
func isBot(userAgent string) bool {
if botRegex == nil {
botRegex, _ = regexp.Compile("bot|slurp|bing|crawler|spider")
}
userAgent = strings.ToLower(userAgent)
return botRegex.MatchString(userAgent)
}
func BotFilter(ctx *context.Context) {
if strings.HasPrefix(ctx.Request.URL.Path, "/api/") {
return
}
if isBot(ctx.Request.UserAgent()) {
ctx.ResponseWriter.WriteHeader(200)
urlStr := fmt.Sprintf("http://%s%s", ctx.Request.Host, ctx.Request.URL.Path)
if !isChromeInit {
InitChromeDp()
}
if !isChromeInstalled {
_, err := ctx.ResponseWriter.Write([]byte("Chrome is not installed in your server"))
if err != nil {
panic(err)
}
}
// the context will be canceled when the task send to channel
// sync.WaitGroup will wait for the task to be finished, it can avoid this problem
var wg sync.WaitGroup
wg.Add(1)
// create ssr_task and put it into task channel
task := NewRenderTask(ctx, urlStr, &wg)
chromeCtxPool.TaskChannel <- task
wg.Wait()
}
}

View File

@ -1,23 +1,8 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package routers
import (
"github.com/astaxie/beego"
"github.com/casbin/confita/controllers"
"github.com/casbin/casbase/controllers"
)
func init() {
@ -37,41 +22,46 @@ func initAPI() {
beego.Router("/api/signout", &controllers.ApiController{}, "POST:Signout")
beego.Router("/api/get-account", &controllers.ApiController{}, "GET:GetAccount")
beego.Router("/api/get-global-conferences", &controllers.ApiController{}, "GET:GetGlobalConferences")
beego.Router("/api/get-conferences", &controllers.ApiController{}, "GET:GetConferences")
beego.Router("/api/get-conference", &controllers.ApiController{}, "GET:GetConference")
beego.Router("/api/update-conference", &controllers.ApiController{}, "POST:UpdateConference")
beego.Router("/api/add-conference", &controllers.ApiController{}, "POST:AddConference")
beego.Router("/api/delete-conference", &controllers.ApiController{}, "POST:DeleteConference")
beego.Router("/api/get-global-wordsets", &controllers.ApiController{}, "GET:GetGlobalWordsets")
beego.Router("/api/get-wordsets", &controllers.ApiController{}, "GET:GetWordsets")
beego.Router("/api/get-wordset", &controllers.ApiController{}, "GET:GetWordset")
beego.Router("/api/get-wordset-graph", &controllers.ApiController{}, "GET:GetWordsetGraph")
beego.Router("/api/get-wordset-match", &controllers.ApiController{}, "GET:GetWordsetMatch")
beego.Router("/api/update-wordset", &controllers.ApiController{}, "POST:UpdateWordset")
beego.Router("/api/add-wordset", &controllers.ApiController{}, "POST:AddWordset")
beego.Router("/api/delete-wordset", &controllers.ApiController{}, "POST:DeleteWordset")
beego.Router("/api/get-global-codes", &controllers.ApiController{}, "GET:GetGlobalCodes")
beego.Router("/api/get-codes", &controllers.ApiController{}, "GET:GetCodes")
beego.Router("/api/get-code", &controllers.ApiController{}, "GET:GetCode")
beego.Router("/api/update-code", &controllers.ApiController{}, "POST:UpdateCode")
beego.Router("/api/add-code", &controllers.ApiController{}, "POST:AddCode")
beego.Router("/api/delete-code", &controllers.ApiController{}, "POST:DeleteCode")
beego.Router("/api/get-global-vectorsets", &controllers.ApiController{}, "GET:GetGlobalVectorsets")
beego.Router("/api/get-vectorsets", &controllers.ApiController{}, "GET:GetVectorsets")
beego.Router("/api/get-vectorset", &controllers.ApiController{}, "GET:GetVectorset")
beego.Router("/api/update-vectorset", &controllers.ApiController{}, "POST:UpdateVectorset")
beego.Router("/api/add-vectorset", &controllers.ApiController{}, "POST:AddVectorset")
beego.Router("/api/delete-vectorset", &controllers.ApiController{}, "POST:DeleteVectorset")
beego.Router("/api/get-global-submissions", &controllers.ApiController{}, "GET:GetGlobalSubmissions")
beego.Router("/api/get-submissions", &controllers.ApiController{}, "GET:GetSubmissions")
beego.Router("/api/get-submission", &controllers.ApiController{}, "GET:GetSubmission")
beego.Router("/api/update-submission", &controllers.ApiController{}, "POST:UpdateSubmission")
beego.Router("/api/add-submission", &controllers.ApiController{}, "POST:AddSubmission")
beego.Router("/api/delete-submission", &controllers.ApiController{}, "POST:DeleteSubmission")
beego.Router("/api/upload-submission-file", &controllers.ApiController{}, "POST:UploadSubmissionFile")
beego.Router("/api/get-global-videos", &controllers.ApiController{}, "GET:GetGlobalVideos")
beego.Router("/api/get-videos", &controllers.ApiController{}, "GET:GetVideos")
beego.Router("/api/get-video", &controllers.ApiController{}, "GET:GetVideo")
beego.Router("/api/update-video", &controllers.ApiController{}, "POST:UpdateVideo")
beego.Router("/api/add-video", &controllers.ApiController{}, "POST:AddVideo")
beego.Router("/api/delete-video", &controllers.ApiController{}, "POST:DeleteVideo")
beego.Router("/api/upload-video", &controllers.ApiController{}, "POST:UploadVideo")
beego.Router("/api/get-global-rooms", &controllers.ApiController{}, "GET:GetGlobalRooms")
beego.Router("/api/get-rooms", &controllers.ApiController{}, "GET:GetRooms")
beego.Router("/api/get-room", &controllers.ApiController{}, "GET:GetRoom")
beego.Router("/api/update-room", &controllers.ApiController{}, "POST:UpdateRoom")
beego.Router("/api/increment-room-viewer", &controllers.ApiController{}, "POST:IncrementRoomViewer")
beego.Router("/api/add-room", &controllers.ApiController{}, "POST:AddRoom")
beego.Router("/api/delete-room", &controllers.ApiController{}, "POST:DeleteRoom")
beego.Router("/api/register-room", &controllers.ApiController{}, "GET:RegisterRoom")
beego.Router("/api/webhook-room", &controllers.ApiController{}, "Post:WebhookRoom")
beego.Router("/api/get-global-stores", &controllers.ApiController{}, "GET:GetGlobalStores")
beego.Router("/api/get-stores", &controllers.ApiController{}, "GET:GetStores")
beego.Router("/api/get-store", &controllers.ApiController{}, "GET:GetStore")
beego.Router("/api/update-store", &controllers.ApiController{}, "POST:UpdateStore")
beego.Router("/api/add-store", &controllers.ApiController{}, "POST:AddStore")
beego.Router("/api/delete-store", &controllers.ApiController{}, "POST:DeleteStore")
beego.Router("/api/get-products", &controllers.ApiController{}, "GET:GetProducts")
beego.Router("/api/get-global-payments", &controllers.ApiController{}, "GET:GetGlobalPayments")
beego.Router("/api/get-payments", &controllers.ApiController{}, "GET:GetPayments")
beego.Router("/api/update-file", &controllers.ApiController{}, "POST:UpdateFile")
beego.Router("/api/add-file", &controllers.ApiController{}, "POST:AddFile")
beego.Router("/api/delete-file", &controllers.ApiController{}, "POST:DeleteFile")
beego.Router("/api/activate-file", &controllers.ApiController{}, "POST:ActivateFile")
beego.Router("/api/get-active-file", &controllers.ApiController{}, "GET:GetActiveFile")
beego.Router("/api/get-users", &controllers.ApiController{}, "GET:GetUsers")
beego.Router("/api/get-permissions", &controllers.ApiController{}, "GET:GetPermissions")
beego.Router("/api/get-permission", &controllers.ApiController{}, "GET:GetPermission")
beego.Router("/api/update-permission", &controllers.ApiController{}, "POST:UpdatePermission")
beego.Router("/api/add-permission", &controllers.ApiController{}, "POST:AddPermission")
beego.Router("/api/delete-permission", &controllers.ApiController{}, "POST:DeletePermission")
}

View File

@ -1,170 +0,0 @@
package routers
import (
ctx "context"
"errors"
"fmt"
"runtime"
"sync"
"time"
"github.com/astaxie/beego"
"github.com/astaxie/beego/context"
"github.com/astaxie/beego/logs"
"github.com/chromedp/chromedp"
)
var renderTimeout = 20 * time.Second
type RenderTask struct {
HttpCtx *context.Context
Url string
Render func(chromeCtx ctx.Context, url string) (string, error)
Wg *sync.WaitGroup
}
type SsrPool struct {
TaskChannel chan *RenderTask
JobsChannel chan *RenderTask
AddWorkerChannel chan bool
WorkerNum int
}
func NewRenderTask(httpCtx *context.Context, url string, wg *sync.WaitGroup) *RenderTask {
return &RenderTask{
HttpCtx: httpCtx,
Url: url,
Render: render,
Wg: wg,
}
}
func NewSsrPool(cap int) *SsrPool {
pool := SsrPool{
TaskChannel: make(chan *RenderTask),
JobsChannel: make(chan *RenderTask),
WorkerNum: cap,
}
return &pool
}
func render(chromeCtx ctx.Context, url string) (string, error) {
cacheExpireSeconds, err := beego.AppConfig.Int64("cacheExpireSeconds")
if err != nil {
return "", err
}
res, cacheHit := cacheRestore(url, cacheExpireSeconds)
if cacheHit {
return res, nil
}
// set timeout for render page
done := make(chan bool, 1)
go func() {
err = chromedp.Run(chromeCtx,
chromedp.Navigate(url),
chromedp.OuterHTML("html", &res),
)
if err != nil {
done <- false
} else {
done <- true
}
}()
select {
case success := <-done:
if success {
cacheSave(url, res)
return res, nil
} else {
return "", err
}
case <-time.After(renderTimeout):
err := chromedp.Cancel(chromeCtx)
if err != nil {
return "", errors.New("context cancel failed")
}
return "", ctx.Canceled
}
}
func (pool *SsrPool) worker() {
// chromeCtx, _ := chromedp.NewExecAllocator(ctx.Background(), append(
// chromedp.DefaultExecAllocatorOptions[:],
// chromedp.Flag("headless", false))...)
// chromeCtx, _ = chromedp.NewContext(chromeCtx)
chromeCtx, _ := chromedp.NewContext(ctx.Background()) // set default context with headless mode
for task := range pool.JobsChannel {
cancel := func() bool {
defer func() {
if err := recover(); err != nil {
handleErr(task.HttpCtx, err.(error))
task.Wg.Done()
}
}()
urlStr, err := task.Render(chromeCtx, task.Url)
if err != nil {
if err == ctx.Canceled { // when browser process has terminated
handleErr(task.HttpCtx, err)
task.Wg.Done()
return true
} else {
panic(err)
}
}
_, err = task.HttpCtx.ResponseWriter.Write([]byte(urlStr))
if err != nil {
panic(err)
}
task.Wg.Done()
return false
}()
// if canceled, break the loop
if cancel {
break
}
}
// if break, add a new worker
pool.AddWorkerChannel <- true
}
func (pool *SsrPool) Run() {
pool.AddWorkerChannel = make(chan bool, pool.WorkerNum)
for i := 0; i < pool.WorkerNum; i++ {
pool.AddWorkerChannel <- true
}
go func() {
for j := range pool.AddWorkerChannel {
if j == true {
go pool.worker()
}
}
}()
for task := range pool.TaskChannel {
pool.JobsChannel <- task
}
}
func handleErr(ctx *context.Context, err error) {
var stack string
logs.Critical("the request url is ", ctx.Input.URL())
logs.Critical("Handler crashed with error:", err)
for i := 1; ; i++ {
_, file, line, ok := runtime.Caller(i)
if !ok {
break
}
logs.Critical(fmt.Sprintf("%s:%d", file, line))
stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line))
}
if ctx.Output.Status != 0 {
ctx.ResponseWriter.WriteHeader(ctx.Output.Status)
} else {
ctx.ResponseWriter.WriteHeader(500)
}
_, _err := ctx.ResponseWriter.Write([]byte(err.(error).Error()))
if _err != nil {
logs.Critical("write response error:", err)
}
}

View File

@ -1,35 +0,0 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package service
import "github.com/casdoor/casdoor-go-sdk/auth"
func UploadFileToStorage(user string, tag string, parent string, fullFilePath string, fileBytes []byte) (string, string) {
fileUrl, objectKey, err := auth.UploadResource(user, tag, parent, fullFilePath, fileBytes)
if err != nil {
panic(err)
}
return fileUrl, objectKey
}
func DeleteFileFromStorage(objectKey string) bool {
affected, err := auth.DeleteResource(objectKey)
if err != nil {
panic(err)
}
return affected
}

View File

@ -1,109 +0,0 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package service
import (
"encoding/json"
"github.com/astaxie/beego"
"github.com/casdoor/casdoor-go-sdk/auth"
)
type Payment struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
Provider string `xorm:"varchar(100)" json:"provider"`
Type string `xorm:"varchar(100)" json:"type"`
Organization string `xorm:"varchar(100)" json:"organization"`
User string `xorm:"varchar(100)" json:"user"`
ProductName string `xorm:"varchar(100)" json:"productName"`
ProductDisplayName string `xorm:"varchar(100)" json:"productDisplayName"`
Detail string `xorm:"varchar(100)" json:"detail"`
Tag string `xorm:"varchar(100)" json:"tag"`
Currency string `xorm:"varchar(100)" json:"currency"`
Price float64 `json:"price"`
PayUrl string `xorm:"varchar(2000)" json:"payUrl"`
ReturnUrl string `xorm:"varchar(1000)" json:"returnUrl"`
State string `xorm:"varchar(100)" json:"state"`
Message string `xorm:"varchar(1000)" json:"message"`
PersonName string `xorm:"varchar(100)" json:"personName"`
PersonIdCard string `xorm:"varchar(100)" json:"personIdCard"`
PersonEmail string `xorm:"varchar(100)" json:"personEmail"`
PersonPhone string `xorm:"varchar(100)" json:"personPhone"`
InvoiceType string `xorm:"varchar(100)" json:"invoiceType"`
InvoiceTitle string `xorm:"varchar(100)" json:"invoiceTitle"`
InvoiceTaxId string `xorm:"varchar(100)" json:"invoiceTaxId"`
InvoiceRemark string `xorm:"varchar(100)" json:"invoiceRemark"`
InvoiceUrl string `xorm:"varchar(255)" json:"invoiceUrl"`
}
func GetGlobalPayments() ([]*Payment, error) {
organization := beego.AppConfig.String("casdoorOrganization")
queryMap := map[string]string{}
url := auth.GetUrl("get-payments", queryMap)
bytes, err := auth.DoGetBytesRaw(url)
if err != nil {
return nil, err
}
var payments []*Payment
err = json.Unmarshal(bytes, &payments)
if err != nil {
return nil, err
}
res := []*Payment{}
for _, payment := range payments {
if payment.Organization == organization {
res = append(res, payment)
}
}
return res, nil
}
func GetPayments(user string) ([]*Payment, error) {
owner := "admin"
organization := beego.AppConfig.String("casdoorOrganization")
queryMap := map[string]string{
"owner": owner,
"organization": organization,
"user": user,
}
url := auth.GetUrl("get-user-payments", queryMap)
bytes, err := auth.DoGetBytes(url)
if err != nil {
return nil, err
}
var payments []*Payment
err = json.Unmarshal(bytes, &payments)
if err != nil {
return nil, err
}
return payments, nil
}

View File

@ -1,62 +0,0 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package service
import (
"encoding/json"
"github.com/casdoor/casdoor-go-sdk/auth"
)
type Product struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
Image string `xorm:"varchar(100)" json:"image"`
Detail string `xorm:"varchar(100)" json:"detail"`
Tag string `xorm:"varchar(100)" json:"tag"`
Currency string `xorm:"varchar(100)" json:"currency"`
Price float64 `json:"price"`
Quantity int `json:"quantity"`
Sold int `json:"sold"`
Providers []string `xorm:"varchar(100)" json:"providers"`
ReturnUrl string `xorm:"varchar(1000)" json:"returnUrl"`
State string `xorm:"varchar(100)" json:"state"`
}
func GetProducts() ([]*Product, error) {
owner := "admin"
queryMap := map[string]string{
"owner": owner,
}
url := auth.GetUrl("get-products", queryMap)
bytes, err := auth.DoGetBytesRaw(url)
if err != nil {
return nil, err
}
var products []*Product
err = json.Unmarshal(bytes, &products)
if err != nil {
return nil, err
}
return products, nil
}

72
storage/aliyun.go Normal file
View File

@ -0,0 +1,72 @@
package storage
import (
"bytes"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
func getBucket(bucketName string) *oss.Bucket {
client, err := oss.New(endpoint, clientId, clientSecret)
if err != nil {
panic(err)
}
bucket, err := client.Bucket(bucketName)
if err != nil {
panic(err)
}
return bucket
}
func ListObjects(bucketName string, prefix string) []oss.ObjectProperties {
res := []oss.ObjectProperties{}
if bucketName == "" {
return res
}
bucket := getBucket(bucketName)
marker := oss.Marker("")
i := 0
for {
resp, err := bucket.ListObjects(oss.Prefix(prefix), oss.MaxKeys(1000), marker)
if err != nil {
panic(err)
}
marker = oss.Marker(resp.NextMarker)
for _, object := range resp.Objects {
res = append(res, object)
//fmt.Printf("[%d] %s\n", i, object.Key)
i += 1
}
if !resp.IsTruncated {
break
}
}
return res
}
func PutObject(bucketName string, key string, fileBuffer *bytes.Buffer) {
bucket := getBucket(bucketName)
err := bucket.PutObject(key, fileBuffer)
if err != nil {
panic(err)
}
}
func DeleteObject(bucketName string, key string) {
bucket := getBucket(bucketName)
err := bucket.DeleteObject(key)
if err != nil {
panic(err)
}
}

5
storage/conf.go Normal file
View File

@ -0,0 +1,5 @@
package storage
var endpoint = ""
var clientId = ""
var clientSecret = ""

7
storage/storage_test.go Normal file
View File

@ -0,0 +1,7 @@
package storage
import "testing"
func TestStorage(t *testing.T) {
ListObjects("casbase", "")
}

19
util/array.go Normal file
View File

@ -0,0 +1,19 @@
package util
import "fmt"
func FloatsToStrings(floatArray []float64) []string {
res := []string{}
for _, f := range floatArray {
res = append(res, fmt.Sprintf("%f", f))
}
return res
}
func StringsToFloats(stringArray []string) []float64 {
res := []float64{}
for _, s := range stringArray {
res = append(res, ParseFloat(s))
}
return res
}

26
util/color.go Normal file
View File

@ -0,0 +1,26 @@
package util
import (
"fmt"
"image/color"
"math"
"math/rand"
)
func mixChannel(a uint8, b uint8, t float64) uint8 {
i := (1-t)*float64(a)*float64(a) + t*float64(b)*float64(b)
return uint8(math.Sqrt(i))
}
func MixColor(c1 color.RGBA, c2 color.RGBA, t float64) color.RGBA {
res := color.RGBA{
R: mixChannel(c1.R, c2.R, t),
G: mixChannel(c1.G, c2.G, t),
B: mixChannel(c1.B, c2.B, t),
}
return res
}
func GetRandomColor() string {
return fmt.Sprintf("rgb(%d,%d,%d)", rand.Intn(256), rand.Intn(256), rand.Intn(256))
}

53
util/csv.go Normal file
View File

@ -0,0 +1,53 @@
package util
import (
"bufio"
"encoding/csv"
"io"
"os"
)
func LoadCsvFile(path string, rows *[][]string) {
file, err := os.Open(path)
if err != nil {
panic(err)
}
defer file.Close()
reader := csv.NewReader(bufio.NewReader(file))
reader.LazyQuotes = true
i := 0
for {
line, err := reader.Read()
if err == io.EOF {
break
} else if err != nil {
// log.Fatal(error)
panic(err)
}
*rows = append(*rows, line)
i += 1
}
}
func WriteCsvFile(path string, rows *[][]string) {
file, err := os.Create(path)
if err != nil {
panic(err)
}
defer file.Close()
writer := csv.NewWriter(file)
defer writer.Flush()
i := 0
for _, row := range *rows {
err = writer.Write(row)
if err != nil {
panic(err)
}
i += 1
}
}

114
util/file.go Normal file
View File

@ -0,0 +1,114 @@
package util
import (
"bufio"
"os"
"strings"
)
func parseJsonToFloats(s string) []float64 {
s = strings.TrimLeft(s, "[")
s = strings.TrimRight(s, "]")
s = strings.ReplaceAll(s, "\n", "")
tokens := strings.Split(s, " ")
res := []float64{}
for _, token := range tokens {
if token == "" {
continue
}
f := ParseFloat(token)
res = append(res, f)
}
return res
}
func LoadVectorFileByCsv(path string) ([]string, [][]float64) {
nameArray := []string{}
dataArray := [][]float64{}
file, err := os.Open(path)
if err != nil {
panic(err)
}
defer file.Close()
rows := [][]string{}
LoadCsvFile(path, &rows)
for _, row := range rows {
if row[0] == "" {
continue
}
nameArray = append(nameArray, row[1])
dataArray = append(dataArray, parseJsonToFloats(row[2]))
}
return nameArray, dataArray
}
func LoadVectorFileByCsv2(path string) ([]string, [][]float64) {
nameArray := []string{}
dataArray := [][]float64{}
file, err := os.Open(path)
if err != nil {
panic(err)
}
defer file.Close()
rows := [][]string{}
LoadCsvFile(path, &rows)
for _, row := range rows {
nameArray = append(nameArray, row[0])
dataArray = append(dataArray, StringsToFloats(row[1:]))
}
return nameArray, dataArray
}
func LoadVectorFileBySpace(path string) ([]string, [][]float64) {
nameArray := []string{}
dataArray := [][]float64{}
file, err := os.Open(path)
if err != nil {
panic(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
const maxCapacity = 1024 * 1024 * 8
buf := make([]byte, maxCapacity)
scanner.Buffer(buf, maxCapacity)
i := 0
for scanner.Scan() {
if i == 0 {
i += 1
continue
}
line := scanner.Text()
line = strings.Trim(line, " ")
tokens := strings.Split(line, " ")
nameArray = append(nameArray, tokens[0])
data := []float64{}
for j := 1; j < len(tokens); j++ {
data = append(data, ParseFloat(tokens[j]))
}
dataArray = append(dataArray, data)
i += 1
}
if err = scanner.Err(); err != nil {
panic(err)
}
return nameArray, dataArray
}

45
util/ip.go Normal file
View File

@ -0,0 +1,45 @@
package util
import (
"fmt"
"net/http"
"strings"
)
func GetIPInfo(clientIP string) string {
if clientIP == "" {
return ""
}
ips := strings.Split(clientIP, ",")
res := ""
for i := range ips {
ip := strings.TrimSpace(ips[i])
// desc := GetDescFromIP(ip)
ipstr := fmt.Sprintf("%s: %s", ip, "")
if i != len(ips)-1 {
res += ipstr + " -> "
} else {
res += ipstr
}
}
return res
}
func GetIPFromRequest(req *http.Request) string {
clientIP := req.Header.Get("x-forwarded-for")
if clientIP == "" {
ipPort := strings.Split(req.RemoteAddr, ":")
if len(ipPort) >= 1 && len(ipPort) <= 2 {
clientIP = ipPort[0]
} else if len(ipPort) > 2 {
idx := strings.LastIndex(req.RemoteAddr, ":")
clientIP = req.RemoteAddr[0:idx]
clientIP = strings.TrimLeft(clientIP, "[")
clientIP = strings.TrimRight(clientIP, "]")
}
}
return GetIPInfo(clientIP)
}

View File

@ -1,32 +1,10 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import "encoding/json"
func StructToJson(v interface{}) string {
data, err := json.MarshalIndent(v, "", " ")
if err != nil {
panic(err)
}
return string(data)
}
func StructToJsonCompact(v interface{}) string {
data, err := json.Marshal(v)
//data, err := json.Marshal(v)
if err != nil {
panic(err)
}

View File

@ -1,30 +1,16 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import (
"io/ioutil"
"net/url"
"os"
"path/filepath"
"strings"
)
func FileExist(path string) bool {
if _, err := os.Stat(path); err != nil {
if os.IsNotExist(err) {
return false
}
if _, err := os.Stat(path); os.IsNotExist(err) {
return false
}
return true
}
@ -63,3 +49,43 @@ func ListFiles(path string) []string {
return res
}
func FilterQuery(urlString string, blackList []string) string {
urlData, err := url.Parse(urlString)
if err != nil {
return urlString
}
queries := urlData.Query()
retQuery := make(url.Values)
inBlackList := false
for key, value := range queries {
inBlackList = false
for _, blackListItem := range blackList {
if blackListItem == key {
inBlackList = true
break
}
}
if !inBlackList {
retQuery[key] = value
}
}
if len(retQuery) > 0 {
return urlData.Path + "?" + strings.ReplaceAll(retQuery.Encode(), "%2F", "/")
} else {
return urlData.Path
}
}
func CopyFile(dest string, src string) {
bs, err := os.ReadFile(src)
if err != nil {
panic(err)
}
err = os.WriteFile(dest, bs, 0644)
if err != nil {
panic(err)
}
}

24
util/routine.go Normal file
View File

@ -0,0 +1,24 @@
package util
import (
"fmt"
"github.com/astaxie/beego/logs"
)
func SafeGoroutine(fn func()) {
var err error
go func() {
defer func() {
if r := recover(); r != nil {
var ok bool
err, ok = r.(error)
if !ok {
err = fmt.Errorf("%v", r)
}
logs.Error("goroutine panic: %v", err)
}
}()
fn()
}()
}

15
util/setting.go Normal file
View File

@ -0,0 +1,15 @@
package util
import "fmt"
func GetUploadXlsxPath(fileId string) string {
return fmt.Sprintf("tmpFiles/%s.xlsx", fileId)
}
func GetUploadCsvPath(fileId string) string {
return fmt.Sprintf("tmpFiles/%s.csv", fileId)
}
func GetUploadFilePath(fileId string) string {
return fmt.Sprintf("tmpFiles/%s", fileId)
}

View File

@ -1,27 +1,12 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import (
"encoding/base64"
"errors"
"fmt"
"io/ioutil"
"math/rand"
"strconv"
"strings"
"unicode"
"github.com/google/uuid"
)
@ -96,6 +81,10 @@ func GetIdFromOwnerAndName(owner string, name string) string {
return fmt.Sprintf("%s/%s", owner, name)
}
func GenerateId() string {
return uuid.NewString()
}
func ReadStringFromPath(path string) string {
data, err := ioutil.ReadFile(path)
if err != nil {
@ -128,22 +117,11 @@ func WriteBytesToPath(b []byte, path string) {
}
}
func GenerateId() string {
return uuid.NewString()
}
func GenerateNumber(min int, max int) string {
res := rand.Intn(max-min) + min
return strconv.Itoa(res)
}
func IsChinese(str string) bool {
var flag bool
for _, v := range str {
if unicode.Is(unicode.Han, v) {
flag = true
break
}
func DecodeBase64(s string) string {
res, err := base64.StdEncoding.DecodeString(s)
if err != nil {
panic(err)
}
return flag
return string(res)
}

View File

@ -1,17 +1,3 @@
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import "time"

5
video/conf.go Normal file
View File

@ -0,0 +1,5 @@
package video
var regionId = ""
var accessKeyId = ""
var accessKeySecret = ""

18
video/init.go Normal file
View File

@ -0,0 +1,18 @@
package video
import "github.com/aliyun/alibaba-cloud-sdk-go/services/vod"
var vodClient *vod.Client
func init() {
vodClient = InitVodClient()
}
func InitVodClient() *vod.Client {
vodClient, err := vod.NewClientWithAccessKey(regionId, accessKeyId, accessKeySecret)
if err != nil {
panic(err)
}
return vodClient
}

28
video/oss_api.go Normal file
View File

@ -0,0 +1,28 @@
package video
import (
"bytes"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
func getOssClient(endpoint string, accessKeyId string, accessKeySecret string, securityToken string) *oss.Client {
client, err := oss.New(endpoint, accessKeyId, accessKeySecret, oss.SecurityToken(securityToken))
if err != nil {
panic(err)
}
return client
}
func uploadLocalFile(ossClient *oss.Client, bucketName string, objectKey string, fileBuffer *bytes.Buffer) {
bucket, err := ossClient.Bucket(bucketName)
if err != nil {
panic(err)
}
err = bucket.PutObject(objectKey, fileBuffer)
if err != nil {
panic(err)
}
}

93
video/vod_api.go Normal file
View File

@ -0,0 +1,93 @@
package video
import (
"bytes"
"fmt"
"time"
"github.com/aliyun/alibaba-cloud-sdk-go/services/vod"
"github.com/casbin/casbase/util"
)
func GetVideoPlayAuth(videoId string) string {
r := vod.CreateGetVideoPlayAuthRequest()
r.VideoId = videoId
r.AcceptFormat = "JSON"
resp, err := vodClient.GetVideoPlayAuth(r)
if err != nil {
fmt.Println(err)
return err.Error()
}
playAuth := resp.PlayAuth
return playAuth
}
type UploadAddress struct {
Endpoint string `json:"Endpoint"`
Bucket string `json:"Bucket"`
FileName string `json:"FileName"`
}
type UploadAuth struct {
SecurityToken string `json:"SecurityToken"`
AccessKeyId string `json:"AccessKeyId"`
ExpireUTCTime time.Time `json:"ExpireUTCTime"`
AccessKeySecret string `json:"AccessKeySecret"`
Expiration string `json:"Expiration"`
Region string `json:"Region"`
}
func UploadVideo(fileId string, filename string, fileBuffer *bytes.Buffer) string {
// https://help.aliyun.com/document_detail/476208.html
r := vod.CreateCreateUploadVideoRequest()
r.Scheme = "https"
r.FileName = filename
r.Title = fileId
resp, err := vodClient.CreateUploadVideo(r)
if err != nil {
panic(err)
}
encodedUploadAddress := resp.UploadAddress
videoId := resp.VideoId
encodedUploadAuth := resp.UploadAuth
uploadAddressStr := util.DecodeBase64(encodedUploadAddress)
uploadAuthStr := util.DecodeBase64(encodedUploadAuth)
uploadAddress := &UploadAddress{}
err = util.JsonToStruct(uploadAddressStr, uploadAddress)
if err != nil {
panic(err)
}
uploadAuth := &UploadAuth{}
err = util.JsonToStruct(uploadAuthStr, uploadAuth)
if err != nil {
panic(err)
}
ossClient := getOssClient(uploadAddress.Endpoint, uploadAuth.AccessKeyId, uploadAuth.AccessKeySecret, uploadAuth.SecurityToken)
uploadLocalFile(ossClient, uploadAddress.Bucket, uploadAddress.FileName, fileBuffer)
return videoId
}
func GetVideoCoverUrl(videoId string) string {
r := vod.CreateGetVideoInfoRequest()
r.VideoId = videoId
r.AcceptFormat = "JSON"
resp, err := vodClient.GetVideoInfo(r)
if err != nil {
fmt.Println(err)
return err.Error()
}
return resp.Video.CoverURL
}

7
video/vod_api_test.go Normal file
View File

@ -0,0 +1,7 @@
package video
import "testing"
func TestGetVideoCoverUrl(t *testing.T) {
println(GetVideoCoverUrl(""))
}

View File

@ -1,117 +0,0 @@
{
"env": {
"browser": true,
"es6": true,
"node": true
},
"parser": "@babel/eslint-parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
},
"requireConfigFile": false,
"babelOptions": {
"babelrc": false,
"configFile": false,
"presets": ["@babel/preset-react"]
}
},
"settings": {
"react": {
"version": "detect"
}
},
"plugins": ["unused-imports"],
"extends": ["eslint:recommended", "plugin:react/recommended"],
"rules": {
"semi": ["error", "always"],
"indent": ["error", 2],
// follow antd's style guide
"quotes": ["error", "double"],
"jsx-quotes": ["error", "prefer-double"],
"space-in-parens": ["error", "never"],
"object-curly-spacing": ["error", "never"],
"array-bracket-spacing": ["error", "never"],
"comma-spacing": ["error", { "before": false, "after": true }],
"react/jsx-curly-spacing": [
"error",
{ "when": "never", "allowMultiline": true, "children": true }
],
"arrow-spacing": ["error", { "before": true, "after": true }],
"space-before-blocks": ["error", "always"],
"spaced-comment": ["error", "always"],
"react/jsx-tag-spacing": ["error", { "beforeSelfClosing": "always" }],
"block-spacing": ["error", "never"],
"space-before-function-paren": ["error", "never"],
"no-trailing-spaces": ["error", { "ignoreComments": true }],
"eol-last": ["error", "always"],
"no-var": ["error"],
"prefer-const": [
"error",
{
"destructuring": "all"
}
],
"curly": ["error", "all"],
"brace-style": ["error", "1tbs", { "allowSingleLine": true }],
"no-mixed-spaces-and-tabs": "error",
"sort-imports": [
"error",
{
"ignoreDeclarationSort": true
}
],
"no-multiple-empty-lines": [
"error",
{ "max": 1, "maxBOF": 0, "maxEOF": 0 }
],
"space-unary-ops": ["error", { "words": true, "nonwords": false }],
"space-infix-ops": "error",
"key-spacing": ["error", { "beforeColon": false, "afterColon": true }],
"comma-style": ["error", "last"],
"comma-dangle": [
"error",
{
"arrays": "always-multiline",
"objects": "always-multiline",
"imports": "never",
"exports": "never",
"functions": "never"
}
],
"no-multi-spaces": ["error", { "ignoreEOLComments": true }],
"unused-imports/no-unused-imports": "error",
"unused-imports/no-unused-vars": [
"error",
{
"vars": "all",
"varsIgnorePattern": "^_",
"args": "none",
"argsIgnorePattern": "^_"
}
],
"no-unused-vars": "off",
"react/no-deprecated": "error",
"react/jsx-key": "error",
"no-console": "error",
"eqeqeq": "error",
"keyword-spacing": "error",
"react/prop-types": "off",
"react/display-name": "off",
"react/react-in-jsx-scope": "off",
"no-case-declarations": "off"
},
"overrides": [
{
"files": [
"**/*.test.js"
],
"env": {
"jest": true
}
}
]
}

View File

@ -6,20 +6,20 @@ This project was bootstrapped with [Create React App](https://github.com/faceboo
In the project directory, you can run:
### `yarn start`
### `npm start`
Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
The page will reload if you make edits.\
You will also see any lint errors in the console.
The page will reload when you make changes.\
You may also see any lint errors in the console.
### `yarn test`
### `npm test`
Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `yarn build`
### `npm run build`
Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.
@ -29,15 +29,15 @@ Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `yarn eject`
### `npm run eject`
**Note: this is a one-way operation. Once you `eject`, you cant go back!**
**Note: this is a one-way operation. Once you `eject`, you can't go back!**
If you arent satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point youre on your own.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
You dont have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldnt feel obligated to use this feature. However we understand that this tool wouldnt be useful if you couldnt customize it when you are ready for it.
You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
## Learn More
@ -65,6 +65,6 @@ This section has moved here: [https://facebook.github.io/create-react-app/docs/a
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
### `yarn build` fails to minify
### `npm run build` fails to minify
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)

View File

@ -1,17 +0,0 @@
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
},
"useBuiltIns": "usage",
"corejs": "3.6.5"
}
]
]
}

Some files were not shown because too many files have changed in this diff Show More