Compare commits

..

10 Commits

28 changed files with 2516 additions and 90 deletions

View File

@ -22,6 +22,18 @@ ctui:
cgui:
go build -o ./bin/$@ ./cmd/$@
cfyne:
go build -o ./bin/$@ ./cmd/$@
cfyne-win:
CGO_ENABLED=1 \
CC=x86_64-w64-mingw32-gcc \
CXX=x86_64-w64-mingw32-g++ \
GOOS=windows \
GOARCH=amd64 \
go build -v -o ./bin/$@ ./cmd/cfyne
gen_test_certs:
openssl ecparam -genkey -name prime256v1 -out server.key
openssl req -new -x509 -key server.key -out server.pem -days 3650

View File

@ -1,14 +1,23 @@
# gotell
# TriCrypt
Simple communication application in golang
TriCrypt is a custom-built client-server application suite designed for secure communication with full end-to-end encryption (E2EE). It leverages the advanced Three-Layer-Encryption-Protocol (TLEP) to ensure robust security across multiple encryption layers.
## Goals
## Features
I want to create as minimalistic communication application in Go as possible.
- **Three-Layer-Encryption-Protocol (TLEP):**
- **Elliptic-Curve Diffie-Hellman (ECDH)**: Uses the `secp521r1` curve for secure key exchange.
- **Lorenz-Based Chaos System**: Adds dynamic and unpredictable transformations for encryption.
- **Zero-Trust Pseudo-Language Dictionary**: Obfuscates communication patterns to prevent unauthorized inference.
So in my list contains:
- **Client Interface**: Built with the Fyne GUI for a user-friendly, cross-platform interface.
- **Future Development**: Planned implementation of a custom terminal-based UI in Go to minimize third-party dependencies and enhance flexibility.
1. Go to stable without use of any third party dependency
2. Add security to the communication
3. Implement and test my idea about rotating public-private key pairs
## Getting Started
### Prerequisites
- **Go** (latest version recommended): [Install Go](https://golang.org/doc/install)
- **Fyne GUI Library**: Install via:
```bash
go get fyne.io/fyne/v2
```

7
cmd/cfyne/actions.go Normal file
View File

@ -0,0 +1,7 @@
package main
const (
ACTION_SET_SCENE_NICKNAME = 1 + iota
ACTION_SET_SCENE_MAIN
ACTION_UPDATE_USER_OPTS_CONTS
)

61
cmd/cfyne/conUsers.go Normal file
View File

@ -0,0 +1,61 @@
package main
import (
"log"
"sync"
)
var (
userCenter UserCenter
)
type UserCenter struct {
UsersSTOI map[string]uint16
UsersITOS map[uint16]string
Mu sync.Mutex
}
func (u *UserCenter) Init() {
u.UsersSTOI = make(map[string]uint16)
u.UsersITOS = make(map[uint16]string)
}
func (u *UserCenter) AddUser(name string, id uint16) error {
u.Mu.Lock()
defer u.Mu.Unlock()
_, alreadyHave := u.UsersSTOI[name]
if alreadyHave {
return ERROR_ALREADY_HAVE
}
log.Printf("Users: add %s with %d id\n", name, id)
u.UsersITOS[id] = name
u.UsersSTOI[name] = id
return nil
}
func (u *UserCenter) DeleteIfHaveOne(id uint16) {
name, found := u.UsersITOS[id]
if !found {
log.Printf("User with %d id is not found; Can not delete\n", id)
return
}
delete(u.UsersITOS, id)
delete(u.UsersSTOI, name)
log.Printf("User with %s name and %d id was found; User is deleted\n", name, id)
}
func (u *UserCenter) GetID(name string) (uint16, error) {
id, have := u.UsersSTOI[name]
if !have {
return 0, ERROR_DONT_HAVE
}
return id, nil
}
func (u *UserCenter) GetName(id uint16) (string, error) {
name, have := u.UsersITOS[id]
if !have {
return "", ERROR_DONT_HAVE
}
return name, nil
}

15
cmd/cfyne/funcs.go Normal file
View File

@ -0,0 +1,15 @@
package main
import (
// "fyne.io/fyne/v2/widget"
com "git.qowevisa.me/Qowevisa/gotell/communication"
)
func getSendMessageFuncToIntercom(intercom chan *com.Message, id uint8, data []byte) func() {
return func() {
intercom <- &com.Message{
ID: id,
Data: data,
}
}
}

31
cmd/cfyne/linksmuar.go Normal file
View File

@ -0,0 +1,31 @@
package main
import (
com "git.qowevisa.me/Qowevisa/gotell/communication"
"sync"
)
// Non-Generic variant
type MutexLinksArray struct {
Ar []com.Link
Mu sync.RWMutex
}
func CreateMutexLinksArray() *MutexLinksArray {
var tmp []com.Link
return &MutexLinksArray{
Ar: tmp,
}
}
func (ma *MutexLinksArray) Add(v com.Link) {
ma.Mu.Lock()
ma.Ar = append(ma.Ar, v)
ma.Mu.Unlock()
}
func (ma *MutexLinksArray) GetArray() []com.Link {
ma.Mu.RLock()
defer ma.Mu.RUnlock()
return ma.Ar
}

648
cmd/cfyne/main.go Normal file
View File

@ -0,0 +1,648 @@
package main
import (
"crypto/tls"
"crypto/x509"
"encoding/binary"
"errors"
"fmt"
"log"
"net"
"os"
"time"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/driver/desktop"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
com "git.qowevisa.me/Qowevisa/gotell/communication"
"git.qowevisa.me/Qowevisa/gotell/env"
"git.qowevisa.me/Qowevisa/gotell/extfyne/widgets"
)
func updateTime(clock *widget.Label) {
formatted := time.Now().Format("Time: 03:04:05")
clock.SetText(formatted)
}
var globalApp *MutableApplication
var globalCfg *FyneConfig
var (
ecdhKeyReceived = false
ecdhKeySent = false
)
var (
globalClipboardChannel = make(chan string)
)
func main() {
tlepCenter.Init()
userCenter.Init()
loadingFileName := env.ServerFullchainFileName
cert, err := os.ReadFile(loadingFileName)
if err != nil {
log.Fatalf("client: load root cert: %s", err)
}
log.Printf("Certificate %s loaded successfully!\n", loadingFileName)
//
roots := x509.NewCertPool()
if ok := roots.AppendCertsFromPEM(cert); !ok {
log.Fatalf("client: failed to parse root certificate")
}
config := &tls.Config{
RootCAs: roots,
}
host := "chat.qowevisa.click"
port := 3232
service := fmt.Sprintf("%s:%d", host, port)
log.Printf("client: connecting to %s", service)
conn, err := tls.Dial("tcp", service, config)
if err != nil {
log.Fatalf("client: dial: %s", err)
}
defer conn.Close()
log.Printf("client: connected to %s", service)
//
a := app.New()
w := a.NewWindow("gotell-fyne")
// w.Resize(fyne.NewSize(640, 400))
// dispatch clipboardChannel
go func(w fyne.Window) {
for val := range globalClipboardChannel {
w.Clipboard().SetContent(val)
}
}(w)
clock := widget.NewLabel("")
go func() {
for range time.Tick(time.Second) {
updateTime(clock)
}
}()
btn := widget.NewButtonWithIcon("testBtn", theme.AccountIcon(), func() {
fmt.Println("I'm pressed!")
})
mainContainer := container.New(layout.NewVBoxLayout(), clock, btn)
w.SetContent(mainContainer)
// w.SetContent(widget.NewLabel("Hello World!"))
// w2 := a.NewWindow("Larger")
// w2.SetContent(widget.NewLabel("More content"))
// w2.Resize(fyne.NewSize(100, 100))
// w2.Show()
intercomFromServer := make(chan *com.Message, 16)
intercomToServer := make(chan *com.Message, 16)
actionsChannel := make(chan int)
cfg := FyneConfig{
App: a,
Window: w,
}
globalCfg = &cfg
go readFromServer(conn, intercomFromServer)
go analyzeMessages(intercomFromServer, actionsChannel)
go actOnActions(cfg, actionsChannel, intercomToServer)
go readFromIntercom(intercomToServer, conn)
w.ShowAndRun()
}
var r com.RegisteredUser
var tmpLink *com.Link
var tmpNick string
func readFromServer(conn net.Conn, intercom chan *com.Message) {
buf := make([]byte, 70000)
for {
err := conn.SetDeadline(time.Now().Add(1 * time.Minute))
if err != nil {
log.Printf("ERROR: conn.SetDeadline: %v", err)
continue
}
n, err := conn.Read(buf)
if err != nil {
log.Printf("ERROR: client: read: %s", err)
if errors.Is(err, net.ErrClosed) {
log.Printf("caught ErrClosed!")
}
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
log.Println("caught! Read timeout occurred")
continue
}
return
}
msg, err := com.Decode(buf[:n])
if err != nil {
log.Printf("ERROR: %#v\n", err)
continue
}
if msg == nil {
continue
}
log.Printf("client: readServer: received message from server: %v", *msg)
switch msg.ID {
case com.ID_SERVER_APPROVE_CLIENT_NICKNAME:
newID := binary.BigEndian.Uint16(msg.Data)
msg.FromID = newID
msg.Data = []byte{}
r.ID = newID
if tmpNick != "" {
r.Name = tmpNick
}
r.IsRegistered = true
case com.ID_SERVER_APPROVE_CLIENT_LINK:
if tmpLink == nil {
continue
}
msg.ToID = tmpLink.UseCount
msg.Data = tmpLink.Data
// Crypto stuff
case com.ID_CLIENT_SEND_CLIENT_ECDH_PUBKEY:
t, err := tlepCenter.GetTLEP(msg.FromID)
if err != nil {
log.Printf("ERROR: tlep: GetTLEP: %v\n", err)
continue
}
err = t.ECDHApplyOtherKeyBytes(msg.Data)
if err != nil {
log.Printf("ERROR: tlep: ECDHApplyOtherKeyBytes: %v\n", err)
continue
}
fromName, err := userCenter.GetName(msg.FromID)
if err != nil {
log.Printf("ERROR: userCenter: GetName: %v\n", err)
} else {
msg.Data = []byte(fromName)
}
case com.ID_CLIENT_SEND_CLIENT_CBES_SPECS:
t, err := tlepCenter.GetTLEP(msg.FromID)
if err != nil {
log.Printf("ERROR: tlep: GetTLEP: %v\n", err)
continue
}
cbes, err := t.DecryptMessageEA(msg.Data)
if err != nil {
log.Printf("ERROR: tlep: DecryptMessageEA: %v\n", err)
continue
}
err = t.CBESSetFromBytes(cbes)
if err != nil {
log.Printf("ERROR: tlep: CBESSetFromBytes: %v\n", err)
continue
}
fromName, err := userCenter.GetName(msg.FromID)
if err != nil {
log.Printf("ERROR: userCenter: GetName: %v\n", err)
} else {
msg.Data = []byte(fromName)
}
// message
case com.ID_CLIENT_SEND_CLIENT_MESSAGE:
t, err := tlepCenter.GetTLEP(msg.FromID)
if err != nil {
log.Printf("ERROR: tlep: GetTLEP: %v\n", err)
continue
}
decrypedMsg, err := t.DecryptMessageAtMax(msg.Data)
if err != nil {
log.Printf("ERROR: tlep: DecryptMessageAtMax: %v\n", err)
continue
}
msg.Data = decrypedMsg
// switch
}
// user stuff
switch msg.ID {
case com.ID_CLIENT_ASK_CLIENT_HANDSHAKE,
com.ID_CLIENT_APPROVE_CLIENT_HANDSHAKE:
userCenter.AddUser(string(msg.Data), msg.FromID)
}
log.Printf("client: readServer: sending message to websocket: %v", *msg)
intercom <- msg
}
}
func analyzeMessages(intercomFromServer chan *com.Message, actionsChannel chan int) {
for msg := range intercomFromServer {
if msg == nil {
log.Printf("ERROR: msg is nil")
continue
}
log.Printf("Handling %v from server", *msg)
switch msg.ID {
case com.ID_SERVER_ASK_CLIENT_NICKNAME:
actionsChannel <- ACTION_SET_SCENE_NICKNAME
case com.ID_SERVER_APPROVE_CLIENT_NICKNAME:
actionsChannel <- ACTION_SET_SCENE_MAIN
case com.ID_SERVER_DECLINE_CLIENT_NICKNAME:
// TODO
// Link stuff
case com.ID_SERVER_APPROVE_CLIENT_LINK:
globalApp.ArrayBundle.LinksMuAr.Add(*tmpLink)
globalApp.Tabs.LinkTab.Content.Refresh()
case com.ID_SERVER_SEND_CLIENT_ANOTHER_ID:
selTab := globalApp.Tabs.AppTabs.Selected()
id := msg.ToID
userStr := getStdUserName(id, string(msg.Data))
globalApp.Widgets.UsersSelect.Options = append(globalApp.Widgets.UsersSelect.Options, userStr)
globalApp.Tabs.ConnsNoty++
globalApp.ArrayBundle.UsersOpts[userStr] = &UserOptions{
Status: USER_STATUS_VISIBLE,
ToID: id,
}
_, exists := globalApp.ArrayBundle.UserShortcuts[id]
if !exists {
globalApp.ArrayBundle.UserShortcuts[id] = userStr
globalApp.ArrayBundle.UserShortcutsRev[userStr] = id
}
if selTab != globalApp.Tabs.ConnectionTab {
updateTabsBasedOnNotyVals(&globalApp.Tabs)
}
actionsChannel <- ACTION_UPDATE_USER_OPTS_CONTS
case com.ID_CLIENT_ASK_CLIENT_HANDSHAKE:
selTab := globalApp.Tabs.AppTabs.Selected()
id := msg.FromID
userStr := getStdUserName(id, string(msg.Data))
globalApp.Widgets.UsersSelect.Options = append(globalApp.Widgets.UsersSelect.Options, userStr)
globalApp.Tabs.ConnsNoty++
globalApp.ArrayBundle.UsersOpts[userStr] = &UserOptions{
Status: USER_STATUS_HANDSHAKE_INIT,
ToID: id,
}
_, exists := globalApp.ArrayBundle.UserShortcuts[id]
if !exists {
globalApp.ArrayBundle.UserShortcuts[id] = userStr
globalApp.ArrayBundle.UserShortcutsRev[userStr] = id
}
if selTab != globalApp.Tabs.ConnectionTab {
updateTabsBasedOnNotyVals(&globalApp.Tabs)
}
actionsChannel <- ACTION_UPDATE_USER_OPTS_CONTS
case com.ID_CLIENT_APPROVE_CLIENT_HANDSHAKE:
id := msg.FromID
userStr := getStdUserName(id, string(msg.Data))
var shortcut string
val, exists := globalApp.ArrayBundle.UserShortcuts[id]
if !exists {
globalApp.ArrayBundle.UserShortcuts[id] = userStr
globalApp.ArrayBundle.UserShortcutsRev[userStr] = id
shortcut = userStr
} else {
shortcut = val
}
u, exists := globalApp.ArrayBundle.UsersOpts[shortcut]
if !exists {
log.Printf("WARNING!!: UserOpts[%s] NOT exists!", shortcut)
continue
}
u.Status = USER_STATUS_HANDSHAKE_ACCEPTED
actionsChannel <- ACTION_UPDATE_USER_OPTS_CONTS
case com.ID_CLIENT_SEND_CLIENT_ECDH_PUBKEY:
id := msg.FromID
if ecdhKeySent {
val, exists := globalApp.ArrayBundle.UserShortcuts[id]
if !exists {
log.Printf("WARNING!!: UserShortcuts[%d] NOT exists!", id)
continue
}
u, exists := globalApp.ArrayBundle.UsersOpts[val]
if !exists {
log.Printf("WARNING!!: UserOpts[%s] NOT exists!", val)
continue
}
u.Status = USER_STATUS_ECDH_ESTABLISHED
actionsChannel <- ACTION_UPDATE_USER_OPTS_CONTS
}
ecdhKeyReceived = true
case com.ID_CLIENT_SEND_CLIENT_CBES_SPECS:
id := msg.FromID
val, exists := globalApp.ArrayBundle.UserShortcuts[id]
if !exists {
log.Printf("WARNING!!: UserShortcuts[%d] NOT exists!", id)
continue
}
u, exists := globalApp.ArrayBundle.UsersOpts[val]
if !exists {
log.Printf("WARNING!!: UserOpts[%s] NOT exists!", val)
continue
}
u.Status = USER_STATUS_ECDH_CBES_ESTABLISHED
actionsChannel <- ACTION_UPDATE_USER_OPTS_CONTS
//
log.Printf("Checkin Messages tab")
userStr := getStdUserName(id, string(msg.Data))
var shortcut string
if !exists {
globalApp.ArrayBundle.UserShortcuts[id] = userStr
shortcut = userStr
} else {
shortcut = val
}
//
haveUser := false
for _, v := range globalApp.Widgets.MessagesSelect.Options {
if v == shortcut {
haveUser = true
break
}
}
log.Printf("MessagesSelect.Options1 are %v\n", globalApp.Widgets.MessagesSelect.Options)
log.Printf("have user is : %t\n", haveUser)
if !haveUser {
log.Printf("MessagesSelect.Options1.5 shortcut is '%s'\n", shortcut)
// LOL wtf
// globalApp.Widgets.MessagesSelect.Options = append(globalApp.Widgets.UsersSelect.Options, shortcut)
globalApp.Widgets.MessagesSelect.Options = append(globalApp.Widgets.MessagesSelect.Options, shortcut)
log.Printf("MessagesSelect.Options2 are %v\n", globalApp.Widgets.MessagesSelect.Options)
globalApp.Tabs.UsersNoty++
globalApp.Widgets.MessagesSelect.Refresh()
updateTabsBasedOnNotyVals(&globalApp.Tabs)
}
case com.ID_CLIENT_SEND_CLIENT_MESSAGE:
id := msg.FromID
shortcut, exists := globalApp.ArrayBundle.UserShortcuts[id]
if !exists {
log.Printf("WARNING: UserShortcuts[%d] NOT exists!", id)
continue
}
msgs, exists := globalApp.ArrayBundle.Messages[shortcut]
mBoardMsg := widgets.MBoardMessage{
LeftAlign: true,
Data: widget.NewLabel(string(msg.Data)),
}
if !exists {
tmp := CreateMutexArray[widgets.MBoardMessage]()
tmp.Add(mBoardMsg)
globalApp.ArrayBundle.Messages[shortcut] = &tmp
globalApp.Widgets.MBoardCaretacker.Refresh()
globalApp.Tabs.UsersTab.Content.Refresh()
} else {
msgs.Add(mBoardMsg)
globalApp.Widgets.MBoardCaretacker.Refresh()
globalApp.Tabs.UsersTab.Content.Refresh()
}
haveUser := false
for _, v := range globalApp.Widgets.MessagesSelect.Options {
if v == shortcut {
haveUser = true
break
}
}
if !haveUser {
globalApp.Widgets.MessagesSelect.Options = append(globalApp.Widgets.MessagesSelect.Options, shortcut)
globalApp.Tabs.UsersNoty++
updateTabsBasedOnNotyVals(&globalApp.Tabs)
globalApp.Widgets.MessagesSelect.Refresh()
}
//
mBoard, exists := globalApp.Widgets.MBoardMap[shortcut]
if exists {
mBoard.Add(mBoardMsg)
}
// TODO
default:
log.Printf("Can not handle msg with id %d", msg.ID)
log.Printf("Msg is different : %v", *msg)
}
}
}
func actOnActions(cfg FyneConfig, actionsChannel chan int, intercomToServer chan *com.Message) {
for action := range actionsChannel {
log.Printf("Receive action %d", action)
switch action {
case ACTION_SET_SCENE_NICKNAME:
// cfg.Window.Content()
scene := GetNicknameScene(intercomToServer)
cfg.Window.Resize(fyne.NewSize(640, 400))
cfg.Window.SetContent(scene)
case ACTION_SET_SCENE_MAIN:
scene, app := GetMainScene(intercomToServer, MainSceneConfig{
UserNickcname: tmpNick,
UserNameSet: true,
UserId: r.ID,
UserIdSet: true,
})
globalApp = app
globalApp.App.App = cfg.App
globalApp.App.Window = cfg.Window
// shortcuts
ctrl1 := &desktop.CustomShortcut{KeyName: fyne.Key1, Modifier: fyne.KeyModifierControl}
ctrl2 := &desktop.CustomShortcut{KeyName: fyne.Key2, Modifier: fyne.KeyModifierControl}
ctrl3 := &desktop.CustomShortcut{KeyName: fyne.Key3, Modifier: fyne.KeyModifierControl}
cfg.Window.Canvas().AddShortcut(ctrl1, func(shortcut fyne.Shortcut) {
app.Tabs.AppTabs.Select(app.Tabs.LinkTab)
})
cfg.Window.Canvas().AddShortcut(ctrl2, func(shortcut fyne.Shortcut) {
app.Tabs.AppTabs.Select(app.Tabs.ConnectionTab)
})
cfg.Window.Canvas().AddShortcut(ctrl3, func(shortcut fyne.Shortcut) {
app.Tabs.AppTabs.Select(app.Tabs.UsersTab)
})
// cfg.Window.Resize(fyne.NewSize(640, 400))
cfg.Window.SetContent(scene)
// ACTION_UPDATE_USER_OPTS_CONTS
case ACTION_UPDATE_USER_OPTS_CONTS:
for _, u := range globalApp.ArrayBundle.UsersOpts {
switch u.Status {
case USER_STATUS_VISIBLE:
btn := widget.NewButton("Init Handhake", func() {})
btn.OnTapped = func() {
intercomToServer <- &com.Message{
ID: com.ID_CLIENT_ASK_CLIENT_HANDSHAKE,
ToID: u.ToID,
}
btn.Hide()
}
u.OptsContainer = container.NewGridWithRows(1, btn)
cTaker := globalApp.Widgets.UserOptsCaretaker
cTaker.RemoveAll()
cTaker.Add(u.OptsContainer)
case USER_STATUS_HANDSHAKE_INIT:
btn := widget.NewButton("Accept Handhake", func() {})
btn.OnTapped = func() {
intercomToServer <- &com.Message{
ID: com.ID_CLIENT_APPROVE_CLIENT_HANDSHAKE,
ToID: u.ToID,
}
btn.Hide()
u.Status = USER_STATUS_HANDSHAKE_ACCEPTED
actionsChannel <- ACTION_UPDATE_USER_OPTS_CONTS
}
u.OptsContainer = container.NewGridWithRows(1, btn)
cTaker := globalApp.Widgets.UserOptsCaretaker
cTaker.RemoveAll()
cTaker.Add(u.OptsContainer)
case USER_STATUS_HANDSHAKE_ACCEPTED:
btn := widget.NewButton("Send ECDH PubKey", func() {})
btn.OnTapped = func() {
intercomToServer <- &com.Message{
ID: com.ID_CLIENT_SEND_CLIENT_ECDH_PUBKEY,
ToID: u.ToID,
}
btn.Hide()
if ecdhKeyReceived {
u.Status = USER_STATUS_ECDH_ESTABLISHED
actionsChannel <- ACTION_UPDATE_USER_OPTS_CONTS
}
ecdhKeySent = true
}
u.OptsContainer = container.NewGridWithRows(1, btn)
cTaker := globalApp.Widgets.UserOptsCaretaker
cTaker.RemoveAll()
cTaker.Add(u.OptsContainer)
case USER_STATUS_ECDH_ESTABLISHED:
btn := widget.NewButton("Send CBES Specs", func() {})
btn.OnTapped = func() {
intercomToServer <- &com.Message{
ID: com.ID_CLIENT_SEND_CLIENT_CBES_SPECS,
ToID: u.ToID,
}
btn.Hide()
}
u.OptsContainer = container.NewGridWithRows(1, btn)
cTaker := globalApp.Widgets.UserOptsCaretaker
cTaker.RemoveAll()
cTaker.Add(u.OptsContainer)
case USER_STATUS_ECDH_CBES_ESTABLISHED:
btn := widget.NewButton("TBC", func() {})
btn.OnTapped = func() {
log.Println("TODO:: 1001")
}
u.OptsContainer = container.NewGridWithRows(1, btn)
cTaker := globalApp.Widgets.UserOptsCaretaker
cTaker.RemoveAll()
cTaker.Add(u.OptsContainer)
default:
}
}
// globalApp.Tabs.ConnectionTab.Content.Refresh()
// ACTION_UPDATE_USER_OPTS_CONTS
default:
}
}
}
func readFromIntercom(intercom chan *com.Message, conn net.Conn) {
for msg := range intercom {
log.Printf("client: received message from Intercom: %v", msg)
msg.Version = com.V1
switch msg.ID {
case com.ID_CLIENT_SEND_SERVER_NICKNAME:
tmpNick = string(msg.Data)
case com.ID_CLIENT_SEND_SERVER_LINK:
if !r.IsRegistered {
continue
}
l, err := r.GenerateLink(msg.ToID)
if err != nil {
log.Printf("Error: link: %v", err)
continue
}
tmpLink = &l
answ, err := com.ClientSendServerLink(r.ID, l)
if err != nil {
log.Printf("Error: com: %v", err)
continue
}
log.Printf("client: readWS: sending data to server: %v", answ)
conn.Write(answ)
continue
case com.ID_CLIENT_ASK_CLIENT_HANDSHAKE,
com.ID_CLIENT_APPROVE_CLIENT_HANDSHAKE,
com.ID_CLIENT_DECLINE_CLIENT_HANDSHAKE,
com.ID_CLIENT_SEND_CLIENT_ECDH_PUBKEY,
com.ID_CLIENT_SEND_CLIENT_CBES_SPECS,
com.ID_CLIENT_SEND_CLIENT_MKLG_FINGERPRINT,
com.ID_CLIENT_DECLINE_CLIENT_MKLG_FINGERPRINT,
com.ID_CLIENT_SEND_CLIENT_MESSAGE:
if !r.IsRegistered {
continue
}
msg.FromID = r.ID
// switch
}
// user stuff
switch msg.ID {
case com.ID_CLIENT_ASK_CLIENT_HANDSHAKE,
com.ID_CLIENT_APPROVE_CLIENT_HANDSHAKE:
if r.IsRegistered {
msg.Data = []byte(r.Name)
}
}
// Crypto stuff
switch msg.ID {
case com.ID_CLIENT_ASK_CLIENT_HANDSHAKE,
com.ID_CLIENT_APPROVE_CLIENT_HANDSHAKE:
err := tlepCenter.AddTLEP(msg.ToID, fmt.Sprintf("%s-%d", r.Name, msg.ToID))
if err != nil {
log.Printf("ERROR: tlepCenter.AddUser: %v\n", err)
}
case com.ID_CLIENT_SEND_CLIENT_ECDH_PUBKEY:
t, err := tlepCenter.GetTLEP(msg.ToID)
if err != nil {
log.Printf("ERROR: tlep: GetTLEP: %v\n", err)
continue
}
key, err := t.ECDHGetPublicKey()
if err != nil {
log.Printf("ERROR: tlep: ECDHGetPublicKey: %v\n", err)
continue
}
msg.Data = key
case com.ID_CLIENT_SEND_CLIENT_CBES_SPECS:
t, err := tlepCenter.GetTLEP(msg.ToID)
if err != nil {
log.Printf("ERROR: tlep: GetTLEP: %v\n", err)
continue
}
err = t.CBESInitRandom()
if err != nil {
log.Printf("ERROR: tlep: CBESInitRandom: %v\n", err)
continue
}
cbes, err := t.CBESGetBytes()
if err != nil {
log.Printf("ERROR: tlep: ECDHGetPublicKey: %v\n", err)
continue
}
cbesEAEncr, err := t.EncryptMessageEA(cbes)
if err != nil {
log.Printf("ERROR: tlep: EncryptMessageEA: %v\n", err)
continue
}
msg.Data = cbesEAEncr
// message
case com.ID_CLIENT_SEND_CLIENT_MESSAGE:
t, err := tlepCenter.GetTLEP(msg.ToID)
if err != nil {
log.Printf("ERROR: tlep: GetTLEP: %v\n", err)
continue
}
encrypedMsg, err := t.EncryptMessageAtMax(msg.Data)
if err != nil {
log.Printf("ERROR: tlep: EncryptMessageAtMax: %v\n", err)
continue
}
msg.Data = encrypedMsg
// switch
}
encodedMsg, err := msg.Bytes()
if err != nil {
log.Printf("Encoding error: %s", err)
continue
}
log.Printf("client: readWS: sending data to server: %v", encodedMsg)
conn.Write(encodedMsg)
}
}

