Compare commits

..

No commits in common. "master" and "v1.0.5" have entirely different histories.

20 changed files with 4796 additions and 77707 deletions

View file

@ -46,7 +46,7 @@ func Authorize(client *Client, authorizationStateHandler AuthorizationStateHandl
}
type clientAuthorizer struct {
TdlibParameters chan *SetTdlibParametersRequest
TdlibParameters chan *TdlibParameters
PhoneNumber chan string
Code chan string
State chan AuthorizationState
@ -55,7 +55,7 @@ type clientAuthorizer struct {
func ClientAuthorizer() *clientAuthorizer {
return &clientAuthorizer{
TdlibParameters: make(chan *SetTdlibParametersRequest, 1),
TdlibParameters: make(chan *TdlibParameters, 1),
PhoneNumber: make(chan string, 1),
Code: make(chan string, 1),
State: make(chan AuthorizationState, 10),
@ -68,7 +68,13 @@ func (stateHandler *clientAuthorizer) Handle(client *Client, state Authorization
switch state.AuthorizationStateType() {
case TypeAuthorizationStateWaitTdlibParameters:
_, err := client.SetTdlibParameters(<-stateHandler.TdlibParameters)
_, err := client.SetTdlibParameters(&SetTdlibParametersRequest{
Parameters: <-stateHandler.TdlibParameters,
})
return err
case TypeAuthorizationStateWaitEncryptionKey:
_, err := client.CheckDatabaseEncryptionKey(&CheckDatabaseEncryptionKeyRequest{})
return err
case TypeAuthorizationStateWaitPhoneNumber:
@ -163,14 +169,14 @@ func CliInteractor(clientAuthorizer *clientAuthorizer) {
}
type botAuthorizer struct {
TdlibParameters chan *SetTdlibParametersRequest
TdlibParameters chan *TdlibParameters
Token chan string
State chan AuthorizationState
}
func BotAuthorizer(token string) *botAuthorizer {
botAuthorizer := &botAuthorizer{
TdlibParameters: make(chan *SetTdlibParametersRequest, 1),
TdlibParameters: make(chan *TdlibParameters, 1),
Token: make(chan string, 1),
State: make(chan AuthorizationState, 10),
}
@ -185,7 +191,13 @@ func (stateHandler *botAuthorizer) Handle(client *Client, state AuthorizationSta
switch state.AuthorizationStateType() {
case TypeAuthorizationStateWaitTdlibParameters:
_, err := client.SetTdlibParameters(<-stateHandler.TdlibParameters)
_, err := client.SetTdlibParameters(&SetTdlibParametersRequest{
Parameters: <-stateHandler.TdlibParameters,
})
return err
case TypeAuthorizationStateWaitEncryptionKey:
_, err := client.CheckDatabaseEncryptionKey(&CheckDatabaseEncryptionKeyRequest{})
return err
case TypeAuthorizationStateWaitPhoneNumber:

View file

@ -21,7 +21,6 @@ type Client struct {
successMsgStore *sync.Map
updatesTimeout time.Duration
catchTimeout time.Duration
DisablePatch bool
}
type Option func(*Client)
@ -44,12 +43,6 @@ func WithProxy(req *AddProxyRequest) Option {
}
}
func WithoutSendMessagePatch() Option {
return func(client *Client) {
client.DisablePatch = true
}
}
func SetLogLevel(level int32) {
_, _ = SetLogVerbosityLevel(&SetLogVerbosityLevelRequest{
NewVerbosityLevel: level,
@ -86,15 +79,15 @@ func NewClient(authorizationStateHandler AuthorizationStateHandler, options ...O
client.extraGenerator = UuidV4Generator()
client.catchTimeout = 60 * time.Second
for _, option := range options {
option(client)
}
tdlibInstance.addClient(client)
go client.processPendingResponse()
go client.receiver()
for _, option := range options {
go option(client)
}
err := Authorize(client, authorizationStateHandler)
if err != nil {
return nil, err
@ -116,10 +109,10 @@ func (client *Client) processResponse(response *Response) {
return
}
if !client.DisablePatch && typ.GetType() == (&UpdateMessageSendSucceeded{}).GetType() {
sendVal, sOk := client.successMsgStore.Load(typ.(*UpdateMessageSendSucceeded).OldMessageId)
if sOk {
sendVal.(chan *Response) <- response
if typ.GetType() == (&UpdateMessageSendSucceeded{}).GetType() {
value, ok := client.successMsgStore.Load(typ.(*UpdateMessageSendSucceeded).OldMessageId)
if ok {
value.(chan *Response) <- response
}
}
@ -134,18 +127,7 @@ func (client *Client) processResponse(response *Response) {
needGc := false
for _, listener := range client.listenerStore.Listeners() {
if listener.IsActive() && listener.Updates != nil && typ.GetType() == listener.Filter.GetType() { // All updates go to Updates channel if type == filter
// Make some delay to UpdateMessageSendSucceeded listener
// This can make UpdateMessageSendSucceeded response later than sendMessage response.
// This may help a bot developer to map temporary message id to actual message id easily.
// Cause an event listener slower than sendMessage response, so you have enough time to do mapping stuff.
if typ.GetType() == (&UpdateMessageSendSucceeded{}).GetType() {
go func(listener *Listener, typ Type) {
time.Sleep(5 * time.Millisecond)
listener.Updates <- typ
}(listener, typ)
} else {
listener.Updates <- typ
}
} else if listener.IsActive() && listener.RawUpdates != nil { // All updates go to RawUpdates channel if filter is empty
listener.RawUpdates <- typ
} else if !listener.IsActive() { // GC inactive listener
@ -155,10 +137,6 @@ func (client *Client) processResponse(response *Response) {
if needGc {
client.listenerStore.gc()
}
if typ.GetType() == TypeUpdateAuthorizationState && typ.(*UpdateAuthorizationState).AuthorizationState.AuthorizationStateType() == TypeAuthorizationStateClosed {
close(client.responses)
}
}
func (client *Client) receiver() {
@ -206,7 +184,7 @@ func (client *Client) Send(req Request) (*Response, error) {
select {
case response := <-catcher:
if !client.DisablePatch && response.Type != "error" && req.Type == "sendMessage" {
if response.Type != "error" && req.Type == "sendMessage" {
m, err := UnmarshalMessage(response.Data)
if err != nil {
return nil, err
@ -227,8 +205,8 @@ func (client *Client) Send(req Request) (*Response, error) {
if err2 != nil {
return response, nil
}
response.Data = bytes.Replace(response.Data, []byte("\"@type\":\"messageSendingStatePending\""), []byte("\"@type\":\"updateMessageSendSucceeded\""), 1)
response.Data = bytes.Replace(response.Data, []byte("\"id\":"+strconv.FormatInt(m.Id, 10)), []byte("\"id\":"+strconv.FormatInt(m2.Message.Id, 10)), 1)
response.Data = bytes.Replace(response.Data, []byte("{\"@type\":\"messageSendingStatePending\"}"), []byte("{\"@type\":\"updateMessageSendSucceeded\"}"), 1)
response.Data = bytes.Replace(response.Data, []byte(strconv.FormatInt(m.Id, 10)), []byte(strconv.FormatInt(m2.Message.Id, 10)), 1)
return response, nil
case <-time.After(1 * time.Second):
return response, nil
@ -261,3 +239,7 @@ func (client *Client) AddEventReceiver(msgType Type, channelCapacity int) *Liste
return listener
}
func (client *Client) Stop() {
client.Destroy()
}

View file

@ -1,49 +1,67 @@
package client
import (
"fmt"
"math/rand"
"strings"
"github.com/google/uuid"
)
type ExtraGenerator func() string
func UuidV4Generator() ExtraGenerator {
return func() string {
return uuid.NewString()
var uuid [16]byte
rand.Read(uuid[:])
uuid[6] = (uuid[6] & 0x0f) | 0x40
uuid[8] = (uuid[8] & 0x3f) | 0x80
return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x", uuid[:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:])
}
}
func IsCommand(text string) bool {
if i := strings.Index(text, "/"); i == 0 {
func IsCommmand(text string) bool {
if text != "" {
if text[0] == '/' {
return true
}
}
return false
}
func CheckCommand(text string, entities []*TextEntity) string {
if IsCommand(text) {
cmd := text
// e.g. ["/hello 123", "/hell o 123"]
// Result: "/hello", "/hell"
if i := strings.Index(cmd, " "); i != -1 {
cmd = cmd[:i]
if IsCommmand(text) {
// Check text entities and make bot happy!
if len(entities) >= 1 {
// Get first command
if entities[0].Type.TextEntityTypeType() == "textEntityTypeBotCommand" {
// e.g.: { "text": "/hello@world_bot", "textEntity": { offset: 0, length: 16 } }
// Result: "/hello"
if i := strings.Index(text[:entities[0].Length], "@"); i != -1 {
return text[:i]
}
return text[:entities[0].Length]
}
} else {
// Since userbot does not have bot command entities in Private Chat, so make userbot happy too!
// e.g.: ["/hello@world_bot", "/hello@", "/hello@123"]
// Result: "/hello"
if i := strings.Index(cmd, "@"); i != -1 {
cmd = cmd[:i]
if i := strings.Index(text, "@"); i != -1 {
return text[:i]
}
// e.g. ["/hello 123", "/hell o 123"]
// Result: "/hello", "/hell"
if i := strings.Index(text, " "); i != -1 {
return text[:i]
}
return text
}
return cmd
}
return ""
}
func CommandArgument(text string) string {
if IsCommand(text) {
if IsCommmand(text) {
// e.g. ["/hello 123", "/hell o 123"]
// Result: "123", "o 123"
if i := strings.Index(text, " "); i != -1 {

File diff suppressed because it is too large Load diff

View file

@ -1,12 +1,10 @@
package client
//#cgo linux CFLAGS: -I/usr/local/include
//#cgo freebsd CFLAGS: -I/usr/local/include
//#cgo darwin CFLAGS: -I/usr/local/include
//#cgo windows CFLAGS: -IE:/src/tdlib -IE:/src/tdlib/build
//#cgo linux LDFLAGS: -L/usr/local/lib -ltdjson_static -ltdjson_private -ltdclient -ltdcore -ltdapi -ltdactor -ltddb -ltde2e -ltdsqlite -ltdmtproto -ltdnet -ltdutils -lstdc++ -lssl -lcrypto -ldl -lz -lm
//#cgo freebsd LDFLAGS: -L/usr/local/lib -ltdjson_static -ltdjson_private -ltdclient -ltdcore -ltdapi -ltdactor -ltddb -ltde2e -ltdsqlite -ltdmtproto -ltdnet -ltdutils -lstdc++ -lssl -lcrypto -ldl -lz -lm
//#cgo darwin LDFLAGS: -L/usr/local/lib -L/usr/local/opt/openssl/lib -ltdjson_static -ltdjson_private -ltdclient -ltdcore -ltdapi -ltdactor -ltddb -ltde2e -ltdsqlite -ltdmtproto -ltdnet -ltdutils -lstdc++ -lssl -lcrypto -ldl -lz -lm
//#cgo linux LDFLAGS: -L/usr/local/lib -ltdjson_static -ltdjson_private -ltdclient -ltdcore -ltdapi -ltdactor -ltddb -ltdsqlite -ltdnet -ltdutils -lstdc++ -lssl -lcrypto -ldl -lz -lm
//#cgo darwin LDFLAGS: -L/usr/local/lib -L/usr/local/opt/openssl/lib -ltdjson_static -ltdjson_private -ltdclient -ltdcore -ltdapi -ltdactor -ltddb -ltdsqlite -ltdnet -ltdutils -lstdc++ -lssl -lcrypto -ldl -lz -lm
//#cgo windows LDFLAGS: -LE:/src/tdlib/build/Release -ltdjson
//#include <stdlib.h>
//#include <td/telegram/td_json_client.h>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -9,8 +9,8 @@ import (
tdlib "github.com/c0re100/gotdlib/client"
)
func GetTdParameters() *tdlib.SetTdlibParametersRequest {
return &tdlib.SetTdlibParametersRequest{
func GetTdParameters() *tdlib.TdlibParameters {
return &tdlib.TdlibParameters{
UseTestDc: false,
DatabaseDirectory: "./tdlib-db",
FilesDirectory: "./tdlib-files",
@ -24,6 +24,8 @@ func GetTdParameters() *tdlib.SetTdlibParametersRequest {
DeviceModel: "HuskyNG",
SystemVersion: "3.0",
ApplicationVersion: "3.0",
EnableStorageOptimizer: true,
IgnoreFileNames: false,
}
}
@ -58,7 +60,7 @@ func main() {
log.Fatalf("GetMe error: %s", err)
}
log.Printf("%v connected", me.Usernames)
log.Printf("%s connected", me.Username)
listener := client.AddEventReceiver(&tdlib.UpdateNewMessage{}, 1000)
@ -85,9 +87,7 @@ func main() {
})
m, err := client.SendMessage(&tdlib.SendMessageRequest{
ChatId: chatId,
ReplyTo: &tdlib.InputMessageReplyToMessage{
MessageId: msgId,
},
ReplyToMessageId: msgId,
InputMessageContent: &tdlib.InputMessageText{
Text: text,
},

View file

@ -17,8 +17,8 @@ func GetSenderId(sender tdlib.MessageSender) int64 {
}
}
func GetTdParameters() *tdlib.SetTdlibParametersRequest {
return &tdlib.SetTdlibParametersRequest{
func GetTdParameters() *tdlib.TdlibParameters {
return &tdlib.TdlibParameters{
UseTestDc: false,
DatabaseDirectory: "./tdlib-db",
FilesDirectory: "./tdlib-files",
@ -32,6 +32,8 @@ func GetTdParameters() *tdlib.SetTdlibParametersRequest {
DeviceModel: "HuskyNG",
SystemVersion: "3.0",
ApplicationVersion: "3.0",
EnableStorageOptimizer: true,
IgnoreFileNames: false,
}
}
@ -66,7 +68,7 @@ func main() {
log.Fatalf("GetMe error: %s", err)
}
log.Printf("%v connected", me.Usernames)
log.Printf("%s connected", me.Username)
listener := client.AddEventReceiver(&tdlib.UpdateNewMessage{}, 1000)
@ -96,9 +98,7 @@ func main() {
})
m, err := client.SendMessage(&tdlib.SendMessageRequest{
ChatId: chatId,
ReplyTo: &tdlib.InputMessageReplyToMessage{
MessageId: msgId,
},
ReplyToMessageId: msgId,
InputMessageContent: &tdlib.InputMessageText{
Text: text,
},
@ -110,9 +110,7 @@ func main() {
case "/repeat":
m, err := client.SendMessage(&tdlib.SendMessageRequest{
ChatId: chatId,
ReplyTo: &tdlib.InputMessageReplyToMessage{
MessageId: msgId,
},
ReplyToMessageId: msgId,
InputMessageContent: &tdlib.InputMessageText{
Text: &tdlib.FormattedText{Text: tdlib.CommandArgument(msgText)},
},

View file

@ -17,8 +17,8 @@ func GetSenderId(sender tdlib.MessageSender) int64 {
}
}
func GetTdParameters() *tdlib.SetTdlibParametersRequest {
return &tdlib.SetTdlibParametersRequest{
func GetTdParameters() *tdlib.TdlibParameters {
return &tdlib.TdlibParameters{
UseTestDc: false,
DatabaseDirectory: "./tdlib-db",
FilesDirectory: "./tdlib-files",
@ -32,6 +32,8 @@ func GetTdParameters() *tdlib.SetTdlibParametersRequest {
DeviceModel: "HuskyNG",
SystemVersion: "3.0",
ApplicationVersion: "3.0",
EnableStorageOptimizer: true,
IgnoreFileNames: false,
}
}
@ -66,7 +68,7 @@ func main() {
log.Fatalf("GetMe error: %s", err)
}
log.Printf("%v connected", me.Usernames)
log.Printf("%s connected", me.Username)
listener := client.AddEventReceiver(&tdlib.UpdateNewMessage{}, 1000)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 794 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 900 KiB

View file

@ -17,8 +17,8 @@ func GetSenderId(sender tdlib.MessageSender) int64 {
}
}
func GetTdParameters() *tdlib.SetTdlibParametersRequest {
return &tdlib.SetTdlibParametersRequest{
func GetTdParameters() *tdlib.TdlibParameters {
return &tdlib.TdlibParameters{
UseTestDc: false,
DatabaseDirectory: "./tdlib-db",
FilesDirectory: "./tdlib-files",
@ -32,6 +32,8 @@ func GetTdParameters() *tdlib.SetTdlibParametersRequest {
DeviceModel: "HuskyNG",
SystemVersion: "3.0",
ApplicationVersion: "3.0",
EnableStorageOptimizer: true,
IgnoreFileNames: false,
}
}
@ -66,7 +68,7 @@ func main() {
log.Fatalf("GetMe error: %s", err)
}
log.Printf("%v connected", me.Usernames)
log.Printf("%s connected", me.Username)
listener := client.AddEventReceiver(&tdlib.UpdateNewMessage{}, 1000)
@ -96,12 +98,10 @@ func main() {
})
m, err := client.SendMessage(&tdlib.SendMessageRequest{
ChatId: chatId,
ReplyTo: &tdlib.InputMessageReplyToMessage{
MessageId: msgId,
},
ReplyToMessageId: msgId,
InputMessageContent: &tdlib.InputMessagePhoto{
Photo: &tdlib.InputFileLocal{
Path: "./Meru_01.png",
Path: "./myht9-1486821485193084928.jpg",
},
Caption: text,
},
@ -117,19 +117,17 @@ func main() {
})
m, err := client.SendMessageAlbum(&tdlib.SendMessageAlbumRequest{
ChatId: chatId,
ReplyTo: &tdlib.InputMessageReplyToMessage{
MessageId: msgId,
},
ReplyToMessageId: msgId,
InputMessageContents: []tdlib.InputMessageContent{
&tdlib.InputMessagePhoto{
Photo: &tdlib.InputFileLocal{
Path: "./Meru_01.png",
Path: "./myht9-1486821485193084928.jpg",
},
Caption: text,
},
&tdlib.InputMessagePhoto{
Photo: &tdlib.InputFileLocal{
Path: "./Meru_02.png",
Path: "./hisagi_02-1486983199280738309.jpg",
},
},
},

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

View file

@ -9,8 +9,8 @@ import (
tdlib "github.com/c0re100/gotdlib/client"
)
func GetTdParameters() *tdlib.SetTdlibParametersRequest {
return &tdlib.SetTdlibParametersRequest{
func GetTdParameters() *tdlib.TdlibParameters {
return &tdlib.TdlibParameters{
UseTestDc: false,
DatabaseDirectory: "./tdlib-db",
FilesDirectory: "./tdlib-files",
@ -24,6 +24,8 @@ func GetTdParameters() *tdlib.SetTdlibParametersRequest {
DeviceModel: "HuskyNG",
SystemVersion: "3.0",
ApplicationVersion: "3.0",
EnableStorageOptimizer: true,
IgnoreFileNames: false,
}
}
@ -63,7 +65,7 @@ func main() {
log.Fatalf("GetMe error: %s", err)
}
log.Printf("%v connected", me.Usernames)
log.Printf("%s connected", me.Username)
listener := client.AddEventReceiver(&tdlib.UpdateNewMessage{}, 1000)
@ -90,9 +92,7 @@ func main() {
})
m, err := client.SendMessage(&tdlib.SendMessageRequest{
ChatId: chatId,
ReplyTo: &tdlib.InputMessageReplyToMessage{
MessageId: msgId,
},
ReplyToMessageId: msgId,
InputMessageContent: &tdlib.InputMessageText{
Text: text,
},

View file

@ -17,8 +17,8 @@ func GetSenderId(sender tdlib.MessageSender) int64 {
}
}
func GetTdParameters() *tdlib.SetTdlibParametersRequest {
return &tdlib.SetTdlibParametersRequest{
func GetTdParameters() *tdlib.TdlibParameters {
return &tdlib.TdlibParameters{
UseTestDc: false,
DatabaseDirectory: "./tdlib-db",
FilesDirectory: "./tdlib-files",
@ -32,6 +32,8 @@ func GetTdParameters() *tdlib.SetTdlibParametersRequest {
DeviceModel: "HuskyNG",
SystemVersion: "3.0",
ApplicationVersion: "3.0",
EnableStorageOptimizer: true,
IgnoreFileNames: false,
}
}
@ -66,7 +68,7 @@ func main() {
log.Fatalf("GetMe error: %s", err)
}
log.Printf("%v connected", me.Usernames)
log.Printf("%s connected", me.Username)
listener := client.GetListener()

5
go.mod
View file

@ -2,7 +2,4 @@ module github.com/c0re100/gotdlib
go 1.16
require (
github.com/google/uuid v1.6.0
golang.org/x/crypto v0.31.0
)
require golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed

72
go.sum
View file

@ -1,69 +1,11 @@
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
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/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
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.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/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/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed h1:YoWVYYAfvQ4ddHv3OKmIvX7NCAhFGTj62VP2l2kfBbA=
golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/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.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/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.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
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/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=