377
cmd/cfyne/scenes.go Normal file
View File

@ -0,0 +1,377 @@
package main
import (
"errors"
"fmt"
"log"
"strconv"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/theme"
// "fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
com "git.qowevisa.me/Qowevisa/gotell/communication"
"git.qowevisa.me/Qowevisa/gotell/extfyne/layouts"
"git.qowevisa.me/Qowevisa/gotell/extfyne/widgets"
)
func GetNicknameScene(intercom chan *com.Message) *fyne.Container {
// button := widget.NewButtonWithIcon(
// "Send",
// theme.ConfirmIcon(),
// getSendMessageFuncToIntercom(intercom, com.ID_CLIENT_SEND_SERVER_NICKNAME, []byte("test")))
entry := widget.NewEntry()
entry.SetPlaceHolder("Enter Nickname:")
btn := widget.NewButtonWithIcon("Send", theme.MailSendIcon(), func() {
log.Println("Nickname submitted:", entry.Text)
intercom <- &com.Message{
ID: com.ID_CLIENT_SEND_SERVER_NICKNAME,
Data: []byte(entry.Text),
}
})
contentInner := container.New(layout.NewVBoxLayout(), entry, btn)
return container.NewGridWithRows(3,
layout.NewSpacer(),
container.NewGridWithColumns(3,
layout.NewSpacer(),
contentInner,
layout.NewSpacer(),
),
layout.NewSpacer(),
)
}
func GetMainScene(intercom chan *com.Message, cfg MainSceneConfig) (*fyne.Container, *MutableApplication) {
headerWidget := widget.NewLabel(fmt.Sprintf("Hello, %s! Your ID: %d", cfg.UserNickcname, cfg.UserId))
header := container.NewGridWithColumns(3,
layout.NewSpacer(),
headerWidget,
layout.NewSpacer(),
)
linksSS, linksArr := GetLinksSubScene(intercom, header)
linksTab := container.NewTabItemWithIcon("Links", theme.MailComposeIcon(), linksSS)
conSS, conBundle, conWidgets := GetConnectionsSubScene(intercom, header)
connsTab := container.NewTabItemWithIcon("Connections", theme.ComputerIcon(), conSS)
userSS, userBundle, userWidgets := GetUsersSubScene(intercom, header, conBundle.UserShortcutsRev)
usersTab := container.NewTabItemWithIcon("Users", theme.AccountIcon(), userSS)
tabs := container.NewAppTabs(
linksTab,
connsTab,
usersTab,
)
tabs.SetTabLocation(container.TabLocationLeading)
return container.NewGridWithColumns(1,
tabs),
&MutableApplication{
Tabs: MutableStructAboutTabs{
AppTabs: tabs,
LinkTab: linksTab,
LinksBT: "Links",
LinksNoty: 0,
ConnectionTab: connsTab,
ConnsBT: "Connections",
ConnsNoty: 0,
UsersTab: usersTab,
UsersBT: "Users",
UsersNoty: 0,
},
ArrayBundle: BundleOfMutexArrays{
LinksMuAr: linksArr,
UsersMuAr: conBundle.UsersMuAr,
UsersOpts: conBundle.UsersOpts,
UserShortcuts: conBundle.UserShortcuts,
UserShortcutsRev: conBundle.UserShortcutsRev,
Messages: userBundle.Messages,
},
Widgets: MutableStructAboutWidgets{
UsersSelect: conWidgets.UsersSelect,
UserOptsCaretaker: conWidgets.UserOptsCaretaker,
MessagesSelect: userWidgets.MessagesSelect,
MBoardCaretacker: userWidgets.MBoardCaretacker,
MsgButton: userWidgets.MsgButton,
MBoardMap: userWidgets.MBoardMap,
},
}
}
func GetLinksSubScene(intercom chan *com.Message, header *fyne.Container) (*fyne.Container, *MutexLinksArray) {
entry := widget.NewEntry()
entry.SetPlaceHolder("Count:")
entry.Validator = func(s string) error {
val, err := strconv.ParseUint(s, 10, 16)
if err == nil && val == 0 {
return errors.New("Use count can't be 0")
}
return err
}
btn := widget.NewButtonWithIcon("Generate", theme.MailSendIcon(), func() {
count, err := strconv.ParseUint(entry.Text, 10, 16)
if err != nil || count == 0 {
log.Printf("dafuq: GetLinksSubScene: %v ; %d\n", err, count)
return
}
intercom <- &com.Message{
ID: com.ID_CLIENT_SEND_SERVER_LINK,
ToID: uint16(count),
}
})
entry.SetOnValidationChanged(func(err error) {
if err != nil {
btn.Hide()
} else {
if btn.Hidden {
btn.Show()
}
}
})
contentInner := container.NewGridWithColumns(2, entry, btn)
// /
linksMutAt := CreateMutexLinksArray()
linksList := widget.NewList(func() int {
return len(linksMutAt.GetArray())
}, func() fyne.CanvasObject {
return widget.NewLabel("template")
}, func(lii widget.ListItemID, co fyne.CanvasObject) {
link := linksMutAt.Ar[lii]
str := fmt.Sprintf("Count: %d ; %s", link.UseCount, link.Data)
co.(*widget.Label).SetText(str)
},
)
linksList.OnSelected = func(id widget.ListItemID) {
link := linksMutAt.Ar[id]
globalClipboardChannel <- string(link.Data)
}
// //
linksGetEntry := widget.NewEntry()
linksGetEntry.SetPlaceHolder("Link:")
linksGetEntry.Validator = func(s string) error {
validated, err := com.IsThisALinkData(s)
if err != nil {
return err
}
if !validated {
return errors.New("Link is not validated")
}
return nil
}
linksGetBtn := widget.NewButtonWithIcon("Get", theme.MailReplyIcon(), func() {
link := linksGetEntry.Text
validated, err := com.IsThisALinkData(link)
if err != nil {
log.Printf("linksGetBtn: Error: %v\n", err)
return
}
if !validated {
log.Printf("linksGetBtn: Error: link %v not validated\n", link)
return
}
intercom <- &com.Message{
ID: com.ID_CLIENT_ASK_SERVER_LINK,
Data: []byte(link),
}
})
linksGetEntry.SetOnValidationChanged(func(err error) {
if err != nil {
linksGetBtn.Hide()
} else {
if linksGetBtn.Hidden {
linksGetBtn.Show()
}
}
})
contentInner2 := container.NewGridWithColumns(2, linksGetEntry, linksGetBtn)
// /
// //
return container.NewGridWithRows(3,
header,
container.New(
layouts.NewVariableGridWithColumns(
6, []int{2, 1, 3}),
container.NewGridWithRows(3,
container.NewGridWithColumns(3,
layout.NewSpacer(),
widget.NewLabel("Create link:"),
layout.NewSpacer()),
contentInner,
layout.NewSpacer(),
),
layout.NewSpacer(),
linksList,
),
container.New(
layouts.NewVariableGridWithColumns(
6, []int{2, 4}),
container.NewGridWithRows(3,
container.NewGridWithColumns(3,
layout.NewSpacer(),
widget.NewLabel("Get user from link:"),
layout.NewSpacer()),
contentInner2,
layout.NewSpacer(),
),
layout.NewSpacer(),
),
), linksMutAt
}
func GetConnectionsSubScene(intercom chan *com.Message, header *fyne.Container) (*fyne.Container, BundleOfMutexArrays, MutableStructAboutWidgets) {
optionsHeaderLabel := widget.NewLabel("Options for user: ")
usersMuAr := CreateMutexStringArray()
usersOptions := make(map[string]*UserOptions)
userShortcuts := make(map[uint16]string)
userShortcutsRev := make(map[string]uint16)
userOptsCaretaker := container.NewGridWithRows(1)
optsContainer := container.NewGridWithRows(2,
optionsHeaderLabel,
userOptsCaretaker,
)
userSelect := widget.NewSelect(usersMuAr.Ar, func(s string) {
optionsHeaderLabel.SetText(fmt.Sprintf("Options for user: %s", s))
uOpts, exists := usersOptions[s]
if !exists {
log.Printf("GetConnectionsSubScene::1 : TODO!!\n")
// TODO
return
}
userOptsCaretaker.RemoveAll()
userOptsCaretaker.Add(uOpts.OptsContainer)
optsContainer.Refresh()
})
contentInner := container.New(layout.NewVBoxLayout(), userSelect, optsContainer)
return container.New(
layout.NewVBoxLayout(),
header,
container.New(
layout.NewHBoxLayout(),
layout.NewSpacer(),
contentInner,
layout.NewSpacer(),
),
), BundleOfMutexArrays{
UsersMuAr: usersMuAr,
UsersOpts: usersOptions,
UserShortcuts: userShortcuts,
UserShortcutsRev: userShortcutsRev,
}, MutableStructAboutWidgets{
UsersSelect: userSelect,
UserOptsCaretaker: userOptsCaretaker,
}
}
func GetUsersSubScene(intercom chan *com.Message, header *fyne.Container, userShortcutsRev map[string]uint16) (*fyne.Container, BundleOfMutexArrays, MutableStructAboutWidgets) {
msgHeader := widget.NewLabel("Messages With User: ")
usersMessages := make(map[string]*MutexArray[widgets.MBoardMessage])
usersMBoards := make(map[string]*widgets.MessageBoard)
msgEntry := widget.NewEntry()
msgEntry.SetPlaceHolder("Message...")
userMsgSendBtn := widget.NewButtonWithIcon("Send", theme.MailSendIcon(), func() {})
mBoardCareTaker := container.NewGridWithRows(1)
userMsgsSelect := widget.NewSelect([]string{}, func(s string) {
msgHeader.SetText(fmt.Sprintf("Messages With User: %s", s))
msgsMuAr, exists := usersMessages[s]
if !exists {
tmp := CreateMutexArray[widgets.MBoardMessage]()
usersMessages[s] = &tmp
msgsMuAr = &tmp
return
}
mBoardCareTaker.RemoveAll()
mmBoard := widgets.NewMessageBoard(msgsMuAr.Ar)
usersMBoards[s] = mmBoard
mBoardCareTaker.Add(mmBoard)
mBoardCareTaker.Refresh()
id, exists := userShortcutsRev[s]
if !exists {
log.Printf("GetUsersSubScene::2 : TODO!!\n")
// TODO
return
}
userMsgSendBtn.Text = fmt.Sprintf("%s", s)
userMsgSendBtn.OnTapped = func() {
intercom <- &com.Message{
ID: com.ID_CLIENT_SEND_CLIENT_MESSAGE,
ToID: id,
Data: []byte(msgEntry.Text),
}
msg := widgets.MBoardMessage{
LeftAlign: false,
Data: widget.NewLabel(msgEntry.Text),
}
msgsMuAr.Add(msg)
mmBoard.Add(msg)
msgEntry.Text = ""
msgEntry.Refresh()
mBoardCareTaker.Refresh()
mmBoard.Refresh()
}
userMsgSendBtn.Refresh()
})
// entryWithButton := container.NewHBox(
// layout.NewSpacer(),
// container.NewPadded(msgEntry),
// userMsgSendBtn,
// )
entryWithButton := container.New(
layouts.NewEntryBtn7030(),
msgEntry,
userMsgSendBtn,
)
fs := globalCfg.Window.Canvas().Size()
scene := container.New(
layout.NewVBoxLayout(),
header,
container.NewGridWithColumns(2,
container.New(
layout.NewVBoxLayout(),
layout.NewSpacer(),
container.New(
layout.NewHBoxLayout(),
userMsgsSelect,
msgHeader,
),
),
container.New(
layout.NewVBoxLayout(),
container.New(
layouts.NewFullWidthWithSize(fyne.NewSize(0, fs.Height*0.8)),
mBoardCareTaker,
),
layout.NewSpacer(),
entryWithButton,
),
),
)
// container.New(
// layouts.NewVariableGridWithRows(3, []int{1, 2}),
// header,
// container.New(
// layouts.NewVariableGridWithColumns(4, []int{1, 3}),
// container.NewGridWithColumns(3,
// layout.NewSpacer(),
// container.NewVBox(userMsgsSelect, msgHeader),
// layout.NewSpacer()),
// container.New(
// layouts.NewVariableGridWithRows(6, []int{5, 1}),
// mBoardCareTaker,
// container.NewHBox(msgEntry, userMsgSendBtn),
// ),
// ),
// )
return scene, BundleOfMutexArrays{
Messages: usersMessages,
}, MutableStructAboutWidgets{
MessagesSelect: userMsgsSelect,
MBoardCaretacker: mBoardCareTaker,
MsgButton: userMsgSendBtn,
MBoardMap: usersMBoards,
}
}

66
cmd/cfyne/tleps.go Normal file
View File

@ -0,0 +1,66 @@
package main
import (
"errors"
"log"
"sync"
"git.qowevisa.me/Qowevisa/gotell/gmyerr"
"git.qowevisa.me/Qowevisa/gotell/tlep"
)
var (
tlepCenter TlepCenter
)
type TlepCenter struct {
TLEPs map[uint16]*tlep.TLEP
Mu sync.Mutex
}
func (t *TlepCenter) Init() {
t.TLEPs = make(map[uint16]*tlep.TLEP)
}
var (
ERROR_ALREADY_HAVE = errors.New("Already taken")
ERROR_DONT_HAVE = errors.New("Not found")
)
func (t *TlepCenter) AddTLEP(id uint16, name string) error {
t.Mu.Lock()
defer t.Mu.Unlock()
_, alreadyHave := t.TLEPs[id]
if alreadyHave {
return ERROR_ALREADY_HAVE
}
val, err := tlep.InitTLEP(name)
if err != nil {
return gmyerr.WrapPrefix("tlep.InitTLEP", err)
}
val.Debug = true
t.TLEPs[id] = val
log.Printf("TLEPs: add %p for %d id\n", val, id)
return nil
}
func (t *TlepCenter) DeleteIfHaveOne(id uint16) {
t.Mu.Lock()
defer t.Mu.Unlock()
val, found := t.TLEPs[id]
if !found {
log.Printf("TLEP with %d id is not found; Can not delete\n", id)
return
}
delete(t.TLEPs, id)
log.Printf("TLEP with %v val and %d id was found; TLEP is deleted\n", val, id)
}
func (t *TlepCenter) GetTLEP(id uint16) (*tlep.TLEP, error) {
log.Printf("Getting tlep by id = %d\n", id)
name, have := t.TLEPs[id]
if !have {
return nil, ERROR_DONT_HAVE
}
return name, nil
}

125
cmd/cfyne/types.go Normal file
View File

@ -0,0 +1,125 @@
package main
import (
"sync"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/widget"
"git.qowevisa.me/Qowevisa/gotell/extfyne/widgets"
// com "git.qowevisa.me/Qowevisa/gotell/communication"
)
type FyneConfig struct {
App fyne.App
Window fyne.Window
}
type MainSceneConfig struct {
UserNickcname string
// Just for my calmness
UserNameSet bool
UserId uint16
// Just for my calmness
UserIdSet bool
}
type MutableStructAboutTabs struct {
AppTabs *container.AppTabs
LinkTab *container.TabItem
LinksBT string
LinksNoty uint
ConnectionTab *container.TabItem
ConnsBT string
ConnsNoty uint
UsersTab *container.TabItem
UsersBT string
UsersNoty uint
}
type MutableStructAboutWidgets struct {
UsersSelect *widget.Select
UserOptsCaretaker *fyne.Container
MessagesSelect *widget.Select
MBoardCaretacker *fyne.Container
MsgButton *widget.Button
MBoardMap map[string]*widgets.MessageBoard
}
type UserOptions struct {
OptsContainer *fyne.Container
Status int
ToID uint16
Name string
}
type BundleOfMutexArrays struct {
LinksMuAr *MutexLinksArray
UsersMuAr *MutexStringArray
UsersOpts map[string]*UserOptions
UserShortcuts map[uint16]string
UserShortcutsRev map[string]uint16
Messages map[string]*MutexArray[widgets.MBoardMessage]
}
type MutableApp struct {
App fyne.App
Window fyne.Window
}
type MutableApplication struct {
Tabs MutableStructAboutTabs
Widgets MutableStructAboutWidgets
ArrayBundle BundleOfMutexArrays
App MutableApp
}
// I don't know if it is a good idea
type MutexArray[T any] struct {
Ar []T
Mu sync.RWMutex
}
func CreateMutexArray[T any]() MutexArray[T] {
var tmp []T
return MutexArray[T]{
Ar: tmp,
}
}
func (ma *MutexArray[T]) Add(v T) {
ma.Mu.Lock()
ma.Ar = append(ma.Ar, v)
ma.Mu.Unlock()
}
func (ma *MutexArray[T]) GetArray() []T {
ma.Mu.RLock()
defer ma.Mu.RUnlock()
return ma.Ar
}
// Non-Generic variant
type MutexStringArray struct {
Ar []string
Mu sync.RWMutex
}
func CreateMutexStringArray() *MutexStringArray {
var tmp []string
return &MutexStringArray{
Ar: tmp,
}
}
func (ma *MutexStringArray) Add(v string) {
ma.Mu.Lock()
ma.Ar = append(ma.Ar, v)
ma.Mu.Unlock()
}
func (ma *MutexStringArray) GetArray() []string {
ma.Mu.RLock()
defer ma.Mu.RUnlock()
return ma.Ar
}

View File

@ -0,0 +1,36 @@
package main
import (
// "log"
//
// "fyne.io/fyne/v2"
// "fyne.io/fyne/v2/container"
// "fyne.io/fyne/v2/widget"
// com "git.qowevisa.me/Qowevisa/gotell/communication"
)
const (
USER_STATUS_NOT_VISIBLE = 0 + iota
USER_STATUS_VISIBLE
USER_STATUS_HANDSHAKE_INIT
USER_STATUS_HANDSHAKE_ACCEPTED
USER_STATUS_ECDH_ESTABLISHED
USER_STATUS_ECDH_CBES_ESTABLISHED
USER_STATUS_ECDH_CBES_MKLG_ESTABLISHED
)
// func getUserOptsContainer(userStatus int, intercom chan *com.Message) *fyne.Container {
// switch {
// case USER_STATUS_HANDSHAKE_INIT:
// btn := widget.NewButton("Init Hadnshake", func() {
// intercom <- &com.Message{
// ID: ID_CLIENT_ASK_CLIENT_HANDSHAKE,
// ToID: ,
// }
// })
// return container.NewGridWithRows(1, )
// default:
// log.Printf("ERROR: getUserOptsContainer: status %d was not handled!", userStatus)
// return container.NewGridWithRows(1, widget.NewLabel("ERROR: 500"))
// }
// }

18
cmd/cfyne/util.go Normal file
View File

@ -0,0 +1,18 @@
package main
import "fmt"
func getStdUserName(userID uint16, userName string) string {
return fmt.Sprintf("User: %s; ID: %d", userName, userID)
}
func getTabNameBasedOnBaseTextAndNoty(baseText string, noty uint) string {
return fmt.Sprintf("%s (%d)", baseText, noty)
}
func updateTabsBasedOnNotyVals(tabs *MutableStructAboutTabs) {
tabs.LinkTab.Text = getTabNameBasedOnBaseTextAndNoty(tabs.LinksBT, tabs.LinksNoty)
tabs.ConnectionTab.Text = getTabNameBasedOnBaseTextAndNoty(tabs.ConnsBT, tabs.ConnsNoty)
tabs.UsersTab.Text = getTabNameBasedOnBaseTextAndNoty(tabs.UsersBT, tabs.UsersNoty)
tabs.AppTabs.Refresh()
}

61
cmd/cgui/conUsers.go Normal file
View File

@ -0,0 +1,61 @@
package main
import (
"log"
"sync"
)
var (
userCenter UserCenter
)
type UserCenter struct {
UsersSTOI map[string]uint16
UsersITOS map[uint16]string
Mu sync.Mutex
}
func (u *UserCenter) Init() {
u.UsersSTOI = make(map[string]uint16)
u.UsersITOS = make(map[uint16]string)
}
func (u *UserCenter) AddUser(name string, id uint16) error {
u.Mu.Lock()
defer u.Mu.Unlock()
_, alreadyHave := u.UsersSTOI[name]
if alreadyHave {
return ERROR_ALREADY_HAVE
}
log.Printf("Users: add %s with %d id\n", name, id)
u.UsersITOS[id] = name
u.UsersSTOI[name] = id
return nil
}
func (u *UserCenter) DeleteIfHaveOne(id uint16) {
name, found := u.UsersITOS[id]
if !found {
log.Printf("User with %d id is not found; Can not delete\n", id)
return
}
delete(u.UsersITOS, id)
delete(u.UsersSTOI, name)
log.Printf("User with %s name and %d id was found; User is deleted\n", name, id)
}
func (u *UserCenter) GetID(name string) (uint16, error) {
id, have := u.UsersSTOI[name]
if !have {
return 0, ERROR_DONT_HAVE
}
return id, nil
}
func (u *UserCenter) GetName(id uint16) (string, error) {
name, have := u.UsersITOS[id]
if !have {
return "", ERROR_DONT_HAVE
}
return name, nil
}

View File

@ -18,6 +18,7 @@ import (
func main() {
tlepCenter.Init()
userCenter.Init()
loadingFileName := env.ServerFullchainFileName
cert, err := os.ReadFile(loadingFileName)
if err != nil {
@ -120,7 +121,12 @@ func readFromServer(conn net.Conn, ws *websocket.Conn) {
log.Printf("ERROR: tlep: ECDHApplyOtherKeyBytes: %v\n", err)
continue
}
msg.Data = []byte{}
fromName, err := userCenter.GetName(msg.FromID)
if err != nil {
log.Printf("ERROR: userCenter: GetName: %v\n", err)
} else {
msg.Data = []byte(fromName)
}
case com.ID_CLIENT_SEND_CLIENT_CBES_SPECS:
t, err := tlepCenter.GetTLEP(msg.FromID)
if err != nil {
@ -137,6 +143,12 @@ func readFromServer(conn net.Conn, ws *websocket.Conn) {
log.Printf("ERROR: tlep: CBESSetFromBytes: %v\n", err)
continue
}
fromName, err := userCenter.GetName(msg.FromID)
if err != nil {
log.Printf("ERROR: userCenter: GetName: %v\n", err)
} else {
msg.Data = []byte(fromName)
}
// message
case com.ID_CLIENT_SEND_CLIENT_MESSAGE:
t, err := tlepCenter.GetTLEP(msg.FromID)
@ -152,6 +164,12 @@ func readFromServer(conn net.Conn, ws *websocket.Conn) {
msg.Data = decrypedMsg
// switch
}
// user stuff
switch msg.ID {
case com.ID_CLIENT_ASK_CLIENT_HANDSHAKE,
com.ID_CLIENT_APPROVE_CLIENT_HANDSHAKE:
userCenter.AddUser(string(msg.Data), msg.FromID)
}
log.Printf("client: readServer: sending message to websocket: %v", *msg)
ws.WriteJSON(*msg)
}
@ -202,6 +220,14 @@ func readFromWebSocket(conn net.Conn, ws *websocket.Conn) {
msg.FromID = r.ID
// switch
}
// user stuff
switch msg.ID {
case com.ID_CLIENT_ASK_CLIENT_HANDSHAKE,
com.ID_CLIENT_APPROVE_CLIENT_HANDSHAKE:
if r.IsRegistered {
msg.Data = []byte(r.Name)
}
}
// Crypto stuff
switch msg.ID {
case com.ID_CLIENT_ASK_CLIENT_HANDSHAKE,

View File

@ -5,6 +5,7 @@ import (
"crypto/rand"
"encoding/base32"
"encoding/gob"
"errors"
"git.qowevisa.me/Qowevisa/gotell/gmyerr"
)
@ -158,6 +159,18 @@ func (r *RegisteredUser) GenerateLink(count uint16) (Link, error) {
return l, nil
}
func IsThisALinkData(data string) (bool, error) {
dst := make([]byte, len([]byte(data)))
n, err := base32.StdEncoding.Decode(dst, []byte(data))
if err != nil {
return false, err
}
if n != LINK_LEN_V1 {
return false, errors.New("Link len is not standard")
}
return true, nil
}
func (l *Link) Bytes() ([]byte, error) {
var buf bytes.Buffer
encoder := gob.NewEncoder(&buf)

View File

@ -0,0 +1,40 @@
package layouts
import "fyne.io/fyne/v2"
// Implements: fyne.Layout
type EntryBtn7030 struct{}
// Implements: fyne.Layout 1
func (p *EntryBtn7030) MinSize(objects []fyne.CanvasObject) fyne.Size {
minWidth := float32(0)
minHeight := float32(0)
for _, obj := range objects {
minSize := obj.MinSize()
minWidth += minSize.Width
if minSize.Height > minHeight {
minHeight = minSize.Height
}
}
return fyne.NewSize(minWidth, minHeight)
}
// Implements: fyne.Layout 2
func (p *EntryBtn7030) Layout(objects []fyne.CanvasObject, size fyne.Size) {
if len(objects) != 2 {
return
}
entryWidth := size.Width * 0.7
buttonWidth := size.Width * 0.3
objects[0].Resize(fyne.NewSize(entryWidth, size.Height))
objects[1].Resize(fyne.NewSize(buttonWidth, size.Height))
objects[0].Move(fyne.NewPos(0, 0))
objects[1].Move(fyne.NewPos(entryWidth, 0))
}
func NewEntryBtn7030() fyne.Layout {
return &EntryBtn7030{}
}

View File

@ -0,0 +1,41 @@
package layouts
import (
"fyne.io/fyne/v2"
)
// Implements: fyne.Layout
type FullScale struct {
size fyne.Size
}
// Implements: fyne.Layout 1
func (p *FullScale) MinSize(objects []fyne.CanvasObject) fyne.Size {
return p.size
}
// Implements: fyne.Layout 2
func (p *FullScale) Layout(objects []fyne.CanvasObject, size fyne.Size) {
if len(objects) != 1 {
return
}
if p.size.Width < size.Width {
p.size.Width = size.Width
}
if p.size.Height < size.Height {
p.size.Height = size.Height
}
objects[0].Resize(fyne.NewSize(p.size.Width, p.size.Height))
objects[0].Move(fyne.NewPos(0, 0))
}
func NewFullWidth() fyne.Layout {
return &FullScale{}
}
func NewFullWidthWithSize(s fyne.Size) fyne.Layout {
return &FullScale{
size: s,
}
}

View File

@ -0,0 +1,58 @@
package layouts
import "fyne.io/fyne/v2"
// Implements: fyne.Layout
type VarGridCols struct {
cols int
cfg []int
}
func NewVariableGridWithColumns(cols int, cfg []int) *VarGridCols {
return &VarGridCols{
cols: cols,
cfg: cfg,
}
}
// Implements: fyne.Layout : 1
func (v *VarGridCols) MinSize(objects []fyne.CanvasObject) fyne.Size {
w, h := float32(0), float32(0)
i := 0
for _, o := range objects {
if !o.Visible() {
continue
}
childSize := o.MinSize()
// NOTE: can be out-of-bounds error if not checked at creation
takenCols := v.cfg[i]
if takenCols > 1 {
w += childSize.Width * float32(takenCols)
} else {
w += childSize.Width
}
if h+childSize.Height > h {
h += childSize.Height
}
i++
}
return fyne.NewSize(w, h)
}
// Implements: fyne.Layout : 2
func (v *VarGridCols) Layout(objects []fyne.CanvasObject, contSize fyne.Size) {
// pos := fyne.NewPos(0, contSize.Height-v.MinSize(objects).Height)
pos := fyne.NewPos(0, 0)
cellWidthSingular := float64(contSize.Width) / float64(v.cols)
cellHeight := contSize.Height
for i, o := range objects {
numCols := v.cfg[i]
w := cellWidthSingular * float64(numCols)
o.Move(pos)
o.Resize(fyne.NewSize(float32(w), cellHeight))
pos = pos.Add(fyne.NewPos(float32(w), 0))
}
}

View File

@ -0,0 +1,53 @@
package layouts
import "fyne.io/fyne/v2"
// Implements: fyne.Layout
type VarGridRows struct {
rows int
cfg []int
}
func NewVariableGridWithRows(cols int, cfg []int) *VarGridRows {
return &VarGridRows{
rows: cols,
cfg: cfg,
}
}
// Implements: fyne.Layout : 1
func (v *VarGridRows) MinSize(objects []fyne.CanvasObject) fyne.Size {
w, h := float32(0), float32(0)
for i, o := range objects {
childSize := o.MinSize()
// NOTE: can be out-of-bounds error if not checked at creation
takenRows := v.cfg[i]
if takenRows > 1 {
h += childSize.Height * float32(takenRows)
} else {
h += childSize.Height
}
if h+childSize.Height > h {
w += childSize.Width
}
}
return fyne.NewSize(w, h)
}
// Implements: fyne.Layout : 2
func (v *VarGridRows) Layout(objects []fyne.CanvasObject, contSize fyne.Size) {
// pos := fyne.NewPos(0, contSize.Height-v.MinSize(objects).Height)
pos := fyne.NewPos(0, 0)
cellHeightSingular := float64(contSize.Height) / float64(v.rows)
cellWidth := contSize.Height
for i, o := range objects {
numRows := v.cfg[i]
h := cellHeightSingular * float64(numRows)
o.Move(pos)
o.Resize(fyne.NewSize(cellWidth, float32(h)))
pos = pos.Add(fyne.NewPos(0, float32(h)))
}
}

1
extfyne/main.go Normal file
View File

@ -0,0 +1 @@
package extfyne

View File

@ -0,0 +1,106 @@
package widgets
import (
"image/color"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/widget"
)
type MBoardMessage struct {
LeftAlign bool
Data *widget.Label
}
type MessageBoard struct {
widget.BaseWidget
Messages []MBoardMessage
}
func NewEmptyMessageBoard() *MessageBoard {
board := &MessageBoard{
Messages: make([]MBoardMessage, 0),
}
board.ExtendBaseWidget(board)
return board
}
func NewMessageBoard(msgs []MBoardMessage) *MessageBoard {
board := &MessageBoard{
Messages: msgs,
}
board.ExtendBaseWidget(board)
return board
}
func (m *MessageBoard) Add(msg MBoardMessage) {
m.Messages = append(m.Messages, msg)
m.Refresh()
}
func (m *MessageBoard) CreateRenderer() fyne.WidgetRenderer {
content := container.NewVBox()
for _, msg := range m.Messages {
hbox := container.NewHBox()
background := canvas.NewRectangle(&color.RGBA{R: 0, G: 0, B: 255, A: 128})
background.SetMinSize(msg.Data.MinSize())
if msg.LeftAlign {
hbox.Add(container.NewStack(background, msg.Data))
} else {
hbox.Add(layout.NewSpacer())
hbox.Add(container.NewStack(background, msg.Data))
}
content.Add(hbox)
}
scrollContainer := container.NewScroll(content)
return &messageBoardRenderer{
board: m,
content: scrollContainer,
}
}
type messageBoardRenderer struct {
board *MessageBoard
content *container.Scroll
}
func (r *messageBoardRenderer) Layout(size fyne.Size) {
r.content.Resize(size)
}
func (r *messageBoardRenderer) MinSize() fyne.Size {
return r.content.MinSize()
}
func (r *messageBoardRenderer) Refresh() {
r.content.Content.(*fyne.Container).Objects = nil
for _, msg := range r.board.Messages {
hbox := container.NewHBox()
if msg.LeftAlign {
background := canvas.NewRectangle(&color.RGBA{R: 0, G: 0, B: 255, A: 128})
background.SetMinSize(msg.Data.MinSize())
hbox.Add(container.NewStack(background, msg.Data))
} else {
background := canvas.NewRectangle(&color.RGBA{R: 0, G: 255, B: 0, A: 128})
background.SetMinSize(msg.Data.MinSize())
hbox.Add(layout.NewSpacer())
hbox.Add(container.NewStack(background, msg.Data))
}
r.content.Content.(*fyne.Container).Add(hbox)
}
r.content.Refresh()
}
func (r *messageBoardRenderer) Destroy() {
// Clean up resources if needed
}
func (r *messageBoardRenderer) Objects() []fyne.CanvasObject {
return []fyne.CanvasObject{r.content}
}

28
go.mod
View File

@ -3,12 +3,38 @@ module git.qowevisa.me/Qowevisa/gotell
go 1.20
require (
fyne.io/fyne/v2 v2.4.5
github.com/gorilla/websocket v1.5.1
golang.org/x/crypto v0.21.0
golang.org/x/term v0.18.0
)
require (
github.com/gorilla/websocket v1.5.1 // indirect
fyne.io/systray v1.10.1-0.20231115130155-104f5ef7839e // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fredbi/uri v1.0.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe // indirect
github.com/fyne-io/glfw-js v0.0.0-20220120001248-ee7290d23504 // indirect
github.com/fyne-io/image v0.0.0-20220602074514-4956b0afb3d2 // indirect
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6 // indirect
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240306074159-ea2d69986ecb // indirect
github.com/go-text/render v0.1.0 // indirect
github.com/go-text/typesetting v0.1.0 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gopherjs/gopherjs v1.17.2 // indirect
github.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect
github.com/stretchr/testify v1.8.4 // indirect
github.com/tevino/abool v1.2.0 // indirect
github.com/yuin/goldmark v1.5.5 // indirect
golang.org/x/image v0.11.0 // indirect
golang.org/x/mobile v0.0.0-20230531173138-3c911d8e3eda // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
honnef.co/go/js/dom v0.0.0-20210725211120-f030747120f2 // indirect
)

661
go.sum
View File

@ -1,10 +1,671 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
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=
fyne.io/fyne/v2 v2.4.5 h1:W6jpAEmLoBbKyBB+EXqI7GMJ7kLgHQWCa0wZHUV2VfQ=
fyne.io/fyne/v2 v2.4.5/go.mod h1:SlOgbca0y80cRObu/JOhxIJdIgtoW7aCyqUVlTMgs0Y=
fyne.io/systray v1.10.1-0.20231115130155-104f5ef7839e h1:Hvs+kW2VwCzNToF3FmnIAzmivNgrclwPgoUdVSrjkP8=
fyne.io/systray v1.10.1-0.20231115130155-104f5ef7839e/go.mod h1:oM2AQqGJ1AMo4nNqZFYU8xYygSBZkW2hmdJ7n4yjedE=
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/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
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/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
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/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
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/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/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
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/fredbi/uri v1.0.0 h1:s4QwUAZ8fz+mbTsukND+4V5f+mJ/wjaTokwstGUAemg=
github.com/fredbi/uri v1.0.0/go.mod h1:1xC40RnIOGCaQzswaOvrzvG/3M3F0hyDVb3aO/1iGy0=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe h1:A/wiwvQ0CAjPkuJytaD+SsXkPU0asQ+guQEIg1BJGX4=
github.com/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe/go.mod h1:d4clgH0/GrRwWjRzJJQXxT/h1TyuNSfF/X64zb/3Ggg=
github.com/fyne-io/glfw-js v0.0.0-20220120001248-ee7290d23504 h1:+31CdF/okdokeFNoy9L/2PccG3JFidQT3ev64/r4pYU=
github.com/fyne-io/glfw-js v0.0.0-20220120001248-ee7290d23504/go.mod h1:gLRWYfYnMA9TONeppRSikMdXlHQ97xVsPojddUv3b/E=
github.com/fyne-io/image v0.0.0-20220602074514-4956b0afb3d2 h1:hnLq+55b7Zh7/2IRzWCpiTcAvjv/P8ERF+N7+xXbZhk=
github.com/fyne-io/image v0.0.0-20220602074514-4956b0afb3d2/go.mod h1:eO7W361vmlPOrykIg+Rsh1SZ3tQBaOsfzZhsIOb/Lm0=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6 h1:zDw5v7qm4yH7N8C8uWd+8Ii9rROdgWxQuGoJ9WDXxfk=
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw=
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-gl/glfw/v3.3/glfw v0.0.0-20211213063430-748e38ca8aec/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240306074159-ea2d69986ecb h1:S9I8pIVT5JHKDvmI1vQ0qs5fqxzUfhcZm/YbUC/8k1k=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240306074159-ea2d69986ecb/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-text/render v0.1.0 h1:osrmVDZNHuP1RSu3pNG7Z77Sd2xSbcb/xWytAj9kyVs=
github.com/go-text/render v0.1.0/go.mod h1:jqEuNMenrmj6QRnkdpeaP0oKGFLDNhDkVKwGjsWWYU4=
github.com/go-text/typesetting v0.1.0 h1:vioSaLPYcHwPEPLT7gsjCGDCoYSbljxoHJzMnKwVvHw=
github.com/go-text/typesetting v0.1.0/go.mod h1:d22AnmeKq/on0HNv73UFriMKc4Ez6EqZAofLhAzpSzI=
github.com/go-text/typesetting-utils v0.0.0-20240329101916-eee87fb235a3 h1:levTnuLLUmpavLGbJYLJA7fQnKeS7P1eCdAlM+vReXk=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
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=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.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/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.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.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
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/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=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
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-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/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/gopherjs/gopherjs v0.0.0-20211219123610-ec9572f70e60/go.mod h1:cz9oNYuRUWGdHmLF2IodMLkAhcPtXeULvcBNagUrxTI=
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/goxjs/gl v0.0.0-20210104184919-e3fafc6f8f2a/go.mod h1:dy/f2gjY09hwVfIyATps4G2ai7/hLwLkc5TrPqONuXY=
github.com/goxjs/glfw v0.0.0-20191126052801-d2efb5f20838/go.mod h1:oS8P8gVOT4ywTcjV6wZlOU4GuVFQ8F5328KY3MJ79CY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/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.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/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
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/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
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/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e h1:LvL4XsI70QxOGHed6yhQtAU34Kx3Qq2wwBzGFKY8zKk=
github.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e/go.mod h1:kLgvv7o6UM+0QSf0QjAse3wReFDsb9qbZJdfexWlrQw=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/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/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/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/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
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_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
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/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiYWEedbTT0qnSxrCjsVbb7yKY1KE=
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q=
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ=
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA=
github.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg=
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/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.5.5 h1:IJznPe8wOzfIKETmMkd06F8nXkmlhaHqFRM9l1hAGsU=
github.com/yuin/goldmark v1.5.5/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
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.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
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-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-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/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-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/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/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
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.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo=
golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mobile v0.0.0-20211207041440-4e6c2922fdee/go.mod h1:pe2sM7Uk+2Su1y7u/6Z8KJ24D7lepUjFZbhFOrmDfuQ=
golang.org/x/mobile v0.0.0-20230531173138-3c911d8e3eda h1:O+EUvnBNPwI4eLthn8W5K+cS8zQZfgTABPLNm6Bna34=
golang.org/x/mobile v0.0.0-20230531173138-3c911d8e3eda/go.mod h1:aAjjkJNdrh3PMckS4B10TGS2nag27cbKR1y2BpUxsiY=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/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/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
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-20181023162649-9b4f9f5ad519/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-20190108225652-1e06a53dbb7e/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=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-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-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=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-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-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-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/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-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/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=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
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/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/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-20181026203630-95b1ffbd15a5/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-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-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-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/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-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/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-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
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/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
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/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
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/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
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-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/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=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
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-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=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
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-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
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/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
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/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/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=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.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/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=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/js/dom v0.0.0-20210725211120-f030747120f2 h1:oomkgU6VaQDsV6qZby2uz1Lap0eXmku8+2em3A/l700=
honnef.co/go/js/dom v0.0.0-20210725211120-f030747120f2/go.mod h1:sUMDUKNB2ZcVjt92UnLy3cdGs+wDAcrPdV3JP6sVgA4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/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=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

View File

@ -1 +0,0 @@
use fyne for GUI

View File

@ -1,66 +0,0 @@
package tlep
import (
"fmt"
)
func main() {
tlep1, err := InitTLEP("user2")
if err != nil {
panic(err)
}
err = tlep1.CBESInitRandom()
if err != nil {
panic(err)
}
keyA, err := tlep1.ECDHGetPublicKey()
if err != nil {
panic(err)
}
tlep2, err := InitTLEP("user1")
if err != nil {
panic(err)
}
keyB, err := tlep2.ECDHGetPublicKey()
if err != nil {
panic(err)
}
// Acception
err = tlep1.ECDHApplyOtherKeyBytes(keyB)
if err != nil {
panic(err)
}
err = tlep2.ECDHApplyOtherKeyBytes(keyA)
if err != nil {
panic(err)
}
// First EA encryption
fmt.Printf("TLEP1 CBES specs: %#v\n", tlep1.CBES)
cbesSpecs, err := tlep1.CBESGetBytes()
if err != nil {
panic(err)
}
encryptedCBESSpecs, err := tlep1.EncryptMessageEA(cbesSpecs)
if err != nil {
panic(err)
}
realSpecs, err := tlep2.DecryptMessageEA(encryptedCBESSpecs)
if err != nil {
panic(err)
}
tlep2.CBESSetFromBytes(realSpecs)
fmt.Printf("TLEP2 CBES specs: %#v\n", tlep2.CBES)
// Second layer CAFEA encryption
someMsg := "lol real msg i don't wanna joke xdd"
fmt.Printf("Sending %s to TLEP2\n", someMsg)
encryptedMsg, err := tlep1.EncryptMessageCAFEA([]byte(someMsg))
if err != nil {
panic(err)
}
fmt.Printf("Encrypted Message = %v\n", encryptedMsg)
decryptedMsg, err := tlep2.DecryptMessageCAFEA(encryptedMsg)
if err != nil {
panic(err)
}
fmt.Printf("Getting %s on TLEP2 from TLEP1\n", decryptedMsg)
}

View File

@ -1,6 +0,0 @@
Three Lock Encryption Protocol
This is a protocol of most inefficient encryption algorithm for most secure message tranfser.
It is paranoidal and maybe diabolical.
Monkey Chaos Ecdh
MECHA

View File

@ -53,6 +53,9 @@ func InitTLEP(name string) (*TLEP, error) {
cbes := chaos.CreateNewChaosSystem()
t.CBES = cbes
t.SLLevel = TLEP_LEVEL_NO_CONNECTION
if t.Debug {
log.Printf("TLEP initiated")
}
return &t, nil
}
@ -60,6 +63,9 @@ func (t *TLEP) ECDHGetPublicKey() ([]byte, error) {
if t.ECDHConnection == nil {
return nil, gmyerr.WrapPrefix("t.ECDHConnection", IS_NIL)
}
if t.Debug {
log.Printf("TLEP uses GetMyPublicKeyBytes")
}
ar := t.ECDHConnection.GetMyPublicKeyBytes()
return ar, nil
}
@ -73,6 +79,9 @@ func (t *TLEP) ECDHApplyOtherKeyBytes(otherKey []byte) error {
return gmyerr.WrapPrefix("t.ECDHConnection.AcceptOtherPubKeyBytes", err)
}
t.SLLevel = TLEP_LEVEL_ECDH
if t.Debug {
log.Printf("TLEP is upgraded to ECDH level")
}
return nil
}
@ -85,6 +94,9 @@ func (t *TLEP) CBESInitRandom() error {
return gmyerr.WrapPrefix("t.CBES.InitRandom", IS_NIL)
}
t.SLLevel = TLEP_LEVEL_ECDH_CBES
if t.Debug {
log.Printf("TLEP is upgraded to ECDH_CBES level")
}
return nil
}
@ -102,6 +114,9 @@ func (t *TLEP) CBESSetFromBytes(bytes []byte) error {
}
t.CBES = newCBES
t.SLLevel = TLEP_LEVEL_ECDH_CBES
if t.Debug {
log.Printf("TLEP is upgraded to ECDH_CBES level")
}
return nil
}

View File

@ -1,7 +0,0 @@
create a way to convert WORD into float
integrate mklg with some parts
create communication scheme using ECHD + AES + digital signatures + shuffle + mklg changes + CBES
CBES = Chaos-Based-Encryption-Scheme