diff --git a/.DS_Store b/.DS_Store
index af95e2f5..1aff60ee 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/.gitignore b/.gitignore
index ee064b32..c0f450c0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,7 @@ bin/*
.idea
/hidden
.hidden
-*/.DS_Store
\ No newline at end of file
+*/.DS_Store
+cmd/streaming/sample.yaml
+/test/streaming/config/*
+gitleaks-report.json
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 8bb5b5d4..578bad7f 100644
--- a/Makefile
+++ b/Makefile
@@ -112,3 +112,21 @@ build/docker:
docker buildx build --platform linux/amd64 -t sqlpipe/sqlpipe:latest -f sqlpipe.dockerfile . --load
@echo 'Pushing docker image...'
docker push sqlpipe/sqlpipe:latest
+
+## test: run tests in the /test directory
+.PHONY: test
+test:
+ @echo 'Running tests in the /test directory...'
+ STRIPE_API_KEY=$(STRIPE_API_KEY) go test -v -count=1 ./test/...
+
+## one-table: run the two_table_test.go test in the /test directory
+.PHONY: one-table
+one-table:
+ @echo 'Running one_table_test.go in the /test directory...'
+ STRIPE_API_KEY=$(STRIPE_API_KEY) go test -v -count=1 ./test/streaming/one_table_test.go
+
+## two-table: run the two_table_test.go test in the /test directory
+.PHONY: two-tables
+two-table:
+ @echo 'Running two_tables_test.go in the /test directory...'
+ STRIPE_API_KEY=$(STRIPE_API_KEY) go test -v -count=1 ./test/streaming/two_tables_test.go
diff --git a/sqlpipe.dockerfile b/batch.dockerfile
similarity index 100%
rename from sqlpipe.dockerfile
rename to batch.dockerfile
diff --git a/cmd/sqlpipe/errors.go b/cmd/batch/errors.go
similarity index 100%
rename from cmd/sqlpipe/errors.go
rename to cmd/batch/errors.go
diff --git a/cmd/sqlpipe/helpers.go b/cmd/batch/helpers.go
similarity index 100%
rename from cmd/sqlpipe/helpers.go
rename to cmd/batch/helpers.go
diff --git a/cmd/sqlpipe/main.go b/cmd/batch/main.go
similarity index 100%
rename from cmd/sqlpipe/main.go
rename to cmd/batch/main.go
diff --git a/cmd/sqlpipe/routes.go b/cmd/batch/routes.go
similarity index 100%
rename from cmd/sqlpipe/routes.go
rename to cmd/batch/routes.go
diff --git a/cmd/sqlpipe/system_mssql.go b/cmd/batch/system_mssql.go
similarity index 100%
rename from cmd/sqlpipe/system_mssql.go
rename to cmd/batch/system_mssql.go
diff --git a/cmd/sqlpipe/system_mysql.go b/cmd/batch/system_mysql.go
similarity index 100%
rename from cmd/sqlpipe/system_mysql.go
rename to cmd/batch/system_mysql.go
diff --git a/cmd/sqlpipe/system_oracle.go b/cmd/batch/system_oracle.go
similarity index 100%
rename from cmd/sqlpipe/system_oracle.go
rename to cmd/batch/system_oracle.go
diff --git a/cmd/sqlpipe/system_postgresql.go b/cmd/batch/system_postgresql.go
similarity index 99%
rename from cmd/sqlpipe/system_postgresql.go
rename to cmd/batch/system_postgresql.go
index 5139dc12..cedd5b5c 100644
--- a/cmd/sqlpipe/system_postgresql.go
+++ b/cmd/batch/system_postgresql.go
@@ -385,7 +385,6 @@ func (system Postgresql) getPipeFileFormatters() (
timeVal, err := time.Parse("15:04:05.999999", timeString)
if err != nil {
- fmt.Println(timeString)
return "", errors.New("error parsing time value in postgresqlPipeFileFormatters")
}
diff --git a/cmd/sqlpipe/system_snowflake.go b/cmd/batch/system_snowflake.go
similarity index 100%
rename from cmd/sqlpipe/system_snowflake.go
rename to cmd/batch/system_snowflake.go
diff --git a/cmd/sqlpipe/systems.go b/cmd/batch/systems.go
similarity index 100%
rename from cmd/sqlpipe/systems.go
rename to cmd/batch/systems.go
diff --git a/cmd/sqlpipe/transfers.go b/cmd/batch/transfers.go
similarity index 100%
rename from cmd/sqlpipe/transfers.go
rename to cmd/batch/transfers.go
diff --git a/cmd/streaming/.DS_Store b/cmd/streaming/.DS_Store
new file mode 100644
index 00000000..4bd27771
Binary files /dev/null and b/cmd/streaming/.DS_Store differ
diff --git a/cmd/streaming/errors.go b/cmd/streaming/errors.go
new file mode 100644
index 00000000..82e7706c
--- /dev/null
+++ b/cmd/streaming/errors.go
@@ -0,0 +1,41 @@
+package main
+
+import (
+ "fmt"
+ "net/http"
+)
+
+func (app *application) notFoundResponse(w http.ResponseWriter, r *http.Request) {
+ message := "the requested resource could not be found"
+ app.errorResponse(w, r, http.StatusNotFound, message)
+}
+
+func (app *application) methodNotAllowedResponse(w http.ResponseWriter, r *http.Request) {
+ message := fmt.Sprintf("the %s method is not supported for this resource", r.Method)
+ app.errorResponse(w, r, http.StatusMethodNotAllowed, message)
+}
+
+func (app *application) errorResponse(w http.ResponseWriter, r *http.Request, status int, message any) {
+ env := envelope{"error": message}
+
+ err := app.writeJSON(w, status, env, nil)
+ if err != nil {
+ app.logError(r, err)
+ w.WriteHeader(500)
+ }
+}
+func (app *application) logError(r *http.Request, err error) {
+ var (
+ method = r.Method
+ uri = r.URL.RequestURI()
+ )
+
+ app.logger.Error(err.Error(), "method", method, "uri", uri)
+}
+
+func (app *application) serverErrorResponse(w http.ResponseWriter, r *http.Request, err error) {
+ app.logError(r, err)
+
+ message := "the server encountered a problem and could not process your request"
+ app.errorResponse(w, r, http.StatusInternalServerError, message)
+}
diff --git a/cmd/streaming/helpers.go b/cmd/streaming/helpers.go
new file mode 100644
index 00000000..dfaf9b87
--- /dev/null
+++ b/cmd/streaming/helpers.go
@@ -0,0 +1,100 @@
+package main
+
+import (
+ "context"
+ "database/sql"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "reflect"
+ "strings"
+ "time"
+)
+
+type envelope map[string]any
+
+func (app *application) writeJSON(w http.ResponseWriter, status int, data envelope, headers http.Header) error {
+ js, err := json.MarshalIndent(data, "", "\t")
+ if err != nil {
+ return err
+ }
+
+ js = append(js, '\n')
+
+ for key, value := range headers {
+ w.Header()[key] = value
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(status)
+ w.Write(js)
+
+ return nil
+}
+
+func (app *application) healthcheckHandler(w http.ResponseWriter, r *http.Request) {
+ env := envelope{
+ "status": "available",
+ "system_info": map[string]string{
+ "version": version,
+ },
+ }
+
+ err := app.writeJSON(w, http.StatusOK, env, nil)
+ if err != nil {
+ app.serverErrorResponse(w, r, err)
+ }
+}
+
+func openConnectionPool(name, connectionString, driverName string) (connectionPool *sql.DB, err error) {
+
+ connectionPool, err = sql.Open(driverName, connectionString)
+ if err != nil {
+ return nil, fmt.Errorf("error opening connection to %v :: %v", name, err)
+ }
+
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ defer cancel()
+
+ err = connectionPool.PingContext(ctx)
+ if err != nil {
+ return nil, fmt.Errorf("error pinging %v :: %v", name, err)
+ }
+
+ return connectionPool, nil
+}
+
+func (app *application) receiveHandler(w http.ResponseWriter, r *http.Request) {
+
+ path := r.URL.Path
+ if len(path) > 0 && path[0] == '/' {
+ path = path[1:]
+ }
+
+ app.systemMap[path].handleWebhook(w, r)
+}
+
+// getNestedValue traverses a map[string]any using dot notation for nested fields
+func getNestedValue(obj map[string]any, dottedKey string) any {
+ keys := strings.Split(dottedKey, ".")
+ var val any = obj
+ for _, k := range keys {
+ m, ok := val.(map[string]any)
+ if !ok {
+ return nil
+ }
+ val, ok = m[k]
+ if !ok {
+ return nil
+ }
+ }
+ return val
+}
+
+// isZeroValue checks if the given value is the zero value for its type.
+func isZeroValue(x interface{}) bool {
+ if x == nil {
+ return true
+ }
+ return reflect.ValueOf(x).IsZero()
+}
diff --git a/cmd/streaming/main.go b/cmd/streaming/main.go
new file mode 100644
index 00000000..7ede7c27
--- /dev/null
+++ b/cmd/streaming/main.go
@@ -0,0 +1,453 @@
+package main
+
+import (
+ "encoding/json"
+ "expvar"
+ "flag"
+ "fmt"
+ "io"
+ "io/fs"
+ "log/slog"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/santhosh-tekuri/jsonschema/v6"
+ "github.com/sqlpipe/sqlpipe/internal/vcs"
+
+ "gopkg.in/yaml.v3"
+
+ _ "github.com/jackc/pgx/v5/stdlib"
+)
+
+var (
+ version = vcs.Version()
+)
+
+type config struct {
+ port int
+ systemsDir string
+ modelsDir string
+ keepDuplicatesFor time.Duration
+}
+
+type application struct {
+ config config
+ logger *slog.Logger
+ wg sync.WaitGroup
+ systemMap map[string]SystemInterface
+ // receiveRouter map[string]map[string]map[string]map[string]Location // system_name.object_name.model_name.key_name_from_obj.key_name_from_schema
+ // pushFieldMap map[string]map[string]map[string]map[string]Location // system_name.object_name.model_name.key_name_from_schema.key_name_for_obj]
+ schemaMap map[string]*jsonschema.Schema
+ storageEngine *storageEngine
+ schemaRootMap map[string]*SchemaRoot
+}
+
+func main() {
+
+ var cfg config
+ flag.IntVar(&cfg.port, "port", 4000, "API port")
+ flag.StringVar(&cfg.systemsDir, "systems-dir", "./systems", "Directory for systems configuration")
+ flag.StringVar(&cfg.modelsDir, "models-dir", "./models", "Directory for models configuration")
+ flag.DurationVar(&cfg.keepDuplicatesFor, "keep-duplicates-for", 1*time.Hour, "Duration to keep duplicate entries")
+ displayVersion := flag.Bool("version", false, "Display version and exit")
+
+ flag.Parse()
+
+ if *displayVersion {
+ fmt.Printf("Version:\t%s\n", version)
+ os.Exit(0)
+ }
+
+ logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
+
+ expvar.NewString("version").Set(version)
+ expvar.Publish("goroutines", expvar.Func(func() any {
+ return runtime.NumGoroutine()
+ }))
+ expvar.Publish("timestamp", expvar.Func(func() any {
+ return time.Now().Unix()
+ }))
+
+ schemaMap, schemaRootMap, err := createModelMap(cfg)
+ if err != nil {
+ logger.Error("failed to load model schemas", "error", err)
+ os.Exit(1)
+ }
+
+ systemInfoMap, err := createSystemInfoMap(cfg)
+ if err != nil {
+ logger.Error("failed to load system configurations", "error", err)
+ os.Exit(1)
+ }
+
+ storageEngine, err := newStorageEngine()
+ if err != nil {
+ logger.Error("failed to create storage engine", "error", err)
+ os.Exit(1)
+ }
+
+ app := &application{
+ config: cfg,
+ logger: logger,
+ systemMap: make(map[string]SystemInterface),
+ schemaMap: schemaMap,
+ // receiveRouter: receiveRouter,
+ // pushFieldMap: pushFieldMap,
+ storageEngine: storageEngine,
+ schemaRootMap: schemaRootMap,
+ }
+
+ serveQuitCh := make(chan struct{})
+
+ duplicateChecker := make(map[string][]ExpiringObject)
+
+ for schemaName := range app.schemaMap {
+ duplicateChecker[schemaName] = []ExpiringObject{}
+ }
+
+ // The server must be running to check that webhooks are valid (needed for system initialization)
+ go func() {
+ err = app.serve()
+ if err != nil {
+ logger.Error(err.Error())
+ os.Exit(1)
+ }
+ close(serveQuitCh)
+ }()
+
+ app.setSystemMap(systemInfoMap, duplicateChecker)
+ if err != nil {
+ logger.Error("failed to create system map", "error", err)
+ os.Exit(1)
+ }
+
+ <-serveQuitCh
+ app.logger.Info("shutting down server")
+}
+
+func createSystemInfoMap(cfg config) (map[string]SystemInfo, error) {
+ systemInfoMap := make(map[string]SystemInfo)
+
+ err := filepath.Walk(cfg.systemsDir, func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return fmt.Errorf("error walking path %s: %w", path, err)
+ }
+
+ if !info.IsDir() && (filepath.Ext(path) == ".yaml" || filepath.Ext(path) == ".yml") {
+ f, err := os.Open(path)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+
+ var infos map[string]SystemInfo
+ decoder := yaml.NewDecoder(f)
+ err = decoder.Decode(&infos)
+ if err != nil {
+ if err == io.EOF {
+ // Empty YAML file, skip it
+ return nil
+ }
+ return err
+ }
+ for name, info := range infos {
+ info.Name = name
+ systemInfoMap[info.Name] = info
+ }
+ }
+ return nil
+ })
+ if err != nil {
+ return nil, fmt.Errorf("failed to walk systems dir: %w", err)
+ }
+
+ return systemInfoMap, nil
+}
+
+func (app *application) setSystemMap(systemInfoMap map[string]SystemInfo, duplicateChecker map[string][]ExpiringObject) {
+ var systemMapMu sync.Mutex
+ errCh := make(chan error, len(systemInfoMap))
+ doneCh := make(chan struct{}, len(systemInfoMap))
+
+ for systemName, systemInfo := range systemInfoMap {
+ go func(systemName string, systemInfo SystemInfo) {
+ // Create a new copy of duplicateChecker for each system
+ dupCheckerCopy := make(map[string][]ExpiringObject, len(duplicateChecker))
+ for k, v := range duplicateChecker {
+ // Create a new slice for each key to avoid sharing underlying arrays
+ copiedSlice := make([]ExpiringObject, len(v))
+ copy(copiedSlice, v)
+ dupCheckerCopy[k] = copiedSlice
+ }
+
+ system, err := app.NewSystem(systemInfo, app.config.port, dupCheckerCopy)
+ if err != nil {
+ errCh <- err
+ } else {
+ systemMapMu.Lock()
+ app.systemMap[systemInfo.Name] = system
+ systemMapMu.Unlock()
+ }
+ doneCh <- struct{}{}
+ }(systemName, systemInfo)
+ }
+
+ // Wait for all goroutines to finish
+ for i := 0; i < len(systemInfoMap); i++ {
+ <-doneCh
+ }
+
+ // Collect and handle errors from errCh
+ var systemInitErrs []error
+ for e := range errCh {
+ systemInitErrs = append(systemInitErrs, e)
+ }
+ if len(systemInitErrs) > 0 {
+ app.logger.Error("failed to initialize one or more systems", "errors", systemInitErrs)
+ os.Exit(1)
+ }
+}
+
+type Location struct {
+ PullObject string `json:"pull_object,omitempty"`
+ PushObject string `json:"push_object,omitempty"`
+ Field string `json:"field,omitempty"`
+ SearchKey bool `json:"search_key,omitempty"`
+ Pull bool `json:"pull,omitempty"`
+ Push bool `json:"push,omitempty"`
+}
+
+type PropertySystemConfig struct {
+ RequireForCreate bool `json:"require_for_create"`
+ Receive []Location `json:"receive"`
+ Push []Location `json:"push"`
+ Sync []Location `json:"sync"`
+}
+
+type Property struct {
+ Type any `json:"type"`
+ Systems map[string]PropertySystemConfig `json:"systems"`
+}
+
+type SchemaRoot struct {
+ Title string `json:"title"`
+ Properties map[string]Property `json:"properties"`
+}
+
+// type Field struct {
+// Name string
+// SearchKey bool
+// }
+
+// type FieldRemaps struct {
+// Title string
+// Fields map[string]Field
+// }
+
+// type FieldMapper struct {
+// Systems map[string]map[string][]Model
+// }
+
+func createModelMap(cfg config) (
+ schemaMap map[string]*jsonschema.Schema,
+ schemaRoot map[string]*SchemaRoot,
+ err error,
+) {
+
+ jsonFiles := []string{}
+
+ err = filepath.WalkDir(cfg.modelsDir, func(path string, d fs.DirEntry, err error) error {
+ if err != nil {
+ return err
+ }
+ // Skip directories and non-JSON files
+ if d.IsDir() || !strings.HasSuffix(d.Name(), ".json") {
+ return nil
+ }
+ jsonFiles = append(jsonFiles, path)
+ return nil
+ })
+ if err != nil {
+ return nil, nil, err
+ }
+
+ schemaMap = make(map[string]*jsonschema.Schema)
+ // fieldMapper = map[string]map[string][]FieldRemaps{}
+ // receiveRouter = make(map[string]map[string]map[string]map[string]Location)
+ // pushFieldMap = make(map[string]map[string]map[string]map[string]Location)
+ // searchFieldMap = make(map[string]map[string]map[string]bool)
+ schemaRootMap := map[string]*SchemaRoot{}
+ compiler := jsonschema.NewCompiler()
+
+ for _, path := range jsonFiles {
+
+ schemaRoot := &SchemaRoot{}
+
+ url := "file://" + filepath.ToSlash(path)
+ schema, err := compiler.Compile(url)
+ if err != nil {
+ return nil, nil, fmt.Errorf("compile %s: %w", path, err)
+ }
+
+ if schema.Title == "" {
+ return nil, nil, fmt.Errorf("schema %s has no title", path)
+ }
+
+ schemaMap[schema.Title] = schema
+
+ f, err := os.Open(path)
+ if err != nil {
+ return nil, nil, fmt.Errorf("failed to open model file %s: %w", path, err)
+ }
+ defer f.Close()
+
+ decoder := json.NewDecoder(f)
+ if err := decoder.Decode(&schemaRoot); err != nil {
+ return nil, nil, fmt.Errorf("failed to decode model file %s: %w", path, err)
+ }
+
+ schemaRootMap[schema.Title] = schemaRoot
+
+ // for propertyNameInSchema, schemaProperty := range schemaRoot.Properties {
+
+ // for systemName, system := range schemaProperty.Systems {
+
+ // if _, ok := receiveFieldMap[systemName]; !ok {
+ // receiveFieldMap[systemName] = make(map[string]map[string]map[string]Location)
+ // }
+
+ // for _, location := range system.Receive {
+
+ // if _, ok := receiveFieldMap[systemName][location.PullObject]; !ok {
+ // receiveFieldMap[systemName][location.PullObject] = make(map[string]map[string]Location)
+ // }
+
+ // if _, ok := receiveFieldMap[systemName][location.PullObject][schema.Title]; !ok {
+ // receiveFieldMap[systemName][location.PullObject][schema.Title] = make(map[string]Location)
+ // }
+
+ // receiveFieldMap[systemName][location.PullObject][schema.Title][location.Field] = Location{
+ // Field: propertyNameInSchema,
+ // SearchKey: location.SearchKey,
+ // Pull: true,
+ // Push: false,
+ // }
+ // }
+
+ // for _, location := range system.Sync {
+
+ // if _, ok := receiveFieldMap[systemName][location.PullObject]; !ok {
+ // receiveFieldMap[systemName][location.PullObject] = make(map[string]map[string]Location)
+ // }
+
+ // if _, ok := receiveFieldMap[systemName][location.PullObject][schema.Title]; !ok {
+ // receiveFieldMap[systemName][location.PullObject][schema.Title] = make(map[string]Location)
+ // }
+
+ // receiveFieldMap[systemName][location.PullObject][schema.Title][location.Field] = Location{
+ // Field: propertyNameInSchema,
+ // SearchKey: location.SearchKey,
+ // Pull: true,
+ // Push: true,
+ // }
+ // }
+
+ // for _, location := range system.Push {
+
+ // if _, ok := receiveFieldMap[systemName][location.PullObject]; !ok {
+ // receiveFieldMap[systemName][location.PullObject] = make(map[string]map[string]Location)
+ // }
+
+ // if _, ok := receiveFieldMap[systemName][location.PullObject][schema.Title]; !ok {
+ // receiveFieldMap[systemName][location.PullObject][schema.Title] = make(map[string]Location)
+ // }
+
+ // receiveFieldMap[systemName][location.PullObject][schema.Title][location.Field] = Location{
+ // Field: propertyNameInSchema,
+ // SearchKey: location.SearchKey,
+ // Pull: false,
+ // Push: true,
+ // }
+ // }
+
+ // if _, ok := pushFieldMap[systemName]; !ok {
+ // pushFieldMap[systemName] = make(map[string]map[string]map[string]Location)
+ // }
+
+ // for _, location := range system.Receive {
+ // if _, ok := pushFieldMap[systemName][schema.Title]; !ok {
+ // pushFieldMap[systemName][schema.Title] = make(map[string]map[string]Location)
+ // }
+
+ // if _, ok := pushFieldMap[systemName][schema.Title][location.PushObject]; !ok {
+ // pushFieldMap[systemName][schema.Title][location.PushObject] = make(map[string]Location)
+ // }
+
+ // pushFieldMap[systemName][schema.Title][location.PushObject][propertyNameInSchema] = Location{
+ // Field: location.Field,
+ // SearchKey: location.SearchKey,
+ // Pull: false,
+ // Push: false,
+ // PushObject: location.PushObject,
+ // }
+ // }
+
+ // for _, location := range system.Push {
+ // if _, ok := pushFieldMap[systemName][schema.Title]; !ok {
+ // pushFieldMap[systemName][schema.Title] = make(map[string]map[string]Location)
+ // }
+
+ // if _, ok := pushFieldMap[systemName][schema.Title][location.PushObject]; !ok {
+ // pushFieldMap[systemName][schema.Title][location.PushObject] = make(map[string]Location)
+ // }
+
+ // pushFieldMap[systemName][schema.Title][location.PushObject][propertyNameInSchema] = Location{
+ // Field: location.Field,
+ // SearchKey: location.SearchKey,
+ // Pull: false,
+ // Push: true,
+ // PushObject: location.PushObject,
+ // }
+ // }
+
+ // for _, location := range system.Sync {
+ // if _, ok := pushFieldMap[systemName][schema.Title]; !ok {
+ // pushFieldMap[systemName][schema.Title] = make(map[string]map[string]Location)
+ // }
+
+ // if _, ok := pushFieldMap[systemName][schema.Title][location.PushObject]; !ok {
+ // pushFieldMap[systemName][schema.Title][location.PushObject] = make(map[string]Location)
+ // }
+
+ // pushFieldMap[systemName][schema.Title][location.PushObject][propertyNameInSchema] = Location{
+ // Field: location.Field,
+ // SearchKey: location.SearchKey,
+ // Pull: false,
+ // Push: true,
+ // PushObject: location.PushObject,
+ // }
+ // }
+ // }
+ // }
+ }
+
+ // b, err := json.MarshalIndent(receiveFieldMap, "", " ")
+ // if err != nil {
+ // fmt.Fprintf(os.Stderr, "failed to marshal receiveFieldMap: %v\n", err)
+ // } else {
+ // fmt.Printf("receiveFieldMap:\n%s\n", string(b))
+ // }
+
+ // b, err = json.MarshalIndent(pushFieldMap, "", " ")
+ // if err != nil {
+ // fmt.Fprintf(os.Stderr, "failed to marshal pushFieldMap: %v\n", err)
+ // } else {
+ // fmt.Printf("pushFieldMap:\n%s\n", string(b))
+ // }
+
+ return schemaMap, schemaRootMap, nil
+}
diff --git a/cmd/streaming/postgresql.go b/cmd/streaming/postgresql.go
new file mode 100644
index 00000000..d12a20a1
--- /dev/null
+++ b/cmd/streaming/postgresql.go
@@ -0,0 +1,526 @@
+package main
+
+import (
+ "context"
+ "database/sql"
+ "encoding/json"
+ "fmt"
+ "log"
+ "net/http"
+ "os"
+ "strings"
+ "time"
+
+ "github.com/jackc/pglogrepl"
+ "github.com/jackc/pgx/v5/pgconn"
+ "github.com/jackc/pgx/v5/pgproto3"
+ "golang.org/x/time/rate"
+)
+
+type ExpiringObject struct {
+ Object Object `json:"object"`
+ Expiry time.Time `json:"expiry"`
+}
+
+func newExpiringObject(object Object, timeFromNow time.Duration) ExpiringObject {
+ return ExpiringObject{
+ Object: object,
+ Expiry: time.Now().Add(timeFromNow),
+ }
+}
+
+type Postgresql struct {
+ db *sql.DB
+ replConn *pgconn.PgConn
+ app *application
+ systemInfo SystemInfo
+ limiter *rate.Limiter
+ duplicateChecker map[string][]ExpiringObject
+}
+
+func (app *application) newPostgresql(systemInfo SystemInfo, duplicateChecker map[string][]ExpiringObject) (postgresql Postgresql, err error) {
+ db, err := openConnectionPool(systemInfo.Name, systemInfo.ConnectionString, DriverPostgreSQL)
+ if err != nil {
+ return postgresql, fmt.Errorf("error opening postgresql db :: %v", err)
+ }
+
+ // Create replication connection
+ replConn, err := pgconn.Connect(context.Background(), systemInfo.ReplicationDsn)
+ if err != nil {
+ return postgresql, fmt.Errorf("error opening postgresql replication connection :: %v", err)
+ }
+
+ postgresql.db = db
+ postgresql.replConn = replConn
+ postgresql.app = app
+ postgresql.systemInfo = systemInfo
+ postgresql.limiter = rate.NewLimiter(rate.Limit(systemInfo.RateLimit), systemInfo.RateBucketSize)
+ postgresql.duplicateChecker = duplicateChecker
+
+ app.storageEngine.setSafeIndexMap(systemInfo.Name, 0)
+
+ go postgresql.watchQueue()
+ go postgresql.watchCDC()
+
+ return postgresql, nil
+}
+
+func (p Postgresql) watchQueue() {
+ var index int64
+ for {
+ // Get the last safe object index for this system
+ var exists bool
+ index, exists = p.app.storageEngine.getSafeIndexMap(p.systemInfo.Name)
+ if !exists {
+ panic(fmt.Sprintf("safe index not found for system %s", p.systemInfo.Name))
+ }
+
+ // Wait for rate limiter
+ err := p.limiter.Wait(context.Background())
+ if err != nil {
+ // Optionally log or handle error, then break or continue
+ continue
+ }
+
+ // Query safeObjects after lastIndex
+ objects := p.app.storageEngine.getSafeObjectsFromIndex(index)
+ if len(objects) > 0 {
+ // Process new objects as needed
+ index += int64(len(objects))
+ }
+
+ for _, object := range objects {
+ searchFields := []string{}
+
+ prettyObj, err := json.MarshalIndent(object, "", " ")
+ if err != nil {
+ p.app.logger.Error("error pretty printing object", "error", err)
+ } else {
+ fmt.Printf("Postgresql got object from queue:\n%s\n", string(prettyObj))
+ }
+
+ for locationInSystem, fields := range p.systemInfo.PushRouter[object.Type] {
+ newObj := map[string]any{}
+ for keyInSchema, location := range fields {
+ if _, ok := object.Payload[keyInSchema]; ok {
+ newObj[location.Field] = object.Payload[keyInSchema]
+
+ if fields[keyInSchema].SearchKey {
+ searchFields = append(searchFields, location.Field)
+ }
+ }
+ }
+
+ var objectIsDuplicate bool
+ foundDuplicate := false
+ for i, expiringObj := range p.duplicateChecker[object.Type] {
+
+ objectIsDuplicate = true
+
+ for k, v := range newObj {
+ if _, ok := expiringObj.Object.Payload[k]; !ok {
+ objectIsDuplicate = false
+ break
+ }
+ if v != expiringObj.Object.Payload[k] {
+ objectIsDuplicate = false
+ break
+ }
+ }
+
+ if objectIsDuplicate {
+ fmt.Println("Postgresql found duplicate object in duplicate checker while watching queue:", expiringObj.Object)
+ // If we found a duplicate, we can remove it from the duplicate checker
+ p.duplicateChecker[object.Type] = append(p.duplicateChecker[object.Type][:i], p.duplicateChecker[object.Type][i+1:]...)
+ foundDuplicate = true
+ break
+ }
+ }
+
+ if !foundDuplicate {
+ fmt.Println("No duplicate found for object, upserting to PostgreSQL", object)
+ fmt.Printf("PostgreSQL is upserting object: %v\n", newObj)
+
+ switch object.Operation {
+ case "upsert":
+ err = p.upsertJSON(object.Payload, searchFields, locationInSystem, object.Type)
+ if err != nil {
+ p.app.logger.Error("error upserting JSON to PostgreSQL", "error", err, "objectType", object.Type, "locationInSystem", locationInSystem, "data", newObj)
+ }
+ case "delete":
+ err = p.deleteFromPostgresql(object.Payload, searchFields, locationInSystem)
+ if err != nil {
+ p.app.logger.Error("error deleting from PostgreSQL", "error", err, "objectType", object.Type, "locationInSystem", locationInSystem, "data", newObj)
+ }
+ }
+ }
+
+ }
+ }
+
+ // Update the safe index map for this system
+ p.app.storageEngine.setSafeIndexMap(p.systemInfo.Name, index)
+ }
+}
+
+func (p Postgresql) handleWebhook(w http.ResponseWriter, r *http.Request) {
+ p.app.logger.Error("PostgreSQL does not support webhooks", "system", p.systemInfo.Name)
+}
+
+func (p Postgresql) upsertJSON(data map[string]any, searchFields []string, locationInSystem string, objectType string) error {
+ var foundMatch bool
+ var conflictField string
+ var conflictValue any
+
+ for _, field := range searchFields {
+ if v, ok := data[field]; ok {
+ // Check if a row exists with this search field
+ query := fmt.Sprintf("SELECT 1 FROM %s WHERE %s = $1 LIMIT 1", locationInSystem, field)
+ row := p.db.QueryRow(query, v)
+ var dummy int
+ err := row.Scan(&dummy)
+ if err == nil {
+ foundMatch = true
+ conflictField = field
+ conflictValue = v
+ break
+ }
+ if err != sql.ErrNoRows && err != nil {
+ p.app.logger.Error("error checking for existing row", "error", err, "query", query, "value", v)
+ return fmt.Errorf("error checking for existing row: %v", err)
+ }
+ }
+ }
+
+ if foundMatch {
+ // Prepare UPDATE: set all columns except the conflict field
+ setCols := make([]string, 0, len(data))
+ values := make([]any, 0, len(data))
+ idx := 1
+ for k, v := range data {
+ if k != conflictField {
+ setCols = append(setCols, fmt.Sprintf("%s = $%d", k, idx))
+ values = append(values, v)
+ idx++
+ }
+ }
+ // Add WHERE for the conflict field
+ whereClause := fmt.Sprintf("%s = $%d", conflictField, idx)
+ values = append(values, conflictValue)
+
+ updateQuery := fmt.Sprintf(
+ "UPDATE %s SET %s WHERE %s",
+ locationInSystem,
+ strings.Join(setCols, ", "),
+ whereClause,
+ )
+
+ _, err := p.db.Exec(updateQuery, values...)
+ if err != nil {
+ p.app.logger.Error("error executing update query", "error", err, "query", updateQuery, "values", values)
+ return fmt.Errorf("error executing update query: %v", err)
+ }
+ } else {
+ // Build INSERT
+ columns := make([]string, 0, len(data))
+ placeholders := make([]string, 0, len(data))
+ insertValues := make([]any, 0, len(data))
+
+ idx := 1
+ for k, v := range data {
+ columns = append(columns, k)
+ placeholders = append(placeholders, fmt.Sprintf("$%d", idx))
+ insertValues = append(insertValues, v)
+ idx++
+ }
+ insertQuery := fmt.Sprintf(
+ "INSERT INTO %s (%s) VALUES (%s)",
+ locationInSystem,
+ strings.Join(columns, ", "),
+ strings.Join(placeholders, ", "),
+ )
+ _, err := p.db.Exec(insertQuery, insertValues...)
+ if err != nil {
+ p.app.logger.Error("error executing insert query", "error", err, "query", insertQuery, "values", insertValues)
+ return fmt.Errorf("error executing insert query: %v", err)
+ }
+ }
+
+ object := Object{
+ Type: objectType,
+ Payload: data,
+ }
+
+ expiringObj := newExpiringObject(object, p.app.config.keepDuplicatesFor)
+ p.duplicateChecker[objectType] = append(p.duplicateChecker[objectType], expiringObj)
+
+ return nil
+}
+
+// Start CDC for all tables in publication
+func (p *Postgresql) watchCDC() {
+ slotName := "sqlpipe_slot"
+ outputPlugin := "wal2json"
+
+ replConn, err := pgconn.Connect(context.Background(), p.systemInfo.ReplicationDsn)
+ if err != nil {
+ p.app.logger.Error("failed to connect", "error", err)
+ os.Exit(1)
+ }
+ defer replConn.Close(context.Background())
+
+ sysident, err := pglogrepl.IdentifySystem(context.Background(), replConn)
+ if err != nil {
+ p.app.logger.Error("IdentifySystem failed", "error", err)
+ os.Exit(1)
+ }
+
+ _, err = pglogrepl.CreateReplicationSlot(context.Background(), replConn, slotName, outputPlugin, pglogrepl.CreateReplicationSlotOptions{Temporary: false, Mode: pglogrepl.LogicalReplication})
+ if err != nil {
+ // If the error is "already exists", it's OK, otherwise fail
+ if !strings.Contains(err.Error(), "already exists") {
+ p.app.logger.Error("CreateReplicationSlot failed", "error", err)
+ os.Exit(1)
+ }
+ }
+
+ pluginArguments := []string{"\"pretty-print\" 'true'"}
+ err = pglogrepl.StartReplication(context.Background(), replConn, slotName, sysident.XLogPos,
+ pglogrepl.StartReplicationOptions{
+ PluginArgs: pluginArguments,
+ })
+ if err != nil {
+ p.app.logger.Error("StartReplication failed", "error", err)
+ os.Exit(1)
+ }
+
+ clientXLogPos := sysident.XLogPos
+ standbyMessageTimeout := time.Second * 10
+ nextStandbyMessageDeadline := time.Now().Add(standbyMessageTimeout)
+
+ for {
+ if time.Now().After(nextStandbyMessageDeadline) {
+ err = pglogrepl.SendStandbyStatusUpdate(context.Background(), replConn, pglogrepl.StandbyStatusUpdate{WALWritePosition: clientXLogPos})
+ if err != nil {
+ log.Fatalln("SendStandbyStatusUpdate failed:", err)
+ }
+ nextStandbyMessageDeadline = time.Now().Add(standbyMessageTimeout)
+ }
+
+ ctx, cancel := context.WithDeadline(context.Background(), nextStandbyMessageDeadline)
+ rawMsg, err := replConn.ReceiveMessage(ctx)
+ cancel()
+ if err != nil {
+ if pgconn.Timeout(err) {
+ continue
+ }
+ log.Fatalln("ReceiveMessage failed:", err)
+ }
+
+ if errMsg, ok := rawMsg.(*pgproto3.ErrorResponse); ok {
+ log.Fatalf("received Postgres WAL error: %+v", errMsg)
+ }
+
+ msg, ok := rawMsg.(*pgproto3.CopyData)
+ if !ok {
+ log.Printf("Received unexpected message: %T\n", rawMsg)
+ continue
+ }
+
+ switch msg.Data[0] {
+ case pglogrepl.PrimaryKeepaliveMessageByteID:
+ pkm, err := pglogrepl.ParsePrimaryKeepaliveMessage(msg.Data[1:])
+ if err != nil {
+ log.Fatalln("ParsePrimaryKeepaliveMessage failed:", err)
+ }
+ if pkm.ServerWALEnd > clientXLogPos {
+ clientXLogPos = pkm.ServerWALEnd
+ }
+ if pkm.ReplyRequested {
+ nextStandbyMessageDeadline = time.Time{}
+ }
+
+ case pglogrepl.XLogDataByteID:
+ xld, err := pglogrepl.ParseXLogData(msg.Data[1:])
+ if err != nil {
+ log.Fatalln("ParseXLogData failed:", err)
+ }
+
+ // if outputPlugin == "wal2json" {
+ // log.Printf("wal2json data: %s\n", string(xld.WALData))
+ // }
+
+ err = p.handleCdcEvent(string(xld.WALData))
+ if err != nil {
+ p.app.logger.Error("error handling CDC event", "error", err, "data", string(xld.WALData))
+ return
+ }
+
+ if xld.WALStart > clientXLogPos {
+ clientXLogPos = xld.WALStart
+ }
+ default:
+ }
+ }
+}
+
+type OldKeys struct {
+ KeyNames []string `json:"keynames"`
+ KeyValues []any `json:"keyvalues,omitempty"` // Optional, if not provided, the old keys are not included
+}
+
+type CdcChange struct {
+ Kind string `json:"kind"`
+ Schema string `json:"schema"`
+ Table string `json:"table"`
+ ColumnNames []string `json:"columnnames"`
+ ColumnTypes []string `json:"columntypes"`
+ ColumnValues []any `json:"columnvalues"`
+ OldKeys OldKeys `json:"oldkeys,omitempty"` // Optional, if not provided, the old keys are not included
+}
+
+type CdcEvent struct {
+ Change []CdcChange `json:"change"`
+}
+
+func (p Postgresql) handleCdcEvent(jsonString string) error {
+
+ // fmt.Println("receive field map: ", p.receiveFieldMap)
+
+ var event CdcEvent
+ err := json.Unmarshal([]byte(jsonString), &event)
+ if err != nil {
+ return fmt.Errorf("error unmarshalling CDC event: %v", err)
+ }
+
+ // objs := []map[string]any{}
+
+ for _, change := range event.Change {
+ pullLocation := change.Schema + "." + change.Table
+ operationType := change.Kind
+
+ obj := map[string]any{}
+ newObjs := make(map[string]map[string]any)
+
+ switch operationType {
+ case "insert", "update":
+ operationType = "upsert"
+ for i, colName := range change.ColumnNames {
+ if change.ColumnValues[i] != nil {
+ obj[colName] = change.ColumnValues[i]
+ }
+ }
+ case "delete":
+ operationType = "delete"
+ for i, colName := range change.OldKeys.KeyNames {
+ if change.OldKeys.KeyValues != nil {
+ obj[colName] = change.OldKeys.KeyValues[i]
+ }
+ }
+ default:
+ return fmt.Errorf("unknown operation type: %s", operationType)
+ }
+
+ fmt.Println("Received cdc data from PostgreSQL:", jsonString)
+
+ for objectType, pullObject := range p.systemInfo.ReceiveRouter[pullLocation] {
+ newObj := map[string]any{}
+
+ for keyInObj, fields := range pullObject {
+ newObj[fields.Field] = obj[keyInObj]
+ }
+
+ newObjs[objectType] = newObj
+ }
+
+ for schemaName, obj := range newObjs {
+
+ for k, v := range obj {
+ if v == nil {
+ delete(obj, k)
+ }
+ }
+
+ fmt.Println("Postgresql validating / dupe scanning obj:", obj)
+
+ schema, inMap := p.app.schemaMap[schemaName]
+ if !inMap {
+ return fmt.Errorf("no schema found for pull location: %s", pullLocation)
+ }
+
+ err = schema.Validate(obj)
+ if err != nil {
+ return fmt.Errorf("object failed postgresql schema validation for '%s': %v", pullLocation, err)
+ }
+
+ var objectIsDuplicate bool
+ foundDuplicate := false
+ for i, expiringObj := range p.duplicateChecker[schemaName] {
+
+ objectIsDuplicate = true
+
+ for k, v := range obj {
+ if v != expiringObj.Object.Payload[k] {
+ objectIsDuplicate = false
+ break
+ }
+ }
+
+ if objectIsDuplicate {
+ fmt.Println("Postgresql found duplicate object in duplicate checker while handling cdc event:", expiringObj.Object)
+ // If we found a duplicate, we can remove it from the duplicate checker
+ p.duplicateChecker[schemaName] = append(p.duplicateChecker[schemaName][:i], p.duplicateChecker[schemaName][i+1:]...)
+ foundDuplicate = true
+ break
+ }
+ }
+
+ if !foundDuplicate {
+
+ object := Object{
+ Operation: operationType,
+ Type: schemaName,
+ Payload: obj,
+ }
+
+ // also add to storage engine
+ fmt.Println("PostgreSQL no duplicate found. Storing object in queue", obj)
+ p.app.storageEngine.addSafeObject(object)
+
+ fmt.Println("PostgreSQL no duplicate found for object, adding to duplicate checker", obj)
+ expiringObj := newExpiringObject(object, p.app.config.keepDuplicatesFor)
+ p.duplicateChecker[schemaName] = append(p.duplicateChecker[schemaName], expiringObj)
+ }
+ }
+ }
+
+ return nil
+}
+
+// deleteFromPostgresql deletes a row from PostgreSQL based on the searchFields and payload.
+func (p Postgresql) deleteFromPostgresql(payload map[string]any, searchFields []string, locationInSystem string) error {
+ if len(searchFields) == 0 {
+ return fmt.Errorf("no search fields provided for delete operation")
+ }
+
+ whereClauses := make([]string, 0, len(searchFields))
+ values := make([]any, 0, len(searchFields))
+ idx := 1
+ for _, field := range searchFields {
+ val, ok := payload[field]
+ if !ok {
+ return fmt.Errorf("search field '%s' not found in payload", field)
+ }
+ whereClauses = append(whereClauses, fmt.Sprintf("%s = $%d", field, idx))
+ values = append(values, val)
+ idx++
+ }
+
+ deleteQuery := fmt.Sprintf("DELETE FROM %s WHERE %s", locationInSystem, strings.Join(whereClauses, " AND "))
+ _, err := p.db.Exec(deleteQuery, values...)
+ if err != nil {
+ p.app.logger.Error("error executing delete query", "error", err, "query", deleteQuery, "values", values)
+ return fmt.Errorf("error executing delete query: %v", err)
+ }
+ return nil
+}
diff --git a/cmd/streaming/routes.go b/cmd/streaming/routes.go
new file mode 100644
index 00000000..9664943a
--- /dev/null
+++ b/cmd/streaming/routes.go
@@ -0,0 +1,22 @@
+package main
+
+import (
+ "expvar"
+ "net/http"
+
+ "github.com/julienschmidt/httprouter"
+)
+
+func (app *application) routes() http.Handler {
+ router := httprouter.New()
+
+ router.NotFound = http.HandlerFunc(app.receiveHandler)
+ router.MethodNotAllowed = http.HandlerFunc(app.methodNotAllowedResponse)
+
+ router.HandlerFunc(http.MethodGet, "/v1/healthcheck", app.healthcheckHandler)
+ router.Handler(http.MethodGet, "/debug/vars", expvar.Handler())
+
+ return router
+
+ // return app.metrics(app.recoverPanic(app.enableCORS(app.rateLimit(app.authenticate(router)))))
+}
diff --git a/cmd/streaming/server.go b/cmd/streaming/server.go
new file mode 100644
index 00000000..b742ffb4
--- /dev/null
+++ b/cmd/streaming/server.go
@@ -0,0 +1,62 @@
+package main
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net/http"
+ "os"
+ "os/signal"
+ "syscall"
+ "time"
+)
+
+func (app *application) serve() error {
+
+ srv := &http.Server{
+ Addr: fmt.Sprintf(":%d", app.config.port),
+ Handler: app.routes(),
+ IdleTimeout: time.Minute,
+ ReadTimeout: 5 * time.Second,
+ WriteTimeout: 10 * time.Second,
+ }
+
+ shutdownError := make(chan error)
+
+ go func() {
+ quit := make(chan os.Signal, 1)
+ signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
+ s := <-quit
+
+ app.logger.Info("caught signal", "signal", s.String())
+
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+ defer cancel()
+
+ err := srv.Shutdown(ctx)
+ if err != nil {
+ shutdownError <- err
+ }
+
+ app.logger.Info("completing background tasks", "addr", srv.Addr)
+
+ app.wg.Wait()
+ shutdownError <- nil
+ }()
+
+ app.logger.Info("starting server", "addr", srv.Addr)
+
+ err := srv.ListenAndServe()
+ if !errors.Is(err, http.ErrServerClosed) {
+ return err
+ }
+
+ err = <-shutdownError
+ if err != nil {
+ return err
+ }
+
+ app.logger.Info("stopped server", "addr", srv.Addr)
+
+ return nil
+}
diff --git a/cmd/streaming/snowflake.go b/cmd/streaming/snowflake.go
new file mode 100644
index 00000000..fade084d
--- /dev/null
+++ b/cmd/streaming/snowflake.go
@@ -0,0 +1,33 @@
+package main
+
+import (
+ "database/sql"
+ "errors"
+ "fmt"
+ "net/http"
+
+ _ "github.com/snowflakedb/gosnowflake"
+)
+
+type Snowflake struct {
+ Connection *sql.DB
+}
+
+func newSnowflake(systemInfo SystemInfo) (snowflake Snowflake, err error) {
+ db, err := openConnectionPool(systemInfo.Name, systemInfo.ConnectionString, DriverSnowflake)
+ if err != nil {
+ return snowflake, fmt.Errorf("error opening snowflake db :: %v", err)
+ }
+
+ snowflake.Connection = db
+
+ return snowflake, nil
+}
+
+func (s Snowflake) handleWebhook(w http.ResponseWriter, r *http.Request) {
+ // Snowflake will not send us webhooks, so this is a no-op
+}
+
+func (s Snowflake) mapProperties(obj map[string]interface{}) (map[string]interface{}, error) {
+ return nil, errors.New("not implemented for snowflake yet")
+}
diff --git a/cmd/streaming/storageEngine.go b/cmd/streaming/storageEngine.go
new file mode 100644
index 00000000..0d5c1b4c
--- /dev/null
+++ b/cmd/streaming/storageEngine.go
@@ -0,0 +1,75 @@
+package main
+
+import (
+ "fmt"
+ "sync"
+)
+
+type Object struct {
+ Type string `json:"type"`
+ Operation string `json:"operation"`
+ Payload map[string]any `json:"payload"`
+}
+
+type storageEngine struct {
+ safeIndexMap map[string]int64
+ indexMapMu sync.RWMutex
+ safeObjects []Object
+ objectsMu sync.RWMutex
+}
+
+func newStorageEngine() (*storageEngine, error) {
+ storageEngine := &storageEngine{
+ safeIndexMap: make(map[string]int64),
+ safeObjects: make([]Object, 0),
+ }
+ return storageEngine, nil
+}
+
+func (s *storageEngine) setSafeIndexMap(key string, index int64) {
+ s.indexMapMu.Lock()
+ defer s.indexMapMu.Unlock()
+ s.safeIndexMap[key] = index
+}
+
+func (s *storageEngine) getSafeIndexMap(key string) (int64, bool) {
+ s.indexMapMu.RLock()
+ defer s.indexMapMu.RUnlock()
+ index, exists := s.safeIndexMap[key]
+ return index, exists
+}
+
+func (s *storageEngine) addSafeObject(object Object) {
+ s.objectsMu.Lock()
+ defer s.objectsMu.Unlock()
+ s.safeObjects = append(s.safeObjects, object)
+}
+
+func (s *storageEngine) getSafeObjectsFromIndex(index int64) []Object {
+ s.objectsMu.RLock()
+ defer s.objectsMu.RUnlock()
+
+ if index < 0 || index >= int64(len(s.safeObjects)) {
+ return nil
+ }
+
+ // Return a slice of safeObjects starting from the given index
+ return s.safeObjects[index:]
+}
+
+func (s *storageEngine) printAllContents() {
+ s.indexMapMu.RLock()
+ defer s.indexMapMu.RUnlock()
+ s.objectsMu.RLock()
+ defer s.objectsMu.RUnlock()
+
+ println("safeIndexMap contents:")
+ for k, v := range s.safeIndexMap {
+ println(" Key:", k, "Value:", v)
+ }
+
+ println("safeObjects contents:")
+ for i, obj := range s.safeObjects {
+ println(" Index:", i, "Value:", fmt.Sprintf("%v", obj))
+ }
+}
diff --git a/cmd/streaming/stripe.go b/cmd/streaming/stripe.go
new file mode 100644
index 00000000..787fbd29
--- /dev/null
+++ b/cmd/streaming/stripe.go
@@ -0,0 +1,451 @@
+package main
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "os"
+ "os/exec"
+ "time"
+
+ "github.com/stripe/stripe-go/v82"
+ "golang.org/x/time/rate"
+)
+
+// deleteFromStripe simulates deleting an object from Stripe based on the searchKey and searchValue.
+func (s Stripe) deleteFromStripe(endpoint string, object Object, searchKey, searchValue string) error {
+ if searchKey == "" || searchValue == "" {
+ return fmt.Errorf("deleteFromStripe: searchKey and searchValue must be provided")
+ }
+
+ baseURL := "https://api.stripe.com/v1"
+ deleteUrl := fmt.Sprintf("%s/%s/%s", baseURL, endpoint, searchValue)
+ req, err := http.NewRequest("DELETE", deleteUrl, nil)
+ if err != nil {
+ return err
+ }
+ req.Header.Set("Authorization", "Bearer "+s.apiKey)
+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+
+ fmt.Printf("Making DELETE request to Stripe: %s\n", deleteUrl)
+ resp, err := http.DefaultClient.Do(req)
+ if err != nil {
+ return fmt.Errorf("failed to delete object at stripe route %s, error making request: %w", deleteUrl, err)
+ }
+ defer resp.Body.Close()
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return fmt.Errorf("failed to read response body from stripe route %s, error reading response body: %w", deleteUrl, err)
+ }
+
+ if resp.StatusCode >= 400 {
+ return fmt.Errorf("failed to delete object at stripe route %s, status code: %d, response: %s", deleteUrl, resp.StatusCode, string(body))
+ }
+
+ fmt.Println("Stripe deleted object:", string(body))
+ return nil
+}
+
+type Stripe struct {
+ client *stripe.Client
+ apiKey string
+ app *application
+ // receiveFieldMap map[string]map[string]map[string]Location
+ // pushFieldMap map[string]map[string]map[string]Location
+ limiter *rate.Limiter
+ systemInfo SystemInfo
+ duplicateChecker map[string][]ExpiringObject
+}
+
+func (app *application) newStripe(systemInfo SystemInfo, duplicateChecker map[string][]ExpiringObject) (system SystemInterface, err error) {
+
+ if systemInfo.UseCliListener {
+
+ if _, err := exec.LookPath("stripe"); err != nil {
+ return nil, fmt.Errorf("Stripe CLI not found in PATH. Please install it to use Stripe listening mode: %w", err)
+ }
+
+ // Forward Stripe events to our local endpoint
+ forwardURL := fmt.Sprintf("http://localhost:%d/%v", app.config.port, systemInfo.Name)
+ cmd := exec.Command("stripe", "listen", "--forward-to", forwardURL)
+ cmd.Stderr = os.Stderr
+
+ cmd.Env = append(os.Environ(), fmt.Sprintf("STRIPE_API_KEY=%s", systemInfo.ApiKey))
+
+ go func() {
+ app.logger.Info("Starting Stripe CLI listener", "command", cmd.String())
+ err := cmd.Run()
+ if err != nil {
+ return
+ }
+ }()
+ }
+
+ stripeClient := stripe.NewClient(systemInfo.ApiKey)
+
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
+ defer cancel()
+
+ listParams := &stripe.CouponListParams{}
+ listParams.Limit = stripe.Int64(1)
+
+ for _, err := range stripeClient.V1Coupons.List(ctx, listParams) {
+ // We are only testing the connection, so we don't want to do anything with
+ // the data. Do not read it, store it, print it, or log it. Nothing!
+ if err != nil {
+ return nil, err
+ }
+
+ break
+ }
+
+ app.logger.Info("Stripe test api call was successful", "system", systemInfo.Name)
+
+ stripeSystem := &Stripe{
+ client: stripeClient,
+ app: app,
+ limiter: rate.NewLimiter(rate.Limit(systemInfo.RateLimit), systemInfo.RateBucketSize),
+ systemInfo: systemInfo,
+ duplicateChecker: duplicateChecker,
+ apiKey: systemInfo.ApiKey,
+ }
+
+ app.storageEngine.setSafeIndexMap(systemInfo.Name, 0)
+
+ go stripeSystem.watchQueue()
+
+ return stripeSystem, nil
+}
+
+func (s Stripe) watchQueue() {
+ var index int64
+ for {
+ // Get the last safe object index for this system
+ var exists bool
+ index, exists = s.app.storageEngine.getSafeIndexMap(s.systemInfo.Name)
+ if !exists {
+ panic(fmt.Sprintf("safe index not found for system %s", s.systemInfo.Name))
+ }
+
+ // Wait for rate limiter
+ err := s.limiter.Wait(context.Background())
+ if err != nil {
+ // Optionally log or handle error, then break or continue
+ continue
+ }
+
+ // Query safeObjects after lastIndex
+ objects := s.app.storageEngine.getSafeObjectsFromIndex(index)
+ if len(objects) > 0 {
+ // Process new objects as needed
+ index += int64(len(objects))
+ }
+
+ for _, object := range objects {
+
+ fmt.Printf("Stripe got object from queue: %v\n", object)
+ var searchKey string
+ var searchValue string
+
+ for locationInSystem, pushLocation := range s.systemInfo.PushRouter[object.Type] {
+ newObj := Object{
+ Payload: make(map[string]any),
+ Operation: object.Operation,
+ Type: object.Type,
+ }
+ for keyInSchema, field := range pushLocation {
+ if _, ok := object.Payload[keyInSchema]; ok {
+ newObj.Payload[field.Field] = object.Payload[keyInSchema]
+
+ if field.SearchKey {
+ searchKey = field.Field
+ searchValue = fmt.Sprint(newObj.Payload[field.Field])
+ }
+ }
+
+ if field.Hardcode != nil && !isZeroValue(field.Hardcode) {
+ newObj.Payload[field.Field] = field.Hardcode
+ }
+ }
+
+ var objectIsDuplicate bool
+ foundDuplicate := false
+ for i, expiringObj := range s.duplicateChecker[object.Type] {
+ fmt.Println("Stripe checking duplicate checker for object:", expiringObj.Object)
+ objectIsDuplicate = true
+ for k, v := range expiringObj.Object.Payload {
+ if v != object.Payload[k] {
+ objectIsDuplicate = false
+ break
+ }
+ }
+ if objectIsDuplicate {
+ fmt.Println("Stripe found duplicate object in duplicate checker while watching queue:", expiringObj.Object)
+ // If we found a duplicate, we can remove it from the duplicate checker
+ s.duplicateChecker[object.Type] = append(s.duplicateChecker[object.Type][:i], s.duplicateChecker[object.Type][i+1:]...)
+ foundDuplicate = true
+ break
+ }
+ }
+
+ if !foundDuplicate {
+ switch object.Operation {
+ case "upsert":
+ fmt.Printf("Stripe is upserting object. Search key: %v, Search value: %v (route: %s): %v\n", searchKey, searchValue, locationInSystem, newObj)
+ // Upsert the object to Stripe
+ _, err := s.upsertObject(locationInSystem, newObj, object.Type, searchKey, searchValue)
+ if err != nil {
+ s.app.logger.Error("Failed to upsert object to Stripe", "error", err, "object", newObj)
+ continue
+ }
+ case "delete":
+ fmt.Printf("Stripe is deleting object. Search key: %v, Search value: %v (route: %s): %v\n", searchKey, searchValue, locationInSystem, newObj)
+ err := s.deleteFromStripe(locationInSystem, newObj, searchKey, searchValue)
+ if err != nil {
+ s.app.logger.Error("Failed to delete object from Stripe", "error", err, "object", newObj)
+ continue
+ }
+ }
+ }
+ }
+ }
+
+ // Update the safe index map for this system
+ s.app.storageEngine.setSafeIndexMap(s.systemInfo.Name, index)
+ }
+}
+
+func (s Stripe) upsertObject(endpoint string, object Object, objectType string, searchKey, searchValue string) ([]byte, error) {
+ // Replace with your actual secret key or use an environment variable
+ form := url.Values{}
+
+ for key, value := range object.Payload {
+
+ if key == searchKey {
+ continue
+ }
+
+ switch v := value.(type) {
+ case string:
+ form.Set(key, v)
+ case int, int64, float64:
+ form.Set(key, fmt.Sprintf("%v", v))
+ case bool:
+ if v {
+ form.Set(key, "true")
+ } else {
+ form.Set(key, "false")
+ }
+ default:
+ return nil, fmt.Errorf("unsupported value type for key %s: %T", key, value)
+ }
+ }
+
+ if len(form) == 0 {
+ return nil, nil
+ }
+
+ baseURL := "https://api.stripe.com/v1"
+ encoded := form.Encode()
+
+ // If searchValue is empty, just create (insert) the object
+ if searchValue == "" {
+ createUrl := fmt.Sprintf("%s/%s", baseURL, endpoint)
+ req, err := http.NewRequest("POST", createUrl, bytes.NewBufferString(encoded))
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Set("Authorization", "Bearer "+s.apiKey)
+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+
+ fmt.Printf("Making request to Stripe to create object: %s\n", createUrl)
+ fmt.Println("Stripe create form data:", form.Encode())
+ resp, err := http.DefaultClient.Do(req)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create object at stripe route %s, error making request: %w", createUrl, err)
+ }
+ defer resp.Body.Close()
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create object at stripe route %s, error reading response body: %w", createUrl, err)
+ }
+
+ if resp.StatusCode >= 400 {
+ return nil, fmt.Errorf("failed to create object at stripe route %s, status code: %d, response: %s", createUrl, resp.StatusCode, string(body))
+ }
+
+ fmt.Println("Stripe created object:", string(body))
+ expiringObj := newExpiringObject(object, s.app.config.keepDuplicatesFor)
+ s.duplicateChecker[objectType] = append(s.duplicateChecker[objectType], expiringObj)
+ return body, nil
+ }
+
+ // Otherwise, update it
+ updateUrl := fmt.Sprintf("%s/%s/%s", baseURL, endpoint, searchValue)
+ req, err := http.NewRequest("POST", updateUrl, bytes.NewBufferString(encoded))
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Set("Authorization", "Bearer "+s.apiKey)
+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+
+ fmt.Printf("Making request to Stripe: %s\n", updateUrl)
+ resp, err := http.DefaultClient.Do(req)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read response body from stripe route %s, error reading response body: %w", updateUrl, err)
+ }
+
+ expiringObj := newExpiringObject(object, s.app.config.keepDuplicatesFor)
+ s.duplicateChecker[objectType] = append(s.duplicateChecker[objectType], expiringObj)
+
+ return body, nil
+}
+
+func (s *Stripe) handleWebhook(w http.ResponseWriter, r *http.Request) {
+ // Immediately acknowledge receipt to Stripe
+ w.WriteHeader(http.StatusOK)
+ var err error
+
+ // fmt.Println("Received Stripe webhook")
+
+ var event stripe.Event
+ if err := json.NewDecoder(r.Body).Decode(&event); err != nil {
+ s.app.logger.Error("Failed to decode Stripe event", "error", err)
+ return
+ }
+
+ prettyData, err := json.MarshalIndent(event, "", " ")
+ if err != nil {
+ s.app.logger.Error("Failed to pretty print Stripe event", "error", err)
+ } else {
+ fmt.Printf("Received Stripe event:\n%s\n", string(prettyData))
+ }
+
+ objectName := string(event.Type)
+ var operationType string
+ // If the event type contains a period, we only want the part before it
+ if idx := indexOfPeriod(objectName); idx > 0 {
+ operationType = objectName[idx+1:]
+ objectName = objectName[:idx]
+ }
+
+ switch operationType {
+ case "created", "updated":
+ operationType = "upsert"
+ case "deleted":
+ operationType = "delete"
+ default:
+ s.app.logger.Error("Unknown Stripe event type", "event_type", event.Type)
+ return
+ }
+
+ var obj map[string]any
+ err = json.Unmarshal(event.Data.Raw, &obj)
+ if err != nil {
+ s.app.logger.Error("Failed to unmarshal Stripe event data", "error", err)
+ return
+ }
+
+ newObjs := make(map[string]map[string]any)
+
+ for schemaName, fields := range s.systemInfo.ReceiveRouter[objectName] {
+ newModel := map[string]any{}
+
+ for keyInObj, field := range fields {
+ if field.Hardcode != nil && !isZeroValue(field.Hardcode) {
+ newModel[field.Field] = field.Hardcode
+ } else {
+ newModel[field.Field] = getNestedValue(obj, keyInObj)
+ }
+ }
+
+ newObjs[schemaName] = newModel
+ }
+
+ for schemaName, obj := range newObjs {
+
+ schema, inMap := s.app.schemaMap[schemaName]
+ if !inMap {
+ fmt.Printf("No schema found for object: %s\n", objectName)
+ return
+ }
+
+ for k, v := range obj {
+ if v == nil {
+ delete(obj, k)
+ }
+ }
+
+ fmt.Println("About to validate new object against schema:", schemaName, obj)
+
+ err = schema.Validate(obj)
+ if err != nil {
+ fmt.Printf("Object failed stripe schema validation for '%s': %v\n", objectName, err)
+ return
+ }
+
+ var objectIsDuplicate bool
+ foundDuplicate := false
+ for i, expiringObj := range s.duplicateChecker[schemaName] {
+
+ fmt.Println("Stripe checking duplicate checker for object:", expiringObj.Object)
+
+ objectIsDuplicate = true
+
+ for k, v := range obj {
+ if v != expiringObj.Object.Payload[k] {
+ objectIsDuplicate = false
+ break
+ }
+ }
+
+ if objectIsDuplicate {
+ fmt.Println("Stripe found duplicate object in duplicate checker while handling cdc event:", expiringObj.Object)
+ // If we found a duplicate, we can remove it from the duplicate checker
+ s.duplicateChecker[schemaName] = append(s.duplicateChecker[schemaName][:i], s.duplicateChecker[schemaName][i+1:]...)
+ foundDuplicate = true
+ break
+ }
+ }
+
+ if !foundDuplicate {
+
+ object := Object{
+ Type: schemaName,
+ Operation: operationType,
+ Payload: obj,
+ }
+
+ fmt.Println("Stripe no duplicate found for object, adding to queue", obj)
+ s.app.storageEngine.addSafeObject(object)
+
+ fmt.Println("Stripe no duplicate found for object, adding to duplicate checker", obj)
+ expiringObj := newExpiringObject(object, s.app.config.keepDuplicatesFor)
+ s.duplicateChecker[schemaName] = append(s.duplicateChecker[schemaName], expiringObj)
+ }
+ }
+}
+
+// indexOfPeriod returns the index of the first period in s, or -1 if not found
+func indexOfPeriod(s string) int {
+ for i, c := range s {
+ if c == '.' {
+ return i
+ }
+ }
+ return -1
+}
diff --git a/cmd/streaming/systems.go b/cmd/streaming/systems.go
new file mode 100644
index 00000000..9b497500
--- /dev/null
+++ b/cmd/streaming/systems.go
@@ -0,0 +1,86 @@
+package main
+
+import (
+ "fmt"
+ "net/http"
+ "time"
+)
+
+var (
+ Statuses = []string{StatusQueued, StatusRunning, StatusCancelled, StatusError, StatusComplete, ""}
+
+ StatusQueued = "queued"
+ StatusRunning = "running"
+ StatusCancelled = "cancelled"
+ StatusError = "error"
+ StatusComplete = "complete"
+
+ TypePostgreSQL = "postgresql"
+ TypeMySQL = "mysql"
+ TypeMSSQL = "mssql"
+ TypeOracle = "oracle"
+ TypeSnowflake = "snowflake"
+ TypeStripe = "stripe"
+
+ DriverPostgreSQL = "pgx"
+ DriverMySQL = "mysql"
+ DriverMSSQL = "sqlserver"
+ DriverOracle = "oracle"
+ DriverSnowflake = "snowflake"
+)
+
+type Field struct {
+ Field string `yaml:"field" json:"field"`
+ SearchKey bool `yaml:"search_key,omitempty" json:"search_key,omitempty"`
+ Hardcode any `yaml:"hardcode,omitempty" json:"hardcode,omitempty"`
+}
+
+type PullObject map[string]Field
+type PullLocation map[string]PullObject
+type ReceiveRouter map[string]PullLocation
+
+type PushRouter map[string]PushObject
+type PushObject map[string]PushLocation
+type PushLocation map[string]Field
+
+type SystemInfo struct {
+ Name string `yaml:"name" json:"name"`
+ Type string `yaml:"type" json:"type"`
+ ConnectionString string `yaml:"dsn" json:"dsn"`
+ MaxOpenConnections int `yaml:"max_open_connections" json:"max_open_connections"`
+ MaxIdleConnections int `yaml:"max_idle_connections" json:"max_idle_connections"`
+ MaxIdleTime time.Duration `yaml:"max_connection_idle_time" json:"max_connection_idle_time"`
+ Hostname string `yaml:"hostname,omitempty" json:"hostname,omitempty"`
+ Port int `yaml:"port,omitempty" json:"port,omitempty"`
+ Database string `yaml:"database,omitempty" json:"database,omitempty"`
+ Username string `yaml:"username,omitempty" json:"username,omitempty"`
+ Password string `yaml:"-" json:"-"`
+ Dsn string `yaml:"-" json:"-"`
+ ReplicationDsn string `yaml:"replication_dsn,omitempty" json:"replication_dsn,omitempty"`
+ ApiKey string `yaml:"api_key" json:"-"`
+ EndpointSecret string `yaml:"-" json:"-"`
+ RateLimit int `yaml:"rate_limit,omitempty" json:"rate_limit,omitempty"`
+ RateBucketSize int `yaml:"rate_bucket_size,omitempty" json:"rate_bucket_size,omitempty"`
+ UseCliListener bool `yaml:"use_cli_listener,omitempty" json:"use_cli_listener,omitempty"`
+ ReceiveRouter ReceiveRouter `yaml:"receive_router,omitempty" json:"receive_router,omitempty"`
+ PushRouter PushRouter `yaml:"push_router,omitempty" json:"push_router,omitempty"`
+}
+
+type SystemInterface interface {
+ handleWebhook(w http.ResponseWriter, r *http.Request)
+ // getFieldMap() map[string]string
+ // createModels(obj map[string]interface{}) (map[string]interface{}, error)
+}
+
+func (app *application) NewSystem(systemInfo SystemInfo, port int, duplicateChecker map[string][]ExpiringObject) (system SystemInterface, err error) {
+ switch systemInfo.Type {
+ case TypePostgreSQL:
+ return app.newPostgresql(systemInfo, duplicateChecker)
+ case TypeSnowflake:
+ return newSnowflake(systemInfo)
+ case TypeStripe:
+ return app.newStripe(systemInfo, duplicateChecker)
+ default:
+ return system, fmt.Errorf("unsupported system type %v", systemInfo.Type)
+ }
+}
diff --git a/entrypoint.sh b/entrypoint.sh
new file mode 100644
index 00000000..7981546f
--- /dev/null
+++ b/entrypoint.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+exec /bin/streaming \
+ -port $PORT \
+ -systems-dir "$SYSTEMS_DIR" \
+ -models-dir "$MODELS_DIR"
+# -segment-size $SEGMENT_SIZE \
+# -queue-dir "$QUEUE_DIR"
diff --git a/go.mod b/go.mod
index 0a521e56..3195cf39 100644
--- a/go.mod
+++ b/go.mod
@@ -1,25 +1,36 @@
-module github.com/sqlpipe/sqlpipe-pro
+module github.com/sqlpipe/sqlpipe
-go 1.20
+go 1.24
require (
- github.com/go-sql-driver/mysql v1.7.1
+ github.com/go-sql-driver/mysql v1.8.1
github.com/google/uuid v1.4.0
- github.com/jackc/pgx/v5 v5.5.0
+ github.com/jackc/pglogrepl v0.0.0-20250509230407-a9884f6bd75a
+ github.com/jackc/pgx/v5 v5.5.4
github.com/julienschmidt/httprouter v1.3.0
github.com/microsoft/go-mssqldb v1.6.0
+ github.com/ory/dockertest/v3 v3.12.0
+ github.com/santhosh-tekuri/jsonschema/v6 v6.0.2
github.com/sijms/go-ora/v2 v2.7.19
github.com/snowflakedb/gosnowflake v1.6.25
- golang.org/x/sync v0.5.0
+ github.com/stripe/stripe-go/v82 v82.3.0
+ golang.org/x/sync v0.8.0
+ golang.org/x/time v0.12.0
+ gopkg.in/yaml.v3 v3.0.1
)
require (
+ dario.cat/mergo v1.0.0 // indirect
+ filippo.io/edwards25519 v1.1.0 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/99designs/keyring v1.2.2 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0 // indirect
+ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c // indirect
+ github.com/Microsoft/go-winio v0.6.2 // indirect
+ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
github.com/andybalholm/brotli v1.0.6 // indirect
github.com/apache/arrow/go/v12 v12.0.1 // indirect
github.com/apache/thrift v0.19.0 // indirect
@@ -36,17 +47,27 @@ require (
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.2 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.42.1 // indirect
github.com/aws/smithy-go v1.16.0 // indirect
+ github.com/cenkalti/backoff/v4 v4.3.0 // indirect
+ github.com/containerd/continuity v0.4.5 // indirect
github.com/danieljoos/wincred v1.2.0 // indirect
+ github.com/docker/cli v27.4.1+incompatible // indirect
+ github.com/docker/docker v27.1.1+incompatible // indirect
+ github.com/docker/go-connections v0.5.0 // indirect
+ github.com/docker/go-units v0.5.0 // indirect
github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
github.com/form3tech-oss/jwt-go v3.2.5+incompatible // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
+ github.com/go-viper/mapstructure/v2 v2.1.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
+ github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
github.com/golang-sql/sqlexp v0.1.0 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/flatbuffers v23.5.26+incompatible // indirect
+ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
+ github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
@@ -56,18 +77,30 @@ require (
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 // indirect
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 // indirect
+ github.com/moby/docker-image-spec v1.3.1 // indirect
+ github.com/moby/sys/user v0.3.0 // indirect
+ github.com/moby/term v0.5.0 // indirect
github.com/mtibben/percent v0.2.1 // indirect
+ github.com/opencontainers/go-digest v1.0.0 // indirect
+ github.com/opencontainers/image-spec v1.1.0 // indirect
+ github.com/opencontainers/runc v1.2.3 // indirect
github.com/pierrec/lz4/v4 v4.1.18 // indirect
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
+ github.com/pkg/errors v0.9.1 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
+ github.com/stretchr/objx v0.5.2 // indirect
+ github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
+ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
+ github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
- golang.org/x/crypto v0.15.0 // indirect
+ golang.org/x/crypto v0.22.0 // indirect
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 // indirect
golang.org/x/mod v0.14.0 // indirect
- golang.org/x/net v0.18.0 // indirect
- golang.org/x/sys v0.14.0 // indirect
- golang.org/x/term v0.14.0 // indirect
+ golang.org/x/net v0.24.0 // indirect
+ golang.org/x/sys v0.28.0 // indirect
+ golang.org/x/term v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.15.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
+ gopkg.in/yaml.v2 v2.4.0 // indirect
)
diff --git a/go.sum b/go.sum
index d2786ae8..83c02caa 100644
--- a/go.sum
+++ b/go.sum
@@ -1,3 +1,7 @@
+dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
+dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
+filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
+filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs=
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4=
github.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0=
@@ -5,16 +9,27 @@ github.com/99designs/keyring v1.2.2/go.mod h1:wes/FrByc8j7lFOAGLGSNEg8f/PaI3cgTB
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0 h1:fb8kj/Dh4CSwgsOzHeZY4Xh68cFVbzXx+ONXGMY//4w=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0/go.mod h1:uReU2sSxZExRPBAg3qKzmAucSi51+SP1OhohieR821Q=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0 h1:d81/ng9rET2YqdVkVwkb6EXeRrLJIwyGnJcAlAWKwhs=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0 h1:Ma67P/GGprNwsslzEH6+Kb8nybI8jpDTm4Wmzu2ReK8=
+github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0/go.mod h1:c+Lifp3EDEamAkPVzMooRNOK6CZjNSdEnf1A7jsI9u4=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0 h1:yfJe15aSwEQ6Oo6J+gdfdulPNoZ3TEhmbhLIoxZcA+U=
+github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0/go.mod h1:Q28U+75mpCaSCDowNEmhIo/rmgdkqmkmzI7N6TGR4UY=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0 h1:T028gtTPiYt/RMUfs8nVsAL7FDQrfLlrm/NnRG/zcC4=
+github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0/go.mod h1:cw4zVQgBby0Z5f2v0itn6se2dDP17nTjbZFXW5uPyHA=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0 h1:gggzg0SUMs6SQbEw+3LoSsYf9YMjkupeAnHMX8O9mmY=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0/go.mod h1:+6KLcKIVgxoBDMqMO/Nvy7bZ9a0nbU3I1DtFQK3YvB4=
+github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
+github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0 h1:HCc0+LpPfpCKs6LGGLAhwBARt9632unrVcI6i8s/8os=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c h1:RGWPOewvKIROun94nF7v2cua9qP+thov/7M50KEoeSU=
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk=
+github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
+github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
+github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
+github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/apache/arrow/go/v12 v12.0.1 h1:JsR2+hzYYjgSUkBSaahpqCetqZMr76djX80fF/DiJbg=
@@ -26,9 +41,11 @@ github.com/aws/aws-sdk-go-v2 v1.22.2/go.mod h1:Kd0OJtkW3Q0M0lUWGszapWjEvrXDzRW+D
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.0 h1:hHgLiIrTRtddC0AKcJr5s7i/hLgcpTt+q/FKxf1Zayk=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.0/go.mod h1:w4I/v3NOWgD+qvs1NPEwhd++1h3XPHFaVxasfY6HlYQ=
github.com/aws/aws-sdk-go-v2/config v1.22.3 h1:JewoyAW8yPRpWus3gy/rIGhorHN4zInB8wgJfavaxwM=
+github.com/aws/aws-sdk-go-v2/config v1.22.3/go.mod h1:/kLz7rok3cKoM3dcQuNr86T4rXnC6HYIMWMx8vFUXig=
github.com/aws/aws-sdk-go-v2/credentials v1.15.2 h1:rKH7khRMxPdD0u3dHecd0Q7NOVw3EUe7AqdkUOkiOGI=
github.com/aws/aws-sdk-go-v2/credentials v1.15.2/go.mod h1:tXM8wmaeAhfC7nZoCxb0FzM/aRaB1m1WQ7x0qlBLq80=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.3 h1:G5KawTAkyHH6WyKQCdHiW4h3PmAXNJpOgwKg3H7sDRE=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.3/go.mod h1:hugKmSFnZB+HgNI1sYGT14BUPZkO6alC/e0AWu+0IAQ=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.13.4 h1:MD4eOs8lbf86CUawDXwkPoRrY0Ds2gDo1QLfDnwrAfk=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.13.4/go.mod h1:C4NNsNsbOD7YwuQRmNToEizYYoJVBM7CjpjvppTPl+k=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.2 h1:AaQsr5vvGR7rmeSWBtTCcw16tT9r51mWijuCQhzLnq8=
@@ -36,6 +53,7 @@ github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.2/go.mod h1:o1IiRn7CWoc
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.2 h1:UZx8SXZ0YtzRiALzYAWcjb9Y9hZUR7MBKaBQ5ouOjPs=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.2/go.mod h1:ipuRpcSaklmxR6C39G187TpBAO132gUfleTGccUPs8c=
github.com/aws/aws-sdk-go-v2/internal/ini v1.5.2 h1:5KL4rS1yq5rJ6Q8lrlsFPHCPWwhkMINNiRXHb4YbFyc=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.5.2/go.mod h1:rdAuXeHWhI/zkpYcO5n8WCpaIgY9MUxFyBsuqq3kjyA=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.2 h1:pyVrNAf7Hwz0u39dLKN5t+n0+K/3rMYKuiOoIum3AsU=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.2/go.mod h1:mydrfOb9uiOYCxuCPR8YHQNQyGQwUQ7gPMZGBKbH8NY=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.0 h1:CJxo7ZBbaIzmXfV3hjcx36n9V87gJsIUPJflwqEHl3Q=
@@ -49,29 +67,54 @@ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.2/go.mod h1:p+S7RNb
github.com/aws/aws-sdk-go-v2/service/s3 v1.42.1 h1:o6MCcX1rJW8Y3g+hvg2xpjF6JR6DftuYhfl3Nc1WV9Q=
github.com/aws/aws-sdk-go-v2/service/s3 v1.42.1/go.mod h1:UDtxEWbREX6y4KREapT+jjtjoH0TiVSS6f5nfaY1UaM=
github.com/aws/aws-sdk-go-v2/service/sso v1.17.1 h1:km+ZNjtLtpXYf42RdaDZnNHm9s7SYAuDGTafy6nd89A=
+github.com/aws/aws-sdk-go-v2/service/sso v1.17.1/go.mod h1:aHBr3pvBSD5MbzOvQtYutyPLLRPbl/y9x86XyJJnUXQ=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.19.1 h1:iRFNqZH4a67IqPvK8xxtyQYnyrlsvwmpHOe9r55ggBA=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.19.1/go.mod h1:pTy5WM+6sNv2tB24JNKFtn6EvciQ5k40ZJ0pq/Iaxj0=
github.com/aws/aws-sdk-go-v2/service/sts v1.25.1 h1:txgVXIXWPXyqdiVn92BV6a/rgtpX31HYdsOYj0sVQQQ=
+github.com/aws/aws-sdk-go-v2/service/sts v1.25.1/go.mod h1:VAiJiNaoP1L89STFlEMgmHX1bKixY+FaP+TpRFrmyZ4=
github.com/aws/smithy-go v1.16.0 h1:gJZEH/Fqh+RsvlJ1Zt4tVAtV6bKkp3cC+R6FCZMNzik=
github.com/aws/smithy-go v1.16.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE=
+github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
+github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
+github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4=
+github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE=
+github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
+github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE=
github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0SkRa/eYHgec=
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/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
+github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
+github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
+github.com/docker/cli v27.4.1+incompatible h1:VzPiUlRJ/xh+otB75gva3r05isHMo5wXDfPRi5/b4hI=
+github.com/docker/cli v27.4.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY=
+github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
+github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
+github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
+github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM=
github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU=
github.com/form3tech-oss/jwt-go v3.2.5+incompatible h1:/l4kBbb4/vGSsdtB5nUe8L7B9mImVMaBPw9L/0TBHU8=
github.com/form3tech-oss/jwt-go v3.2.5+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
-github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
-github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
+github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
+github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
+github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpGyP1XxdC/w=
+github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0=
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE=
+github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
@@ -80,17 +123,24 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8ioaQmyPLg1b8VwK5WJg=
github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
-github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
+github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU=
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0=
+github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
+github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
+github.com/jackc/pglogrepl v0.0.0-20250509230407-a9884f6bd75a h1:f2a1BtfxAaGSs+kI2MfZjNf9KiHzynJKqOPLTkF8L4Y=
+github.com/jackc/pglogrepl v0.0.0-20250509230407-a9884f6bd75a/go.mod h1:YC4Mb92BuoJKDNno/uRIBKU9FOt+y2uMFLQqo2fMgN4=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
-github.com/jackc/pgx/v5 v5.5.0 h1:NxstgwndsTRy7eq9/kqYc/BZh5w2hHJV86wjvO+1xPw=
-github.com/jackc/pgx/v5 v5.5.0/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
+github.com/jackc/pgx/v5 v5.5.4 h1:Xp2aQS8uXButQdnCMWNmvx6UysWQQC+u1EoizjguY+8=
+github.com/jackc/pgx/v5 v5.5.4/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
@@ -99,6 +149,8 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+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/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4=
github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE=
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
@@ -106,26 +158,50 @@ github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQs
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
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/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
+github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
+github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/microsoft/go-mssqldb v1.6.0 h1:mM3gYdVwEPFrlg/Dvr2DNVEgYFG7L42l+dGc67NNNpc=
github.com/microsoft/go-mssqldb v1.6.0/go.mod h1:00mDtPbeQCRGC1HwOOR5K/gr30P1NcEG0vx6Kbv2aJU=
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs=
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI=
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE=
+github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
+github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
+github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
+github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
+github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
+github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs=
github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
+github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
+github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
+github.com/opencontainers/runc v1.2.3 h1:fxE7amCzfZflJO2lHXf4y/y8M1BoAqp+FVmG19oYB80=
+github.com/opencontainers/runc v1.2.3/go.mod h1:nSxcWUydXrsBZVYNSkTjoQ/N6rcyTtn+1SD5D4+kRIM=
+github.com/ory/dockertest/v3 v3.12.0 h1:3oV9d0sDzlSQfHtIaB5k6ghUCVMVLpAY8hwrqoCyRCw=
+github.com/ory/dockertest/v3 v3.12.0/go.mod h1:aKNDTva3cp8dwOWwb9cWuX84aH5akkxXRvO7KCwWVjE=
github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ=
github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
+github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
+github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
+github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
+github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
github.com/sijms/go-ora/v2 v2.7.19 h1:+p0V51zrnpchRIIfx9kcEFGNUXkC0q9uZiyh05tyybI=
github.com/sijms/go-ora/v2 v2.7.19/go.mod h1:EHxlY6x7y9HAsdfumurRfTd+v8NrEOTR3Xl4FWlH6xk=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
@@ -133,41 +209,89 @@ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs
github.com/snowflakedb/gosnowflake v1.6.25 h1:o5zUmxTOo0Eo9AdkEj8blCeiMuILrQJ+rjUMAeZhcRE=
github.com/snowflakedb/gosnowflake v1.6.25/go.mod h1:KfO4F7bk+aXPUIvBqYxvPhxLlu2/w4TtSC8Rw/yr5Mg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
+github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/stripe/stripe-go/v82 v82.3.0 h1:6+E33xPmZ1Kzo2P/k90+Q5w2jwdKUU1XoEcrv3Fvtvk=
+github.com/stripe/stripe-go/v82 v82.3.0/go.mod h1:majCQX6AfObAvJiHraPi/5udwHi4ojRvJnnxckvHrX8=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
+github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
+github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
+github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
+github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
-golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
-golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+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.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
+golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 h1:mchzmB1XO2pMaKFRqk/+MV3mgGG96aqaPXaMifQU47w=
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
+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.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
-golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
-golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
-golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/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-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
+golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
+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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
-golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8=
-golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
+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/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
+golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
+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.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
+golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
+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.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
+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=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
gonum.org/v1/gonum v0.11.0 h1:f1IJhK4Km5tBJmaiJXtk/PkL4cdVX6J+tGiM187uT5E=
+gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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=
+gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
+gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
diff --git a/internal/vcs/vcs.go b/internal/vcs/vcs.go
new file mode 100644
index 00000000..87910aba
--- /dev/null
+++ b/internal/vcs/vcs.go
@@ -0,0 +1,14 @@
+package vcs
+
+import (
+ "runtime/debug"
+)
+
+func Version() string {
+ bi, ok := debug.ReadBuildInfo()
+ if ok {
+ return bi.Main.Version
+ }
+
+ return ""
+}
diff --git a/postgresql.dockerfile b/postgresql.dockerfile
new file mode 100644
index 00000000..2a29623e
--- /dev/null
+++ b/postgresql.dockerfile
@@ -0,0 +1,6 @@
+FROM postgres:15
+
+# Install wal2json (uses apt for Debian-based images)
+RUN apt-get update \
+ && apt-get install -y postgresql-15-wal2json \
+ && rm -rf /var/lib/apt/lists/*
diff --git a/streaming b/streaming
new file mode 100755
index 00000000..fa6ae104
Binary files /dev/null and b/streaming differ
diff --git a/streaming.dockerfile b/streaming.dockerfile
new file mode 100644
index 00000000..ada98834
--- /dev/null
+++ b/streaming.dockerfile
@@ -0,0 +1,23 @@
+FROM debian:12
+
+# Install required tools for HTTPS repositories and GPG
+RUN apt-get update && apt-get install -y \
+ ca-certificates \
+ curl \
+ gnupg
+
+RUN curl -s https://packages.stripe.dev/api/security/keypair/stripe-cli-gpg/public | gpg --dearmor | tee /usr/share/keyrings/stripe.gpg
+RUN echo "deb [signed-by=/usr/share/keyrings/stripe.gpg] https://packages.stripe.dev/stripe-cli-debian-local stable main" | tee -a /etc/apt/sources.list.d/stripe.list
+
+RUN apt-get update
+RUN apt-get install stripe -y
+
+RUN rm -rf /var/lib/apt/lists/*
+
+COPY /bin/streaming /bin/streaming
+COPY entrypoint.sh /entrypoint.sh
+RUN chmod +x /entrypoint.sh
+
+EXPOSE 4000
+
+ENTRYPOINT ["/entrypoint.sh"]
diff --git a/streaming.test b/streaming.test
new file mode 100755
index 00000000..890b94de
Binary files /dev/null and b/streaming.test differ
diff --git a/setup-sql/mssql.sql b/test/setup-sql/mssql.sql
similarity index 100%
rename from setup-sql/mssql.sql
rename to test/setup-sql/mssql.sql
diff --git a/setup-sql/mysql.sql b/test/setup-sql/mysql.sql
similarity index 100%
rename from setup-sql/mysql.sql
rename to test/setup-sql/mysql.sql
diff --git a/setup-sql/oracle.sql b/test/setup-sql/oracle.sql
similarity index 100%
rename from setup-sql/oracle.sql
rename to test/setup-sql/oracle.sql
diff --git a/setup-sql/postgresql-complex.sql b/test/setup-sql/postgresql-complex.sql
similarity index 100%
rename from setup-sql/postgresql-complex.sql
rename to test/setup-sql/postgresql-complex.sql
diff --git a/setup-sql/postgresql-simple.sql b/test/setup-sql/postgresql-simple.sql
similarity index 100%
rename from setup-sql/postgresql-simple.sql
rename to test/setup-sql/postgresql-simple.sql
diff --git a/test/streaming/one_table_test.go b/test/streaming/one_table_test.go
new file mode 100644
index 00000000..6f8dd2b3
--- /dev/null
+++ b/test/streaming/one_table_test.go
@@ -0,0 +1,267 @@
+package test
+
+import (
+ "database/sql"
+ "fmt"
+ "log"
+ "net/http"
+ "os"
+ "os/exec"
+ "os/signal"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+ "time"
+
+ _ "github.com/jackc/pgx/v5/stdlib"
+ "github.com/ory/dockertest/v3"
+ "github.com/ory/dockertest/v3/docker"
+)
+
+func createPostgresqlProductsTable(t *testing.T, db *sql.DB) {
+ _, err := db.Exec(`
+ CREATE TABLE products (
+ id bigserial PRIMARY KEY,
+ stripe_id TEXT UNIQUE,
+ name TEXT NOT NULL,
+ active BOOLEAN DEFAULT TRUE,
+ price int,
+ created TIMESTAMPTZ,
+ updated TIMESTAMPTZ,
+ description TEXT,
+ livemode BOOLEAN DEFAULT FALSE,
+ statement_descriptor TEXT,
+ unit_label TEXT,
+ category TEXT,
+ internal_notes TEXT
+ );
+ `)
+ if err != nil {
+ t.Fatalf("Failed to create table: %v", err)
+ }
+}
+
+func TestOneTableStreaming(t *testing.T) {
+
+ pool, err := dockertest.NewPool("")
+ if err != nil {
+ t.Fatalf("Could not connect to docker: %s", err)
+ }
+
+ pool.MaxWait = 20 * time.Second
+
+ postgresqlPassword := "Mypass123"
+ postgresqlUsername := "postgres"
+ postgresqlDatabase := "postgres"
+
+ // Resource handles for cleanup
+ var (
+ network *dockertest.Network
+ postgresqlContainer *dockertest.Resource
+ sqlpipeContainer *dockertest.Resource
+ )
+
+ // Setup signal handler for cleanup with improved error handling
+ cleanup := func() {
+ // Helper to check for specific Docker errors
+ isAlreadyRemoving := func(err error) bool {
+ return err != nil && (strings.Contains(err.Error(), "removal of container") && strings.Contains(err.Error(), "is already in progress"))
+ }
+ isNetworkActive := func(err error) bool {
+ return err != nil && (strings.Contains(err.Error(), "network") && strings.Contains(err.Error(), "has active endpoints"))
+ }
+
+ if sqlpipeContainer != nil {
+ if err := pool.Purge(sqlpipeContainer); err != nil && !isAlreadyRemoving(err) {
+ log.Printf("Could not purge sqlpipe resource: %s", err)
+ }
+ }
+ if postgresqlContainer != nil {
+ if err := pool.Purge(postgresqlContainer); err != nil && !isAlreadyRemoving(err) {
+ log.Printf("Could not purge resource: %s", err)
+ }
+ }
+ if network != nil {
+ // Retry network removal if it has active endpoints
+ for i := 0; i < 5; i++ {
+ if err := pool.RemoveNetwork(network); err != nil {
+ if isNetworkActive(err) {
+ time.Sleep(1 * time.Second)
+ continue
+ }
+ log.Printf("Could not remove docker network: %s", err)
+ break
+ }
+ break // success
+ }
+ }
+ }
+
+ sigs := make(chan os.Signal, 1)
+ signal.Notify(sigs, os.Interrupt)
+ go func() {
+ <-sigs
+ log.Println("Interrupt received, cleaning up Docker resources...")
+ cleanup()
+ os.Exit(1)
+ }()
+
+ defer cleanup()
+
+ // Create a network for both containers
+ network, err = pool.CreateNetwork("sqlpipe-test-network")
+ if err != nil {
+ t.Fatalf("Could not create docker network: %s", err)
+ }
+
+ postgresqlContainer, err = pool.BuildAndRunWithOptions("../../postgresql.dockerfile", &dockertest.RunOptions{
+ Name: "test-postgres",
+ Env: []string{
+ fmt.Sprintf("POSTGRES_USER=%v", postgresqlUsername),
+ fmt.Sprintf("POSTGRES_PASSWORD=%v", postgresqlPassword),
+ fmt.Sprintf("POSTGRES_DB=%v", postgresqlDatabase),
+ },
+ NetworkID: network.Network.ID,
+ ExposedPorts: []string{"5432/tcp"},
+ PortBindings: map[docker.Port][]docker.PortBinding{
+ "5432/tcp": {{HostIP: "0.0.0.0", HostPort: "5432"}},
+ },
+ Cmd: []string{
+ "postgres",
+ "-c", "wal_level=logical",
+ "-c", "max_replication_slots=5",
+ "-c", "max_wal_senders=5",
+ "-c", "max_connections=100",
+ },
+ })
+ if err != nil {
+ t.Fatalf("Could not start resource: %s", err)
+ }
+
+ var db *sql.DB
+ if err := pool.Retry(func() error {
+ var err error
+ port := postgresqlContainer.GetPort("5432/tcp")
+ dsn := fmt.Sprintf("postgres://%v:%v@localhost:%s/%v?sslmode=disable", postgresqlUsername, postgresqlPassword, port, postgresqlDatabase)
+ db, err = sql.Open("pgx", dsn)
+ if err != nil {
+ return err
+ }
+ return db.Ping()
+ }); err != nil {
+ t.Fatalf("Could not connect to database: %s", err)
+ }
+
+ createPostgresqlProductsTable(t, db)
+
+ _, err = db.Exec(`CREATE PUBLICATION my_pub FOR ALL TABLES;`)
+ if err != nil {
+ t.Fatalf("Failed to create publication: %v", err)
+ }
+
+ buildCmd := exec.Command("go", []string{"build", "-o", "../../bin/streaming", "../../cmd/streaming"}...)
+ buildCmd.Env = append(os.Environ(),
+ "GOOS=linux",
+ fmt.Sprintf("GOARCH=%v", runtime.GOARCH),
+ "CGO_ENABLED=0",
+ )
+
+ // buildCmd.Stdout = os.Stdout
+ buildCmd.Stderr = os.Stderr
+ if err := buildCmd.Run(); err != nil {
+ t.Fatalf("Failed to build streaming app: %v", err)
+ }
+
+ systemsHostDir, err := filepath.Abs("./config/one-table/systems")
+ if err != nil {
+ t.Fatalf("Failed to get absolute path for systems config: %v", err)
+ }
+ if _, err := os.Stat(systemsHostDir); os.IsNotExist(err) {
+ t.Fatalf("Systems config directory does not exist: %s", systemsHostDir)
+ }
+
+ modelsHostDir, err := filepath.Abs("./config/one-table/models")
+ if err != nil {
+ t.Fatalf("Failed to get absolute path for models config: %v", err)
+ }
+ if _, err := os.Stat(modelsHostDir); os.IsNotExist(err) {
+ t.Fatalf("Models config directory does not exist: %s", modelsHostDir)
+ }
+
+ sqlpipeContainer, err = pool.BuildAndRunWithOptions("../../streaming.dockerfile", &dockertest.RunOptions{
+ Name: "sqlpipe-streaming",
+ Env: []string{
+ "PORT=4000",
+ "SYSTEMS_DIR=/config/one-table/systems",
+ "MODELS_DIR=/config/one-table/models",
+ },
+ Mounts: []string{
+ fmt.Sprintf("%s:/config/one-table/systems", systemsHostDir),
+ fmt.Sprintf("%s:/config/one-table/models", modelsHostDir),
+ },
+ NetworkID: network.Network.ID,
+ })
+ if err != nil {
+ t.Fatalf("Could not start resource: %s", err)
+ }
+
+ go func() {
+ pool.Client.Logs(docker.LogsOptions{
+ Container: sqlpipeContainer.Container.ID,
+ OutputStream: os.Stdout,
+ ErrorStream: os.Stderr,
+ Follow: true,
+ Stdout: true,
+ Stderr: true,
+ })
+ }()
+
+ err = pool.Retry(func() error {
+
+ inspect, err := pool.Client.InspectContainer(sqlpipeContainer.Container.ID)
+ if err != nil {
+ return fmt.Errorf("failed to inspect container: %w", err)
+ }
+ if !inspect.State.Running {
+ return fmt.Errorf("container exited with code: %d", inspect.State.ExitCode)
+ }
+
+ hostPort := sqlpipeContainer.GetPort("4000/tcp")
+ healthcheckURL := fmt.Sprintf("http://localhost:%s/v1/healthcheck", hostPort)
+
+ resp, err := http.Get(healthcheckURL)
+ if err != nil {
+ return fmt.Errorf("healthcheck error: %w", err)
+ }
+ defer resp.Body.Close()
+ if resp.StatusCode != http.StatusOK {
+ return fmt.Errorf("healthcheck returned status %d", resp.StatusCode)
+ }
+ return nil // success!
+ })
+ if err != nil {
+ t.Fatalf("SQLpipe healthcheck failed: %v", err)
+ }
+
+ fmt.Println("SQLpipe is running and healthy!")
+
+ // stripeCmd := exec.Command("stripe", "trigger", "price.created")
+ // stripeCmd := exec.Command("stripe", "trigger", "tax_rate.created")
+
+ time.Sleep(1 * time.Second)
+
+ stripeCmd := exec.Command("stripe", "trigger", "product.created")
+ stripeCmd.Stdout = os.Stdout
+ stripeCmd.Stderr = os.Stderr
+ fmt.Println("stripe api key: ", os.Getenv("STRIPE_API_KEY"))
+ stripeCmd.Env = append(os.Environ(), fmt.Sprintf("STRIPE_API_KEY=%s", os.Getenv("STRIPE_API_KEY")))
+ err = stripeCmd.Run()
+ if err != nil {
+ t.Fatalf("Failed to run stripe trigger: %v", err)
+ }
+
+ fmt.Println("Test is running. Press Ctrl+C to exit.")
+ select {}
+
+}
diff --git a/test/streaming/two_tables_test.go b/test/streaming/two_tables_test.go
new file mode 100644
index 00000000..ef2ac720
--- /dev/null
+++ b/test/streaming/two_tables_test.go
@@ -0,0 +1,274 @@
+package test
+
+import (
+ "database/sql"
+ "fmt"
+ "log"
+ "net/http"
+ "os"
+ "os/exec"
+ "os/signal"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+ "time"
+
+ _ "github.com/jackc/pgx/v5/stdlib"
+ "github.com/ory/dockertest/v3"
+ "github.com/ory/dockertest/v3/docker"
+)
+
+func createPostgresqlProductsAndPricesTables(t *testing.T, db *sql.DB) {
+ _, err := db.Exec(`
+ CREATE TABLE products (
+ id TEXT PRIMARY KEY,
+ name TEXT NOT NULL,
+ default_price_id TEXT UNIQUE,
+ active BOOLEAN DEFAULT TRUE,
+ created TIMESTAMPTZ,
+ updated TIMESTAMPTZ,
+ description TEXT,
+ livemode BOOLEAN DEFAULT FALSE,
+ statement_descriptor TEXT,
+ unit_label TEXT,
+ category TEXT,
+ internal_notes TEXT
+ );
+ `)
+ if err != nil {
+ t.Fatalf("Failed to create table: %v", err)
+ }
+
+ _, err = db.Exec(`
+ CREATE TABLE prices (
+ id text PRIMARY KEY,
+ product_id TEXT NOT NULL,
+ unit_amount INT NOT NULL,
+ currency TEXT NOT NULL
+ );
+ `)
+ if err != nil {
+ t.Fatalf("Failed to create prices table: %v", err)
+ }
+}
+
+func TestTwoTablesStreaming(t *testing.T) {
+
+ pool, err := dockertest.NewPool("")
+ if err != nil {
+ t.Fatalf("Could not connect to docker: %s", err)
+ }
+
+ pool.MaxWait = 20 * time.Second
+
+ postgresqlPassword := "Mypass123"
+ postgresqlUsername := "postgres"
+ postgresqlDatabase := "postgres"
+
+ // Resource handles for cleanup
+ var (
+ network *dockertest.Network
+ postgresqlContainer *dockertest.Resource
+ sqlpipeContainer *dockertest.Resource
+ )
+
+ // Setup signal handler for cleanup with improved error handling
+ cleanup := func() {
+ // Helper to check for specific Docker errors
+ isAlreadyRemoving := func(err error) bool {
+ return err != nil && (strings.Contains(err.Error(), "removal of container") && strings.Contains(err.Error(), "is already in progress"))
+ }
+ isNetworkActive := func(err error) bool {
+ return err != nil && (strings.Contains(err.Error(), "network") && strings.Contains(err.Error(), "has active endpoints"))
+ }
+
+ if sqlpipeContainer != nil {
+ if err := pool.Purge(sqlpipeContainer); err != nil && !isAlreadyRemoving(err) {
+ log.Printf("Could not purge sqlpipe resource: %s", err)
+ }
+ }
+ if postgresqlContainer != nil {
+ if err := pool.Purge(postgresqlContainer); err != nil && !isAlreadyRemoving(err) {
+ log.Printf("Could not purge resource: %s", err)
+ }
+ }
+ if network != nil {
+ // Retry network removal if it has active endpoints
+ for i := 0; i < 5; i++ {
+ if err := pool.RemoveNetwork(network); err != nil {
+ if isNetworkActive(err) {
+ time.Sleep(1 * time.Second)
+ continue
+ }
+ log.Printf("Could not remove docker network: %s", err)
+ break
+ }
+ break // success
+ }
+ }
+ }
+
+ sigs := make(chan os.Signal, 1)
+ signal.Notify(sigs, os.Interrupt)
+ go func() {
+ <-sigs
+ log.Println("Interrupt received, cleaning up Docker resources...")
+ cleanup()
+ os.Exit(1)
+ }()
+
+ defer cleanup()
+
+ // Create a network for both containers
+ network, err = pool.CreateNetwork("sqlpipe-test-network")
+ if err != nil {
+ t.Fatalf("Could not create docker network: %s", err)
+ }
+
+ postgresqlContainer, err = pool.BuildAndRunWithOptions("../../postgresql.dockerfile", &dockertest.RunOptions{
+ Name: "test-postgres",
+ Env: []string{
+ fmt.Sprintf("POSTGRES_USER=%v", postgresqlUsername),
+ fmt.Sprintf("POSTGRES_PASSWORD=%v", postgresqlPassword),
+ fmt.Sprintf("POSTGRES_DB=%v", postgresqlDatabase),
+ },
+ NetworkID: network.Network.ID,
+ ExposedPorts: []string{"5432/tcp"},
+ PortBindings: map[docker.Port][]docker.PortBinding{
+ "5432/tcp": {{HostIP: "0.0.0.0", HostPort: "5432"}},
+ },
+ Cmd: []string{
+ "postgres",
+ "-c", "wal_level=logical",
+ "-c", "max_replication_slots=5",
+ "-c", "max_wal_senders=5",
+ "-c", "max_connections=100",
+ },
+ })
+ if err != nil {
+ t.Fatalf("Could not start resource: %s", err)
+ }
+
+ var db *sql.DB
+ if err := pool.Retry(func() error {
+ var err error
+ port := postgresqlContainer.GetPort("5432/tcp")
+ dsn := fmt.Sprintf("postgres://%v:%v@localhost:%s/%v?sslmode=disable", postgresqlUsername, postgresqlPassword, port, postgresqlDatabase)
+ db, err = sql.Open("pgx", dsn)
+ if err != nil {
+ return err
+ }
+ return db.Ping()
+ }); err != nil {
+ t.Fatalf("Could not connect to database: %s", err)
+ }
+
+ createPostgresqlProductsAndPricesTables(t, db)
+
+ _, err = db.Exec(`CREATE PUBLICATION my_pub FOR ALL TABLES;`)
+ if err != nil {
+ t.Fatalf("Failed to create publication: %v", err)
+ }
+
+ buildCmd := exec.Command("go", []string{"build", "-o", "../../bin/streaming", "../../cmd/streaming"}...)
+ buildCmd.Env = append(os.Environ(),
+ "GOOS=linux",
+ fmt.Sprintf("GOARCH=%v", runtime.GOARCH),
+ "CGO_ENABLED=0",
+ )
+
+ // buildCmd.Stdout = os.Stdout
+ buildCmd.Stderr = os.Stderr
+ if err := buildCmd.Run(); err != nil {
+ t.Fatalf("Failed to build streaming app: %v", err)
+ }
+
+ systemsHostDir, err := filepath.Abs("./config/two-tables/systems")
+ if err != nil {
+ t.Fatalf("Failed to get absolute path for systems config: %v", err)
+ }
+ if _, err := os.Stat(systemsHostDir); os.IsNotExist(err) {
+ t.Fatalf("Systems config directory does not exist: %s", systemsHostDir)
+ }
+
+ modelsHostDir, err := filepath.Abs("./config/two-tables/models")
+ if err != nil {
+ t.Fatalf("Failed to get absolute path for models config: %v", err)
+ }
+ if _, err := os.Stat(modelsHostDir); os.IsNotExist(err) {
+ t.Fatalf("Models config directory does not exist: %s", modelsHostDir)
+ }
+
+ sqlpipeContainer, err = pool.BuildAndRunWithOptions("../../streaming.dockerfile", &dockertest.RunOptions{
+ Name: "sqlpipe-streaming",
+ Env: []string{
+ "PORT=4000",
+ "SYSTEMS_DIR=/config/two-tables/systems",
+ "MODELS_DIR=/config/two-tables/models",
+ },
+ Mounts: []string{
+ fmt.Sprintf("%s:/config/two-tables/systems", systemsHostDir),
+ fmt.Sprintf("%s:/config/two-tables/models", modelsHostDir),
+ },
+ NetworkID: network.Network.ID,
+ })
+ if err != nil {
+ t.Fatalf("Could not start resource: %s", err)
+ }
+
+ go func() {
+ pool.Client.Logs(docker.LogsOptions{
+ Container: sqlpipeContainer.Container.ID,
+ OutputStream: os.Stdout,
+ ErrorStream: os.Stderr,
+ Follow: true,
+ Stdout: true,
+ Stderr: true,
+ })
+ }()
+
+ err = pool.Retry(func() error {
+
+ inspect, err := pool.Client.InspectContainer(sqlpipeContainer.Container.ID)
+ if err != nil {
+ return fmt.Errorf("failed to inspect container: %w", err)
+ }
+ if !inspect.State.Running {
+ return fmt.Errorf("container exited with code: %d", inspect.State.ExitCode)
+ }
+
+ hostPort := sqlpipeContainer.GetPort("4000/tcp")
+ healthcheckURL := fmt.Sprintf("http://localhost:%s/v1/healthcheck", hostPort)
+
+ resp, err := http.Get(healthcheckURL)
+ if err != nil {
+ return fmt.Errorf("healthcheck error: %w", err)
+ }
+ defer resp.Body.Close()
+ if resp.StatusCode != http.StatusOK {
+ return fmt.Errorf("healthcheck returned status %d", resp.StatusCode)
+ }
+ return nil // success!
+ })
+ if err != nil {
+ t.Fatalf("SQLpipe healthcheck failed: %v", err)
+ }
+
+ fmt.Println("SQLpipe is running and healthy!")
+
+ time.Sleep(1 * time.Second)
+
+ stripeCmd := exec.Command("stripe", "trigger", "product.created")
+ stripeCmd.Stdout = os.Stdout
+ stripeCmd.Stderr = os.Stderr
+ fmt.Println("stripe api key: ", os.Getenv("STRIPE_API_KEY"))
+ stripeCmd.Env = append(os.Environ(), fmt.Sprintf("STRIPE_API_KEY=%s", os.Getenv("STRIPE_API_KEY")))
+ err = stripeCmd.Run()
+ if err != nil {
+ t.Fatalf("Failed to run stripe trigger: %v", err)
+ }
+
+ fmt.Println("Test is running. Press Ctrl+C to exit.")
+ select {}
+}
diff --git a/vendor/dario.cat/mergo/.deepsource.toml b/vendor/dario.cat/mergo/.deepsource.toml
new file mode 100644
index 00000000..a8bc979e
--- /dev/null
+++ b/vendor/dario.cat/mergo/.deepsource.toml
@@ -0,0 +1,12 @@
+version = 1
+
+test_patterns = [
+ "*_test.go"
+]
+
+[[analyzers]]
+name = "go"
+enabled = true
+
+ [analyzers.meta]
+ import_path = "dario.cat/mergo"
\ No newline at end of file
diff --git a/vendor/dario.cat/mergo/.gitignore b/vendor/dario.cat/mergo/.gitignore
new file mode 100644
index 00000000..529c3412
--- /dev/null
+++ b/vendor/dario.cat/mergo/.gitignore
@@ -0,0 +1,33 @@
+#### joe made this: http://goel.io/joe
+
+#### go ####
+# Binaries for programs and plugins
+*.exe
+*.dll
+*.so
+*.dylib
+
+# Test binary, build with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
+.glide/
+
+#### vim ####
+# Swap
+[._]*.s[a-v][a-z]
+[._]*.sw[a-p]
+[._]s[a-v][a-z]
+[._]sw[a-p]
+
+# Session
+Session.vim
+
+# Temporary
+.netrwhist
+*~
+# Auto-generated tag files
+tags
diff --git a/vendor/dario.cat/mergo/.travis.yml b/vendor/dario.cat/mergo/.travis.yml
new file mode 100644
index 00000000..d324c43b
--- /dev/null
+++ b/vendor/dario.cat/mergo/.travis.yml
@@ -0,0 +1,12 @@
+language: go
+arch:
+ - amd64
+ - ppc64le
+install:
+ - go get -t
+ - go get golang.org/x/tools/cmd/cover
+ - go get github.com/mattn/goveralls
+script:
+ - go test -race -v ./...
+after_script:
+ - $HOME/gopath/bin/goveralls -service=travis-ci -repotoken $COVERALLS_TOKEN
diff --git a/vendor/dario.cat/mergo/CODE_OF_CONDUCT.md b/vendor/dario.cat/mergo/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..469b4490
--- /dev/null
+++ b/vendor/dario.cat/mergo/CODE_OF_CONDUCT.md
@@ -0,0 +1,46 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at i@dario.im. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/4/
diff --git a/vendor/dario.cat/mergo/CONTRIBUTING.md b/vendor/dario.cat/mergo/CONTRIBUTING.md
new file mode 100644
index 00000000..0a1ff9f9
--- /dev/null
+++ b/vendor/dario.cat/mergo/CONTRIBUTING.md
@@ -0,0 +1,112 @@
+
+# Contributing to mergo
+
+First off, thanks for taking the time to contribute! ❤️
+
+All types of contributions are encouraged and valued. See the [Table of Contents](#table-of-contents) for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 🎉
+
+> And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about:
+> - Star the project
+> - Tweet about it
+> - Refer this project in your project's readme
+> - Mention the project at local meetups and tell your friends/colleagues
+
+
+## Table of Contents
+
+- [Code of Conduct](#code-of-conduct)
+- [I Have a Question](#i-have-a-question)
+- [I Want To Contribute](#i-want-to-contribute)
+- [Reporting Bugs](#reporting-bugs)
+- [Suggesting Enhancements](#suggesting-enhancements)
+
+## Code of Conduct
+
+This project and everyone participating in it is governed by the
+[mergo Code of Conduct](https://github.com/imdario/mergoblob/master/CODE_OF_CONDUCT.md).
+By participating, you are expected to uphold this code. Please report unacceptable behavior
+to <>.
+
+
+## I Have a Question
+
+> If you want to ask a question, we assume that you have read the available [Documentation](https://pkg.go.dev/github.com/imdario/mergo).
+
+Before you ask a question, it is best to search for existing [Issues](https://github.com/imdario/mergo/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first.
+
+If you then still feel the need to ask a question and need clarification, we recommend the following:
+
+- Open an [Issue](https://github.com/imdario/mergo/issues/new).
+- Provide as much context as you can about what you're running into.
+- Provide project and platform versions (nodejs, npm, etc), depending on what seems relevant.
+
+We will then take care of the issue as soon as possible.
+
+## I Want To Contribute
+
+> ### Legal Notice
+> When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license.
+
+### Reporting Bugs
+
+
+#### Before Submitting a Bug Report
+
+A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible.
+
+- Make sure that you are using the latest version.
+- Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the [documentation](). If you are looking for support, you might want to check [this section](#i-have-a-question)).
+- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker](https://github.com/imdario/mergoissues?q=label%3Abug).
+- Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue.
+- Collect information about the bug:
+- Stack trace (Traceback)
+- OS, Platform and Version (Windows, Linux, macOS, x86, ARM)
+- Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant.
+- Possibly your input and the output
+- Can you reliably reproduce the issue? And can you also reproduce it with older versions?
+
+
+#### How Do I Submit a Good Bug Report?
+
+> You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to .
+
+
+We use GitHub issues to track bugs and errors. If you run into an issue with the project:
+
+- Open an [Issue](https://github.com/imdario/mergo/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.)
+- Explain the behavior you would expect and the actual behavior.
+- Please provide as much context as possible and describe the *reproduction steps* that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case.
+- Provide the information you collected in the previous section.
+
+Once it's filed:
+
+- The project team will label the issue accordingly.
+- A team member will try to reproduce the issue with your provided steps. If there are no reproduction steps or no obvious way to reproduce the issue, the team will ask you for those steps and mark the issue as `needs-repro`. Bugs with the `needs-repro` tag will not be addressed until they are reproduced.
+- If the team is able to reproduce the issue, it will be marked `needs-fix`, as well as possibly other tags (such as `critical`), and the issue will be left to be implemented by someone.
+
+### Suggesting Enhancements
+
+This section guides you through submitting an enhancement suggestion for mergo, **including completely new features and minor improvements to existing functionality**. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions.
+
+
+#### Before Submitting an Enhancement
+
+- Make sure that you are using the latest version.
+- Read the [documentation]() carefully and find out if the functionality is already covered, maybe by an individual configuration.
+- Perform a [search](https://github.com/imdario/mergo/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
+- Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library.
+
+
+#### How Do I Submit a Good Enhancement Suggestion?
+
+Enhancement suggestions are tracked as [GitHub issues](https://github.com/imdario/mergo/issues).
+
+- Use a **clear and descriptive title** for the issue to identify the suggestion.
+- Provide a **step-by-step description of the suggested enhancement** in as many details as possible.
+- **Describe the current behavior** and **explain which behavior you expected to see instead** and why. At this point you can also tell which alternatives do not work for you.
+- You may want to **include screenshots and animated GIFs** which help you demonstrate the steps or point out the part which the suggestion is related to. You can use [this tool](https://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [this tool](https://github.com/colinkeenan/silentcast) or [this tool](https://github.com/GNOME/byzanz) on Linux.
+- **Explain why this enhancement would be useful** to most mergo users. You may also want to point out the other projects that solved it better and which could serve as inspiration.
+
+
+## Attribution
+This guide is based on the **contributing-gen**. [Make your own](https://github.com/bttger/contributing-gen)!
diff --git a/vendor/dario.cat/mergo/LICENSE b/vendor/dario.cat/mergo/LICENSE
new file mode 100644
index 00000000..68668029
--- /dev/null
+++ b/vendor/dario.cat/mergo/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2013 Dario Castañé. All rights reserved.
+Copyright (c) 2012 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/dario.cat/mergo/README.md b/vendor/dario.cat/mergo/README.md
new file mode 100644
index 00000000..7d0cf9f3
--- /dev/null
+++ b/vendor/dario.cat/mergo/README.md
@@ -0,0 +1,248 @@
+# Mergo
+
+[![GitHub release][5]][6]
+[![GoCard][7]][8]
+[![Test status][1]][2]
+[![OpenSSF Scorecard][21]][22]
+[![OpenSSF Best Practices][19]][20]
+[![Coverage status][9]][10]
+[![Sourcegraph][11]][12]
+[![FOSSA status][13]][14]
+
+[![GoDoc][3]][4]
+[![Become my sponsor][15]][16]
+[![Tidelift][17]][18]
+
+[1]: https://github.com/imdario/mergo/workflows/tests/badge.svg?branch=master
+[2]: https://github.com/imdario/mergo/actions/workflows/tests.yml
+[3]: https://godoc.org/github.com/imdario/mergo?status.svg
+[4]: https://godoc.org/github.com/imdario/mergo
+[5]: https://img.shields.io/github/release/imdario/mergo.svg
+[6]: https://github.com/imdario/mergo/releases
+[7]: https://goreportcard.com/badge/imdario/mergo
+[8]: https://goreportcard.com/report/github.com/imdario/mergo
+[9]: https://coveralls.io/repos/github/imdario/mergo/badge.svg?branch=master
+[10]: https://coveralls.io/github/imdario/mergo?branch=master
+[11]: https://sourcegraph.com/github.com/imdario/mergo/-/badge.svg
+[12]: https://sourcegraph.com/github.com/imdario/mergo?badge
+[13]: https://app.fossa.io/api/projects/git%2Bgithub.com%2Fimdario%2Fmergo.svg?type=shield
+[14]: https://app.fossa.io/projects/git%2Bgithub.com%2Fimdario%2Fmergo?ref=badge_shield
+[15]: https://img.shields.io/github/sponsors/imdario
+[16]: https://github.com/sponsors/imdario
+[17]: https://tidelift.com/badges/package/go/github.com%2Fimdario%2Fmergo
+[18]: https://tidelift.com/subscription/pkg/go-github.com-imdario-mergo
+[19]: https://bestpractices.coreinfrastructure.org/projects/7177/badge
+[20]: https://bestpractices.coreinfrastructure.org/projects/7177
+[21]: https://api.securityscorecards.dev/projects/github.com/imdario/mergo/badge
+[22]: https://api.securityscorecards.dev/projects/github.com/imdario/mergo
+
+A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements.
+
+Mergo merges same-type structs and maps by setting default values in zero-value fields. Mergo won't merge unexported (private) fields. It will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection).
+
+Also a lovely [comune](http://en.wikipedia.org/wiki/Mergo) (municipality) in the Province of Ancona in the Italian region of Marche.
+
+## Status
+
+It is ready for production use. [It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, Microsoft, etc](https://github.com/imdario/mergo#mergo-in-the-wild).
+
+### Important notes
+
+#### 1.0.0
+
+In [1.0.0](//github.com/imdario/mergo/releases/tag/1.0.0) Mergo moves to a vanity URL `dario.cat/mergo`.
+
+#### 0.3.9
+
+Please keep in mind that a problematic PR broke [0.3.9](//github.com/imdario/mergo/releases/tag/0.3.9). I reverted it in [0.3.10](//github.com/imdario/mergo/releases/tag/0.3.10), and I consider it stable but not bug-free. Also, this version adds support for go modules.
+
+Keep in mind that in [0.3.2](//github.com/imdario/mergo/releases/tag/0.3.2), Mergo changed `Merge()`and `Map()` signatures to support [transformers](#transformers). I added an optional/variadic argument so that it won't break the existing code.
+
+If you were using Mergo before April 6th, 2015, please check your project works as intended after updating your local copy with ```go get -u dario.cat/mergo```. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause in existing projects after the change (release 0.2.0).
+
+### Donations
+
+If Mergo is useful to you, consider buying me a coffee, a beer, or making a monthly donation to allow me to keep building great free software. :heart_eyes:
+
+
+
+
+
+### Mergo in the wild
+
+- [moby/moby](https://github.com/moby/moby)
+- [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes)
+- [vmware/dispatch](https://github.com/vmware/dispatch)
+- [Shopify/themekit](https://github.com/Shopify/themekit)
+- [imdario/zas](https://github.com/imdario/zas)
+- [matcornic/hermes](https://github.com/matcornic/hermes)
+- [OpenBazaar/openbazaar-go](https://github.com/OpenBazaar/openbazaar-go)
+- [kataras/iris](https://github.com/kataras/iris)
+- [michaelsauter/crane](https://github.com/michaelsauter/crane)
+- [go-task/task](https://github.com/go-task/task)
+- [sensu/uchiwa](https://github.com/sensu/uchiwa)
+- [ory/hydra](https://github.com/ory/hydra)
+- [sisatech/vcli](https://github.com/sisatech/vcli)
+- [dairycart/dairycart](https://github.com/dairycart/dairycart)
+- [projectcalico/felix](https://github.com/projectcalico/felix)
+- [resin-os/balena](https://github.com/resin-os/balena)
+- [go-kivik/kivik](https://github.com/go-kivik/kivik)
+- [Telefonica/govice](https://github.com/Telefonica/govice)
+- [supergiant/supergiant](supergiant/supergiant)
+- [SergeyTsalkov/brooce](https://github.com/SergeyTsalkov/brooce)
+- [soniah/dnsmadeeasy](https://github.com/soniah/dnsmadeeasy)
+- [ohsu-comp-bio/funnel](https://github.com/ohsu-comp-bio/funnel)
+- [EagerIO/Stout](https://github.com/EagerIO/Stout)
+- [lynndylanhurley/defsynth-api](https://github.com/lynndylanhurley/defsynth-api)
+- [russross/canvasassignments](https://github.com/russross/canvasassignments)
+- [rdegges/cryptly-api](https://github.com/rdegges/cryptly-api)
+- [casualjim/exeggutor](https://github.com/casualjim/exeggutor)
+- [divshot/gitling](https://github.com/divshot/gitling)
+- [RWJMurphy/gorl](https://github.com/RWJMurphy/gorl)
+- [andrerocker/deploy42](https://github.com/andrerocker/deploy42)
+- [elwinar/rambler](https://github.com/elwinar/rambler)
+- [tmaiaroto/gopartman](https://github.com/tmaiaroto/gopartman)
+- [jfbus/impressionist](https://github.com/jfbus/impressionist)
+- [Jmeyering/zealot](https://github.com/Jmeyering/zealot)
+- [godep-migrator/rigger-host](https://github.com/godep-migrator/rigger-host)
+- [Dronevery/MultiwaySwitch-Go](https://github.com/Dronevery/MultiwaySwitch-Go)
+- [thoas/picfit](https://github.com/thoas/picfit)
+- [mantasmatelis/whooplist-server](https://github.com/mantasmatelis/whooplist-server)
+- [jnuthong/item_search](https://github.com/jnuthong/item_search)
+- [bukalapak/snowboard](https://github.com/bukalapak/snowboard)
+- [containerssh/containerssh](https://github.com/containerssh/containerssh)
+- [goreleaser/goreleaser](https://github.com/goreleaser/goreleaser)
+- [tjpnz/structbot](https://github.com/tjpnz/structbot)
+
+## Install
+
+ go get dario.cat/mergo
+
+ // use in your .go code
+ import (
+ "dario.cat/mergo"
+ )
+
+## Usage
+
+You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. It won't merge empty structs value as [they are zero values](https://golang.org/ref/spec#The_zero_value) too. Also, maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection).
+
+```go
+if err := mergo.Merge(&dst, src); err != nil {
+ // ...
+}
+```
+
+Also, you can merge overwriting values using the transformer `WithOverride`.
+
+```go
+if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil {
+ // ...
+}
+```
+
+Additionally, you can map a `map[string]interface{}` to a struct (and otherwise, from struct to map), following the same restrictions as in `Merge()`. Keys are capitalized to find each corresponding exported field.
+
+```go
+if err := mergo.Map(&dst, srcMap); err != nil {
+ // ...
+}
+```
+
+Warning: if you map a struct to map, it won't do it recursively. Don't expect Mergo to map struct members of your struct as `map[string]interface{}`. They will be just assigned as values.
+
+Here is a nice example:
+
+```go
+package main
+
+import (
+ "fmt"
+ "dario.cat/mergo"
+)
+
+type Foo struct {
+ A string
+ B int64
+}
+
+func main() {
+ src := Foo{
+ A: "one",
+ B: 2,
+ }
+ dest := Foo{
+ A: "two",
+ }
+ mergo.Merge(&dest, src)
+ fmt.Println(dest)
+ // Will print
+ // {two 2}
+}
+```
+
+Note: if test are failing due missing package, please execute:
+
+ go get gopkg.in/yaml.v3
+
+### Transformers
+
+Transformers allow to merge specific types differently than in the default behavior. In other words, now you can customize how some types are merged. For example, `time.Time` is a struct; it doesn't have zero value but IsZero can return true because it has fields with zero value. How can we merge a non-zero `time.Time`?
+
+```go
+package main
+
+import (
+ "fmt"
+ "dario.cat/mergo"
+ "reflect"
+ "time"
+)
+
+type timeTransformer struct {
+}
+
+func (t timeTransformer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error {
+ if typ == reflect.TypeOf(time.Time{}) {
+ return func(dst, src reflect.Value) error {
+ if dst.CanSet() {
+ isZero := dst.MethodByName("IsZero")
+ result := isZero.Call([]reflect.Value{})
+ if result[0].Bool() {
+ dst.Set(src)
+ }
+ }
+ return nil
+ }
+ }
+ return nil
+}
+
+type Snapshot struct {
+ Time time.Time
+ // ...
+}
+
+func main() {
+ src := Snapshot{time.Now()}
+ dest := Snapshot{}
+ mergo.Merge(&dest, src, mergo.WithTransformers(timeTransformer{}))
+ fmt.Println(dest)
+ // Will print
+ // { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 }
+}
+```
+
+## Contact me
+
+If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): [@im_dario](https://twitter.com/im_dario)
+
+## About
+
+Written by [Dario Castañé](http://dario.im).
+
+## License
+
+[BSD 3-Clause](http://opensource.org/licenses/BSD-3-Clause) license, as [Go language](http://golang.org/LICENSE).
+
+[](https://app.fossa.io/projects/git%2Bgithub.com%2Fimdario%2Fmergo?ref=badge_large)
diff --git a/vendor/dario.cat/mergo/SECURITY.md b/vendor/dario.cat/mergo/SECURITY.md
new file mode 100644
index 00000000..a5de61f7
--- /dev/null
+++ b/vendor/dario.cat/mergo/SECURITY.md
@@ -0,0 +1,14 @@
+# Security Policy
+
+## Supported Versions
+
+| Version | Supported |
+| ------- | ------------------ |
+| 0.3.x | :white_check_mark: |
+| < 0.3 | :x: |
+
+## Security contact information
+
+To report a security vulnerability, please use the
+[Tidelift security contact](https://tidelift.com/security).
+Tidelift will coordinate the fix and disclosure.
diff --git a/vendor/dario.cat/mergo/doc.go b/vendor/dario.cat/mergo/doc.go
new file mode 100644
index 00000000..7d96ec05
--- /dev/null
+++ b/vendor/dario.cat/mergo/doc.go
@@ -0,0 +1,148 @@
+// Copyright 2013 Dario Castañé. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements.
+
+Mergo merges same-type structs and maps by setting default values in zero-value fields. Mergo won't merge unexported (private) fields. It will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection).
+
+# Status
+
+It is ready for production use. It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, etc.
+
+# Important notes
+
+1.0.0
+
+In 1.0.0 Mergo moves to a vanity URL `dario.cat/mergo`.
+
+0.3.9
+
+Please keep in mind that a problematic PR broke 0.3.9. We reverted it in 0.3.10. We consider 0.3.10 as stable but not bug-free. . Also, this version adds suppot for go modules.
+
+Keep in mind that in 0.3.2, Mergo changed Merge() and Map() signatures to support transformers. We added an optional/variadic argument so that it won't break the existing code.
+
+If you were using Mergo before April 6th, 2015, please check your project works as intended after updating your local copy with go get -u dario.cat/mergo. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause in existing projects after the change (release 0.2.0).
+
+# Install
+
+Do your usual installation procedure:
+
+ go get dario.cat/mergo
+
+ // use in your .go code
+ import (
+ "dario.cat/mergo"
+ )
+
+# Usage
+
+You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. It won't merge empty structs value as they are zero values too. Also, maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection).
+
+ if err := mergo.Merge(&dst, src); err != nil {
+ // ...
+ }
+
+Also, you can merge overwriting values using the transformer WithOverride.
+
+ if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil {
+ // ...
+ }
+
+Additionally, you can map a map[string]interface{} to a struct (and otherwise, from struct to map), following the same restrictions as in Merge(). Keys are capitalized to find each corresponding exported field.
+
+ if err := mergo.Map(&dst, srcMap); err != nil {
+ // ...
+ }
+
+Warning: if you map a struct to map, it won't do it recursively. Don't expect Mergo to map struct members of your struct as map[string]interface{}. They will be just assigned as values.
+
+Here is a nice example:
+
+ package main
+
+ import (
+ "fmt"
+ "dario.cat/mergo"
+ )
+
+ type Foo struct {
+ A string
+ B int64
+ }
+
+ func main() {
+ src := Foo{
+ A: "one",
+ B: 2,
+ }
+ dest := Foo{
+ A: "two",
+ }
+ mergo.Merge(&dest, src)
+ fmt.Println(dest)
+ // Will print
+ // {two 2}
+ }
+
+# Transformers
+
+Transformers allow to merge specific types differently than in the default behavior. In other words, now you can customize how some types are merged. For example, time.Time is a struct; it doesn't have zero value but IsZero can return true because it has fields with zero value. How can we merge a non-zero time.Time?
+
+ package main
+
+ import (
+ "fmt"
+ "dario.cat/mergo"
+ "reflect"
+ "time"
+ )
+
+ type timeTransformer struct {
+ }
+
+ func (t timeTransformer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error {
+ if typ == reflect.TypeOf(time.Time{}) {
+ return func(dst, src reflect.Value) error {
+ if dst.CanSet() {
+ isZero := dst.MethodByName("IsZero")
+ result := isZero.Call([]reflect.Value{})
+ if result[0].Bool() {
+ dst.Set(src)
+ }
+ }
+ return nil
+ }
+ }
+ return nil
+ }
+
+ type Snapshot struct {
+ Time time.Time
+ // ...
+ }
+
+ func main() {
+ src := Snapshot{time.Now()}
+ dest := Snapshot{}
+ mergo.Merge(&dest, src, mergo.WithTransformers(timeTransformer{}))
+ fmt.Println(dest)
+ // Will print
+ // { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 }
+ }
+
+# Contact me
+
+If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): https://twitter.com/im_dario
+
+# About
+
+Written by Dario Castañé: https://da.rio.hn
+
+# License
+
+BSD 3-Clause license, as Go language.
+*/
+package mergo
diff --git a/vendor/dario.cat/mergo/map.go b/vendor/dario.cat/mergo/map.go
new file mode 100644
index 00000000..b50d5c2a
--- /dev/null
+++ b/vendor/dario.cat/mergo/map.go
@@ -0,0 +1,178 @@
+// Copyright 2014 Dario Castañé. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Based on src/pkg/reflect/deepequal.go from official
+// golang's stdlib.
+
+package mergo
+
+import (
+ "fmt"
+ "reflect"
+ "unicode"
+ "unicode/utf8"
+)
+
+func changeInitialCase(s string, mapper func(rune) rune) string {
+ if s == "" {
+ return s
+ }
+ r, n := utf8.DecodeRuneInString(s)
+ return string(mapper(r)) + s[n:]
+}
+
+func isExported(field reflect.StructField) bool {
+ r, _ := utf8.DecodeRuneInString(field.Name)
+ return r >= 'A' && r <= 'Z'
+}
+
+// Traverses recursively both values, assigning src's fields values to dst.
+// The map argument tracks comparisons that have already been seen, which allows
+// short circuiting on recursive types.
+func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) {
+ overwrite := config.Overwrite
+ if dst.CanAddr() {
+ addr := dst.UnsafeAddr()
+ h := 17 * addr
+ seen := visited[h]
+ typ := dst.Type()
+ for p := seen; p != nil; p = p.next {
+ if p.ptr == addr && p.typ == typ {
+ return nil
+ }
+ }
+ // Remember, remember...
+ visited[h] = &visit{typ, seen, addr}
+ }
+ zeroValue := reflect.Value{}
+ switch dst.Kind() {
+ case reflect.Map:
+ dstMap := dst.Interface().(map[string]interface{})
+ for i, n := 0, src.NumField(); i < n; i++ {
+ srcType := src.Type()
+ field := srcType.Field(i)
+ if !isExported(field) {
+ continue
+ }
+ fieldName := field.Name
+ fieldName = changeInitialCase(fieldName, unicode.ToLower)
+ if v, ok := dstMap[fieldName]; !ok || (isEmptyValue(reflect.ValueOf(v), !config.ShouldNotDereference) || overwrite) {
+ dstMap[fieldName] = src.Field(i).Interface()
+ }
+ }
+ case reflect.Ptr:
+ if dst.IsNil() {
+ v := reflect.New(dst.Type().Elem())
+ dst.Set(v)
+ }
+ dst = dst.Elem()
+ fallthrough
+ case reflect.Struct:
+ srcMap := src.Interface().(map[string]interface{})
+ for key := range srcMap {
+ config.overwriteWithEmptyValue = true
+ srcValue := srcMap[key]
+ fieldName := changeInitialCase(key, unicode.ToUpper)
+ dstElement := dst.FieldByName(fieldName)
+ if dstElement == zeroValue {
+ // We discard it because the field doesn't exist.
+ continue
+ }
+ srcElement := reflect.ValueOf(srcValue)
+ dstKind := dstElement.Kind()
+ srcKind := srcElement.Kind()
+ if srcKind == reflect.Ptr && dstKind != reflect.Ptr {
+ srcElement = srcElement.Elem()
+ srcKind = reflect.TypeOf(srcElement.Interface()).Kind()
+ } else if dstKind == reflect.Ptr {
+ // Can this work? I guess it can't.
+ if srcKind != reflect.Ptr && srcElement.CanAddr() {
+ srcPtr := srcElement.Addr()
+ srcElement = reflect.ValueOf(srcPtr)
+ srcKind = reflect.Ptr
+ }
+ }
+
+ if !srcElement.IsValid() {
+ continue
+ }
+ if srcKind == dstKind {
+ if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
+ return
+ }
+ } else if dstKind == reflect.Interface && dstElement.Kind() == reflect.Interface {
+ if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
+ return
+ }
+ } else if srcKind == reflect.Map {
+ if err = deepMap(dstElement, srcElement, visited, depth+1, config); err != nil {
+ return
+ }
+ } else {
+ return fmt.Errorf("type mismatch on %s field: found %v, expected %v", fieldName, srcKind, dstKind)
+ }
+ }
+ }
+ return
+}
+
+// Map sets fields' values in dst from src.
+// src can be a map with string keys or a struct. dst must be the opposite:
+// if src is a map, dst must be a valid pointer to struct. If src is a struct,
+// dst must be map[string]interface{}.
+// It won't merge unexported (private) fields and will do recursively
+// any exported field.
+// If dst is a map, keys will be src fields' names in lower camel case.
+// Missing key in src that doesn't match a field in dst will be skipped. This
+// doesn't apply if dst is a map.
+// This is separated method from Merge because it is cleaner and it keeps sane
+// semantics: merging equal types, mapping different (restricted) types.
+func Map(dst, src interface{}, opts ...func(*Config)) error {
+ return _map(dst, src, opts...)
+}
+
+// MapWithOverwrite will do the same as Map except that non-empty dst attributes will be overridden by
+// non-empty src attribute values.
+// Deprecated: Use Map(…) with WithOverride
+func MapWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
+ return _map(dst, src, append(opts, WithOverride)...)
+}
+
+func _map(dst, src interface{}, opts ...func(*Config)) error {
+ if dst != nil && reflect.ValueOf(dst).Kind() != reflect.Ptr {
+ return ErrNonPointerArgument
+ }
+ var (
+ vDst, vSrc reflect.Value
+ err error
+ )
+ config := &Config{}
+
+ for _, opt := range opts {
+ opt(config)
+ }
+
+ if vDst, vSrc, err = resolveValues(dst, src); err != nil {
+ return err
+ }
+ // To be friction-less, we redirect equal-type arguments
+ // to deepMerge. Only because arguments can be anything.
+ if vSrc.Kind() == vDst.Kind() {
+ return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
+ }
+ switch vSrc.Kind() {
+ case reflect.Struct:
+ if vDst.Kind() != reflect.Map {
+ return ErrExpectedMapAsDestination
+ }
+ case reflect.Map:
+ if vDst.Kind() != reflect.Struct {
+ return ErrExpectedStructAsDestination
+ }
+ default:
+ return ErrNotSupported
+ }
+ return deepMap(vDst, vSrc, make(map[uintptr]*visit), 0, config)
+}
diff --git a/vendor/dario.cat/mergo/merge.go b/vendor/dario.cat/mergo/merge.go
new file mode 100644
index 00000000..0ef9b213
--- /dev/null
+++ b/vendor/dario.cat/mergo/merge.go
@@ -0,0 +1,409 @@
+// Copyright 2013 Dario Castañé. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Based on src/pkg/reflect/deepequal.go from official
+// golang's stdlib.
+
+package mergo
+
+import (
+ "fmt"
+ "reflect"
+)
+
+func hasMergeableFields(dst reflect.Value) (exported bool) {
+ for i, n := 0, dst.NumField(); i < n; i++ {
+ field := dst.Type().Field(i)
+ if field.Anonymous && dst.Field(i).Kind() == reflect.Struct {
+ exported = exported || hasMergeableFields(dst.Field(i))
+ } else if isExportedComponent(&field) {
+ exported = exported || len(field.PkgPath) == 0
+ }
+ }
+ return
+}
+
+func isExportedComponent(field *reflect.StructField) bool {
+ pkgPath := field.PkgPath
+ if len(pkgPath) > 0 {
+ return false
+ }
+ c := field.Name[0]
+ if 'a' <= c && c <= 'z' || c == '_' {
+ return false
+ }
+ return true
+}
+
+type Config struct {
+ Transformers Transformers
+ Overwrite bool
+ ShouldNotDereference bool
+ AppendSlice bool
+ TypeCheck bool
+ overwriteWithEmptyValue bool
+ overwriteSliceWithEmptyValue bool
+ sliceDeepCopy bool
+ debug bool
+}
+
+type Transformers interface {
+ Transformer(reflect.Type) func(dst, src reflect.Value) error
+}
+
+// Traverses recursively both values, assigning src's fields values to dst.
+// The map argument tracks comparisons that have already been seen, which allows
+// short circuiting on recursive types.
+func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) {
+ overwrite := config.Overwrite
+ typeCheck := config.TypeCheck
+ overwriteWithEmptySrc := config.overwriteWithEmptyValue
+ overwriteSliceWithEmptySrc := config.overwriteSliceWithEmptyValue
+ sliceDeepCopy := config.sliceDeepCopy
+
+ if !src.IsValid() {
+ return
+ }
+ if dst.CanAddr() {
+ addr := dst.UnsafeAddr()
+ h := 17 * addr
+ seen := visited[h]
+ typ := dst.Type()
+ for p := seen; p != nil; p = p.next {
+ if p.ptr == addr && p.typ == typ {
+ return nil
+ }
+ }
+ // Remember, remember...
+ visited[h] = &visit{typ, seen, addr}
+ }
+
+ if config.Transformers != nil && !isReflectNil(dst) && dst.IsValid() {
+ if fn := config.Transformers.Transformer(dst.Type()); fn != nil {
+ err = fn(dst, src)
+ return
+ }
+ }
+
+ switch dst.Kind() {
+ case reflect.Struct:
+ if hasMergeableFields(dst) {
+ for i, n := 0, dst.NumField(); i < n; i++ {
+ if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, config); err != nil {
+ return
+ }
+ }
+ } else {
+ if dst.CanSet() && (isReflectNil(dst) || overwrite) && (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc) {
+ dst.Set(src)
+ }
+ }
+ case reflect.Map:
+ if dst.IsNil() && !src.IsNil() {
+ if dst.CanSet() {
+ dst.Set(reflect.MakeMap(dst.Type()))
+ } else {
+ dst = src
+ return
+ }
+ }
+
+ if src.Kind() != reflect.Map {
+ if overwrite && dst.CanSet() {
+ dst.Set(src)
+ }
+ return
+ }
+
+ for _, key := range src.MapKeys() {
+ srcElement := src.MapIndex(key)
+ if !srcElement.IsValid() {
+ continue
+ }
+ dstElement := dst.MapIndex(key)
+ switch srcElement.Kind() {
+ case reflect.Chan, reflect.Func, reflect.Map, reflect.Interface, reflect.Slice:
+ if srcElement.IsNil() {
+ if overwrite {
+ dst.SetMapIndex(key, srcElement)
+ }
+ continue
+ }
+ fallthrough
+ default:
+ if !srcElement.CanInterface() {
+ continue
+ }
+ switch reflect.TypeOf(srcElement.Interface()).Kind() {
+ case reflect.Struct:
+ fallthrough
+ case reflect.Ptr:
+ fallthrough
+ case reflect.Map:
+ srcMapElm := srcElement
+ dstMapElm := dstElement
+ if srcMapElm.CanInterface() {
+ srcMapElm = reflect.ValueOf(srcMapElm.Interface())
+ if dstMapElm.IsValid() {
+ dstMapElm = reflect.ValueOf(dstMapElm.Interface())
+ }
+ }
+ if err = deepMerge(dstMapElm, srcMapElm, visited, depth+1, config); err != nil {
+ return
+ }
+ case reflect.Slice:
+ srcSlice := reflect.ValueOf(srcElement.Interface())
+
+ var dstSlice reflect.Value
+ if !dstElement.IsValid() || dstElement.IsNil() {
+ dstSlice = reflect.MakeSlice(srcSlice.Type(), 0, srcSlice.Len())
+ } else {
+ dstSlice = reflect.ValueOf(dstElement.Interface())
+ }
+
+ if (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) && !config.AppendSlice && !sliceDeepCopy {
+ if typeCheck && srcSlice.Type() != dstSlice.Type() {
+ return fmt.Errorf("cannot override two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
+ }
+ dstSlice = srcSlice
+ } else if config.AppendSlice {
+ if srcSlice.Type() != dstSlice.Type() {
+ return fmt.Errorf("cannot append two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
+ }
+ dstSlice = reflect.AppendSlice(dstSlice, srcSlice)
+ } else if sliceDeepCopy {
+ i := 0
+ for ; i < srcSlice.Len() && i < dstSlice.Len(); i++ {
+ srcElement := srcSlice.Index(i)
+ dstElement := dstSlice.Index(i)
+
+ if srcElement.CanInterface() {
+ srcElement = reflect.ValueOf(srcElement.Interface())
+ }
+ if dstElement.CanInterface() {
+ dstElement = reflect.ValueOf(dstElement.Interface())
+ }
+
+ if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
+ return
+ }
+ }
+
+ }
+ dst.SetMapIndex(key, dstSlice)
+ }
+ }
+
+ if dstElement.IsValid() && !isEmptyValue(dstElement, !config.ShouldNotDereference) {
+ if reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Slice {
+ continue
+ }
+ if reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Map && reflect.TypeOf(dstElement.Interface()).Kind() == reflect.Map {
+ continue
+ }
+ }
+
+ if srcElement.IsValid() && ((srcElement.Kind() != reflect.Ptr && overwrite) || !dstElement.IsValid() || isEmptyValue(dstElement, !config.ShouldNotDereference)) {
+ if dst.IsNil() {
+ dst.Set(reflect.MakeMap(dst.Type()))
+ }
+ dst.SetMapIndex(key, srcElement)
+ }
+ }
+
+ // Ensure that all keys in dst are deleted if they are not in src.
+ if overwriteWithEmptySrc {
+ for _, key := range dst.MapKeys() {
+ srcElement := src.MapIndex(key)
+ if !srcElement.IsValid() {
+ dst.SetMapIndex(key, reflect.Value{})
+ }
+ }
+ }
+ case reflect.Slice:
+ if !dst.CanSet() {
+ break
+ }
+ if (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) && !config.AppendSlice && !sliceDeepCopy {
+ dst.Set(src)
+ } else if config.AppendSlice {
+ if src.Type() != dst.Type() {
+ return fmt.Errorf("cannot append two slice with different type (%s, %s)", src.Type(), dst.Type())
+ }
+ dst.Set(reflect.AppendSlice(dst, src))
+ } else if sliceDeepCopy {
+ for i := 0; i < src.Len() && i < dst.Len(); i++ {
+ srcElement := src.Index(i)
+ dstElement := dst.Index(i)
+ if srcElement.CanInterface() {
+ srcElement = reflect.ValueOf(srcElement.Interface())
+ }
+ if dstElement.CanInterface() {
+ dstElement = reflect.ValueOf(dstElement.Interface())
+ }
+
+ if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
+ return
+ }
+ }
+ }
+ case reflect.Ptr:
+ fallthrough
+ case reflect.Interface:
+ if isReflectNil(src) {
+ if overwriteWithEmptySrc && dst.CanSet() && src.Type().AssignableTo(dst.Type()) {
+ dst.Set(src)
+ }
+ break
+ }
+
+ if src.Kind() != reflect.Interface {
+ if dst.IsNil() || (src.Kind() != reflect.Ptr && overwrite) {
+ if dst.CanSet() && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) {
+ dst.Set(src)
+ }
+ } else if src.Kind() == reflect.Ptr {
+ if !config.ShouldNotDereference {
+ if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
+ return
+ }
+ } else {
+ if overwriteWithEmptySrc || (overwrite && !src.IsNil()) || dst.IsNil() {
+ dst.Set(src)
+ }
+ }
+ } else if dst.Elem().Type() == src.Type() {
+ if err = deepMerge(dst.Elem(), src, visited, depth+1, config); err != nil {
+ return
+ }
+ } else {
+ return ErrDifferentArgumentsTypes
+ }
+ break
+ }
+
+ if dst.IsNil() || overwrite {
+ if dst.CanSet() && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) {
+ dst.Set(src)
+ }
+ break
+ }
+
+ if dst.Elem().Kind() == src.Elem().Kind() {
+ if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
+ return
+ }
+ break
+ }
+ default:
+ mustSet := (isEmptyValue(dst, !config.ShouldNotDereference) || overwrite) && (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc)
+ if mustSet {
+ if dst.CanSet() {
+ dst.Set(src)
+ } else {
+ dst = src
+ }
+ }
+ }
+
+ return
+}
+
+// Merge will fill any empty for value type attributes on the dst struct using corresponding
+// src attributes if they themselves are not empty. dst and src must be valid same-type structs
+// and dst must be a pointer to struct.
+// It won't merge unexported (private) fields and will do recursively any exported field.
+func Merge(dst, src interface{}, opts ...func(*Config)) error {
+ return merge(dst, src, opts...)
+}
+
+// MergeWithOverwrite will do the same as Merge except that non-empty dst attributes will be overridden by
+// non-empty src attribute values.
+// Deprecated: use Merge(…) with WithOverride
+func MergeWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
+ return merge(dst, src, append(opts, WithOverride)...)
+}
+
+// WithTransformers adds transformers to merge, allowing to customize the merging of some types.
+func WithTransformers(transformers Transformers) func(*Config) {
+ return func(config *Config) {
+ config.Transformers = transformers
+ }
+}
+
+// WithOverride will make merge override non-empty dst attributes with non-empty src attributes values.
+func WithOverride(config *Config) {
+ config.Overwrite = true
+}
+
+// WithOverwriteWithEmptyValue will make merge override non empty dst attributes with empty src attributes values.
+func WithOverwriteWithEmptyValue(config *Config) {
+ config.Overwrite = true
+ config.overwriteWithEmptyValue = true
+}
+
+// WithOverrideEmptySlice will make merge override empty dst slice with empty src slice.
+func WithOverrideEmptySlice(config *Config) {
+ config.overwriteSliceWithEmptyValue = true
+}
+
+// WithoutDereference prevents dereferencing pointers when evaluating whether they are empty
+// (i.e. a non-nil pointer is never considered empty).
+func WithoutDereference(config *Config) {
+ config.ShouldNotDereference = true
+}
+
+// WithAppendSlice will make merge append slices instead of overwriting it.
+func WithAppendSlice(config *Config) {
+ config.AppendSlice = true
+}
+
+// WithTypeCheck will make merge check types while overwriting it (must be used with WithOverride).
+func WithTypeCheck(config *Config) {
+ config.TypeCheck = true
+}
+
+// WithSliceDeepCopy will merge slice element one by one with Overwrite flag.
+func WithSliceDeepCopy(config *Config) {
+ config.sliceDeepCopy = true
+ config.Overwrite = true
+}
+
+func merge(dst, src interface{}, opts ...func(*Config)) error {
+ if dst != nil && reflect.ValueOf(dst).Kind() != reflect.Ptr {
+ return ErrNonPointerArgument
+ }
+ var (
+ vDst, vSrc reflect.Value
+ err error
+ )
+
+ config := &Config{}
+
+ for _, opt := range opts {
+ opt(config)
+ }
+
+ if vDst, vSrc, err = resolveValues(dst, src); err != nil {
+ return err
+ }
+ if vDst.Type() != vSrc.Type() {
+ return ErrDifferentArgumentsTypes
+ }
+ return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
+}
+
+// IsReflectNil is the reflect value provided nil
+func isReflectNil(v reflect.Value) bool {
+ k := v.Kind()
+ switch k {
+ case reflect.Interface, reflect.Slice, reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr:
+ // Both interface and slice are nil if first word is 0.
+ // Both are always bigger than a word; assume flagIndir.
+ return v.IsNil()
+ default:
+ return false
+ }
+}
diff --git a/vendor/dario.cat/mergo/mergo.go b/vendor/dario.cat/mergo/mergo.go
new file mode 100644
index 00000000..0a721e2d
--- /dev/null
+++ b/vendor/dario.cat/mergo/mergo.go
@@ -0,0 +1,81 @@
+// Copyright 2013 Dario Castañé. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Based on src/pkg/reflect/deepequal.go from official
+// golang's stdlib.
+
+package mergo
+
+import (
+ "errors"
+ "reflect"
+)
+
+// Errors reported by Mergo when it finds invalid arguments.
+var (
+ ErrNilArguments = errors.New("src and dst must not be nil")
+ ErrDifferentArgumentsTypes = errors.New("src and dst must be of same type")
+ ErrNotSupported = errors.New("only structs, maps, and slices are supported")
+ ErrExpectedMapAsDestination = errors.New("dst was expected to be a map")
+ ErrExpectedStructAsDestination = errors.New("dst was expected to be a struct")
+ ErrNonPointerArgument = errors.New("dst must be a pointer")
+)
+
+// During deepMerge, must keep track of checks that are
+// in progress. The comparison algorithm assumes that all
+// checks in progress are true when it reencounters them.
+// Visited are stored in a map indexed by 17 * a1 + a2;
+type visit struct {
+ typ reflect.Type
+ next *visit
+ ptr uintptr
+}
+
+// From src/pkg/encoding/json/encode.go.
+func isEmptyValue(v reflect.Value, shouldDereference bool) bool {
+ switch v.Kind() {
+ case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+ return v.Len() == 0
+ case reflect.Bool:
+ return !v.Bool()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return v.Int() == 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return v.Uint() == 0
+ case reflect.Float32, reflect.Float64:
+ return v.Float() == 0
+ case reflect.Interface, reflect.Ptr:
+ if v.IsNil() {
+ return true
+ }
+ if shouldDereference {
+ return isEmptyValue(v.Elem(), shouldDereference)
+ }
+ return false
+ case reflect.Func:
+ return v.IsNil()
+ case reflect.Invalid:
+ return true
+ }
+ return false
+}
+
+func resolveValues(dst, src interface{}) (vDst, vSrc reflect.Value, err error) {
+ if dst == nil || src == nil {
+ err = ErrNilArguments
+ return
+ }
+ vDst = reflect.ValueOf(dst).Elem()
+ if vDst.Kind() != reflect.Struct && vDst.Kind() != reflect.Map && vDst.Kind() != reflect.Slice {
+ err = ErrNotSupported
+ return
+ }
+ vSrc = reflect.ValueOf(src)
+ // We check if vSrc is a pointer to dereference it.
+ if vSrc.Kind() == reflect.Ptr {
+ vSrc = vSrc.Elem()
+ }
+ return
+}
diff --git a/vendor/filippo.io/edwards25519/LICENSE b/vendor/filippo.io/edwards25519/LICENSE
new file mode 100644
index 00000000..6a66aea5
--- /dev/null
+++ b/vendor/filippo.io/edwards25519/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/filippo.io/edwards25519/README.md b/vendor/filippo.io/edwards25519/README.md
new file mode 100644
index 00000000..24e2457d
--- /dev/null
+++ b/vendor/filippo.io/edwards25519/README.md
@@ -0,0 +1,14 @@
+# filippo.io/edwards25519
+
+```
+import "filippo.io/edwards25519"
+```
+
+This library implements the edwards25519 elliptic curve, exposing the necessary APIs to build a wide array of higher-level primitives.
+Read the docs at [pkg.go.dev/filippo.io/edwards25519](https://pkg.go.dev/filippo.io/edwards25519).
+
+The code is originally derived from Adam Langley's internal implementation in the Go standard library, and includes George Tankersley's [performance improvements](https://golang.org/cl/71950). It was then further developed by Henry de Valence for use in ristretto255, and was finally [merged back into the Go standard library](https://golang.org/cl/276272) as of Go 1.17. It now tracks the upstream codebase and extends it with additional functionality.
+
+Most users don't need this package, and should instead use `crypto/ed25519` for signatures, `golang.org/x/crypto/curve25519` for Diffie-Hellman, or `github.com/gtank/ristretto255` for prime order group logic. However, for anyone currently using a fork of `crypto/internal/edwards25519`/`crypto/ed25519/internal/edwards25519` or `github.com/agl/edwards25519`, this package should be a safer, faster, and more powerful alternative.
+
+Since this package is meant to curb proliferation of edwards25519 implementations in the Go ecosystem, it welcomes requests for new APIs or reviewable performance improvements.
diff --git a/vendor/filippo.io/edwards25519/doc.go b/vendor/filippo.io/edwards25519/doc.go
new file mode 100644
index 00000000..ab6aaebc
--- /dev/null
+++ b/vendor/filippo.io/edwards25519/doc.go
@@ -0,0 +1,20 @@
+// Copyright (c) 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package edwards25519 implements group logic for the twisted Edwards curve
+//
+// -x^2 + y^2 = 1 + -(121665/121666)*x^2*y^2
+//
+// This is better known as the Edwards curve equivalent to Curve25519, and is
+// the curve used by the Ed25519 signature scheme.
+//
+// Most users don't need this package, and should instead use crypto/ed25519 for
+// signatures, golang.org/x/crypto/curve25519 for Diffie-Hellman, or
+// github.com/gtank/ristretto255 for prime order group logic.
+//
+// However, developers who do need to interact with low-level edwards25519
+// operations can use this package, which is an extended version of
+// crypto/internal/edwards25519 from the standard library repackaged as
+// an importable module.
+package edwards25519
diff --git a/vendor/filippo.io/edwards25519/edwards25519.go b/vendor/filippo.io/edwards25519/edwards25519.go
new file mode 100644
index 00000000..a744da2c
--- /dev/null
+++ b/vendor/filippo.io/edwards25519/edwards25519.go
@@ -0,0 +1,427 @@
+// Copyright (c) 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package edwards25519
+
+import (
+ "errors"
+
+ "filippo.io/edwards25519/field"
+)
+
+// Point types.
+
+type projP1xP1 struct {
+ X, Y, Z, T field.Element
+}
+
+type projP2 struct {
+ X, Y, Z field.Element
+}
+
+// Point represents a point on the edwards25519 curve.
+//
+// This type works similarly to math/big.Int, and all arguments and receivers
+// are allowed to alias.
+//
+// The zero value is NOT valid, and it may be used only as a receiver.
+type Point struct {
+ // Make the type not comparable (i.e. used with == or as a map key), as
+ // equivalent points can be represented by different Go values.
+ _ incomparable
+
+ // The point is internally represented in extended coordinates (X, Y, Z, T)
+ // where x = X/Z, y = Y/Z, and xy = T/Z per https://eprint.iacr.org/2008/522.
+ x, y, z, t field.Element
+}
+
+type incomparable [0]func()
+
+func checkInitialized(points ...*Point) {
+ for _, p := range points {
+ if p.x == (field.Element{}) && p.y == (field.Element{}) {
+ panic("edwards25519: use of uninitialized Point")
+ }
+ }
+}
+
+type projCached struct {
+ YplusX, YminusX, Z, T2d field.Element
+}
+
+type affineCached struct {
+ YplusX, YminusX, T2d field.Element
+}
+
+// Constructors.
+
+func (v *projP2) Zero() *projP2 {
+ v.X.Zero()
+ v.Y.One()
+ v.Z.One()
+ return v
+}
+
+// identity is the point at infinity.
+var identity, _ = new(Point).SetBytes([]byte{
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
+
+// NewIdentityPoint returns a new Point set to the identity.
+func NewIdentityPoint() *Point {
+ return new(Point).Set(identity)
+}
+
+// generator is the canonical curve basepoint. See TestGenerator for the
+// correspondence of this encoding with the values in RFC 8032.
+var generator, _ = new(Point).SetBytes([]byte{
+ 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66})
+
+// NewGeneratorPoint returns a new Point set to the canonical generator.
+func NewGeneratorPoint() *Point {
+ return new(Point).Set(generator)
+}
+
+func (v *projCached) Zero() *projCached {
+ v.YplusX.One()
+ v.YminusX.One()
+ v.Z.One()
+ v.T2d.Zero()
+ return v
+}
+
+func (v *affineCached) Zero() *affineCached {
+ v.YplusX.One()
+ v.YminusX.One()
+ v.T2d.Zero()
+ return v
+}
+
+// Assignments.
+
+// Set sets v = u, and returns v.
+func (v *Point) Set(u *Point) *Point {
+ *v = *u
+ return v
+}
+
+// Encoding.
+
+// Bytes returns the canonical 32-byte encoding of v, according to RFC 8032,
+// Section 5.1.2.
+func (v *Point) Bytes() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var buf [32]byte
+ return v.bytes(&buf)
+}
+
+func (v *Point) bytes(buf *[32]byte) []byte {
+ checkInitialized(v)
+
+ var zInv, x, y field.Element
+ zInv.Invert(&v.z) // zInv = 1 / Z
+ x.Multiply(&v.x, &zInv) // x = X / Z
+ y.Multiply(&v.y, &zInv) // y = Y / Z
+
+ out := copyFieldElement(buf, &y)
+ out[31] |= byte(x.IsNegative() << 7)
+ return out
+}
+
+var feOne = new(field.Element).One()
+
+// SetBytes sets v = x, where x is a 32-byte encoding of v. If x does not
+// represent a valid point on the curve, SetBytes returns nil and an error and
+// the receiver is unchanged. Otherwise, SetBytes returns v.
+//
+// Note that SetBytes accepts all non-canonical encodings of valid points.
+// That is, it follows decoding rules that match most implementations in
+// the ecosystem rather than RFC 8032.
+func (v *Point) SetBytes(x []byte) (*Point, error) {
+ // Specifically, the non-canonical encodings that are accepted are
+ // 1) the ones where the field element is not reduced (see the
+ // (*field.Element).SetBytes docs) and
+ // 2) the ones where the x-coordinate is zero and the sign bit is set.
+ //
+ // Read more at https://hdevalence.ca/blog/2020-10-04-its-25519am,
+ // specifically the "Canonical A, R" section.
+
+ y, err := new(field.Element).SetBytes(x)
+ if err != nil {
+ return nil, errors.New("edwards25519: invalid point encoding length")
+ }
+
+ // -x² + y² = 1 + dx²y²
+ // x² + dx²y² = x²(dy² + 1) = y² - 1
+ // x² = (y² - 1) / (dy² + 1)
+
+ // u = y² - 1
+ y2 := new(field.Element).Square(y)
+ u := new(field.Element).Subtract(y2, feOne)
+
+ // v = dy² + 1
+ vv := new(field.Element).Multiply(y2, d)
+ vv = vv.Add(vv, feOne)
+
+ // x = +√(u/v)
+ xx, wasSquare := new(field.Element).SqrtRatio(u, vv)
+ if wasSquare == 0 {
+ return nil, errors.New("edwards25519: invalid point encoding")
+ }
+
+ // Select the negative square root if the sign bit is set.
+ xxNeg := new(field.Element).Negate(xx)
+ xx = xx.Select(xxNeg, xx, int(x[31]>>7))
+
+ v.x.Set(xx)
+ v.y.Set(y)
+ v.z.One()
+ v.t.Multiply(xx, y) // xy = T / Z
+
+ return v, nil
+}
+
+func copyFieldElement(buf *[32]byte, v *field.Element) []byte {
+ copy(buf[:], v.Bytes())
+ return buf[:]
+}
+
+// Conversions.
+
+func (v *projP2) FromP1xP1(p *projP1xP1) *projP2 {
+ v.X.Multiply(&p.X, &p.T)
+ v.Y.Multiply(&p.Y, &p.Z)
+ v.Z.Multiply(&p.Z, &p.T)
+ return v
+}
+
+func (v *projP2) FromP3(p *Point) *projP2 {
+ v.X.Set(&p.x)
+ v.Y.Set(&p.y)
+ v.Z.Set(&p.z)
+ return v
+}
+
+func (v *Point) fromP1xP1(p *projP1xP1) *Point {
+ v.x.Multiply(&p.X, &p.T)
+ v.y.Multiply(&p.Y, &p.Z)
+ v.z.Multiply(&p.Z, &p.T)
+ v.t.Multiply(&p.X, &p.Y)
+ return v
+}
+
+func (v *Point) fromP2(p *projP2) *Point {
+ v.x.Multiply(&p.X, &p.Z)
+ v.y.Multiply(&p.Y, &p.Z)
+ v.z.Square(&p.Z)
+ v.t.Multiply(&p.X, &p.Y)
+ return v
+}
+
+// d is a constant in the curve equation.
+var d, _ = new(field.Element).SetBytes([]byte{
+ 0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75,
+ 0xab, 0xd8, 0x41, 0x41, 0x4d, 0x0a, 0x70, 0x00,
+ 0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c,
+ 0x73, 0xfe, 0x6f, 0x2b, 0xee, 0x6c, 0x03, 0x52})
+var d2 = new(field.Element).Add(d, d)
+
+func (v *projCached) FromP3(p *Point) *projCached {
+ v.YplusX.Add(&p.y, &p.x)
+ v.YminusX.Subtract(&p.y, &p.x)
+ v.Z.Set(&p.z)
+ v.T2d.Multiply(&p.t, d2)
+ return v
+}
+
+func (v *affineCached) FromP3(p *Point) *affineCached {
+ v.YplusX.Add(&p.y, &p.x)
+ v.YminusX.Subtract(&p.y, &p.x)
+ v.T2d.Multiply(&p.t, d2)
+
+ var invZ field.Element
+ invZ.Invert(&p.z)
+ v.YplusX.Multiply(&v.YplusX, &invZ)
+ v.YminusX.Multiply(&v.YminusX, &invZ)
+ v.T2d.Multiply(&v.T2d, &invZ)
+ return v
+}
+
+// (Re)addition and subtraction.
+
+// Add sets v = p + q, and returns v.
+func (v *Point) Add(p, q *Point) *Point {
+ checkInitialized(p, q)
+ qCached := new(projCached).FromP3(q)
+ result := new(projP1xP1).Add(p, qCached)
+ return v.fromP1xP1(result)
+}
+
+// Subtract sets v = p - q, and returns v.
+func (v *Point) Subtract(p, q *Point) *Point {
+ checkInitialized(p, q)
+ qCached := new(projCached).FromP3(q)
+ result := new(projP1xP1).Sub(p, qCached)
+ return v.fromP1xP1(result)
+}
+
+func (v *projP1xP1) Add(p *Point, q *projCached) *projP1xP1 {
+ var YplusX, YminusX, PP, MM, TT2d, ZZ2 field.Element
+
+ YplusX.Add(&p.y, &p.x)
+ YminusX.Subtract(&p.y, &p.x)
+
+ PP.Multiply(&YplusX, &q.YplusX)
+ MM.Multiply(&YminusX, &q.YminusX)
+ TT2d.Multiply(&p.t, &q.T2d)
+ ZZ2.Multiply(&p.z, &q.Z)
+
+ ZZ2.Add(&ZZ2, &ZZ2)
+
+ v.X.Subtract(&PP, &MM)
+ v.Y.Add(&PP, &MM)
+ v.Z.Add(&ZZ2, &TT2d)
+ v.T.Subtract(&ZZ2, &TT2d)
+ return v
+}
+
+func (v *projP1xP1) Sub(p *Point, q *projCached) *projP1xP1 {
+ var YplusX, YminusX, PP, MM, TT2d, ZZ2 field.Element
+
+ YplusX.Add(&p.y, &p.x)
+ YminusX.Subtract(&p.y, &p.x)
+
+ PP.Multiply(&YplusX, &q.YminusX) // flipped sign
+ MM.Multiply(&YminusX, &q.YplusX) // flipped sign
+ TT2d.Multiply(&p.t, &q.T2d)
+ ZZ2.Multiply(&p.z, &q.Z)
+
+ ZZ2.Add(&ZZ2, &ZZ2)
+
+ v.X.Subtract(&PP, &MM)
+ v.Y.Add(&PP, &MM)
+ v.Z.Subtract(&ZZ2, &TT2d) // flipped sign
+ v.T.Add(&ZZ2, &TT2d) // flipped sign
+ return v
+}
+
+func (v *projP1xP1) AddAffine(p *Point, q *affineCached) *projP1xP1 {
+ var YplusX, YminusX, PP, MM, TT2d, Z2 field.Element
+
+ YplusX.Add(&p.y, &p.x)
+ YminusX.Subtract(&p.y, &p.x)
+
+ PP.Multiply(&YplusX, &q.YplusX)
+ MM.Multiply(&YminusX, &q.YminusX)
+ TT2d.Multiply(&p.t, &q.T2d)
+
+ Z2.Add(&p.z, &p.z)
+
+ v.X.Subtract(&PP, &MM)
+ v.Y.Add(&PP, &MM)
+ v.Z.Add(&Z2, &TT2d)
+ v.T.Subtract(&Z2, &TT2d)
+ return v
+}
+
+func (v *projP1xP1) SubAffine(p *Point, q *affineCached) *projP1xP1 {
+ var YplusX, YminusX, PP, MM, TT2d, Z2 field.Element
+
+ YplusX.Add(&p.y, &p.x)
+ YminusX.Subtract(&p.y, &p.x)
+
+ PP.Multiply(&YplusX, &q.YminusX) // flipped sign
+ MM.Multiply(&YminusX, &q.YplusX) // flipped sign
+ TT2d.Multiply(&p.t, &q.T2d)
+
+ Z2.Add(&p.z, &p.z)
+
+ v.X.Subtract(&PP, &MM)
+ v.Y.Add(&PP, &MM)
+ v.Z.Subtract(&Z2, &TT2d) // flipped sign
+ v.T.Add(&Z2, &TT2d) // flipped sign
+ return v
+}
+
+// Doubling.
+
+func (v *projP1xP1) Double(p *projP2) *projP1xP1 {
+ var XX, YY, ZZ2, XplusYsq field.Element
+
+ XX.Square(&p.X)
+ YY.Square(&p.Y)
+ ZZ2.Square(&p.Z)
+ ZZ2.Add(&ZZ2, &ZZ2)
+ XplusYsq.Add(&p.X, &p.Y)
+ XplusYsq.Square(&XplusYsq)
+
+ v.Y.Add(&YY, &XX)
+ v.Z.Subtract(&YY, &XX)
+
+ v.X.Subtract(&XplusYsq, &v.Y)
+ v.T.Subtract(&ZZ2, &v.Z)
+ return v
+}
+
+// Negation.
+
+// Negate sets v = -p, and returns v.
+func (v *Point) Negate(p *Point) *Point {
+ checkInitialized(p)
+ v.x.Negate(&p.x)
+ v.y.Set(&p.y)
+ v.z.Set(&p.z)
+ v.t.Negate(&p.t)
+ return v
+}
+
+// Equal returns 1 if v is equivalent to u, and 0 otherwise.
+func (v *Point) Equal(u *Point) int {
+ checkInitialized(v, u)
+
+ var t1, t2, t3, t4 field.Element
+ t1.Multiply(&v.x, &u.z)
+ t2.Multiply(&u.x, &v.z)
+ t3.Multiply(&v.y, &u.z)
+ t4.Multiply(&u.y, &v.z)
+
+ return t1.Equal(&t2) & t3.Equal(&t4)
+}
+
+// Constant-time operations
+
+// Select sets v to a if cond == 1 and to b if cond == 0.
+func (v *projCached) Select(a, b *projCached, cond int) *projCached {
+ v.YplusX.Select(&a.YplusX, &b.YplusX, cond)
+ v.YminusX.Select(&a.YminusX, &b.YminusX, cond)
+ v.Z.Select(&a.Z, &b.Z, cond)
+ v.T2d.Select(&a.T2d, &b.T2d, cond)
+ return v
+}
+
+// Select sets v to a if cond == 1 and to b if cond == 0.
+func (v *affineCached) Select(a, b *affineCached, cond int) *affineCached {
+ v.YplusX.Select(&a.YplusX, &b.YplusX, cond)
+ v.YminusX.Select(&a.YminusX, &b.YminusX, cond)
+ v.T2d.Select(&a.T2d, &b.T2d, cond)
+ return v
+}
+
+// CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0.
+func (v *projCached) CondNeg(cond int) *projCached {
+ v.YplusX.Swap(&v.YminusX, cond)
+ v.T2d.Select(new(field.Element).Negate(&v.T2d), &v.T2d, cond)
+ return v
+}
+
+// CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0.
+func (v *affineCached) CondNeg(cond int) *affineCached {
+ v.YplusX.Swap(&v.YminusX, cond)
+ v.T2d.Select(new(field.Element).Negate(&v.T2d), &v.T2d, cond)
+ return v
+}
diff --git a/vendor/filippo.io/edwards25519/extra.go b/vendor/filippo.io/edwards25519/extra.go
new file mode 100644
index 00000000..d152d68f
--- /dev/null
+++ b/vendor/filippo.io/edwards25519/extra.go
@@ -0,0 +1,349 @@
+// Copyright (c) 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package edwards25519
+
+// This file contains additional functionality that is not included in the
+// upstream crypto/internal/edwards25519 package.
+
+import (
+ "errors"
+
+ "filippo.io/edwards25519/field"
+)
+
+// ExtendedCoordinates returns v in extended coordinates (X:Y:Z:T) where
+// x = X/Z, y = Y/Z, and xy = T/Z as in https://eprint.iacr.org/2008/522.
+func (v *Point) ExtendedCoordinates() (X, Y, Z, T *field.Element) {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap. Don't change the style without making
+ // sure it doesn't increase the inliner cost.
+ var e [4]field.Element
+ X, Y, Z, T = v.extendedCoordinates(&e)
+ return
+}
+
+func (v *Point) extendedCoordinates(e *[4]field.Element) (X, Y, Z, T *field.Element) {
+ checkInitialized(v)
+ X = e[0].Set(&v.x)
+ Y = e[1].Set(&v.y)
+ Z = e[2].Set(&v.z)
+ T = e[3].Set(&v.t)
+ return
+}
+
+// SetExtendedCoordinates sets v = (X:Y:Z:T) in extended coordinates where
+// x = X/Z, y = Y/Z, and xy = T/Z as in https://eprint.iacr.org/2008/522.
+//
+// If the coordinates are invalid or don't represent a valid point on the curve,
+// SetExtendedCoordinates returns nil and an error and the receiver is
+// unchanged. Otherwise, SetExtendedCoordinates returns v.
+func (v *Point) SetExtendedCoordinates(X, Y, Z, T *field.Element) (*Point, error) {
+ if !isOnCurve(X, Y, Z, T) {
+ return nil, errors.New("edwards25519: invalid point coordinates")
+ }
+ v.x.Set(X)
+ v.y.Set(Y)
+ v.z.Set(Z)
+ v.t.Set(T)
+ return v, nil
+}
+
+func isOnCurve(X, Y, Z, T *field.Element) bool {
+ var lhs, rhs field.Element
+ XX := new(field.Element).Square(X)
+ YY := new(field.Element).Square(Y)
+ ZZ := new(field.Element).Square(Z)
+ TT := new(field.Element).Square(T)
+ // -x² + y² = 1 + dx²y²
+ // -(X/Z)² + (Y/Z)² = 1 + d(T/Z)²
+ // -X² + Y² = Z² + dT²
+ lhs.Subtract(YY, XX)
+ rhs.Multiply(d, TT).Add(&rhs, ZZ)
+ if lhs.Equal(&rhs) != 1 {
+ return false
+ }
+ // xy = T/Z
+ // XY/Z² = T/Z
+ // XY = TZ
+ lhs.Multiply(X, Y)
+ rhs.Multiply(T, Z)
+ return lhs.Equal(&rhs) == 1
+}
+
+// BytesMontgomery converts v to a point on the birationally-equivalent
+// Curve25519 Montgomery curve, and returns its canonical 32 bytes encoding
+// according to RFC 7748.
+//
+// Note that BytesMontgomery only encodes the u-coordinate, so v and -v encode
+// to the same value. If v is the identity point, BytesMontgomery returns 32
+// zero bytes, analogously to the X25519 function.
+//
+// The lack of an inverse operation (such as SetMontgomeryBytes) is deliberate:
+// while every valid edwards25519 point has a unique u-coordinate Montgomery
+// encoding, X25519 accepts inputs on the quadratic twist, which don't correspond
+// to any edwards25519 point, and every other X25519 input corresponds to two
+// edwards25519 points.
+func (v *Point) BytesMontgomery() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var buf [32]byte
+ return v.bytesMontgomery(&buf)
+}
+
+func (v *Point) bytesMontgomery(buf *[32]byte) []byte {
+ checkInitialized(v)
+
+ // RFC 7748, Section 4.1 provides the bilinear map to calculate the
+ // Montgomery u-coordinate
+ //
+ // u = (1 + y) / (1 - y)
+ //
+ // where y = Y / Z.
+
+ var y, recip, u field.Element
+
+ y.Multiply(&v.y, y.Invert(&v.z)) // y = Y / Z
+ recip.Invert(recip.Subtract(feOne, &y)) // r = 1/(1 - y)
+ u.Multiply(u.Add(feOne, &y), &recip) // u = (1 + y)*r
+
+ return copyFieldElement(buf, &u)
+}
+
+// MultByCofactor sets v = 8 * p, and returns v.
+func (v *Point) MultByCofactor(p *Point) *Point {
+ checkInitialized(p)
+ result := projP1xP1{}
+ pp := (&projP2{}).FromP3(p)
+ result.Double(pp)
+ pp.FromP1xP1(&result)
+ result.Double(pp)
+ pp.FromP1xP1(&result)
+ result.Double(pp)
+ return v.fromP1xP1(&result)
+}
+
+// Given k > 0, set s = s**(2*i).
+func (s *Scalar) pow2k(k int) {
+ for i := 0; i < k; i++ {
+ s.Multiply(s, s)
+ }
+}
+
+// Invert sets s to the inverse of a nonzero scalar v, and returns s.
+//
+// If t is zero, Invert returns zero.
+func (s *Scalar) Invert(t *Scalar) *Scalar {
+ // Uses a hardcoded sliding window of width 4.
+ var table [8]Scalar
+ var tt Scalar
+ tt.Multiply(t, t)
+ table[0] = *t
+ for i := 0; i < 7; i++ {
+ table[i+1].Multiply(&table[i], &tt)
+ }
+ // Now table = [t**1, t**3, t**5, t**7, t**9, t**11, t**13, t**15]
+ // so t**k = t[k/2] for odd k
+
+ // To compute the sliding window digits, use the following Sage script:
+
+ // sage: import itertools
+ // sage: def sliding_window(w,k):
+ // ....: digits = []
+ // ....: while k > 0:
+ // ....: if k % 2 == 1:
+ // ....: kmod = k % (2**w)
+ // ....: digits.append(kmod)
+ // ....: k = k - kmod
+ // ....: else:
+ // ....: digits.append(0)
+ // ....: k = k // 2
+ // ....: return digits
+
+ // Now we can compute s roughly as follows:
+
+ // sage: s = 1
+ // sage: for coeff in reversed(sliding_window(4,l-2)):
+ // ....: s = s*s
+ // ....: if coeff > 0 :
+ // ....: s = s*t**coeff
+
+ // This works on one bit at a time, with many runs of zeros.
+ // The digits can be collapsed into [(count, coeff)] as follows:
+
+ // sage: [(len(list(group)),d) for d,group in itertools.groupby(sliding_window(4,l-2))]
+
+ // Entries of the form (k, 0) turn into pow2k(k)
+ // Entries of the form (1, coeff) turn into a squaring and then a table lookup.
+ // We can fold the squaring into the previous pow2k(k) as pow2k(k+1).
+
+ *s = table[1/2]
+ s.pow2k(127 + 1)
+ s.Multiply(s, &table[1/2])
+ s.pow2k(4 + 1)
+ s.Multiply(s, &table[9/2])
+ s.pow2k(3 + 1)
+ s.Multiply(s, &table[11/2])
+ s.pow2k(3 + 1)
+ s.Multiply(s, &table[13/2])
+ s.pow2k(3 + 1)
+ s.Multiply(s, &table[15/2])
+ s.pow2k(4 + 1)
+ s.Multiply(s, &table[7/2])
+ s.pow2k(4 + 1)
+ s.Multiply(s, &table[15/2])
+ s.pow2k(3 + 1)
+ s.Multiply(s, &table[5/2])
+ s.pow2k(3 + 1)
+ s.Multiply(s, &table[1/2])
+ s.pow2k(4 + 1)
+ s.Multiply(s, &table[15/2])
+ s.pow2k(4 + 1)
+ s.Multiply(s, &table[15/2])
+ s.pow2k(4 + 1)
+ s.Multiply(s, &table[7/2])
+ s.pow2k(3 + 1)
+ s.Multiply(s, &table[3/2])
+ s.pow2k(4 + 1)
+ s.Multiply(s, &table[11/2])
+ s.pow2k(5 + 1)
+ s.Multiply(s, &table[11/2])
+ s.pow2k(9 + 1)
+ s.Multiply(s, &table[9/2])
+ s.pow2k(3 + 1)
+ s.Multiply(s, &table[3/2])
+ s.pow2k(4 + 1)
+ s.Multiply(s, &table[3/2])
+ s.pow2k(4 + 1)
+ s.Multiply(s, &table[3/2])
+ s.pow2k(4 + 1)
+ s.Multiply(s, &table[9/2])
+ s.pow2k(3 + 1)
+ s.Multiply(s, &table[7/2])
+ s.pow2k(3 + 1)
+ s.Multiply(s, &table[3/2])
+ s.pow2k(3 + 1)
+ s.Multiply(s, &table[13/2])
+ s.pow2k(3 + 1)
+ s.Multiply(s, &table[7/2])
+ s.pow2k(4 + 1)
+ s.Multiply(s, &table[9/2])
+ s.pow2k(3 + 1)
+ s.Multiply(s, &table[15/2])
+ s.pow2k(4 + 1)
+ s.Multiply(s, &table[11/2])
+
+ return s
+}
+
+// MultiScalarMult sets v = sum(scalars[i] * points[i]), and returns v.
+//
+// Execution time depends only on the lengths of the two slices, which must match.
+func (v *Point) MultiScalarMult(scalars []*Scalar, points []*Point) *Point {
+ if len(scalars) != len(points) {
+ panic("edwards25519: called MultiScalarMult with different size inputs")
+ }
+ checkInitialized(points...)
+
+ // Proceed as in the single-base case, but share doublings
+ // between each point in the multiscalar equation.
+
+ // Build lookup tables for each point
+ tables := make([]projLookupTable, len(points))
+ for i := range tables {
+ tables[i].FromP3(points[i])
+ }
+ // Compute signed radix-16 digits for each scalar
+ digits := make([][64]int8, len(scalars))
+ for i := range digits {
+ digits[i] = scalars[i].signedRadix16()
+ }
+
+ // Unwrap first loop iteration to save computing 16*identity
+ multiple := &projCached{}
+ tmp1 := &projP1xP1{}
+ tmp2 := &projP2{}
+ // Lookup-and-add the appropriate multiple of each input point
+ for j := range tables {
+ tables[j].SelectInto(multiple, digits[j][63])
+ tmp1.Add(v, multiple) // tmp1 = v + x_(j,63)*Q in P1xP1 coords
+ v.fromP1xP1(tmp1) // update v
+ }
+ tmp2.FromP3(v) // set up tmp2 = v in P2 coords for next iteration
+ for i := 62; i >= 0; i-- {
+ tmp1.Double(tmp2) // tmp1 = 2*(prev) in P1xP1 coords
+ tmp2.FromP1xP1(tmp1) // tmp2 = 2*(prev) in P2 coords
+ tmp1.Double(tmp2) // tmp1 = 4*(prev) in P1xP1 coords
+ tmp2.FromP1xP1(tmp1) // tmp2 = 4*(prev) in P2 coords
+ tmp1.Double(tmp2) // tmp1 = 8*(prev) in P1xP1 coords
+ tmp2.FromP1xP1(tmp1) // tmp2 = 8*(prev) in P2 coords
+ tmp1.Double(tmp2) // tmp1 = 16*(prev) in P1xP1 coords
+ v.fromP1xP1(tmp1) // v = 16*(prev) in P3 coords
+ // Lookup-and-add the appropriate multiple of each input point
+ for j := range tables {
+ tables[j].SelectInto(multiple, digits[j][i])
+ tmp1.Add(v, multiple) // tmp1 = v + x_(j,i)*Q in P1xP1 coords
+ v.fromP1xP1(tmp1) // update v
+ }
+ tmp2.FromP3(v) // set up tmp2 = v in P2 coords for next iteration
+ }
+ return v
+}
+
+// VarTimeMultiScalarMult sets v = sum(scalars[i] * points[i]), and returns v.
+//
+// Execution time depends on the inputs.
+func (v *Point) VarTimeMultiScalarMult(scalars []*Scalar, points []*Point) *Point {
+ if len(scalars) != len(points) {
+ panic("edwards25519: called VarTimeMultiScalarMult with different size inputs")
+ }
+ checkInitialized(points...)
+
+ // Generalize double-base NAF computation to arbitrary sizes.
+ // Here all the points are dynamic, so we only use the smaller
+ // tables.
+
+ // Build lookup tables for each point
+ tables := make([]nafLookupTable5, len(points))
+ for i := range tables {
+ tables[i].FromP3(points[i])
+ }
+ // Compute a NAF for each scalar
+ nafs := make([][256]int8, len(scalars))
+ for i := range nafs {
+ nafs[i] = scalars[i].nonAdjacentForm(5)
+ }
+
+ multiple := &projCached{}
+ tmp1 := &projP1xP1{}
+ tmp2 := &projP2{}
+ tmp2.Zero()
+
+ // Move from high to low bits, doubling the accumulator
+ // at each iteration and checking whether there is a nonzero
+ // coefficient to look up a multiple of.
+ //
+ // Skip trying to find the first nonzero coefficent, because
+ // searching might be more work than a few extra doublings.
+ for i := 255; i >= 0; i-- {
+ tmp1.Double(tmp2)
+
+ for j := range nafs {
+ if nafs[j][i] > 0 {
+ v.fromP1xP1(tmp1)
+ tables[j].SelectInto(multiple, nafs[j][i])
+ tmp1.Add(v, multiple)
+ } else if nafs[j][i] < 0 {
+ v.fromP1xP1(tmp1)
+ tables[j].SelectInto(multiple, -nafs[j][i])
+ tmp1.Sub(v, multiple)
+ }
+ }
+
+ tmp2.FromP1xP1(tmp1)
+ }
+
+ v.fromP2(tmp2)
+ return v
+}
diff --git a/vendor/filippo.io/edwards25519/field/fe.go b/vendor/filippo.io/edwards25519/field/fe.go
new file mode 100644
index 00000000..5518ef2b
--- /dev/null
+++ b/vendor/filippo.io/edwards25519/field/fe.go
@@ -0,0 +1,420 @@
+// Copyright (c) 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package field implements fast arithmetic modulo 2^255-19.
+package field
+
+import (
+ "crypto/subtle"
+ "encoding/binary"
+ "errors"
+ "math/bits"
+)
+
+// Element represents an element of the field GF(2^255-19). Note that this
+// is not a cryptographically secure group, and should only be used to interact
+// with edwards25519.Point coordinates.
+//
+// This type works similarly to math/big.Int, and all arguments and receivers
+// are allowed to alias.
+//
+// The zero value is a valid zero element.
+type Element struct {
+ // An element t represents the integer
+ // t.l0 + t.l1*2^51 + t.l2*2^102 + t.l3*2^153 + t.l4*2^204
+ //
+ // Between operations, all limbs are expected to be lower than 2^52.
+ l0 uint64
+ l1 uint64
+ l2 uint64
+ l3 uint64
+ l4 uint64
+}
+
+const maskLow51Bits uint64 = (1 << 51) - 1
+
+var feZero = &Element{0, 0, 0, 0, 0}
+
+// Zero sets v = 0, and returns v.
+func (v *Element) Zero() *Element {
+ *v = *feZero
+ return v
+}
+
+var feOne = &Element{1, 0, 0, 0, 0}
+
+// One sets v = 1, and returns v.
+func (v *Element) One() *Element {
+ *v = *feOne
+ return v
+}
+
+// reduce reduces v modulo 2^255 - 19 and returns it.
+func (v *Element) reduce() *Element {
+ v.carryPropagate()
+
+ // After the light reduction we now have a field element representation
+ // v < 2^255 + 2^13 * 19, but need v < 2^255 - 19.
+
+ // If v >= 2^255 - 19, then v + 19 >= 2^255, which would overflow 2^255 - 1,
+ // generating a carry. That is, c will be 0 if v < 2^255 - 19, and 1 otherwise.
+ c := (v.l0 + 19) >> 51
+ c = (v.l1 + c) >> 51
+ c = (v.l2 + c) >> 51
+ c = (v.l3 + c) >> 51
+ c = (v.l4 + c) >> 51
+
+ // If v < 2^255 - 19 and c = 0, this will be a no-op. Otherwise, it's
+ // effectively applying the reduction identity to the carry.
+ v.l0 += 19 * c
+
+ v.l1 += v.l0 >> 51
+ v.l0 = v.l0 & maskLow51Bits
+ v.l2 += v.l1 >> 51
+ v.l1 = v.l1 & maskLow51Bits
+ v.l3 += v.l2 >> 51
+ v.l2 = v.l2 & maskLow51Bits
+ v.l4 += v.l3 >> 51
+ v.l3 = v.l3 & maskLow51Bits
+ // no additional carry
+ v.l4 = v.l4 & maskLow51Bits
+
+ return v
+}
+
+// Add sets v = a + b, and returns v.
+func (v *Element) Add(a, b *Element) *Element {
+ v.l0 = a.l0 + b.l0
+ v.l1 = a.l1 + b.l1
+ v.l2 = a.l2 + b.l2
+ v.l3 = a.l3 + b.l3
+ v.l4 = a.l4 + b.l4
+ // Using the generic implementation here is actually faster than the
+ // assembly. Probably because the body of this function is so simple that
+ // the compiler can figure out better optimizations by inlining the carry
+ // propagation.
+ return v.carryPropagateGeneric()
+}
+
+// Subtract sets v = a - b, and returns v.
+func (v *Element) Subtract(a, b *Element) *Element {
+ // We first add 2 * p, to guarantee the subtraction won't underflow, and
+ // then subtract b (which can be up to 2^255 + 2^13 * 19).
+ v.l0 = (a.l0 + 0xFFFFFFFFFFFDA) - b.l0
+ v.l1 = (a.l1 + 0xFFFFFFFFFFFFE) - b.l1
+ v.l2 = (a.l2 + 0xFFFFFFFFFFFFE) - b.l2
+ v.l3 = (a.l3 + 0xFFFFFFFFFFFFE) - b.l3
+ v.l4 = (a.l4 + 0xFFFFFFFFFFFFE) - b.l4
+ return v.carryPropagate()
+}
+
+// Negate sets v = -a, and returns v.
+func (v *Element) Negate(a *Element) *Element {
+ return v.Subtract(feZero, a)
+}
+
+// Invert sets v = 1/z mod p, and returns v.
+//
+// If z == 0, Invert returns v = 0.
+func (v *Element) Invert(z *Element) *Element {
+ // Inversion is implemented as exponentiation with exponent p − 2. It uses the
+ // same sequence of 255 squarings and 11 multiplications as [Curve25519].
+ var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t Element
+
+ z2.Square(z) // 2
+ t.Square(&z2) // 4
+ t.Square(&t) // 8
+ z9.Multiply(&t, z) // 9
+ z11.Multiply(&z9, &z2) // 11
+ t.Square(&z11) // 22
+ z2_5_0.Multiply(&t, &z9) // 31 = 2^5 - 2^0
+
+ t.Square(&z2_5_0) // 2^6 - 2^1
+ for i := 0; i < 4; i++ {
+ t.Square(&t) // 2^10 - 2^5
+ }
+ z2_10_0.Multiply(&t, &z2_5_0) // 2^10 - 2^0
+
+ t.Square(&z2_10_0) // 2^11 - 2^1
+ for i := 0; i < 9; i++ {
+ t.Square(&t) // 2^20 - 2^10
+ }
+ z2_20_0.Multiply(&t, &z2_10_0) // 2^20 - 2^0
+
+ t.Square(&z2_20_0) // 2^21 - 2^1
+ for i := 0; i < 19; i++ {
+ t.Square(&t) // 2^40 - 2^20
+ }
+ t.Multiply(&t, &z2_20_0) // 2^40 - 2^0
+
+ t.Square(&t) // 2^41 - 2^1
+ for i := 0; i < 9; i++ {
+ t.Square(&t) // 2^50 - 2^10
+ }
+ z2_50_0.Multiply(&t, &z2_10_0) // 2^50 - 2^0
+
+ t.Square(&z2_50_0) // 2^51 - 2^1
+ for i := 0; i < 49; i++ {
+ t.Square(&t) // 2^100 - 2^50
+ }
+ z2_100_0.Multiply(&t, &z2_50_0) // 2^100 - 2^0
+
+ t.Square(&z2_100_0) // 2^101 - 2^1
+ for i := 0; i < 99; i++ {
+ t.Square(&t) // 2^200 - 2^100
+ }
+ t.Multiply(&t, &z2_100_0) // 2^200 - 2^0
+
+ t.Square(&t) // 2^201 - 2^1
+ for i := 0; i < 49; i++ {
+ t.Square(&t) // 2^250 - 2^50
+ }
+ t.Multiply(&t, &z2_50_0) // 2^250 - 2^0
+
+ t.Square(&t) // 2^251 - 2^1
+ t.Square(&t) // 2^252 - 2^2
+ t.Square(&t) // 2^253 - 2^3
+ t.Square(&t) // 2^254 - 2^4
+ t.Square(&t) // 2^255 - 2^5
+
+ return v.Multiply(&t, &z11) // 2^255 - 21
+}
+
+// Set sets v = a, and returns v.
+func (v *Element) Set(a *Element) *Element {
+ *v = *a
+ return v
+}
+
+// SetBytes sets v to x, where x is a 32-byte little-endian encoding. If x is
+// not of the right length, SetBytes returns nil and an error, and the
+// receiver is unchanged.
+//
+// Consistent with RFC 7748, the most significant bit (the high bit of the
+// last byte) is ignored, and non-canonical values (2^255-19 through 2^255-1)
+// are accepted. Note that this is laxer than specified by RFC 8032, but
+// consistent with most Ed25519 implementations.
+func (v *Element) SetBytes(x []byte) (*Element, error) {
+ if len(x) != 32 {
+ return nil, errors.New("edwards25519: invalid field element input size")
+ }
+
+ // Bits 0:51 (bytes 0:8, bits 0:64, shift 0, mask 51).
+ v.l0 = binary.LittleEndian.Uint64(x[0:8])
+ v.l0 &= maskLow51Bits
+ // Bits 51:102 (bytes 6:14, bits 48:112, shift 3, mask 51).
+ v.l1 = binary.LittleEndian.Uint64(x[6:14]) >> 3
+ v.l1 &= maskLow51Bits
+ // Bits 102:153 (bytes 12:20, bits 96:160, shift 6, mask 51).
+ v.l2 = binary.LittleEndian.Uint64(x[12:20]) >> 6
+ v.l2 &= maskLow51Bits
+ // Bits 153:204 (bytes 19:27, bits 152:216, shift 1, mask 51).
+ v.l3 = binary.LittleEndian.Uint64(x[19:27]) >> 1
+ v.l3 &= maskLow51Bits
+ // Bits 204:255 (bytes 24:32, bits 192:256, shift 12, mask 51).
+ // Note: not bytes 25:33, shift 4, to avoid overread.
+ v.l4 = binary.LittleEndian.Uint64(x[24:32]) >> 12
+ v.l4 &= maskLow51Bits
+
+ return v, nil
+}
+
+// Bytes returns the canonical 32-byte little-endian encoding of v.
+func (v *Element) Bytes() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [32]byte
+ return v.bytes(&out)
+}
+
+func (v *Element) bytes(out *[32]byte) []byte {
+ t := *v
+ t.reduce()
+
+ var buf [8]byte
+ for i, l := range [5]uint64{t.l0, t.l1, t.l2, t.l3, t.l4} {
+ bitsOffset := i * 51
+ binary.LittleEndian.PutUint64(buf[:], l<= len(out) {
+ break
+ }
+ out[off] |= bb
+ }
+ }
+
+ return out[:]
+}
+
+// Equal returns 1 if v and u are equal, and 0 otherwise.
+func (v *Element) Equal(u *Element) int {
+ sa, sv := u.Bytes(), v.Bytes()
+ return subtle.ConstantTimeCompare(sa, sv)
+}
+
+// mask64Bits returns 0xffffffff if cond is 1, and 0 otherwise.
+func mask64Bits(cond int) uint64 { return ^(uint64(cond) - 1) }
+
+// Select sets v to a if cond == 1, and to b if cond == 0.
+func (v *Element) Select(a, b *Element, cond int) *Element {
+ m := mask64Bits(cond)
+ v.l0 = (m & a.l0) | (^m & b.l0)
+ v.l1 = (m & a.l1) | (^m & b.l1)
+ v.l2 = (m & a.l2) | (^m & b.l2)
+ v.l3 = (m & a.l3) | (^m & b.l3)
+ v.l4 = (m & a.l4) | (^m & b.l4)
+ return v
+}
+
+// Swap swaps v and u if cond == 1 or leaves them unchanged if cond == 0, and returns v.
+func (v *Element) Swap(u *Element, cond int) {
+ m := mask64Bits(cond)
+ t := m & (v.l0 ^ u.l0)
+ v.l0 ^= t
+ u.l0 ^= t
+ t = m & (v.l1 ^ u.l1)
+ v.l1 ^= t
+ u.l1 ^= t
+ t = m & (v.l2 ^ u.l2)
+ v.l2 ^= t
+ u.l2 ^= t
+ t = m & (v.l3 ^ u.l3)
+ v.l3 ^= t
+ u.l3 ^= t
+ t = m & (v.l4 ^ u.l4)
+ v.l4 ^= t
+ u.l4 ^= t
+}
+
+// IsNegative returns 1 if v is negative, and 0 otherwise.
+func (v *Element) IsNegative() int {
+ return int(v.Bytes()[0] & 1)
+}
+
+// Absolute sets v to |u|, and returns v.
+func (v *Element) Absolute(u *Element) *Element {
+ return v.Select(new(Element).Negate(u), u, u.IsNegative())
+}
+
+// Multiply sets v = x * y, and returns v.
+func (v *Element) Multiply(x, y *Element) *Element {
+ feMul(v, x, y)
+ return v
+}
+
+// Square sets v = x * x, and returns v.
+func (v *Element) Square(x *Element) *Element {
+ feSquare(v, x)
+ return v
+}
+
+// Mult32 sets v = x * y, and returns v.
+func (v *Element) Mult32(x *Element, y uint32) *Element {
+ x0lo, x0hi := mul51(x.l0, y)
+ x1lo, x1hi := mul51(x.l1, y)
+ x2lo, x2hi := mul51(x.l2, y)
+ x3lo, x3hi := mul51(x.l3, y)
+ x4lo, x4hi := mul51(x.l4, y)
+ v.l0 = x0lo + 19*x4hi // carried over per the reduction identity
+ v.l1 = x1lo + x0hi
+ v.l2 = x2lo + x1hi
+ v.l3 = x3lo + x2hi
+ v.l4 = x4lo + x3hi
+ // The hi portions are going to be only 32 bits, plus any previous excess,
+ // so we can skip the carry propagation.
+ return v
+}
+
+// mul51 returns lo + hi * 2⁵¹ = a * b.
+func mul51(a uint64, b uint32) (lo uint64, hi uint64) {
+ mh, ml := bits.Mul64(a, uint64(b))
+ lo = ml & maskLow51Bits
+ hi = (mh << 13) | (ml >> 51)
+ return
+}
+
+// Pow22523 set v = x^((p-5)/8), and returns v. (p-5)/8 is 2^252-3.
+func (v *Element) Pow22523(x *Element) *Element {
+ var t0, t1, t2 Element
+
+ t0.Square(x) // x^2
+ t1.Square(&t0) // x^4
+ t1.Square(&t1) // x^8
+ t1.Multiply(x, &t1) // x^9
+ t0.Multiply(&t0, &t1) // x^11
+ t0.Square(&t0) // x^22
+ t0.Multiply(&t1, &t0) // x^31
+ t1.Square(&t0) // x^62
+ for i := 1; i < 5; i++ { // x^992
+ t1.Square(&t1)
+ }
+ t0.Multiply(&t1, &t0) // x^1023 -> 1023 = 2^10 - 1
+ t1.Square(&t0) // 2^11 - 2
+ for i := 1; i < 10; i++ { // 2^20 - 2^10
+ t1.Square(&t1)
+ }
+ t1.Multiply(&t1, &t0) // 2^20 - 1
+ t2.Square(&t1) // 2^21 - 2
+ for i := 1; i < 20; i++ { // 2^40 - 2^20
+ t2.Square(&t2)
+ }
+ t1.Multiply(&t2, &t1) // 2^40 - 1
+ t1.Square(&t1) // 2^41 - 2
+ for i := 1; i < 10; i++ { // 2^50 - 2^10
+ t1.Square(&t1)
+ }
+ t0.Multiply(&t1, &t0) // 2^50 - 1
+ t1.Square(&t0) // 2^51 - 2
+ for i := 1; i < 50; i++ { // 2^100 - 2^50
+ t1.Square(&t1)
+ }
+ t1.Multiply(&t1, &t0) // 2^100 - 1
+ t2.Square(&t1) // 2^101 - 2
+ for i := 1; i < 100; i++ { // 2^200 - 2^100
+ t2.Square(&t2)
+ }
+ t1.Multiply(&t2, &t1) // 2^200 - 1
+ t1.Square(&t1) // 2^201 - 2
+ for i := 1; i < 50; i++ { // 2^250 - 2^50
+ t1.Square(&t1)
+ }
+ t0.Multiply(&t1, &t0) // 2^250 - 1
+ t0.Square(&t0) // 2^251 - 2
+ t0.Square(&t0) // 2^252 - 4
+ return v.Multiply(&t0, x) // 2^252 - 3 -> x^(2^252-3)
+}
+
+// sqrtM1 is 2^((p-1)/4), which squared is equal to -1 by Euler's Criterion.
+var sqrtM1 = &Element{1718705420411056, 234908883556509,
+ 2233514472574048, 2117202627021982, 765476049583133}
+
+// SqrtRatio sets r to the non-negative square root of the ratio of u and v.
+//
+// If u/v is square, SqrtRatio returns r and 1. If u/v is not square, SqrtRatio
+// sets r according to Section 4.3 of draft-irtf-cfrg-ristretto255-decaf448-00,
+// and returns r and 0.
+func (r *Element) SqrtRatio(u, v *Element) (R *Element, wasSquare int) {
+ t0 := new(Element)
+
+ // r = (u * v3) * (u * v7)^((p-5)/8)
+ v2 := new(Element).Square(v)
+ uv3 := new(Element).Multiply(u, t0.Multiply(v2, v))
+ uv7 := new(Element).Multiply(uv3, t0.Square(v2))
+ rr := new(Element).Multiply(uv3, t0.Pow22523(uv7))
+
+ check := new(Element).Multiply(v, t0.Square(rr)) // check = v * r^2
+
+ uNeg := new(Element).Negate(u)
+ correctSignSqrt := check.Equal(u)
+ flippedSignSqrt := check.Equal(uNeg)
+ flippedSignSqrtI := check.Equal(t0.Multiply(uNeg, sqrtM1))
+
+ rPrime := new(Element).Multiply(rr, sqrtM1) // r_prime = SQRT_M1 * r
+ // r = CT_SELECT(r_prime IF flipped_sign_sqrt | flipped_sign_sqrt_i ELSE r)
+ rr.Select(rPrime, rr, flippedSignSqrt|flippedSignSqrtI)
+
+ r.Absolute(rr) // Choose the nonnegative square root.
+ return r, correctSignSqrt | flippedSignSqrt
+}
diff --git a/vendor/filippo.io/edwards25519/field/fe_amd64.go b/vendor/filippo.io/edwards25519/field/fe_amd64.go
new file mode 100644
index 00000000..edcf163c
--- /dev/null
+++ b/vendor/filippo.io/edwards25519/field/fe_amd64.go
@@ -0,0 +1,16 @@
+// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
+
+//go:build amd64 && gc && !purego
+// +build amd64,gc,!purego
+
+package field
+
+// feMul sets out = a * b. It works like feMulGeneric.
+//
+//go:noescape
+func feMul(out *Element, a *Element, b *Element)
+
+// feSquare sets out = a * a. It works like feSquareGeneric.
+//
+//go:noescape
+func feSquare(out *Element, a *Element)
diff --git a/vendor/filippo.io/edwards25519/field/fe_amd64.s b/vendor/filippo.io/edwards25519/field/fe_amd64.s
new file mode 100644
index 00000000..293f013c
--- /dev/null
+++ b/vendor/filippo.io/edwards25519/field/fe_amd64.s
@@ -0,0 +1,379 @@
+// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
+
+//go:build amd64 && gc && !purego
+// +build amd64,gc,!purego
+
+#include "textflag.h"
+
+// func feMul(out *Element, a *Element, b *Element)
+TEXT ·feMul(SB), NOSPLIT, $0-24
+ MOVQ a+8(FP), CX
+ MOVQ b+16(FP), BX
+
+ // r0 = a0×b0
+ MOVQ (CX), AX
+ MULQ (BX)
+ MOVQ AX, DI
+ MOVQ DX, SI
+
+ // r0 += 19×a1×b4
+ MOVQ 8(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 32(BX)
+ ADDQ AX, DI
+ ADCQ DX, SI
+
+ // r0 += 19×a2×b3
+ MOVQ 16(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 24(BX)
+ ADDQ AX, DI
+ ADCQ DX, SI
+
+ // r0 += 19×a3×b2
+ MOVQ 24(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 16(BX)
+ ADDQ AX, DI
+ ADCQ DX, SI
+
+ // r0 += 19×a4×b1
+ MOVQ 32(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 8(BX)
+ ADDQ AX, DI
+ ADCQ DX, SI
+
+ // r1 = a0×b1
+ MOVQ (CX), AX
+ MULQ 8(BX)
+ MOVQ AX, R9
+ MOVQ DX, R8
+
+ // r1 += a1×b0
+ MOVQ 8(CX), AX
+ MULQ (BX)
+ ADDQ AX, R9
+ ADCQ DX, R8
+
+ // r1 += 19×a2×b4
+ MOVQ 16(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 32(BX)
+ ADDQ AX, R9
+ ADCQ DX, R8
+
+ // r1 += 19×a3×b3
+ MOVQ 24(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 24(BX)
+ ADDQ AX, R9
+ ADCQ DX, R8
+
+ // r1 += 19×a4×b2
+ MOVQ 32(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 16(BX)
+ ADDQ AX, R9
+ ADCQ DX, R8
+
+ // r2 = a0×b2
+ MOVQ (CX), AX
+ MULQ 16(BX)
+ MOVQ AX, R11
+ MOVQ DX, R10
+
+ // r2 += a1×b1
+ MOVQ 8(CX), AX
+ MULQ 8(BX)
+ ADDQ AX, R11
+ ADCQ DX, R10
+
+ // r2 += a2×b0
+ MOVQ 16(CX), AX
+ MULQ (BX)
+ ADDQ AX, R11
+ ADCQ DX, R10
+
+ // r2 += 19×a3×b4
+ MOVQ 24(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 32(BX)
+ ADDQ AX, R11
+ ADCQ DX, R10
+
+ // r2 += 19×a4×b3
+ MOVQ 32(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 24(BX)
+ ADDQ AX, R11
+ ADCQ DX, R10
+
+ // r3 = a0×b3
+ MOVQ (CX), AX
+ MULQ 24(BX)
+ MOVQ AX, R13
+ MOVQ DX, R12
+
+ // r3 += a1×b2
+ MOVQ 8(CX), AX
+ MULQ 16(BX)
+ ADDQ AX, R13
+ ADCQ DX, R12
+
+ // r3 += a2×b1
+ MOVQ 16(CX), AX
+ MULQ 8(BX)
+ ADDQ AX, R13
+ ADCQ DX, R12
+
+ // r3 += a3×b0
+ MOVQ 24(CX), AX
+ MULQ (BX)
+ ADDQ AX, R13
+ ADCQ DX, R12
+
+ // r3 += 19×a4×b4
+ MOVQ 32(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 32(BX)
+ ADDQ AX, R13
+ ADCQ DX, R12
+
+ // r4 = a0×b4
+ MOVQ (CX), AX
+ MULQ 32(BX)
+ MOVQ AX, R15
+ MOVQ DX, R14
+
+ // r4 += a1×b3
+ MOVQ 8(CX), AX
+ MULQ 24(BX)
+ ADDQ AX, R15
+ ADCQ DX, R14
+
+ // r4 += a2×b2
+ MOVQ 16(CX), AX
+ MULQ 16(BX)
+ ADDQ AX, R15
+ ADCQ DX, R14
+
+ // r4 += a3×b1
+ MOVQ 24(CX), AX
+ MULQ 8(BX)
+ ADDQ AX, R15
+ ADCQ DX, R14
+
+ // r4 += a4×b0
+ MOVQ 32(CX), AX
+ MULQ (BX)
+ ADDQ AX, R15
+ ADCQ DX, R14
+
+ // First reduction chain
+ MOVQ $0x0007ffffffffffff, AX
+ SHLQ $0x0d, DI, SI
+ SHLQ $0x0d, R9, R8
+ SHLQ $0x0d, R11, R10
+ SHLQ $0x0d, R13, R12
+ SHLQ $0x0d, R15, R14
+ ANDQ AX, DI
+ IMUL3Q $0x13, R14, R14
+ ADDQ R14, DI
+ ANDQ AX, R9
+ ADDQ SI, R9
+ ANDQ AX, R11
+ ADDQ R8, R11
+ ANDQ AX, R13
+ ADDQ R10, R13
+ ANDQ AX, R15
+ ADDQ R12, R15
+
+ // Second reduction chain (carryPropagate)
+ MOVQ DI, SI
+ SHRQ $0x33, SI
+ MOVQ R9, R8
+ SHRQ $0x33, R8
+ MOVQ R11, R10
+ SHRQ $0x33, R10
+ MOVQ R13, R12
+ SHRQ $0x33, R12
+ MOVQ R15, R14
+ SHRQ $0x33, R14
+ ANDQ AX, DI
+ IMUL3Q $0x13, R14, R14
+ ADDQ R14, DI
+ ANDQ AX, R9
+ ADDQ SI, R9
+ ANDQ AX, R11
+ ADDQ R8, R11
+ ANDQ AX, R13
+ ADDQ R10, R13
+ ANDQ AX, R15
+ ADDQ R12, R15
+
+ // Store output
+ MOVQ out+0(FP), AX
+ MOVQ DI, (AX)
+ MOVQ R9, 8(AX)
+ MOVQ R11, 16(AX)
+ MOVQ R13, 24(AX)
+ MOVQ R15, 32(AX)
+ RET
+
+// func feSquare(out *Element, a *Element)
+TEXT ·feSquare(SB), NOSPLIT, $0-16
+ MOVQ a+8(FP), CX
+
+ // r0 = l0×l0
+ MOVQ (CX), AX
+ MULQ (CX)
+ MOVQ AX, SI
+ MOVQ DX, BX
+
+ // r0 += 38×l1×l4
+ MOVQ 8(CX), AX
+ IMUL3Q $0x26, AX, AX
+ MULQ 32(CX)
+ ADDQ AX, SI
+ ADCQ DX, BX
+
+ // r0 += 38×l2×l3
+ MOVQ 16(CX), AX
+ IMUL3Q $0x26, AX, AX
+ MULQ 24(CX)
+ ADDQ AX, SI
+ ADCQ DX, BX
+
+ // r1 = 2×l0×l1
+ MOVQ (CX), AX
+ SHLQ $0x01, AX
+ MULQ 8(CX)
+ MOVQ AX, R8
+ MOVQ DX, DI
+
+ // r1 += 38×l2×l4
+ MOVQ 16(CX), AX
+ IMUL3Q $0x26, AX, AX
+ MULQ 32(CX)
+ ADDQ AX, R8
+ ADCQ DX, DI
+
+ // r1 += 19×l3×l3
+ MOVQ 24(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 24(CX)
+ ADDQ AX, R8
+ ADCQ DX, DI
+
+ // r2 = 2×l0×l2
+ MOVQ (CX), AX
+ SHLQ $0x01, AX
+ MULQ 16(CX)
+ MOVQ AX, R10
+ MOVQ DX, R9
+
+ // r2 += l1×l1
+ MOVQ 8(CX), AX
+ MULQ 8(CX)
+ ADDQ AX, R10
+ ADCQ DX, R9
+
+ // r2 += 38×l3×l4
+ MOVQ 24(CX), AX
+ IMUL3Q $0x26, AX, AX
+ MULQ 32(CX)
+ ADDQ AX, R10
+ ADCQ DX, R9
+
+ // r3 = 2×l0×l3
+ MOVQ (CX), AX
+ SHLQ $0x01, AX
+ MULQ 24(CX)
+ MOVQ AX, R12
+ MOVQ DX, R11
+
+ // r3 += 2×l1×l2
+ MOVQ 8(CX), AX
+ IMUL3Q $0x02, AX, AX
+ MULQ 16(CX)
+ ADDQ AX, R12
+ ADCQ DX, R11
+
+ // r3 += 19×l4×l4
+ MOVQ 32(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 32(CX)
+ ADDQ AX, R12
+ ADCQ DX, R11
+
+ // r4 = 2×l0×l4
+ MOVQ (CX), AX
+ SHLQ $0x01, AX
+ MULQ 32(CX)
+ MOVQ AX, R14
+ MOVQ DX, R13
+
+ // r4 += 2×l1×l3
+ MOVQ 8(CX), AX
+ IMUL3Q $0x02, AX, AX
+ MULQ 24(CX)
+ ADDQ AX, R14
+ ADCQ DX, R13
+
+ // r4 += l2×l2
+ MOVQ 16(CX), AX
+ MULQ 16(CX)
+ ADDQ AX, R14
+ ADCQ DX, R13
+
+ // First reduction chain
+ MOVQ $0x0007ffffffffffff, AX
+ SHLQ $0x0d, SI, BX
+ SHLQ $0x0d, R8, DI
+ SHLQ $0x0d, R10, R9
+ SHLQ $0x0d, R12, R11
+ SHLQ $0x0d, R14, R13
+ ANDQ AX, SI
+ IMUL3Q $0x13, R13, R13
+ ADDQ R13, SI
+ ANDQ AX, R8
+ ADDQ BX, R8
+ ANDQ AX, R10
+ ADDQ DI, R10
+ ANDQ AX, R12
+ ADDQ R9, R12
+ ANDQ AX, R14
+ ADDQ R11, R14
+
+ // Second reduction chain (carryPropagate)
+ MOVQ SI, BX
+ SHRQ $0x33, BX
+ MOVQ R8, DI
+ SHRQ $0x33, DI
+ MOVQ R10, R9
+ SHRQ $0x33, R9
+ MOVQ R12, R11
+ SHRQ $0x33, R11
+ MOVQ R14, R13
+ SHRQ $0x33, R13
+ ANDQ AX, SI
+ IMUL3Q $0x13, R13, R13
+ ADDQ R13, SI
+ ANDQ AX, R8
+ ADDQ BX, R8
+ ANDQ AX, R10
+ ADDQ DI, R10
+ ANDQ AX, R12
+ ADDQ R9, R12
+ ANDQ AX, R14
+ ADDQ R11, R14
+
+ // Store output
+ MOVQ out+0(FP), AX
+ MOVQ SI, (AX)
+ MOVQ R8, 8(AX)
+ MOVQ R10, 16(AX)
+ MOVQ R12, 24(AX)
+ MOVQ R14, 32(AX)
+ RET
diff --git a/vendor/filippo.io/edwards25519/field/fe_amd64_noasm.go b/vendor/filippo.io/edwards25519/field/fe_amd64_noasm.go
new file mode 100644
index 00000000..ddb6c9b8
--- /dev/null
+++ b/vendor/filippo.io/edwards25519/field/fe_amd64_noasm.go
@@ -0,0 +1,12 @@
+// Copyright (c) 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !amd64 || !gc || purego
+// +build !amd64 !gc purego
+
+package field
+
+func feMul(v, x, y *Element) { feMulGeneric(v, x, y) }
+
+func feSquare(v, x *Element) { feSquareGeneric(v, x) }
diff --git a/vendor/filippo.io/edwards25519/field/fe_arm64.go b/vendor/filippo.io/edwards25519/field/fe_arm64.go
new file mode 100644
index 00000000..af459ef5
--- /dev/null
+++ b/vendor/filippo.io/edwards25519/field/fe_arm64.go
@@ -0,0 +1,16 @@
+// Copyright (c) 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build arm64 && gc && !purego
+// +build arm64,gc,!purego
+
+package field
+
+//go:noescape
+func carryPropagate(v *Element)
+
+func (v *Element) carryPropagate() *Element {
+ carryPropagate(v)
+ return v
+}
diff --git a/vendor/filippo.io/edwards25519/field/fe_arm64.s b/vendor/filippo.io/edwards25519/field/fe_arm64.s
new file mode 100644
index 00000000..3126a434
--- /dev/null
+++ b/vendor/filippo.io/edwards25519/field/fe_arm64.s
@@ -0,0 +1,42 @@
+// Copyright (c) 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build arm64 && gc && !purego
+
+#include "textflag.h"
+
+// carryPropagate works exactly like carryPropagateGeneric and uses the
+// same AND, ADD, and LSR+MADD instructions emitted by the compiler, but
+// avoids loading R0-R4 twice and uses LDP and STP.
+//
+// See https://golang.org/issues/43145 for the main compiler issue.
+//
+// func carryPropagate(v *Element)
+TEXT ·carryPropagate(SB),NOFRAME|NOSPLIT,$0-8
+ MOVD v+0(FP), R20
+
+ LDP 0(R20), (R0, R1)
+ LDP 16(R20), (R2, R3)
+ MOVD 32(R20), R4
+
+ AND $0x7ffffffffffff, R0, R10
+ AND $0x7ffffffffffff, R1, R11
+ AND $0x7ffffffffffff, R2, R12
+ AND $0x7ffffffffffff, R3, R13
+ AND $0x7ffffffffffff, R4, R14
+
+ ADD R0>>51, R11, R11
+ ADD R1>>51, R12, R12
+ ADD R2>>51, R13, R13
+ ADD R3>>51, R14, R14
+ // R4>>51 * 19 + R10 -> R10
+ LSR $51, R4, R21
+ MOVD $19, R22
+ MADD R22, R10, R21, R10
+
+ STP (R10, R11), 0(R20)
+ STP (R12, R13), 16(R20)
+ MOVD R14, 32(R20)
+
+ RET
diff --git a/vendor/filippo.io/edwards25519/field/fe_arm64_noasm.go b/vendor/filippo.io/edwards25519/field/fe_arm64_noasm.go
new file mode 100644
index 00000000..234a5b2e
--- /dev/null
+++ b/vendor/filippo.io/edwards25519/field/fe_arm64_noasm.go
@@ -0,0 +1,12 @@
+// Copyright (c) 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !arm64 || !gc || purego
+// +build !arm64 !gc purego
+
+package field
+
+func (v *Element) carryPropagate() *Element {
+ return v.carryPropagateGeneric()
+}
diff --git a/vendor/filippo.io/edwards25519/field/fe_extra.go b/vendor/filippo.io/edwards25519/field/fe_extra.go
new file mode 100644
index 00000000..1ef503b9
--- /dev/null
+++ b/vendor/filippo.io/edwards25519/field/fe_extra.go
@@ -0,0 +1,50 @@
+// Copyright (c) 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package field
+
+import "errors"
+
+// This file contains additional functionality that is not included in the
+// upstream crypto/ed25519/edwards25519/field package.
+
+// SetWideBytes sets v to x, where x is a 64-byte little-endian encoding, which
+// is reduced modulo the field order. If x is not of the right length,
+// SetWideBytes returns nil and an error, and the receiver is unchanged.
+//
+// SetWideBytes is not necessary to select a uniformly distributed value, and is
+// only provided for compatibility: SetBytes can be used instead as the chance
+// of bias is less than 2⁻²⁵⁰.
+func (v *Element) SetWideBytes(x []byte) (*Element, error) {
+ if len(x) != 64 {
+ return nil, errors.New("edwards25519: invalid SetWideBytes input size")
+ }
+
+ // Split the 64 bytes into two elements, and extract the most significant
+ // bit of each, which is ignored by SetBytes.
+ lo, _ := new(Element).SetBytes(x[:32])
+ loMSB := uint64(x[31] >> 7)
+ hi, _ := new(Element).SetBytes(x[32:])
+ hiMSB := uint64(x[63] >> 7)
+
+ // The output we want is
+ //
+ // v = lo + loMSB * 2²⁵⁵ + hi * 2²⁵⁶ + hiMSB * 2⁵¹¹
+ //
+ // which applying the reduction identity comes out to
+ //
+ // v = lo + loMSB * 19 + hi * 2 * 19 + hiMSB * 2 * 19²
+ //
+ // l0 will be the sum of a 52 bits value (lo.l0), plus a 5 bits value
+ // (loMSB * 19), a 6 bits value (hi.l0 * 2 * 19), and a 10 bits value
+ // (hiMSB * 2 * 19²), so it fits in a uint64.
+
+ v.l0 = lo.l0 + loMSB*19 + hi.l0*2*19 + hiMSB*2*19*19
+ v.l1 = lo.l1 + hi.l1*2*19
+ v.l2 = lo.l2 + hi.l2*2*19
+ v.l3 = lo.l3 + hi.l3*2*19
+ v.l4 = lo.l4 + hi.l4*2*19
+
+ return v.carryPropagate(), nil
+}
diff --git a/vendor/filippo.io/edwards25519/field/fe_generic.go b/vendor/filippo.io/edwards25519/field/fe_generic.go
new file mode 100644
index 00000000..86f5fd95
--- /dev/null
+++ b/vendor/filippo.io/edwards25519/field/fe_generic.go
@@ -0,0 +1,266 @@
+// Copyright (c) 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package field
+
+import "math/bits"
+
+// uint128 holds a 128-bit number as two 64-bit limbs, for use with the
+// bits.Mul64 and bits.Add64 intrinsics.
+type uint128 struct {
+ lo, hi uint64
+}
+
+// mul64 returns a * b.
+func mul64(a, b uint64) uint128 {
+ hi, lo := bits.Mul64(a, b)
+ return uint128{lo, hi}
+}
+
+// addMul64 returns v + a * b.
+func addMul64(v uint128, a, b uint64) uint128 {
+ hi, lo := bits.Mul64(a, b)
+ lo, c := bits.Add64(lo, v.lo, 0)
+ hi, _ = bits.Add64(hi, v.hi, c)
+ return uint128{lo, hi}
+}
+
+// shiftRightBy51 returns a >> 51. a is assumed to be at most 115 bits.
+func shiftRightBy51(a uint128) uint64 {
+ return (a.hi << (64 - 51)) | (a.lo >> 51)
+}
+
+func feMulGeneric(v, a, b *Element) {
+ a0 := a.l0
+ a1 := a.l1
+ a2 := a.l2
+ a3 := a.l3
+ a4 := a.l4
+
+ b0 := b.l0
+ b1 := b.l1
+ b2 := b.l2
+ b3 := b.l3
+ b4 := b.l4
+
+ // Limb multiplication works like pen-and-paper columnar multiplication, but
+ // with 51-bit limbs instead of digits.
+ //
+ // a4 a3 a2 a1 a0 x
+ // b4 b3 b2 b1 b0 =
+ // ------------------------
+ // a4b0 a3b0 a2b0 a1b0 a0b0 +
+ // a4b1 a3b1 a2b1 a1b1 a0b1 +
+ // a4b2 a3b2 a2b2 a1b2 a0b2 +
+ // a4b3 a3b3 a2b3 a1b3 a0b3 +
+ // a4b4 a3b4 a2b4 a1b4 a0b4 =
+ // ----------------------------------------------
+ // r8 r7 r6 r5 r4 r3 r2 r1 r0
+ //
+ // We can then use the reduction identity (a * 2²⁵⁵ + b = a * 19 + b) to
+ // reduce the limbs that would overflow 255 bits. r5 * 2²⁵⁵ becomes 19 * r5,
+ // r6 * 2³⁰⁶ becomes 19 * r6 * 2⁵¹, etc.
+ //
+ // Reduction can be carried out simultaneously to multiplication. For
+ // example, we do not compute r5: whenever the result of a multiplication
+ // belongs to r5, like a1b4, we multiply it by 19 and add the result to r0.
+ //
+ // a4b0 a3b0 a2b0 a1b0 a0b0 +
+ // a3b1 a2b1 a1b1 a0b1 19×a4b1 +
+ // a2b2 a1b2 a0b2 19×a4b2 19×a3b2 +
+ // a1b3 a0b3 19×a4b3 19×a3b3 19×a2b3 +
+ // a0b4 19×a4b4 19×a3b4 19×a2b4 19×a1b4 =
+ // --------------------------------------
+ // r4 r3 r2 r1 r0
+ //
+ // Finally we add up the columns into wide, overlapping limbs.
+
+ a1_19 := a1 * 19
+ a2_19 := a2 * 19
+ a3_19 := a3 * 19
+ a4_19 := a4 * 19
+
+ // r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
+ r0 := mul64(a0, b0)
+ r0 = addMul64(r0, a1_19, b4)
+ r0 = addMul64(r0, a2_19, b3)
+ r0 = addMul64(r0, a3_19, b2)
+ r0 = addMul64(r0, a4_19, b1)
+
+ // r1 = a0×b1 + a1×b0 + 19×(a2×b4 + a3×b3 + a4×b2)
+ r1 := mul64(a0, b1)
+ r1 = addMul64(r1, a1, b0)
+ r1 = addMul64(r1, a2_19, b4)
+ r1 = addMul64(r1, a3_19, b3)
+ r1 = addMul64(r1, a4_19, b2)
+
+ // r2 = a0×b2 + a1×b1 + a2×b0 + 19×(a3×b4 + a4×b3)
+ r2 := mul64(a0, b2)
+ r2 = addMul64(r2, a1, b1)
+ r2 = addMul64(r2, a2, b0)
+ r2 = addMul64(r2, a3_19, b4)
+ r2 = addMul64(r2, a4_19, b3)
+
+ // r3 = a0×b3 + a1×b2 + a2×b1 + a3×b0 + 19×a4×b4
+ r3 := mul64(a0, b3)
+ r3 = addMul64(r3, a1, b2)
+ r3 = addMul64(r3, a2, b1)
+ r3 = addMul64(r3, a3, b0)
+ r3 = addMul64(r3, a4_19, b4)
+
+ // r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
+ r4 := mul64(a0, b4)
+ r4 = addMul64(r4, a1, b3)
+ r4 = addMul64(r4, a2, b2)
+ r4 = addMul64(r4, a3, b1)
+ r4 = addMul64(r4, a4, b0)
+
+ // After the multiplication, we need to reduce (carry) the five coefficients
+ // to obtain a result with limbs that are at most slightly larger than 2⁵¹,
+ // to respect the Element invariant.
+ //
+ // Overall, the reduction works the same as carryPropagate, except with
+ // wider inputs: we take the carry for each coefficient by shifting it right
+ // by 51, and add it to the limb above it. The top carry is multiplied by 19
+ // according to the reduction identity and added to the lowest limb.
+ //
+ // The largest coefficient (r0) will be at most 111 bits, which guarantees
+ // that all carries are at most 111 - 51 = 60 bits, which fits in a uint64.
+ //
+ // r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
+ // r0 < 2⁵²×2⁵² + 19×(2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵²)
+ // r0 < (1 + 19 × 4) × 2⁵² × 2⁵²
+ // r0 < 2⁷ × 2⁵² × 2⁵²
+ // r0 < 2¹¹¹
+ //
+ // Moreover, the top coefficient (r4) is at most 107 bits, so c4 is at most
+ // 56 bits, and c4 * 19 is at most 61 bits, which again fits in a uint64 and
+ // allows us to easily apply the reduction identity.
+ //
+ // r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
+ // r4 < 5 × 2⁵² × 2⁵²
+ // r4 < 2¹⁰⁷
+ //
+
+ c0 := shiftRightBy51(r0)
+ c1 := shiftRightBy51(r1)
+ c2 := shiftRightBy51(r2)
+ c3 := shiftRightBy51(r3)
+ c4 := shiftRightBy51(r4)
+
+ rr0 := r0.lo&maskLow51Bits + c4*19
+ rr1 := r1.lo&maskLow51Bits + c0
+ rr2 := r2.lo&maskLow51Bits + c1
+ rr3 := r3.lo&maskLow51Bits + c2
+ rr4 := r4.lo&maskLow51Bits + c3
+
+ // Now all coefficients fit into 64-bit registers but are still too large to
+ // be passed around as an Element. We therefore do one last carry chain,
+ // where the carries will be small enough to fit in the wiggle room above 2⁵¹.
+ *v = Element{rr0, rr1, rr2, rr3, rr4}
+ v.carryPropagate()
+}
+
+func feSquareGeneric(v, a *Element) {
+ l0 := a.l0
+ l1 := a.l1
+ l2 := a.l2
+ l3 := a.l3
+ l4 := a.l4
+
+ // Squaring works precisely like multiplication above, but thanks to its
+ // symmetry we get to group a few terms together.
+ //
+ // l4 l3 l2 l1 l0 x
+ // l4 l3 l2 l1 l0 =
+ // ------------------------
+ // l4l0 l3l0 l2l0 l1l0 l0l0 +
+ // l4l1 l3l1 l2l1 l1l1 l0l1 +
+ // l4l2 l3l2 l2l2 l1l2 l0l2 +
+ // l4l3 l3l3 l2l3 l1l3 l0l3 +
+ // l4l4 l3l4 l2l4 l1l4 l0l4 =
+ // ----------------------------------------------
+ // r8 r7 r6 r5 r4 r3 r2 r1 r0
+ //
+ // l4l0 l3l0 l2l0 l1l0 l0l0 +
+ // l3l1 l2l1 l1l1 l0l1 19×l4l1 +
+ // l2l2 l1l2 l0l2 19×l4l2 19×l3l2 +
+ // l1l3 l0l3 19×l4l3 19×l3l3 19×l2l3 +
+ // l0l4 19×l4l4 19×l3l4 19×l2l4 19×l1l4 =
+ // --------------------------------------
+ // r4 r3 r2 r1 r0
+ //
+ // With precomputed 2×, 19×, and 2×19× terms, we can compute each limb with
+ // only three Mul64 and four Add64, instead of five and eight.
+
+ l0_2 := l0 * 2
+ l1_2 := l1 * 2
+
+ l1_38 := l1 * 38
+ l2_38 := l2 * 38
+ l3_38 := l3 * 38
+
+ l3_19 := l3 * 19
+ l4_19 := l4 * 19
+
+ // r0 = l0×l0 + 19×(l1×l4 + l2×l3 + l3×l2 + l4×l1) = l0×l0 + 19×2×(l1×l4 + l2×l3)
+ r0 := mul64(l0, l0)
+ r0 = addMul64(r0, l1_38, l4)
+ r0 = addMul64(r0, l2_38, l3)
+
+ // r1 = l0×l1 + l1×l0 + 19×(l2×l4 + l3×l3 + l4×l2) = 2×l0×l1 + 19×2×l2×l4 + 19×l3×l3
+ r1 := mul64(l0_2, l1)
+ r1 = addMul64(r1, l2_38, l4)
+ r1 = addMul64(r1, l3_19, l3)
+
+ // r2 = l0×l2 + l1×l1 + l2×l0 + 19×(l3×l4 + l4×l3) = 2×l0×l2 + l1×l1 + 19×2×l3×l4
+ r2 := mul64(l0_2, l2)
+ r2 = addMul64(r2, l1, l1)
+ r2 = addMul64(r2, l3_38, l4)
+
+ // r3 = l0×l3 + l1×l2 + l2×l1 + l3×l0 + 19×l4×l4 = 2×l0×l3 + 2×l1×l2 + 19×l4×l4
+ r3 := mul64(l0_2, l3)
+ r3 = addMul64(r3, l1_2, l2)
+ r3 = addMul64(r3, l4_19, l4)
+
+ // r4 = l0×l4 + l1×l3 + l2×l2 + l3×l1 + l4×l0 = 2×l0×l4 + 2×l1×l3 + l2×l2
+ r4 := mul64(l0_2, l4)
+ r4 = addMul64(r4, l1_2, l3)
+ r4 = addMul64(r4, l2, l2)
+
+ c0 := shiftRightBy51(r0)
+ c1 := shiftRightBy51(r1)
+ c2 := shiftRightBy51(r2)
+ c3 := shiftRightBy51(r3)
+ c4 := shiftRightBy51(r4)
+
+ rr0 := r0.lo&maskLow51Bits + c4*19
+ rr1 := r1.lo&maskLow51Bits + c0
+ rr2 := r2.lo&maskLow51Bits + c1
+ rr3 := r3.lo&maskLow51Bits + c2
+ rr4 := r4.lo&maskLow51Bits + c3
+
+ *v = Element{rr0, rr1, rr2, rr3, rr4}
+ v.carryPropagate()
+}
+
+// carryPropagateGeneric brings the limbs below 52 bits by applying the reduction
+// identity (a * 2²⁵⁵ + b = a * 19 + b) to the l4 carry.
+func (v *Element) carryPropagateGeneric() *Element {
+ c0 := v.l0 >> 51
+ c1 := v.l1 >> 51
+ c2 := v.l2 >> 51
+ c3 := v.l3 >> 51
+ c4 := v.l4 >> 51
+
+ // c4 is at most 64 - 51 = 13 bits, so c4*19 is at most 18 bits, and
+ // the final l0 will be at most 52 bits. Similarly for the rest.
+ v.l0 = v.l0&maskLow51Bits + c4*19
+ v.l1 = v.l1&maskLow51Bits + c0
+ v.l2 = v.l2&maskLow51Bits + c1
+ v.l3 = v.l3&maskLow51Bits + c2
+ v.l4 = v.l4&maskLow51Bits + c3
+
+ return v
+}
diff --git a/vendor/filippo.io/edwards25519/scalar.go b/vendor/filippo.io/edwards25519/scalar.go
new file mode 100644
index 00000000..3fd16538
--- /dev/null
+++ b/vendor/filippo.io/edwards25519/scalar.go
@@ -0,0 +1,343 @@
+// Copyright (c) 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package edwards25519
+
+import (
+ "encoding/binary"
+ "errors"
+)
+
+// A Scalar is an integer modulo
+//
+// l = 2^252 + 27742317777372353535851937790883648493
+//
+// which is the prime order of the edwards25519 group.
+//
+// This type works similarly to math/big.Int, and all arguments and
+// receivers are allowed to alias.
+//
+// The zero value is a valid zero element.
+type Scalar struct {
+ // s is the scalar in the Montgomery domain, in the format of the
+ // fiat-crypto implementation.
+ s fiatScalarMontgomeryDomainFieldElement
+}
+
+// The field implementation in scalar_fiat.go is generated by the fiat-crypto
+// project (https://github.com/mit-plv/fiat-crypto) at version v0.0.9 (23d2dbc)
+// from a formally verified model.
+//
+// fiat-crypto code comes under the following license.
+//
+// Copyright (c) 2015-2020 The fiat-crypto Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design,
+// Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+// NewScalar returns a new zero Scalar.
+func NewScalar() *Scalar {
+ return &Scalar{}
+}
+
+// MultiplyAdd sets s = x * y + z mod l, and returns s. It is equivalent to
+// using Multiply and then Add.
+func (s *Scalar) MultiplyAdd(x, y, z *Scalar) *Scalar {
+ // Make a copy of z in case it aliases s.
+ zCopy := new(Scalar).Set(z)
+ return s.Multiply(x, y).Add(s, zCopy)
+}
+
+// Add sets s = x + y mod l, and returns s.
+func (s *Scalar) Add(x, y *Scalar) *Scalar {
+ // s = 1 * x + y mod l
+ fiatScalarAdd(&s.s, &x.s, &y.s)
+ return s
+}
+
+// Subtract sets s = x - y mod l, and returns s.
+func (s *Scalar) Subtract(x, y *Scalar) *Scalar {
+ // s = -1 * y + x mod l
+ fiatScalarSub(&s.s, &x.s, &y.s)
+ return s
+}
+
+// Negate sets s = -x mod l, and returns s.
+func (s *Scalar) Negate(x *Scalar) *Scalar {
+ // s = -1 * x + 0 mod l
+ fiatScalarOpp(&s.s, &x.s)
+ return s
+}
+
+// Multiply sets s = x * y mod l, and returns s.
+func (s *Scalar) Multiply(x, y *Scalar) *Scalar {
+ // s = x * y + 0 mod l
+ fiatScalarMul(&s.s, &x.s, &y.s)
+ return s
+}
+
+// Set sets s = x, and returns s.
+func (s *Scalar) Set(x *Scalar) *Scalar {
+ *s = *x
+ return s
+}
+
+// SetUniformBytes sets s = x mod l, where x is a 64-byte little-endian integer.
+// If x is not of the right length, SetUniformBytes returns nil and an error,
+// and the receiver is unchanged.
+//
+// SetUniformBytes can be used to set s to a uniformly distributed value given
+// 64 uniformly distributed random bytes.
+func (s *Scalar) SetUniformBytes(x []byte) (*Scalar, error) {
+ if len(x) != 64 {
+ return nil, errors.New("edwards25519: invalid SetUniformBytes input length")
+ }
+
+ // We have a value x of 512 bits, but our fiatScalarFromBytes function
+ // expects an input lower than l, which is a little over 252 bits.
+ //
+ // Instead of writing a reduction function that operates on wider inputs, we
+ // can interpret x as the sum of three shorter values a, b, and c.
+ //
+ // x = a + b * 2^168 + c * 2^336 mod l
+ //
+ // We then precompute 2^168 and 2^336 modulo l, and perform the reduction
+ // with two multiplications and two additions.
+
+ s.setShortBytes(x[:21])
+ t := new(Scalar).setShortBytes(x[21:42])
+ s.Add(s, t.Multiply(t, scalarTwo168))
+ t.setShortBytes(x[42:])
+ s.Add(s, t.Multiply(t, scalarTwo336))
+
+ return s, nil
+}
+
+// scalarTwo168 and scalarTwo336 are 2^168 and 2^336 modulo l, encoded as a
+// fiatScalarMontgomeryDomainFieldElement, which is a little-endian 4-limb value
+// in the 2^256 Montgomery domain.
+var scalarTwo168 = &Scalar{s: [4]uint64{0x5b8ab432eac74798, 0x38afddd6de59d5d7,
+ 0xa2c131b399411b7c, 0x6329a7ed9ce5a30}}
+var scalarTwo336 = &Scalar{s: [4]uint64{0xbd3d108e2b35ecc5, 0x5c3a3718bdf9c90b,
+ 0x63aa97a331b4f2ee, 0x3d217f5be65cb5c}}
+
+// setShortBytes sets s = x mod l, where x is a little-endian integer shorter
+// than 32 bytes.
+func (s *Scalar) setShortBytes(x []byte) *Scalar {
+ if len(x) >= 32 {
+ panic("edwards25519: internal error: setShortBytes called with a long string")
+ }
+ var buf [32]byte
+ copy(buf[:], x)
+ fiatScalarFromBytes((*[4]uint64)(&s.s), &buf)
+ fiatScalarToMontgomery(&s.s, (*fiatScalarNonMontgomeryDomainFieldElement)(&s.s))
+ return s
+}
+
+// SetCanonicalBytes sets s = x, where x is a 32-byte little-endian encoding of
+// s, and returns s. If x is not a canonical encoding of s, SetCanonicalBytes
+// returns nil and an error, and the receiver is unchanged.
+func (s *Scalar) SetCanonicalBytes(x []byte) (*Scalar, error) {
+ if len(x) != 32 {
+ return nil, errors.New("invalid scalar length")
+ }
+ if !isReduced(x) {
+ return nil, errors.New("invalid scalar encoding")
+ }
+
+ fiatScalarFromBytes((*[4]uint64)(&s.s), (*[32]byte)(x))
+ fiatScalarToMontgomery(&s.s, (*fiatScalarNonMontgomeryDomainFieldElement)(&s.s))
+
+ return s, nil
+}
+
+// scalarMinusOneBytes is l - 1 in little endian.
+var scalarMinusOneBytes = [32]byte{236, 211, 245, 92, 26, 99, 18, 88, 214, 156, 247, 162, 222, 249, 222, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16}
+
+// isReduced returns whether the given scalar in 32-byte little endian encoded
+// form is reduced modulo l.
+func isReduced(s []byte) bool {
+ if len(s) != 32 {
+ return false
+ }
+
+ for i := len(s) - 1; i >= 0; i-- {
+ switch {
+ case s[i] > scalarMinusOneBytes[i]:
+ return false
+ case s[i] < scalarMinusOneBytes[i]:
+ return true
+ }
+ }
+ return true
+}
+
+// SetBytesWithClamping applies the buffer pruning described in RFC 8032,
+// Section 5.1.5 (also known as clamping) and sets s to the result. The input
+// must be 32 bytes, and it is not modified. If x is not of the right length,
+// SetBytesWithClamping returns nil and an error, and the receiver is unchanged.
+//
+// Note that since Scalar values are always reduced modulo the prime order of
+// the curve, the resulting value will not preserve any of the cofactor-clearing
+// properties that clamping is meant to provide. It will however work as
+// expected as long as it is applied to points on the prime order subgroup, like
+// in Ed25519. In fact, it is lost to history why RFC 8032 adopted the
+// irrelevant RFC 7748 clamping, but it is now required for compatibility.
+func (s *Scalar) SetBytesWithClamping(x []byte) (*Scalar, error) {
+ // The description above omits the purpose of the high bits of the clamping
+ // for brevity, but those are also lost to reductions, and are also
+ // irrelevant to edwards25519 as they protect against a specific
+ // implementation bug that was once observed in a generic Montgomery ladder.
+ if len(x) != 32 {
+ return nil, errors.New("edwards25519: invalid SetBytesWithClamping input length")
+ }
+
+ // We need to use the wide reduction from SetUniformBytes, since clamping
+ // sets the 2^254 bit, making the value higher than the order.
+ var wideBytes [64]byte
+ copy(wideBytes[:], x[:])
+ wideBytes[0] &= 248
+ wideBytes[31] &= 63
+ wideBytes[31] |= 64
+ return s.SetUniformBytes(wideBytes[:])
+}
+
+// Bytes returns the canonical 32-byte little-endian encoding of s.
+func (s *Scalar) Bytes() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var encoded [32]byte
+ return s.bytes(&encoded)
+}
+
+func (s *Scalar) bytes(out *[32]byte) []byte {
+ var ss fiatScalarNonMontgomeryDomainFieldElement
+ fiatScalarFromMontgomery(&ss, &s.s)
+ fiatScalarToBytes(out, (*[4]uint64)(&ss))
+ return out[:]
+}
+
+// Equal returns 1 if s and t are equal, and 0 otherwise.
+func (s *Scalar) Equal(t *Scalar) int {
+ var diff fiatScalarMontgomeryDomainFieldElement
+ fiatScalarSub(&diff, &s.s, &t.s)
+ var nonzero uint64
+ fiatScalarNonzero(&nonzero, (*[4]uint64)(&diff))
+ nonzero |= nonzero >> 32
+ nonzero |= nonzero >> 16
+ nonzero |= nonzero >> 8
+ nonzero |= nonzero >> 4
+ nonzero |= nonzero >> 2
+ nonzero |= nonzero >> 1
+ return int(^nonzero) & 1
+}
+
+// nonAdjacentForm computes a width-w non-adjacent form for this scalar.
+//
+// w must be between 2 and 8, or nonAdjacentForm will panic.
+func (s *Scalar) nonAdjacentForm(w uint) [256]int8 {
+ // This implementation is adapted from the one
+ // in curve25519-dalek and is documented there:
+ // https://github.com/dalek-cryptography/curve25519-dalek/blob/f630041af28e9a405255f98a8a93adca18e4315b/src/scalar.rs#L800-L871
+ b := s.Bytes()
+ if b[31] > 127 {
+ panic("scalar has high bit set illegally")
+ }
+ if w < 2 {
+ panic("w must be at least 2 by the definition of NAF")
+ } else if w > 8 {
+ panic("NAF digits must fit in int8")
+ }
+
+ var naf [256]int8
+ var digits [5]uint64
+
+ for i := 0; i < 4; i++ {
+ digits[i] = binary.LittleEndian.Uint64(b[i*8:])
+ }
+
+ width := uint64(1 << w)
+ windowMask := uint64(width - 1)
+
+ pos := uint(0)
+ carry := uint64(0)
+ for pos < 256 {
+ indexU64 := pos / 64
+ indexBit := pos % 64
+ var bitBuf uint64
+ if indexBit < 64-w {
+ // This window's bits are contained in a single u64
+ bitBuf = digits[indexU64] >> indexBit
+ } else {
+ // Combine the current 64 bits with bits from the next 64
+ bitBuf = (digits[indexU64] >> indexBit) | (digits[1+indexU64] << (64 - indexBit))
+ }
+
+ // Add carry into the current window
+ window := carry + (bitBuf & windowMask)
+
+ if window&1 == 0 {
+ // If the window value is even, preserve the carry and continue.
+ // Why is the carry preserved?
+ // If carry == 0 and window & 1 == 0,
+ // then the next carry should be 0
+ // If carry == 1 and window & 1 == 0,
+ // then bit_buf & 1 == 1 so the next carry should be 1
+ pos += 1
+ continue
+ }
+
+ if window < width/2 {
+ carry = 0
+ naf[pos] = int8(window)
+ } else {
+ carry = 1
+ naf[pos] = int8(window) - int8(width)
+ }
+
+ pos += w
+ }
+ return naf
+}
+
+func (s *Scalar) signedRadix16() [64]int8 {
+ b := s.Bytes()
+ if b[31] > 127 {
+ panic("scalar has high bit set illegally")
+ }
+
+ var digits [64]int8
+
+ // Compute unsigned radix-16 digits:
+ for i := 0; i < 32; i++ {
+ digits[2*i] = int8(b[i] & 15)
+ digits[2*i+1] = int8((b[i] >> 4) & 15)
+ }
+
+ // Recenter coefficients:
+ for i := 0; i < 63; i++ {
+ carry := (digits[i] + 8) >> 4
+ digits[i] -= carry << 4
+ digits[i+1] += carry
+ }
+
+ return digits
+}
diff --git a/vendor/filippo.io/edwards25519/scalar_fiat.go b/vendor/filippo.io/edwards25519/scalar_fiat.go
new file mode 100644
index 00000000..2e5782b6
--- /dev/null
+++ b/vendor/filippo.io/edwards25519/scalar_fiat.go
@@ -0,0 +1,1147 @@
+// Code generated by Fiat Cryptography. DO NOT EDIT.
+//
+// Autogenerated: word_by_word_montgomery --lang Go --cmovznz-by-mul --relax-primitive-carry-to-bitwidth 32,64 --public-function-case camelCase --public-type-case camelCase --private-function-case camelCase --private-type-case camelCase --doc-text-before-function-name '' --doc-newline-before-package-declaration --doc-prepend-header 'Code generated by Fiat Cryptography. DO NOT EDIT.' --package-name edwards25519 Scalar 64 '2^252 + 27742317777372353535851937790883648493' mul add sub opp nonzero from_montgomery to_montgomery to_bytes from_bytes
+//
+// curve description: Scalar
+//
+// machine_wordsize = 64 (from "64")
+//
+// requested operations: mul, add, sub, opp, nonzero, from_montgomery, to_montgomery, to_bytes, from_bytes
+//
+// m = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed (from "2^252 + 27742317777372353535851937790883648493")
+//
+//
+//
+// NOTE: In addition to the bounds specified above each function, all
+//
+// functions synthesized for this Montgomery arithmetic require the
+//
+// input to be strictly less than the prime modulus (m), and also
+//
+// require the input to be in the unique saturated representation.
+//
+// All functions also ensure that these two properties are true of
+//
+// return values.
+//
+//
+//
+// Computed values:
+//
+// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192)
+//
+// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248)
+//
+// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in
+//
+// if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256
+
+package edwards25519
+
+import "math/bits"
+
+type fiatScalarUint1 uint64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927
+type fiatScalarInt1 int64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927
+
+// The type fiatScalarMontgomeryDomainFieldElement is a field element in the Montgomery domain.
+//
+// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+type fiatScalarMontgomeryDomainFieldElement [4]uint64
+
+// The type fiatScalarNonMontgomeryDomainFieldElement is a field element NOT in the Montgomery domain.
+//
+// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+type fiatScalarNonMontgomeryDomainFieldElement [4]uint64
+
+// fiatScalarCmovznzU64 is a single-word conditional move.
+//
+// Postconditions:
+//
+// out1 = (if arg1 = 0 then arg2 else arg3)
+//
+// Input Bounds:
+//
+// arg1: [0x0 ~> 0x1]
+// arg2: [0x0 ~> 0xffffffffffffffff]
+// arg3: [0x0 ~> 0xffffffffffffffff]
+//
+// Output Bounds:
+//
+// out1: [0x0 ~> 0xffffffffffffffff]
+func fiatScalarCmovznzU64(out1 *uint64, arg1 fiatScalarUint1, arg2 uint64, arg3 uint64) {
+ x1 := (uint64(arg1) * 0xffffffffffffffff)
+ x2 := ((x1 & arg3) | ((^x1) & arg2))
+ *out1 = x2
+}
+
+// fiatScalarMul multiplies two field elements in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+// 0 ≤ eval arg2 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m
+// 0 ≤ eval out1 < m
+func fiatScalarMul(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement, arg2 *fiatScalarMontgomeryDomainFieldElement) {
+ x1 := arg1[1]
+ x2 := arg1[2]
+ x3 := arg1[3]
+ x4 := arg1[0]
+ var x5 uint64
+ var x6 uint64
+ x6, x5 = bits.Mul64(x4, arg2[3])
+ var x7 uint64
+ var x8 uint64
+ x8, x7 = bits.Mul64(x4, arg2[2])
+ var x9 uint64
+ var x10 uint64
+ x10, x9 = bits.Mul64(x4, arg2[1])
+ var x11 uint64
+ var x12 uint64
+ x12, x11 = bits.Mul64(x4, arg2[0])
+ var x13 uint64
+ var x14 uint64
+ x13, x14 = bits.Add64(x12, x9, uint64(0x0))
+ var x15 uint64
+ var x16 uint64
+ x15, x16 = bits.Add64(x10, x7, uint64(fiatScalarUint1(x14)))
+ var x17 uint64
+ var x18 uint64
+ x17, x18 = bits.Add64(x8, x5, uint64(fiatScalarUint1(x16)))
+ x19 := (uint64(fiatScalarUint1(x18)) + x6)
+ var x20 uint64
+ _, x20 = bits.Mul64(x11, 0xd2b51da312547e1b)
+ var x22 uint64
+ var x23 uint64
+ x23, x22 = bits.Mul64(x20, 0x1000000000000000)
+ var x24 uint64
+ var x25 uint64
+ x25, x24 = bits.Mul64(x20, 0x14def9dea2f79cd6)
+ var x26 uint64
+ var x27 uint64
+ x27, x26 = bits.Mul64(x20, 0x5812631a5cf5d3ed)
+ var x28 uint64
+ var x29 uint64
+ x28, x29 = bits.Add64(x27, x24, uint64(0x0))
+ x30 := (uint64(fiatScalarUint1(x29)) + x25)
+ var x32 uint64
+ _, x32 = bits.Add64(x11, x26, uint64(0x0))
+ var x33 uint64
+ var x34 uint64
+ x33, x34 = bits.Add64(x13, x28, uint64(fiatScalarUint1(x32)))
+ var x35 uint64
+ var x36 uint64
+ x35, x36 = bits.Add64(x15, x30, uint64(fiatScalarUint1(x34)))
+ var x37 uint64
+ var x38 uint64
+ x37, x38 = bits.Add64(x17, x22, uint64(fiatScalarUint1(x36)))
+ var x39 uint64
+ var x40 uint64
+ x39, x40 = bits.Add64(x19, x23, uint64(fiatScalarUint1(x38)))
+ var x41 uint64
+ var x42 uint64
+ x42, x41 = bits.Mul64(x1, arg2[3])
+ var x43 uint64
+ var x44 uint64
+ x44, x43 = bits.Mul64(x1, arg2[2])
+ var x45 uint64
+ var x46 uint64
+ x46, x45 = bits.Mul64(x1, arg2[1])
+ var x47 uint64
+ var x48 uint64
+ x48, x47 = bits.Mul64(x1, arg2[0])
+ var x49 uint64
+ var x50 uint64
+ x49, x50 = bits.Add64(x48, x45, uint64(0x0))
+ var x51 uint64
+ var x52 uint64
+ x51, x52 = bits.Add64(x46, x43, uint64(fiatScalarUint1(x50)))
+ var x53 uint64
+ var x54 uint64
+ x53, x54 = bits.Add64(x44, x41, uint64(fiatScalarUint1(x52)))
+ x55 := (uint64(fiatScalarUint1(x54)) + x42)
+ var x56 uint64
+ var x57 uint64
+ x56, x57 = bits.Add64(x33, x47, uint64(0x0))
+ var x58 uint64
+ var x59 uint64
+ x58, x59 = bits.Add64(x35, x49, uint64(fiatScalarUint1(x57)))
+ var x60 uint64
+ var x61 uint64
+ x60, x61 = bits.Add64(x37, x51, uint64(fiatScalarUint1(x59)))
+ var x62 uint64
+ var x63 uint64
+ x62, x63 = bits.Add64(x39, x53, uint64(fiatScalarUint1(x61)))
+ var x64 uint64
+ var x65 uint64
+ x64, x65 = bits.Add64(uint64(fiatScalarUint1(x40)), x55, uint64(fiatScalarUint1(x63)))
+ var x66 uint64
+ _, x66 = bits.Mul64(x56, 0xd2b51da312547e1b)
+ var x68 uint64
+ var x69 uint64
+ x69, x68 = bits.Mul64(x66, 0x1000000000000000)
+ var x70 uint64
+ var x71 uint64
+ x71, x70 = bits.Mul64(x66, 0x14def9dea2f79cd6)
+ var x72 uint64
+ var x73 uint64
+ x73, x72 = bits.Mul64(x66, 0x5812631a5cf5d3ed)
+ var x74 uint64
+ var x75 uint64
+ x74, x75 = bits.Add64(x73, x70, uint64(0x0))
+ x76 := (uint64(fiatScalarUint1(x75)) + x71)
+ var x78 uint64
+ _, x78 = bits.Add64(x56, x72, uint64(0x0))
+ var x79 uint64
+ var x80 uint64
+ x79, x80 = bits.Add64(x58, x74, uint64(fiatScalarUint1(x78)))
+ var x81 uint64
+ var x82 uint64
+ x81, x82 = bits.Add64(x60, x76, uint64(fiatScalarUint1(x80)))
+ var x83 uint64
+ var x84 uint64
+ x83, x84 = bits.Add64(x62, x68, uint64(fiatScalarUint1(x82)))
+ var x85 uint64
+ var x86 uint64
+ x85, x86 = bits.Add64(x64, x69, uint64(fiatScalarUint1(x84)))
+ x87 := (uint64(fiatScalarUint1(x86)) + uint64(fiatScalarUint1(x65)))
+ var x88 uint64
+ var x89 uint64
+ x89, x88 = bits.Mul64(x2, arg2[3])
+ var x90 uint64
+ var x91 uint64
+ x91, x90 = bits.Mul64(x2, arg2[2])
+ var x92 uint64
+ var x93 uint64
+ x93, x92 = bits.Mul64(x2, arg2[1])
+ var x94 uint64
+ var x95 uint64
+ x95, x94 = bits.Mul64(x2, arg2[0])
+ var x96 uint64
+ var x97 uint64
+ x96, x97 = bits.Add64(x95, x92, uint64(0x0))
+ var x98 uint64
+ var x99 uint64
+ x98, x99 = bits.Add64(x93, x90, uint64(fiatScalarUint1(x97)))
+ var x100 uint64
+ var x101 uint64
+ x100, x101 = bits.Add64(x91, x88, uint64(fiatScalarUint1(x99)))
+ x102 := (uint64(fiatScalarUint1(x101)) + x89)
+ var x103 uint64
+ var x104 uint64
+ x103, x104 = bits.Add64(x79, x94, uint64(0x0))
+ var x105 uint64
+ var x106 uint64
+ x105, x106 = bits.Add64(x81, x96, uint64(fiatScalarUint1(x104)))
+ var x107 uint64
+ var x108 uint64
+ x107, x108 = bits.Add64(x83, x98, uint64(fiatScalarUint1(x106)))
+ var x109 uint64
+ var x110 uint64
+ x109, x110 = bits.Add64(x85, x100, uint64(fiatScalarUint1(x108)))
+ var x111 uint64
+ var x112 uint64
+ x111, x112 = bits.Add64(x87, x102, uint64(fiatScalarUint1(x110)))
+ var x113 uint64
+ _, x113 = bits.Mul64(x103, 0xd2b51da312547e1b)
+ var x115 uint64
+ var x116 uint64
+ x116, x115 = bits.Mul64(x113, 0x1000000000000000)
+ var x117 uint64
+ var x118 uint64
+ x118, x117 = bits.Mul64(x113, 0x14def9dea2f79cd6)
+ var x119 uint64
+ var x120 uint64
+ x120, x119 = bits.Mul64(x113, 0x5812631a5cf5d3ed)
+ var x121 uint64
+ var x122 uint64
+ x121, x122 = bits.Add64(x120, x117, uint64(0x0))
+ x123 := (uint64(fiatScalarUint1(x122)) + x118)
+ var x125 uint64
+ _, x125 = bits.Add64(x103, x119, uint64(0x0))
+ var x126 uint64
+ var x127 uint64
+ x126, x127 = bits.Add64(x105, x121, uint64(fiatScalarUint1(x125)))
+ var x128 uint64
+ var x129 uint64
+ x128, x129 = bits.Add64(x107, x123, uint64(fiatScalarUint1(x127)))
+ var x130 uint64
+ var x131 uint64
+ x130, x131 = bits.Add64(x109, x115, uint64(fiatScalarUint1(x129)))
+ var x132 uint64
+ var x133 uint64
+ x132, x133 = bits.Add64(x111, x116, uint64(fiatScalarUint1(x131)))
+ x134 := (uint64(fiatScalarUint1(x133)) + uint64(fiatScalarUint1(x112)))
+ var x135 uint64
+ var x136 uint64
+ x136, x135 = bits.Mul64(x3, arg2[3])
+ var x137 uint64
+ var x138 uint64
+ x138, x137 = bits.Mul64(x3, arg2[2])
+ var x139 uint64
+ var x140 uint64
+ x140, x139 = bits.Mul64(x3, arg2[1])
+ var x141 uint64
+ var x142 uint64
+ x142, x141 = bits.Mul64(x3, arg2[0])
+ var x143 uint64
+ var x144 uint64
+ x143, x144 = bits.Add64(x142, x139, uint64(0x0))
+ var x145 uint64
+ var x146 uint64
+ x145, x146 = bits.Add64(x140, x137, uint64(fiatScalarUint1(x144)))
+ var x147 uint64
+ var x148 uint64
+ x147, x148 = bits.Add64(x138, x135, uint64(fiatScalarUint1(x146)))
+ x149 := (uint64(fiatScalarUint1(x148)) + x136)
+ var x150 uint64
+ var x151 uint64
+ x150, x151 = bits.Add64(x126, x141, uint64(0x0))
+ var x152 uint64
+ var x153 uint64
+ x152, x153 = bits.Add64(x128, x143, uint64(fiatScalarUint1(x151)))
+ var x154 uint64
+ var x155 uint64
+ x154, x155 = bits.Add64(x130, x145, uint64(fiatScalarUint1(x153)))
+ var x156 uint64
+ var x157 uint64
+ x156, x157 = bits.Add64(x132, x147, uint64(fiatScalarUint1(x155)))
+ var x158 uint64
+ var x159 uint64
+ x158, x159 = bits.Add64(x134, x149, uint64(fiatScalarUint1(x157)))
+ var x160 uint64
+ _, x160 = bits.Mul64(x150, 0xd2b51da312547e1b)
+ var x162 uint64
+ var x163 uint64
+ x163, x162 = bits.Mul64(x160, 0x1000000000000000)
+ var x164 uint64
+ var x165 uint64
+ x165, x164 = bits.Mul64(x160, 0x14def9dea2f79cd6)
+ var x166 uint64
+ var x167 uint64
+ x167, x166 = bits.Mul64(x160, 0x5812631a5cf5d3ed)
+ var x168 uint64
+ var x169 uint64
+ x168, x169 = bits.Add64(x167, x164, uint64(0x0))
+ x170 := (uint64(fiatScalarUint1(x169)) + x165)
+ var x172 uint64
+ _, x172 = bits.Add64(x150, x166, uint64(0x0))
+ var x173 uint64
+ var x174 uint64
+ x173, x174 = bits.Add64(x152, x168, uint64(fiatScalarUint1(x172)))
+ var x175 uint64
+ var x176 uint64
+ x175, x176 = bits.Add64(x154, x170, uint64(fiatScalarUint1(x174)))
+ var x177 uint64
+ var x178 uint64
+ x177, x178 = bits.Add64(x156, x162, uint64(fiatScalarUint1(x176)))
+ var x179 uint64
+ var x180 uint64
+ x179, x180 = bits.Add64(x158, x163, uint64(fiatScalarUint1(x178)))
+ x181 := (uint64(fiatScalarUint1(x180)) + uint64(fiatScalarUint1(x159)))
+ var x182 uint64
+ var x183 uint64
+ x182, x183 = bits.Sub64(x173, 0x5812631a5cf5d3ed, uint64(0x0))
+ var x184 uint64
+ var x185 uint64
+ x184, x185 = bits.Sub64(x175, 0x14def9dea2f79cd6, uint64(fiatScalarUint1(x183)))
+ var x186 uint64
+ var x187 uint64
+ x186, x187 = bits.Sub64(x177, uint64(0x0), uint64(fiatScalarUint1(x185)))
+ var x188 uint64
+ var x189 uint64
+ x188, x189 = bits.Sub64(x179, 0x1000000000000000, uint64(fiatScalarUint1(x187)))
+ var x191 uint64
+ _, x191 = bits.Sub64(x181, uint64(0x0), uint64(fiatScalarUint1(x189)))
+ var x192 uint64
+ fiatScalarCmovznzU64(&x192, fiatScalarUint1(x191), x182, x173)
+ var x193 uint64
+ fiatScalarCmovznzU64(&x193, fiatScalarUint1(x191), x184, x175)
+ var x194 uint64
+ fiatScalarCmovznzU64(&x194, fiatScalarUint1(x191), x186, x177)
+ var x195 uint64
+ fiatScalarCmovznzU64(&x195, fiatScalarUint1(x191), x188, x179)
+ out1[0] = x192
+ out1[1] = x193
+ out1[2] = x194
+ out1[3] = x195
+}
+
+// fiatScalarAdd adds two field elements in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+// 0 ≤ eval arg2 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m
+// 0 ≤ eval out1 < m
+func fiatScalarAdd(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement, arg2 *fiatScalarMontgomeryDomainFieldElement) {
+ var x1 uint64
+ var x2 uint64
+ x1, x2 = bits.Add64(arg1[0], arg2[0], uint64(0x0))
+ var x3 uint64
+ var x4 uint64
+ x3, x4 = bits.Add64(arg1[1], arg2[1], uint64(fiatScalarUint1(x2)))
+ var x5 uint64
+ var x6 uint64
+ x5, x6 = bits.Add64(arg1[2], arg2[2], uint64(fiatScalarUint1(x4)))
+ var x7 uint64
+ var x8 uint64
+ x7, x8 = bits.Add64(arg1[3], arg2[3], uint64(fiatScalarUint1(x6)))
+ var x9 uint64
+ var x10 uint64
+ x9, x10 = bits.Sub64(x1, 0x5812631a5cf5d3ed, uint64(0x0))
+ var x11 uint64
+ var x12 uint64
+ x11, x12 = bits.Sub64(x3, 0x14def9dea2f79cd6, uint64(fiatScalarUint1(x10)))
+ var x13 uint64
+ var x14 uint64
+ x13, x14 = bits.Sub64(x5, uint64(0x0), uint64(fiatScalarUint1(x12)))
+ var x15 uint64
+ var x16 uint64
+ x15, x16 = bits.Sub64(x7, 0x1000000000000000, uint64(fiatScalarUint1(x14)))
+ var x18 uint64
+ _, x18 = bits.Sub64(uint64(fiatScalarUint1(x8)), uint64(0x0), uint64(fiatScalarUint1(x16)))
+ var x19 uint64
+ fiatScalarCmovznzU64(&x19, fiatScalarUint1(x18), x9, x1)
+ var x20 uint64
+ fiatScalarCmovznzU64(&x20, fiatScalarUint1(x18), x11, x3)
+ var x21 uint64
+ fiatScalarCmovznzU64(&x21, fiatScalarUint1(x18), x13, x5)
+ var x22 uint64
+ fiatScalarCmovznzU64(&x22, fiatScalarUint1(x18), x15, x7)
+ out1[0] = x19
+ out1[1] = x20
+ out1[2] = x21
+ out1[3] = x22
+}
+
+// fiatScalarSub subtracts two field elements in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+// 0 ≤ eval arg2 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m
+// 0 ≤ eval out1 < m
+func fiatScalarSub(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement, arg2 *fiatScalarMontgomeryDomainFieldElement) {
+ var x1 uint64
+ var x2 uint64
+ x1, x2 = bits.Sub64(arg1[0], arg2[0], uint64(0x0))
+ var x3 uint64
+ var x4 uint64
+ x3, x4 = bits.Sub64(arg1[1], arg2[1], uint64(fiatScalarUint1(x2)))
+ var x5 uint64
+ var x6 uint64
+ x5, x6 = bits.Sub64(arg1[2], arg2[2], uint64(fiatScalarUint1(x4)))
+ var x7 uint64
+ var x8 uint64
+ x7, x8 = bits.Sub64(arg1[3], arg2[3], uint64(fiatScalarUint1(x6)))
+ var x9 uint64
+ fiatScalarCmovznzU64(&x9, fiatScalarUint1(x8), uint64(0x0), 0xffffffffffffffff)
+ var x10 uint64
+ var x11 uint64
+ x10, x11 = bits.Add64(x1, (x9 & 0x5812631a5cf5d3ed), uint64(0x0))
+ var x12 uint64
+ var x13 uint64
+ x12, x13 = bits.Add64(x3, (x9 & 0x14def9dea2f79cd6), uint64(fiatScalarUint1(x11)))
+ var x14 uint64
+ var x15 uint64
+ x14, x15 = bits.Add64(x5, uint64(0x0), uint64(fiatScalarUint1(x13)))
+ var x16 uint64
+ x16, _ = bits.Add64(x7, (x9 & 0x1000000000000000), uint64(fiatScalarUint1(x15)))
+ out1[0] = x10
+ out1[1] = x12
+ out1[2] = x14
+ out1[3] = x16
+}
+
+// fiatScalarOpp negates a field element in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = -eval (from_montgomery arg1) mod m
+// 0 ≤ eval out1 < m
+func fiatScalarOpp(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement) {
+ var x1 uint64
+ var x2 uint64
+ x1, x2 = bits.Sub64(uint64(0x0), arg1[0], uint64(0x0))
+ var x3 uint64
+ var x4 uint64
+ x3, x4 = bits.Sub64(uint64(0x0), arg1[1], uint64(fiatScalarUint1(x2)))
+ var x5 uint64
+ var x6 uint64
+ x5, x6 = bits.Sub64(uint64(0x0), arg1[2], uint64(fiatScalarUint1(x4)))
+ var x7 uint64
+ var x8 uint64
+ x7, x8 = bits.Sub64(uint64(0x0), arg1[3], uint64(fiatScalarUint1(x6)))
+ var x9 uint64
+ fiatScalarCmovznzU64(&x9, fiatScalarUint1(x8), uint64(0x0), 0xffffffffffffffff)
+ var x10 uint64
+ var x11 uint64
+ x10, x11 = bits.Add64(x1, (x9 & 0x5812631a5cf5d3ed), uint64(0x0))
+ var x12 uint64
+ var x13 uint64
+ x12, x13 = bits.Add64(x3, (x9 & 0x14def9dea2f79cd6), uint64(fiatScalarUint1(x11)))
+ var x14 uint64
+ var x15 uint64
+ x14, x15 = bits.Add64(x5, uint64(0x0), uint64(fiatScalarUint1(x13)))
+ var x16 uint64
+ x16, _ = bits.Add64(x7, (x9 & 0x1000000000000000), uint64(fiatScalarUint1(x15)))
+ out1[0] = x10
+ out1[1] = x12
+ out1[2] = x14
+ out1[3] = x16
+}
+
+// fiatScalarNonzero outputs a single non-zero word if the input is non-zero and zero otherwise.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// out1 = 0 ↔ eval (from_montgomery arg1) mod m = 0
+//
+// Input Bounds:
+//
+// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+//
+// Output Bounds:
+//
+// out1: [0x0 ~> 0xffffffffffffffff]
+func fiatScalarNonzero(out1 *uint64, arg1 *[4]uint64) {
+ x1 := (arg1[0] | (arg1[1] | (arg1[2] | arg1[3])))
+ *out1 = x1
+}
+
+// fiatScalarFromMontgomery translates a field element out of the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m
+// 0 ≤ eval out1 < m
+func fiatScalarFromMontgomery(out1 *fiatScalarNonMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement) {
+ x1 := arg1[0]
+ var x2 uint64
+ _, x2 = bits.Mul64(x1, 0xd2b51da312547e1b)
+ var x4 uint64
+ var x5 uint64
+ x5, x4 = bits.Mul64(x2, 0x1000000000000000)
+ var x6 uint64
+ var x7 uint64
+ x7, x6 = bits.Mul64(x2, 0x14def9dea2f79cd6)
+ var x8 uint64
+ var x9 uint64
+ x9, x8 = bits.Mul64(x2, 0x5812631a5cf5d3ed)
+ var x10 uint64
+ var x11 uint64
+ x10, x11 = bits.Add64(x9, x6, uint64(0x0))
+ var x13 uint64
+ _, x13 = bits.Add64(x1, x8, uint64(0x0))
+ var x14 uint64
+ var x15 uint64
+ x14, x15 = bits.Add64(uint64(0x0), x10, uint64(fiatScalarUint1(x13)))
+ var x16 uint64
+ var x17 uint64
+ x16, x17 = bits.Add64(x14, arg1[1], uint64(0x0))
+ var x18 uint64
+ _, x18 = bits.Mul64(x16, 0xd2b51da312547e1b)
+ var x20 uint64
+ var x21 uint64
+ x21, x20 = bits.Mul64(x18, 0x1000000000000000)
+ var x22 uint64
+ var x23 uint64
+ x23, x22 = bits.Mul64(x18, 0x14def9dea2f79cd6)
+ var x24 uint64
+ var x25 uint64
+ x25, x24 = bits.Mul64(x18, 0x5812631a5cf5d3ed)
+ var x26 uint64
+ var x27 uint64
+ x26, x27 = bits.Add64(x25, x22, uint64(0x0))
+ var x29 uint64
+ _, x29 = bits.Add64(x16, x24, uint64(0x0))
+ var x30 uint64
+ var x31 uint64
+ x30, x31 = bits.Add64((uint64(fiatScalarUint1(x17)) + (uint64(fiatScalarUint1(x15)) + (uint64(fiatScalarUint1(x11)) + x7))), x26, uint64(fiatScalarUint1(x29)))
+ var x32 uint64
+ var x33 uint64
+ x32, x33 = bits.Add64(x4, (uint64(fiatScalarUint1(x27)) + x23), uint64(fiatScalarUint1(x31)))
+ var x34 uint64
+ var x35 uint64
+ x34, x35 = bits.Add64(x5, x20, uint64(fiatScalarUint1(x33)))
+ var x36 uint64
+ var x37 uint64
+ x36, x37 = bits.Add64(x30, arg1[2], uint64(0x0))
+ var x38 uint64
+ var x39 uint64
+ x38, x39 = bits.Add64(x32, uint64(0x0), uint64(fiatScalarUint1(x37)))
+ var x40 uint64
+ var x41 uint64
+ x40, x41 = bits.Add64(x34, uint64(0x0), uint64(fiatScalarUint1(x39)))
+ var x42 uint64
+ _, x42 = bits.Mul64(x36, 0xd2b51da312547e1b)
+ var x44 uint64
+ var x45 uint64
+ x45, x44 = bits.Mul64(x42, 0x1000000000000000)
+ var x46 uint64
+ var x47 uint64
+ x47, x46 = bits.Mul64(x42, 0x14def9dea2f79cd6)
+ var x48 uint64
+ var x49 uint64
+ x49, x48 = bits.Mul64(x42, 0x5812631a5cf5d3ed)
+ var x50 uint64
+ var x51 uint64
+ x50, x51 = bits.Add64(x49, x46, uint64(0x0))
+ var x53 uint64
+ _, x53 = bits.Add64(x36, x48, uint64(0x0))
+ var x54 uint64
+ var x55 uint64
+ x54, x55 = bits.Add64(x38, x50, uint64(fiatScalarUint1(x53)))
+ var x56 uint64
+ var x57 uint64
+ x56, x57 = bits.Add64(x40, (uint64(fiatScalarUint1(x51)) + x47), uint64(fiatScalarUint1(x55)))
+ var x58 uint64
+ var x59 uint64
+ x58, x59 = bits.Add64((uint64(fiatScalarUint1(x41)) + (uint64(fiatScalarUint1(x35)) + x21)), x44, uint64(fiatScalarUint1(x57)))
+ var x60 uint64
+ var x61 uint64
+ x60, x61 = bits.Add64(x54, arg1[3], uint64(0x0))
+ var x62 uint64
+ var x63 uint64
+ x62, x63 = bits.Add64(x56, uint64(0x0), uint64(fiatScalarUint1(x61)))
+ var x64 uint64
+ var x65 uint64
+ x64, x65 = bits.Add64(x58, uint64(0x0), uint64(fiatScalarUint1(x63)))
+ var x66 uint64
+ _, x66 = bits.Mul64(x60, 0xd2b51da312547e1b)
+ var x68 uint64
+ var x69 uint64
+ x69, x68 = bits.Mul64(x66, 0x1000000000000000)
+ var x70 uint64
+ var x71 uint64
+ x71, x70 = bits.Mul64(x66, 0x14def9dea2f79cd6)
+ var x72 uint64
+ var x73 uint64
+ x73, x72 = bits.Mul64(x66, 0x5812631a5cf5d3ed)
+ var x74 uint64
+ var x75 uint64
+ x74, x75 = bits.Add64(x73, x70, uint64(0x0))
+ var x77 uint64
+ _, x77 = bits.Add64(x60, x72, uint64(0x0))
+ var x78 uint64
+ var x79 uint64
+ x78, x79 = bits.Add64(x62, x74, uint64(fiatScalarUint1(x77)))
+ var x80 uint64
+ var x81 uint64
+ x80, x81 = bits.Add64(x64, (uint64(fiatScalarUint1(x75)) + x71), uint64(fiatScalarUint1(x79)))
+ var x82 uint64
+ var x83 uint64
+ x82, x83 = bits.Add64((uint64(fiatScalarUint1(x65)) + (uint64(fiatScalarUint1(x59)) + x45)), x68, uint64(fiatScalarUint1(x81)))
+ x84 := (uint64(fiatScalarUint1(x83)) + x69)
+ var x85 uint64
+ var x86 uint64
+ x85, x86 = bits.Sub64(x78, 0x5812631a5cf5d3ed, uint64(0x0))
+ var x87 uint64
+ var x88 uint64
+ x87, x88 = bits.Sub64(x80, 0x14def9dea2f79cd6, uint64(fiatScalarUint1(x86)))
+ var x89 uint64
+ var x90 uint64
+ x89, x90 = bits.Sub64(x82, uint64(0x0), uint64(fiatScalarUint1(x88)))
+ var x91 uint64
+ var x92 uint64
+ x91, x92 = bits.Sub64(x84, 0x1000000000000000, uint64(fiatScalarUint1(x90)))
+ var x94 uint64
+ _, x94 = bits.Sub64(uint64(0x0), uint64(0x0), uint64(fiatScalarUint1(x92)))
+ var x95 uint64
+ fiatScalarCmovznzU64(&x95, fiatScalarUint1(x94), x85, x78)
+ var x96 uint64
+ fiatScalarCmovznzU64(&x96, fiatScalarUint1(x94), x87, x80)
+ var x97 uint64
+ fiatScalarCmovznzU64(&x97, fiatScalarUint1(x94), x89, x82)
+ var x98 uint64
+ fiatScalarCmovznzU64(&x98, fiatScalarUint1(x94), x91, x84)
+ out1[0] = x95
+ out1[1] = x96
+ out1[2] = x97
+ out1[3] = x98
+}
+
+// fiatScalarToMontgomery translates a field element into the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = eval arg1 mod m
+// 0 ≤ eval out1 < m
+func fiatScalarToMontgomery(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarNonMontgomeryDomainFieldElement) {
+ x1 := arg1[1]
+ x2 := arg1[2]
+ x3 := arg1[3]
+ x4 := arg1[0]
+ var x5 uint64
+ var x6 uint64
+ x6, x5 = bits.Mul64(x4, 0x399411b7c309a3d)
+ var x7 uint64
+ var x8 uint64
+ x8, x7 = bits.Mul64(x4, 0xceec73d217f5be65)
+ var x9 uint64
+ var x10 uint64
+ x10, x9 = bits.Mul64(x4, 0xd00e1ba768859347)
+ var x11 uint64
+ var x12 uint64
+ x12, x11 = bits.Mul64(x4, 0xa40611e3449c0f01)
+ var x13 uint64
+ var x14 uint64
+ x13, x14 = bits.Add64(x12, x9, uint64(0x0))
+ var x15 uint64
+ var x16 uint64
+ x15, x16 = bits.Add64(x10, x7, uint64(fiatScalarUint1(x14)))
+ var x17 uint64
+ var x18 uint64
+ x17, x18 = bits.Add64(x8, x5, uint64(fiatScalarUint1(x16)))
+ var x19 uint64
+ _, x19 = bits.Mul64(x11, 0xd2b51da312547e1b)
+ var x21 uint64
+ var x22 uint64
+ x22, x21 = bits.Mul64(x19, 0x1000000000000000)
+ var x23 uint64
+ var x24 uint64
+ x24, x23 = bits.Mul64(x19, 0x14def9dea2f79cd6)
+ var x25 uint64
+ var x26 uint64
+ x26, x25 = bits.Mul64(x19, 0x5812631a5cf5d3ed)
+ var x27 uint64
+ var x28 uint64
+ x27, x28 = bits.Add64(x26, x23, uint64(0x0))
+ var x30 uint64
+ _, x30 = bits.Add64(x11, x25, uint64(0x0))
+ var x31 uint64
+ var x32 uint64
+ x31, x32 = bits.Add64(x13, x27, uint64(fiatScalarUint1(x30)))
+ var x33 uint64
+ var x34 uint64
+ x33, x34 = bits.Add64(x15, (uint64(fiatScalarUint1(x28)) + x24), uint64(fiatScalarUint1(x32)))
+ var x35 uint64
+ var x36 uint64
+ x35, x36 = bits.Add64(x17, x21, uint64(fiatScalarUint1(x34)))
+ var x37 uint64
+ var x38 uint64
+ x38, x37 = bits.Mul64(x1, 0x399411b7c309a3d)
+ var x39 uint64
+ var x40 uint64
+ x40, x39 = bits.Mul64(x1, 0xceec73d217f5be65)
+ var x41 uint64
+ var x42 uint64
+ x42, x41 = bits.Mul64(x1, 0xd00e1ba768859347)
+ var x43 uint64
+ var x44 uint64
+ x44, x43 = bits.Mul64(x1, 0xa40611e3449c0f01)
+ var x45 uint64
+ var x46 uint64
+ x45, x46 = bits.Add64(x44, x41, uint64(0x0))
+ var x47 uint64
+ var x48 uint64
+ x47, x48 = bits.Add64(x42, x39, uint64(fiatScalarUint1(x46)))
+ var x49 uint64
+ var x50 uint64
+ x49, x50 = bits.Add64(x40, x37, uint64(fiatScalarUint1(x48)))
+ var x51 uint64
+ var x52 uint64
+ x51, x52 = bits.Add64(x31, x43, uint64(0x0))
+ var x53 uint64
+ var x54 uint64
+ x53, x54 = bits.Add64(x33, x45, uint64(fiatScalarUint1(x52)))
+ var x55 uint64
+ var x56 uint64
+ x55, x56 = bits.Add64(x35, x47, uint64(fiatScalarUint1(x54)))
+ var x57 uint64
+ var x58 uint64
+ x57, x58 = bits.Add64(((uint64(fiatScalarUint1(x36)) + (uint64(fiatScalarUint1(x18)) + x6)) + x22), x49, uint64(fiatScalarUint1(x56)))
+ var x59 uint64
+ _, x59 = bits.Mul64(x51, 0xd2b51da312547e1b)
+ var x61 uint64
+ var x62 uint64
+ x62, x61 = bits.Mul64(x59, 0x1000000000000000)
+ var x63 uint64
+ var x64 uint64
+ x64, x63 = bits.Mul64(x59, 0x14def9dea2f79cd6)
+ var x65 uint64
+ var x66 uint64
+ x66, x65 = bits.Mul64(x59, 0x5812631a5cf5d3ed)
+ var x67 uint64
+ var x68 uint64
+ x67, x68 = bits.Add64(x66, x63, uint64(0x0))
+ var x70 uint64
+ _, x70 = bits.Add64(x51, x65, uint64(0x0))
+ var x71 uint64
+ var x72 uint64
+ x71, x72 = bits.Add64(x53, x67, uint64(fiatScalarUint1(x70)))
+ var x73 uint64
+ var x74 uint64
+ x73, x74 = bits.Add64(x55, (uint64(fiatScalarUint1(x68)) + x64), uint64(fiatScalarUint1(x72)))
+ var x75 uint64
+ var x76 uint64
+ x75, x76 = bits.Add64(x57, x61, uint64(fiatScalarUint1(x74)))
+ var x77 uint64
+ var x78 uint64
+ x78, x77 = bits.Mul64(x2, 0x399411b7c309a3d)
+ var x79 uint64
+ var x80 uint64
+ x80, x79 = bits.Mul64(x2, 0xceec73d217f5be65)
+ var x81 uint64
+ var x82 uint64
+ x82, x81 = bits.Mul64(x2, 0xd00e1ba768859347)
+ var x83 uint64
+ var x84 uint64
+ x84, x83 = bits.Mul64(x2, 0xa40611e3449c0f01)
+ var x85 uint64
+ var x86 uint64
+ x85, x86 = bits.Add64(x84, x81, uint64(0x0))
+ var x87 uint64
+ var x88 uint64
+ x87, x88 = bits.Add64(x82, x79, uint64(fiatScalarUint1(x86)))
+ var x89 uint64
+ var x90 uint64
+ x89, x90 = bits.Add64(x80, x77, uint64(fiatScalarUint1(x88)))
+ var x91 uint64
+ var x92 uint64
+ x91, x92 = bits.Add64(x71, x83, uint64(0x0))
+ var x93 uint64
+ var x94 uint64
+ x93, x94 = bits.Add64(x73, x85, uint64(fiatScalarUint1(x92)))
+ var x95 uint64
+ var x96 uint64
+ x95, x96 = bits.Add64(x75, x87, uint64(fiatScalarUint1(x94)))
+ var x97 uint64
+ var x98 uint64
+ x97, x98 = bits.Add64(((uint64(fiatScalarUint1(x76)) + (uint64(fiatScalarUint1(x58)) + (uint64(fiatScalarUint1(x50)) + x38))) + x62), x89, uint64(fiatScalarUint1(x96)))
+ var x99 uint64
+ _, x99 = bits.Mul64(x91, 0xd2b51da312547e1b)
+ var x101 uint64
+ var x102 uint64
+ x102, x101 = bits.Mul64(x99, 0x1000000000000000)
+ var x103 uint64
+ var x104 uint64
+ x104, x103 = bits.Mul64(x99, 0x14def9dea2f79cd6)
+ var x105 uint64
+ var x106 uint64
+ x106, x105 = bits.Mul64(x99, 0x5812631a5cf5d3ed)
+ var x107 uint64
+ var x108 uint64
+ x107, x108 = bits.Add64(x106, x103, uint64(0x0))
+ var x110 uint64
+ _, x110 = bits.Add64(x91, x105, uint64(0x0))
+ var x111 uint64
+ var x112 uint64
+ x111, x112 = bits.Add64(x93, x107, uint64(fiatScalarUint1(x110)))
+ var x113 uint64
+ var x114 uint64
+ x113, x114 = bits.Add64(x95, (uint64(fiatScalarUint1(x108)) + x104), uint64(fiatScalarUint1(x112)))
+ var x115 uint64
+ var x116 uint64
+ x115, x116 = bits.Add64(x97, x101, uint64(fiatScalarUint1(x114)))
+ var x117 uint64
+ var x118 uint64
+ x118, x117 = bits.Mul64(x3, 0x399411b7c309a3d)
+ var x119 uint64
+ var x120 uint64
+ x120, x119 = bits.Mul64(x3, 0xceec73d217f5be65)
+ var x121 uint64
+ var x122 uint64
+ x122, x121 = bits.Mul64(x3, 0xd00e1ba768859347)
+ var x123 uint64
+ var x124 uint64
+ x124, x123 = bits.Mul64(x3, 0xa40611e3449c0f01)
+ var x125 uint64
+ var x126 uint64
+ x125, x126 = bits.Add64(x124, x121, uint64(0x0))
+ var x127 uint64
+ var x128 uint64
+ x127, x128 = bits.Add64(x122, x119, uint64(fiatScalarUint1(x126)))
+ var x129 uint64
+ var x130 uint64
+ x129, x130 = bits.Add64(x120, x117, uint64(fiatScalarUint1(x128)))
+ var x131 uint64
+ var x132 uint64
+ x131, x132 = bits.Add64(x111, x123, uint64(0x0))
+ var x133 uint64
+ var x134 uint64
+ x133, x134 = bits.Add64(x113, x125, uint64(fiatScalarUint1(x132)))
+ var x135 uint64
+ var x136 uint64
+ x135, x136 = bits.Add64(x115, x127, uint64(fiatScalarUint1(x134)))
+ var x137 uint64
+ var x138 uint64
+ x137, x138 = bits.Add64(((uint64(fiatScalarUint1(x116)) + (uint64(fiatScalarUint1(x98)) + (uint64(fiatScalarUint1(x90)) + x78))) + x102), x129, uint64(fiatScalarUint1(x136)))
+ var x139 uint64
+ _, x139 = bits.Mul64(x131, 0xd2b51da312547e1b)
+ var x141 uint64
+ var x142 uint64
+ x142, x141 = bits.Mul64(x139, 0x1000000000000000)
+ var x143 uint64
+ var x144 uint64
+ x144, x143 = bits.Mul64(x139, 0x14def9dea2f79cd6)
+ var x145 uint64
+ var x146 uint64
+ x146, x145 = bits.Mul64(x139, 0x5812631a5cf5d3ed)
+ var x147 uint64
+ var x148 uint64
+ x147, x148 = bits.Add64(x146, x143, uint64(0x0))
+ var x150 uint64
+ _, x150 = bits.Add64(x131, x145, uint64(0x0))
+ var x151 uint64
+ var x152 uint64
+ x151, x152 = bits.Add64(x133, x147, uint64(fiatScalarUint1(x150)))
+ var x153 uint64
+ var x154 uint64
+ x153, x154 = bits.Add64(x135, (uint64(fiatScalarUint1(x148)) + x144), uint64(fiatScalarUint1(x152)))
+ var x155 uint64
+ var x156 uint64
+ x155, x156 = bits.Add64(x137, x141, uint64(fiatScalarUint1(x154)))
+ x157 := ((uint64(fiatScalarUint1(x156)) + (uint64(fiatScalarUint1(x138)) + (uint64(fiatScalarUint1(x130)) + x118))) + x142)
+ var x158 uint64
+ var x159 uint64
+ x158, x159 = bits.Sub64(x151, 0x5812631a5cf5d3ed, uint64(0x0))
+ var x160 uint64
+ var x161 uint64
+ x160, x161 = bits.Sub64(x153, 0x14def9dea2f79cd6, uint64(fiatScalarUint1(x159)))
+ var x162 uint64
+ var x163 uint64
+ x162, x163 = bits.Sub64(x155, uint64(0x0), uint64(fiatScalarUint1(x161)))
+ var x164 uint64
+ var x165 uint64
+ x164, x165 = bits.Sub64(x157, 0x1000000000000000, uint64(fiatScalarUint1(x163)))
+ var x167 uint64
+ _, x167 = bits.Sub64(uint64(0x0), uint64(0x0), uint64(fiatScalarUint1(x165)))
+ var x168 uint64
+ fiatScalarCmovznzU64(&x168, fiatScalarUint1(x167), x158, x151)
+ var x169 uint64
+ fiatScalarCmovznzU64(&x169, fiatScalarUint1(x167), x160, x153)
+ var x170 uint64
+ fiatScalarCmovznzU64(&x170, fiatScalarUint1(x167), x162, x155)
+ var x171 uint64
+ fiatScalarCmovznzU64(&x171, fiatScalarUint1(x167), x164, x157)
+ out1[0] = x168
+ out1[1] = x169
+ out1[2] = x170
+ out1[3] = x171
+}
+
+// fiatScalarToBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// out1 = map (λ x, ⌊((eval arg1 mod m) mod 2^(8 * (x + 1))) / 2^(8 * x)⌋) [0..31]
+//
+// Input Bounds:
+//
+// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0x1fffffffffffffff]]
+//
+// Output Bounds:
+//
+// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0x1f]]
+func fiatScalarToBytes(out1 *[32]uint8, arg1 *[4]uint64) {
+ x1 := arg1[3]
+ x2 := arg1[2]
+ x3 := arg1[1]
+ x4 := arg1[0]
+ x5 := (uint8(x4) & 0xff)
+ x6 := (x4 >> 8)
+ x7 := (uint8(x6) & 0xff)
+ x8 := (x6 >> 8)
+ x9 := (uint8(x8) & 0xff)
+ x10 := (x8 >> 8)
+ x11 := (uint8(x10) & 0xff)
+ x12 := (x10 >> 8)
+ x13 := (uint8(x12) & 0xff)
+ x14 := (x12 >> 8)
+ x15 := (uint8(x14) & 0xff)
+ x16 := (x14 >> 8)
+ x17 := (uint8(x16) & 0xff)
+ x18 := uint8((x16 >> 8))
+ x19 := (uint8(x3) & 0xff)
+ x20 := (x3 >> 8)
+ x21 := (uint8(x20) & 0xff)
+ x22 := (x20 >> 8)
+ x23 := (uint8(x22) & 0xff)
+ x24 := (x22 >> 8)
+ x25 := (uint8(x24) & 0xff)
+ x26 := (x24 >> 8)
+ x27 := (uint8(x26) & 0xff)
+ x28 := (x26 >> 8)
+ x29 := (uint8(x28) & 0xff)
+ x30 := (x28 >> 8)
+ x31 := (uint8(x30) & 0xff)
+ x32 := uint8((x30 >> 8))
+ x33 := (uint8(x2) & 0xff)
+ x34 := (x2 >> 8)
+ x35 := (uint8(x34) & 0xff)
+ x36 := (x34 >> 8)
+ x37 := (uint8(x36) & 0xff)
+ x38 := (x36 >> 8)
+ x39 := (uint8(x38) & 0xff)
+ x40 := (x38 >> 8)
+ x41 := (uint8(x40) & 0xff)
+ x42 := (x40 >> 8)
+ x43 := (uint8(x42) & 0xff)
+ x44 := (x42 >> 8)
+ x45 := (uint8(x44) & 0xff)
+ x46 := uint8((x44 >> 8))
+ x47 := (uint8(x1) & 0xff)
+ x48 := (x1 >> 8)
+ x49 := (uint8(x48) & 0xff)
+ x50 := (x48 >> 8)
+ x51 := (uint8(x50) & 0xff)
+ x52 := (x50 >> 8)
+ x53 := (uint8(x52) & 0xff)
+ x54 := (x52 >> 8)
+ x55 := (uint8(x54) & 0xff)
+ x56 := (x54 >> 8)
+ x57 := (uint8(x56) & 0xff)
+ x58 := (x56 >> 8)
+ x59 := (uint8(x58) & 0xff)
+ x60 := uint8((x58 >> 8))
+ out1[0] = x5
+ out1[1] = x7
+ out1[2] = x9
+ out1[3] = x11
+ out1[4] = x13
+ out1[5] = x15
+ out1[6] = x17
+ out1[7] = x18
+ out1[8] = x19
+ out1[9] = x21
+ out1[10] = x23
+ out1[11] = x25
+ out1[12] = x27
+ out1[13] = x29
+ out1[14] = x31
+ out1[15] = x32
+ out1[16] = x33
+ out1[17] = x35
+ out1[18] = x37
+ out1[19] = x39
+ out1[20] = x41
+ out1[21] = x43
+ out1[22] = x45
+ out1[23] = x46
+ out1[24] = x47
+ out1[25] = x49
+ out1[26] = x51
+ out1[27] = x53
+ out1[28] = x55
+ out1[29] = x57
+ out1[30] = x59
+ out1[31] = x60
+}
+
+// fiatScalarFromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order.
+//
+// Preconditions:
+//
+// 0 ≤ bytes_eval arg1 < m
+//
+// Postconditions:
+//
+// eval out1 mod m = bytes_eval arg1 mod m
+// 0 ≤ eval out1 < m
+//
+// Input Bounds:
+//
+// arg1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0x1f]]
+//
+// Output Bounds:
+//
+// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0x1fffffffffffffff]]
+func fiatScalarFromBytes(out1 *[4]uint64, arg1 *[32]uint8) {
+ x1 := (uint64(arg1[31]) << 56)
+ x2 := (uint64(arg1[30]) << 48)
+ x3 := (uint64(arg1[29]) << 40)
+ x4 := (uint64(arg1[28]) << 32)
+ x5 := (uint64(arg1[27]) << 24)
+ x6 := (uint64(arg1[26]) << 16)
+ x7 := (uint64(arg1[25]) << 8)
+ x8 := arg1[24]
+ x9 := (uint64(arg1[23]) << 56)
+ x10 := (uint64(arg1[22]) << 48)
+ x11 := (uint64(arg1[21]) << 40)
+ x12 := (uint64(arg1[20]) << 32)
+ x13 := (uint64(arg1[19]) << 24)
+ x14 := (uint64(arg1[18]) << 16)
+ x15 := (uint64(arg1[17]) << 8)
+ x16 := arg1[16]
+ x17 := (uint64(arg1[15]) << 56)
+ x18 := (uint64(arg1[14]) << 48)
+ x19 := (uint64(arg1[13]) << 40)
+ x20 := (uint64(arg1[12]) << 32)
+ x21 := (uint64(arg1[11]) << 24)
+ x22 := (uint64(arg1[10]) << 16)
+ x23 := (uint64(arg1[9]) << 8)
+ x24 := arg1[8]
+ x25 := (uint64(arg1[7]) << 56)
+ x26 := (uint64(arg1[6]) << 48)
+ x27 := (uint64(arg1[5]) << 40)
+ x28 := (uint64(arg1[4]) << 32)
+ x29 := (uint64(arg1[3]) << 24)
+ x30 := (uint64(arg1[2]) << 16)
+ x31 := (uint64(arg1[1]) << 8)
+ x32 := arg1[0]
+ x33 := (x31 + uint64(x32))
+ x34 := (x30 + x33)
+ x35 := (x29 + x34)
+ x36 := (x28 + x35)
+ x37 := (x27 + x36)
+ x38 := (x26 + x37)
+ x39 := (x25 + x38)
+ x40 := (x23 + uint64(x24))
+ x41 := (x22 + x40)
+ x42 := (x21 + x41)
+ x43 := (x20 + x42)
+ x44 := (x19 + x43)
+ x45 := (x18 + x44)
+ x46 := (x17 + x45)
+ x47 := (x15 + uint64(x16))
+ x48 := (x14 + x47)
+ x49 := (x13 + x48)
+ x50 := (x12 + x49)
+ x51 := (x11 + x50)
+ x52 := (x10 + x51)
+ x53 := (x9 + x52)
+ x54 := (x7 + uint64(x8))
+ x55 := (x6 + x54)
+ x56 := (x5 + x55)
+ x57 := (x4 + x56)
+ x58 := (x3 + x57)
+ x59 := (x2 + x58)
+ x60 := (x1 + x59)
+ out1[0] = x39
+ out1[1] = x46
+ out1[2] = x53
+ out1[3] = x60
+}
diff --git a/vendor/filippo.io/edwards25519/scalarmult.go b/vendor/filippo.io/edwards25519/scalarmult.go
new file mode 100644
index 00000000..f7ca3cef
--- /dev/null
+++ b/vendor/filippo.io/edwards25519/scalarmult.go
@@ -0,0 +1,214 @@
+// Copyright (c) 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package edwards25519
+
+import "sync"
+
+// basepointTable is a set of 32 affineLookupTables, where table i is generated
+// from 256i * basepoint. It is precomputed the first time it's used.
+func basepointTable() *[32]affineLookupTable {
+ basepointTablePrecomp.initOnce.Do(func() {
+ p := NewGeneratorPoint()
+ for i := 0; i < 32; i++ {
+ basepointTablePrecomp.table[i].FromP3(p)
+ for j := 0; j < 8; j++ {
+ p.Add(p, p)
+ }
+ }
+ })
+ return &basepointTablePrecomp.table
+}
+
+var basepointTablePrecomp struct {
+ table [32]affineLookupTable
+ initOnce sync.Once
+}
+
+// ScalarBaseMult sets v = x * B, where B is the canonical generator, and
+// returns v.
+//
+// The scalar multiplication is done in constant time.
+func (v *Point) ScalarBaseMult(x *Scalar) *Point {
+ basepointTable := basepointTable()
+
+ // Write x = sum(x_i * 16^i) so x*B = sum( B*x_i*16^i )
+ // as described in the Ed25519 paper
+ //
+ // Group even and odd coefficients
+ // x*B = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B
+ // + x_1*16^1*B + x_3*16^3*B + ... + x_63*16^63*B
+ // x*B = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B
+ // + 16*( x_1*16^0*B + x_3*16^2*B + ... + x_63*16^62*B)
+ //
+ // We use a lookup table for each i to get x_i*16^(2*i)*B
+ // and do four doublings to multiply by 16.
+ digits := x.signedRadix16()
+
+ multiple := &affineCached{}
+ tmp1 := &projP1xP1{}
+ tmp2 := &projP2{}
+
+ // Accumulate the odd components first
+ v.Set(NewIdentityPoint())
+ for i := 1; i < 64; i += 2 {
+ basepointTable[i/2].SelectInto(multiple, digits[i])
+ tmp1.AddAffine(v, multiple)
+ v.fromP1xP1(tmp1)
+ }
+
+ // Multiply by 16
+ tmp2.FromP3(v) // tmp2 = v in P2 coords
+ tmp1.Double(tmp2) // tmp1 = 2*v in P1xP1 coords
+ tmp2.FromP1xP1(tmp1) // tmp2 = 2*v in P2 coords
+ tmp1.Double(tmp2) // tmp1 = 4*v in P1xP1 coords
+ tmp2.FromP1xP1(tmp1) // tmp2 = 4*v in P2 coords
+ tmp1.Double(tmp2) // tmp1 = 8*v in P1xP1 coords
+ tmp2.FromP1xP1(tmp1) // tmp2 = 8*v in P2 coords
+ tmp1.Double(tmp2) // tmp1 = 16*v in P1xP1 coords
+ v.fromP1xP1(tmp1) // now v = 16*(odd components)
+
+ // Accumulate the even components
+ for i := 0; i < 64; i += 2 {
+ basepointTable[i/2].SelectInto(multiple, digits[i])
+ tmp1.AddAffine(v, multiple)
+ v.fromP1xP1(tmp1)
+ }
+
+ return v
+}
+
+// ScalarMult sets v = x * q, and returns v.
+//
+// The scalar multiplication is done in constant time.
+func (v *Point) ScalarMult(x *Scalar, q *Point) *Point {
+ checkInitialized(q)
+
+ var table projLookupTable
+ table.FromP3(q)
+
+ // Write x = sum(x_i * 16^i)
+ // so x*Q = sum( Q*x_i*16^i )
+ // = Q*x_0 + 16*(Q*x_1 + 16*( ... + Q*x_63) ... )
+ // <------compute inside out---------
+ //
+ // We use the lookup table to get the x_i*Q values
+ // and do four doublings to compute 16*Q
+ digits := x.signedRadix16()
+
+ // Unwrap first loop iteration to save computing 16*identity
+ multiple := &projCached{}
+ tmp1 := &projP1xP1{}
+ tmp2 := &projP2{}
+ table.SelectInto(multiple, digits[63])
+
+ v.Set(NewIdentityPoint())
+ tmp1.Add(v, multiple) // tmp1 = x_63*Q in P1xP1 coords
+ for i := 62; i >= 0; i-- {
+ tmp2.FromP1xP1(tmp1) // tmp2 = (prev) in P2 coords
+ tmp1.Double(tmp2) // tmp1 = 2*(prev) in P1xP1 coords
+ tmp2.FromP1xP1(tmp1) // tmp2 = 2*(prev) in P2 coords
+ tmp1.Double(tmp2) // tmp1 = 4*(prev) in P1xP1 coords
+ tmp2.FromP1xP1(tmp1) // tmp2 = 4*(prev) in P2 coords
+ tmp1.Double(tmp2) // tmp1 = 8*(prev) in P1xP1 coords
+ tmp2.FromP1xP1(tmp1) // tmp2 = 8*(prev) in P2 coords
+ tmp1.Double(tmp2) // tmp1 = 16*(prev) in P1xP1 coords
+ v.fromP1xP1(tmp1) // v = 16*(prev) in P3 coords
+ table.SelectInto(multiple, digits[i])
+ tmp1.Add(v, multiple) // tmp1 = x_i*Q + 16*(prev) in P1xP1 coords
+ }
+ v.fromP1xP1(tmp1)
+ return v
+}
+
+// basepointNafTable is the nafLookupTable8 for the basepoint.
+// It is precomputed the first time it's used.
+func basepointNafTable() *nafLookupTable8 {
+ basepointNafTablePrecomp.initOnce.Do(func() {
+ basepointNafTablePrecomp.table.FromP3(NewGeneratorPoint())
+ })
+ return &basepointNafTablePrecomp.table
+}
+
+var basepointNafTablePrecomp struct {
+ table nafLookupTable8
+ initOnce sync.Once
+}
+
+// VarTimeDoubleScalarBaseMult sets v = a * A + b * B, where B is the canonical
+// generator, and returns v.
+//
+// Execution time depends on the inputs.
+func (v *Point) VarTimeDoubleScalarBaseMult(a *Scalar, A *Point, b *Scalar) *Point {
+ checkInitialized(A)
+
+ // Similarly to the single variable-base approach, we compute
+ // digits and use them with a lookup table. However, because
+ // we are allowed to do variable-time operations, we don't
+ // need constant-time lookups or constant-time digit
+ // computations.
+ //
+ // So we use a non-adjacent form of some width w instead of
+ // radix 16. This is like a binary representation (one digit
+ // for each binary place) but we allow the digits to grow in
+ // magnitude up to 2^{w-1} so that the nonzero digits are as
+ // sparse as possible. Intuitively, this "condenses" the
+ // "mass" of the scalar onto sparse coefficients (meaning
+ // fewer additions).
+
+ basepointNafTable := basepointNafTable()
+ var aTable nafLookupTable5
+ aTable.FromP3(A)
+ // Because the basepoint is fixed, we can use a wider NAF
+ // corresponding to a bigger table.
+ aNaf := a.nonAdjacentForm(5)
+ bNaf := b.nonAdjacentForm(8)
+
+ // Find the first nonzero coefficient.
+ i := 255
+ for j := i; j >= 0; j-- {
+ if aNaf[j] != 0 || bNaf[j] != 0 {
+ break
+ }
+ }
+
+ multA := &projCached{}
+ multB := &affineCached{}
+ tmp1 := &projP1xP1{}
+ tmp2 := &projP2{}
+ tmp2.Zero()
+
+ // Move from high to low bits, doubling the accumulator
+ // at each iteration and checking whether there is a nonzero
+ // coefficient to look up a multiple of.
+ for ; i >= 0; i-- {
+ tmp1.Double(tmp2)
+
+ // Only update v if we have a nonzero coeff to add in.
+ if aNaf[i] > 0 {
+ v.fromP1xP1(tmp1)
+ aTable.SelectInto(multA, aNaf[i])
+ tmp1.Add(v, multA)
+ } else if aNaf[i] < 0 {
+ v.fromP1xP1(tmp1)
+ aTable.SelectInto(multA, -aNaf[i])
+ tmp1.Sub(v, multA)
+ }
+
+ if bNaf[i] > 0 {
+ v.fromP1xP1(tmp1)
+ basepointNafTable.SelectInto(multB, bNaf[i])
+ tmp1.AddAffine(v, multB)
+ } else if bNaf[i] < 0 {
+ v.fromP1xP1(tmp1)
+ basepointNafTable.SelectInto(multB, -bNaf[i])
+ tmp1.SubAffine(v, multB)
+ }
+
+ tmp2.FromP1xP1(tmp1)
+ }
+
+ v.fromP2(tmp2)
+ return v
+}
diff --git a/vendor/filippo.io/edwards25519/tables.go b/vendor/filippo.io/edwards25519/tables.go
new file mode 100644
index 00000000..83234bbc
--- /dev/null
+++ b/vendor/filippo.io/edwards25519/tables.go
@@ -0,0 +1,129 @@
+// Copyright (c) 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package edwards25519
+
+import (
+ "crypto/subtle"
+)
+
+// A dynamic lookup table for variable-base, constant-time scalar muls.
+type projLookupTable struct {
+ points [8]projCached
+}
+
+// A precomputed lookup table for fixed-base, constant-time scalar muls.
+type affineLookupTable struct {
+ points [8]affineCached
+}
+
+// A dynamic lookup table for variable-base, variable-time scalar muls.
+type nafLookupTable5 struct {
+ points [8]projCached
+}
+
+// A precomputed lookup table for fixed-base, variable-time scalar muls.
+type nafLookupTable8 struct {
+ points [64]affineCached
+}
+
+// Constructors.
+
+// Builds a lookup table at runtime. Fast.
+func (v *projLookupTable) FromP3(q *Point) {
+ // Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q
+ // This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q
+ v.points[0].FromP3(q)
+ tmpP3 := Point{}
+ tmpP1xP1 := projP1xP1{}
+ for i := 0; i < 7; i++ {
+ // Compute (i+1)*Q as Q + i*Q and convert to a projCached
+ // This is needlessly complicated because the API has explicit
+ // receivers instead of creating stack objects and relying on RVO
+ v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(q, &v.points[i])))
+ }
+}
+
+// This is not optimised for speed; fixed-base tables should be precomputed.
+func (v *affineLookupTable) FromP3(q *Point) {
+ // Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q
+ // This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q
+ v.points[0].FromP3(q)
+ tmpP3 := Point{}
+ tmpP1xP1 := projP1xP1{}
+ for i := 0; i < 7; i++ {
+ // Compute (i+1)*Q as Q + i*Q and convert to affineCached
+ v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(q, &v.points[i])))
+ }
+}
+
+// Builds a lookup table at runtime. Fast.
+func (v *nafLookupTable5) FromP3(q *Point) {
+ // Goal: v.points[i] = (2*i+1)*Q, i.e., Q, 3Q, 5Q, ..., 15Q
+ // This allows lookup of -15Q, ..., -3Q, -Q, 0, Q, 3Q, ..., 15Q
+ v.points[0].FromP3(q)
+ q2 := Point{}
+ q2.Add(q, q)
+ tmpP3 := Point{}
+ tmpP1xP1 := projP1xP1{}
+ for i := 0; i < 7; i++ {
+ v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(&q2, &v.points[i])))
+ }
+}
+
+// This is not optimised for speed; fixed-base tables should be precomputed.
+func (v *nafLookupTable8) FromP3(q *Point) {
+ v.points[0].FromP3(q)
+ q2 := Point{}
+ q2.Add(q, q)
+ tmpP3 := Point{}
+ tmpP1xP1 := projP1xP1{}
+ for i := 0; i < 63; i++ {
+ v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(&q2, &v.points[i])))
+ }
+}
+
+// Selectors.
+
+// Set dest to x*Q, where -8 <= x <= 8, in constant time.
+func (v *projLookupTable) SelectInto(dest *projCached, x int8) {
+ // Compute xabs = |x|
+ xmask := x >> 7
+ xabs := uint8((x + xmask) ^ xmask)
+
+ dest.Zero()
+ for j := 1; j <= 8; j++ {
+ // Set dest = j*Q if |x| = j
+ cond := subtle.ConstantTimeByteEq(xabs, uint8(j))
+ dest.Select(&v.points[j-1], dest, cond)
+ }
+ // Now dest = |x|*Q, conditionally negate to get x*Q
+ dest.CondNeg(int(xmask & 1))
+}
+
+// Set dest to x*Q, where -8 <= x <= 8, in constant time.
+func (v *affineLookupTable) SelectInto(dest *affineCached, x int8) {
+ // Compute xabs = |x|
+ xmask := x >> 7
+ xabs := uint8((x + xmask) ^ xmask)
+
+ dest.Zero()
+ for j := 1; j <= 8; j++ {
+ // Set dest = j*Q if |x| = j
+ cond := subtle.ConstantTimeByteEq(xabs, uint8(j))
+ dest.Select(&v.points[j-1], dest, cond)
+ }
+ // Now dest = |x|*Q, conditionally negate to get x*Q
+ dest.CondNeg(int(xmask & 1))
+}
+
+// Given odd x with 0 < x < 2^4, return x*Q (in variable time).
+func (v *nafLookupTable5) SelectInto(dest *projCached, x int8) {
+ *dest = v.points[x/2]
+}
+
+// Given odd x with 0 < x < 2^7, return x*Q (in variable time).
+func (v *nafLookupTable8) SelectInto(dest *affineCached, x int8) {
+ *dest = v.points[x/2]
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/LICENSE b/vendor/github.com/Azure/go-ansiterm/LICENSE
new file mode 100644
index 00000000..e3d9a64d
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Microsoft Corporation
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/github.com/Azure/go-ansiterm/README.md b/vendor/github.com/Azure/go-ansiterm/README.md
new file mode 100644
index 00000000..261c041e
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/README.md
@@ -0,0 +1,12 @@
+# go-ansiterm
+
+This is a cross platform Ansi Terminal Emulation library. It reads a stream of Ansi characters and produces the appropriate function calls. The results of the function calls are platform dependent.
+
+For example the parser might receive "ESC, [, A" as a stream of three characters. This is the code for Cursor Up (http://www.vt100.net/docs/vt510-rm/CUU). The parser then calls the cursor up function (CUU()) on an event handler. The event handler determines what platform specific work must be done to cause the cursor to move up one position.
+
+The parser (parser.go) is a partial implementation of this state machine (http://vt100.net/emu/vt500_parser.png). There are also two event handler implementations, one for tests (test_event_handler.go) to validate that the expected events are being produced and called, the other is a Windows implementation (winterm/win_event_handler.go).
+
+See parser_test.go for examples exercising the state machine and generating appropriate function calls.
+
+-----
+This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
diff --git a/vendor/github.com/Azure/go-ansiterm/SECURITY.md b/vendor/github.com/Azure/go-ansiterm/SECURITY.md
new file mode 100644
index 00000000..e138ec5d
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/SECURITY.md
@@ -0,0 +1,41 @@
+
+
+## Security
+
+Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
+
+If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
+
+## Reporting Security Issues
+
+**Please do not report security vulnerabilities through public GitHub issues.**
+
+Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
+
+If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
+
+You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
+
+Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
+
+ * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
+ * Full paths of source file(s) related to the manifestation of the issue
+ * The location of the affected source code (tag/branch/commit or direct URL)
+ * Any special configuration required to reproduce the issue
+ * Step-by-step instructions to reproduce the issue
+ * Proof-of-concept or exploit code (if possible)
+ * Impact of the issue, including how an attacker might exploit the issue
+
+This information will help us triage your report more quickly.
+
+If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
+
+## Preferred Languages
+
+We prefer all communications to be in English.
+
+## Policy
+
+Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
+
+
diff --git a/vendor/github.com/Azure/go-ansiterm/constants.go b/vendor/github.com/Azure/go-ansiterm/constants.go
new file mode 100644
index 00000000..96504a33
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/constants.go
@@ -0,0 +1,188 @@
+package ansiterm
+
+const LogEnv = "DEBUG_TERMINAL"
+
+// ANSI constants
+// References:
+// -- http://www.ecma-international.org/publications/standards/Ecma-048.htm
+// -- http://man7.org/linux/man-pages/man4/console_codes.4.html
+// -- http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html
+// -- http://en.wikipedia.org/wiki/ANSI_escape_code
+// -- http://vt100.net/emu/dec_ansi_parser
+// -- http://vt100.net/emu/vt500_parser.svg
+// -- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+// -- http://www.inwap.com/pdp10/ansicode.txt
+const (
+ // ECMA-48 Set Graphics Rendition
+ // Note:
+ // -- Constants leading with an underscore (e.g., _ANSI_xxx) are unsupported or reserved
+ // -- Fonts could possibly be supported via SetCurrentConsoleFontEx
+ // -- Windows does not expose the per-window cursor (i.e., caret) blink times
+ ANSI_SGR_RESET = 0
+ ANSI_SGR_BOLD = 1
+ ANSI_SGR_DIM = 2
+ _ANSI_SGR_ITALIC = 3
+ ANSI_SGR_UNDERLINE = 4
+ _ANSI_SGR_BLINKSLOW = 5
+ _ANSI_SGR_BLINKFAST = 6
+ ANSI_SGR_REVERSE = 7
+ _ANSI_SGR_INVISIBLE = 8
+ _ANSI_SGR_LINETHROUGH = 9
+ _ANSI_SGR_FONT_00 = 10
+ _ANSI_SGR_FONT_01 = 11
+ _ANSI_SGR_FONT_02 = 12
+ _ANSI_SGR_FONT_03 = 13
+ _ANSI_SGR_FONT_04 = 14
+ _ANSI_SGR_FONT_05 = 15
+ _ANSI_SGR_FONT_06 = 16
+ _ANSI_SGR_FONT_07 = 17
+ _ANSI_SGR_FONT_08 = 18
+ _ANSI_SGR_FONT_09 = 19
+ _ANSI_SGR_FONT_10 = 20
+ _ANSI_SGR_DOUBLEUNDERLINE = 21
+ ANSI_SGR_BOLD_DIM_OFF = 22
+ _ANSI_SGR_ITALIC_OFF = 23
+ ANSI_SGR_UNDERLINE_OFF = 24
+ _ANSI_SGR_BLINK_OFF = 25
+ _ANSI_SGR_RESERVED_00 = 26
+ ANSI_SGR_REVERSE_OFF = 27
+ _ANSI_SGR_INVISIBLE_OFF = 28
+ _ANSI_SGR_LINETHROUGH_OFF = 29
+ ANSI_SGR_FOREGROUND_BLACK = 30
+ ANSI_SGR_FOREGROUND_RED = 31
+ ANSI_SGR_FOREGROUND_GREEN = 32
+ ANSI_SGR_FOREGROUND_YELLOW = 33
+ ANSI_SGR_FOREGROUND_BLUE = 34
+ ANSI_SGR_FOREGROUND_MAGENTA = 35
+ ANSI_SGR_FOREGROUND_CYAN = 36
+ ANSI_SGR_FOREGROUND_WHITE = 37
+ _ANSI_SGR_RESERVED_01 = 38
+ ANSI_SGR_FOREGROUND_DEFAULT = 39
+ ANSI_SGR_BACKGROUND_BLACK = 40
+ ANSI_SGR_BACKGROUND_RED = 41
+ ANSI_SGR_BACKGROUND_GREEN = 42
+ ANSI_SGR_BACKGROUND_YELLOW = 43
+ ANSI_SGR_BACKGROUND_BLUE = 44
+ ANSI_SGR_BACKGROUND_MAGENTA = 45
+ ANSI_SGR_BACKGROUND_CYAN = 46
+ ANSI_SGR_BACKGROUND_WHITE = 47
+ _ANSI_SGR_RESERVED_02 = 48
+ ANSI_SGR_BACKGROUND_DEFAULT = 49
+ // 50 - 65: Unsupported
+
+ ANSI_MAX_CMD_LENGTH = 4096
+
+ MAX_INPUT_EVENTS = 128
+ DEFAULT_WIDTH = 80
+ DEFAULT_HEIGHT = 24
+
+ ANSI_BEL = 0x07
+ ANSI_BACKSPACE = 0x08
+ ANSI_TAB = 0x09
+ ANSI_LINE_FEED = 0x0A
+ ANSI_VERTICAL_TAB = 0x0B
+ ANSI_FORM_FEED = 0x0C
+ ANSI_CARRIAGE_RETURN = 0x0D
+ ANSI_ESCAPE_PRIMARY = 0x1B
+ ANSI_ESCAPE_SECONDARY = 0x5B
+ ANSI_OSC_STRING_ENTRY = 0x5D
+ ANSI_COMMAND_FIRST = 0x40
+ ANSI_COMMAND_LAST = 0x7E
+ DCS_ENTRY = 0x90
+ CSI_ENTRY = 0x9B
+ OSC_STRING = 0x9D
+ ANSI_PARAMETER_SEP = ";"
+ ANSI_CMD_G0 = '('
+ ANSI_CMD_G1 = ')'
+ ANSI_CMD_G2 = '*'
+ ANSI_CMD_G3 = '+'
+ ANSI_CMD_DECPNM = '>'
+ ANSI_CMD_DECPAM = '='
+ ANSI_CMD_OSC = ']'
+ ANSI_CMD_STR_TERM = '\\'
+
+ KEY_CONTROL_PARAM_2 = ";2"
+ KEY_CONTROL_PARAM_3 = ";3"
+ KEY_CONTROL_PARAM_4 = ";4"
+ KEY_CONTROL_PARAM_5 = ";5"
+ KEY_CONTROL_PARAM_6 = ";6"
+ KEY_CONTROL_PARAM_7 = ";7"
+ KEY_CONTROL_PARAM_8 = ";8"
+ KEY_ESC_CSI = "\x1B["
+ KEY_ESC_N = "\x1BN"
+ KEY_ESC_O = "\x1BO"
+
+ FILL_CHARACTER = ' '
+)
+
+func getByteRange(start byte, end byte) []byte {
+ bytes := make([]byte, 0, 32)
+ for i := start; i <= end; i++ {
+ bytes = append(bytes, byte(i))
+ }
+
+ return bytes
+}
+
+var toGroundBytes = getToGroundBytes()
+var executors = getExecuteBytes()
+
+// SPACE 20+A0 hex Always and everywhere a blank space
+// Intermediate 20-2F hex !"#$%&'()*+,-./
+var intermeds = getByteRange(0x20, 0x2F)
+
+// Parameters 30-3F hex 0123456789:;<=>?
+// CSI Parameters 30-39, 3B hex 0123456789;
+var csiParams = getByteRange(0x30, 0x3F)
+
+var csiCollectables = append(getByteRange(0x30, 0x39), getByteRange(0x3B, 0x3F)...)
+
+// Uppercase 40-5F hex @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
+var upperCase = getByteRange(0x40, 0x5F)
+
+// Lowercase 60-7E hex `abcdefghijlkmnopqrstuvwxyz{|}~
+var lowerCase = getByteRange(0x60, 0x7E)
+
+// Alphabetics 40-7E hex (all of upper and lower case)
+var alphabetics = append(upperCase, lowerCase...)
+
+var printables = getByteRange(0x20, 0x7F)
+
+var escapeIntermediateToGroundBytes = getByteRange(0x30, 0x7E)
+var escapeToGroundBytes = getEscapeToGroundBytes()
+
+// See http://www.vt100.net/emu/vt500_parser.png for description of the complex
+// byte ranges below
+
+func getEscapeToGroundBytes() []byte {
+ escapeToGroundBytes := getByteRange(0x30, 0x4F)
+ escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x51, 0x57)...)
+ escapeToGroundBytes = append(escapeToGroundBytes, 0x59)
+ escapeToGroundBytes = append(escapeToGroundBytes, 0x5A)
+ escapeToGroundBytes = append(escapeToGroundBytes, 0x5C)
+ escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x60, 0x7E)...)
+ return escapeToGroundBytes
+}
+
+func getExecuteBytes() []byte {
+ executeBytes := getByteRange(0x00, 0x17)
+ executeBytes = append(executeBytes, 0x19)
+ executeBytes = append(executeBytes, getByteRange(0x1C, 0x1F)...)
+ return executeBytes
+}
+
+func getToGroundBytes() []byte {
+ groundBytes := []byte{0x18}
+ groundBytes = append(groundBytes, 0x1A)
+ groundBytes = append(groundBytes, getByteRange(0x80, 0x8F)...)
+ groundBytes = append(groundBytes, getByteRange(0x91, 0x97)...)
+ groundBytes = append(groundBytes, 0x99)
+ groundBytes = append(groundBytes, 0x9A)
+ groundBytes = append(groundBytes, 0x9C)
+ return groundBytes
+}
+
+// Delete 7F hex Always and everywhere ignored
+// C1 Control 80-9F hex 32 additional control characters
+// G1 Displayable A1-FE hex 94 additional displayable characters
+// Special A0+FF hex Same as SPACE and DELETE
diff --git a/vendor/github.com/Azure/go-ansiterm/context.go b/vendor/github.com/Azure/go-ansiterm/context.go
new file mode 100644
index 00000000..8d66e777
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/context.go
@@ -0,0 +1,7 @@
+package ansiterm
+
+type ansiContext struct {
+ currentChar byte
+ paramBuffer []byte
+ interBuffer []byte
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go b/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go
new file mode 100644
index 00000000..bcbe00d0
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go
@@ -0,0 +1,49 @@
+package ansiterm
+
+type csiEntryState struct {
+ baseState
+}
+
+func (csiState csiEntryState) Handle(b byte) (s state, e error) {
+ csiState.parser.logf("CsiEntry::Handle %#x", b)
+
+ nextState, err := csiState.baseState.Handle(b)
+ if nextState != nil || err != nil {
+ return nextState, err
+ }
+
+ switch {
+ case sliceContains(alphabetics, b):
+ return csiState.parser.ground, nil
+ case sliceContains(csiCollectables, b):
+ return csiState.parser.csiParam, nil
+ case sliceContains(executors, b):
+ return csiState, csiState.parser.execute()
+ }
+
+ return csiState, nil
+}
+
+func (csiState csiEntryState) Transition(s state) error {
+ csiState.parser.logf("CsiEntry::Transition %s --> %s", csiState.Name(), s.Name())
+ csiState.baseState.Transition(s)
+
+ switch s {
+ case csiState.parser.ground:
+ return csiState.parser.csiDispatch()
+ case csiState.parser.csiParam:
+ switch {
+ case sliceContains(csiParams, csiState.parser.context.currentChar):
+ csiState.parser.collectParam()
+ case sliceContains(intermeds, csiState.parser.context.currentChar):
+ csiState.parser.collectInter()
+ }
+ }
+
+ return nil
+}
+
+func (csiState csiEntryState) Enter() error {
+ csiState.parser.clear()
+ return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/csi_param_state.go b/vendor/github.com/Azure/go-ansiterm/csi_param_state.go
new file mode 100644
index 00000000..7ed5e01c
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/csi_param_state.go
@@ -0,0 +1,38 @@
+package ansiterm
+
+type csiParamState struct {
+ baseState
+}
+
+func (csiState csiParamState) Handle(b byte) (s state, e error) {
+ csiState.parser.logf("CsiParam::Handle %#x", b)
+
+ nextState, err := csiState.baseState.Handle(b)
+ if nextState != nil || err != nil {
+ return nextState, err
+ }
+
+ switch {
+ case sliceContains(alphabetics, b):
+ return csiState.parser.ground, nil
+ case sliceContains(csiCollectables, b):
+ csiState.parser.collectParam()
+ return csiState, nil
+ case sliceContains(executors, b):
+ return csiState, csiState.parser.execute()
+ }
+
+ return csiState, nil
+}
+
+func (csiState csiParamState) Transition(s state) error {
+ csiState.parser.logf("CsiParam::Transition %s --> %s", csiState.Name(), s.Name())
+ csiState.baseState.Transition(s)
+
+ switch s {
+ case csiState.parser.ground:
+ return csiState.parser.csiDispatch()
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go b/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go
new file mode 100644
index 00000000..1c719db9
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go
@@ -0,0 +1,36 @@
+package ansiterm
+
+type escapeIntermediateState struct {
+ baseState
+}
+
+func (escState escapeIntermediateState) Handle(b byte) (s state, e error) {
+ escState.parser.logf("escapeIntermediateState::Handle %#x", b)
+ nextState, err := escState.baseState.Handle(b)
+ if nextState != nil || err != nil {
+ return nextState, err
+ }
+
+ switch {
+ case sliceContains(intermeds, b):
+ return escState, escState.parser.collectInter()
+ case sliceContains(executors, b):
+ return escState, escState.parser.execute()
+ case sliceContains(escapeIntermediateToGroundBytes, b):
+ return escState.parser.ground, nil
+ }
+
+ return escState, nil
+}
+
+func (escState escapeIntermediateState) Transition(s state) error {
+ escState.parser.logf("escapeIntermediateState::Transition %s --> %s", escState.Name(), s.Name())
+ escState.baseState.Transition(s)
+
+ switch s {
+ case escState.parser.ground:
+ return escState.parser.escDispatch()
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/escape_state.go b/vendor/github.com/Azure/go-ansiterm/escape_state.go
new file mode 100644
index 00000000..6390abd2
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/escape_state.go
@@ -0,0 +1,47 @@
+package ansiterm
+
+type escapeState struct {
+ baseState
+}
+
+func (escState escapeState) Handle(b byte) (s state, e error) {
+ escState.parser.logf("escapeState::Handle %#x", b)
+ nextState, err := escState.baseState.Handle(b)
+ if nextState != nil || err != nil {
+ return nextState, err
+ }
+
+ switch {
+ case b == ANSI_ESCAPE_SECONDARY:
+ return escState.parser.csiEntry, nil
+ case b == ANSI_OSC_STRING_ENTRY:
+ return escState.parser.oscString, nil
+ case sliceContains(executors, b):
+ return escState, escState.parser.execute()
+ case sliceContains(escapeToGroundBytes, b):
+ return escState.parser.ground, nil
+ case sliceContains(intermeds, b):
+ return escState.parser.escapeIntermediate, nil
+ }
+
+ return escState, nil
+}
+
+func (escState escapeState) Transition(s state) error {
+ escState.parser.logf("Escape::Transition %s --> %s", escState.Name(), s.Name())
+ escState.baseState.Transition(s)
+
+ switch s {
+ case escState.parser.ground:
+ return escState.parser.escDispatch()
+ case escState.parser.escapeIntermediate:
+ return escState.parser.collectInter()
+ }
+
+ return nil
+}
+
+func (escState escapeState) Enter() error {
+ escState.parser.clear()
+ return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/event_handler.go b/vendor/github.com/Azure/go-ansiterm/event_handler.go
new file mode 100644
index 00000000..98087b38
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/event_handler.go
@@ -0,0 +1,90 @@
+package ansiterm
+
+type AnsiEventHandler interface {
+ // Print
+ Print(b byte) error
+
+ // Execute C0 commands
+ Execute(b byte) error
+
+ // CUrsor Up
+ CUU(int) error
+
+ // CUrsor Down
+ CUD(int) error
+
+ // CUrsor Forward
+ CUF(int) error
+
+ // CUrsor Backward
+ CUB(int) error
+
+ // Cursor to Next Line
+ CNL(int) error
+
+ // Cursor to Previous Line
+ CPL(int) error
+
+ // Cursor Horizontal position Absolute
+ CHA(int) error
+
+ // Vertical line Position Absolute
+ VPA(int) error
+
+ // CUrsor Position
+ CUP(int, int) error
+
+ // Horizontal and Vertical Position (depends on PUM)
+ HVP(int, int) error
+
+ // Text Cursor Enable Mode
+ DECTCEM(bool) error
+
+ // Origin Mode
+ DECOM(bool) error
+
+ // 132 Column Mode
+ DECCOLM(bool) error
+
+ // Erase in Display
+ ED(int) error
+
+ // Erase in Line
+ EL(int) error
+
+ // Insert Line
+ IL(int) error
+
+ // Delete Line
+ DL(int) error
+
+ // Insert Character
+ ICH(int) error
+
+ // Delete Character
+ DCH(int) error
+
+ // Set Graphics Rendition
+ SGR([]int) error
+
+ // Pan Down
+ SU(int) error
+
+ // Pan Up
+ SD(int) error
+
+ // Device Attributes
+ DA([]string) error
+
+ // Set Top and Bottom Margins
+ DECSTBM(int, int) error
+
+ // Index
+ IND() error
+
+ // Reverse Index
+ RI() error
+
+ // Flush updates from previous commands
+ Flush() error
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/ground_state.go b/vendor/github.com/Azure/go-ansiterm/ground_state.go
new file mode 100644
index 00000000..52451e94
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/ground_state.go
@@ -0,0 +1,24 @@
+package ansiterm
+
+type groundState struct {
+ baseState
+}
+
+func (gs groundState) Handle(b byte) (s state, e error) {
+ gs.parser.context.currentChar = b
+
+ nextState, err := gs.baseState.Handle(b)
+ if nextState != nil || err != nil {
+ return nextState, err
+ }
+
+ switch {
+ case sliceContains(printables, b):
+ return gs, gs.parser.print()
+
+ case sliceContains(executors, b):
+ return gs, gs.parser.execute()
+ }
+
+ return gs, nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/osc_string_state.go b/vendor/github.com/Azure/go-ansiterm/osc_string_state.go
new file mode 100644
index 00000000..593b10ab
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/osc_string_state.go
@@ -0,0 +1,31 @@
+package ansiterm
+
+type oscStringState struct {
+ baseState
+}
+
+func (oscState oscStringState) Handle(b byte) (s state, e error) {
+ oscState.parser.logf("OscString::Handle %#x", b)
+ nextState, err := oscState.baseState.Handle(b)
+ if nextState != nil || err != nil {
+ return nextState, err
+ }
+
+ switch {
+ case isOscStringTerminator(b):
+ return oscState.parser.ground, nil
+ }
+
+ return oscState, nil
+}
+
+// See below for OSC string terminators for linux
+// http://man7.org/linux/man-pages/man4/console_codes.4.html
+func isOscStringTerminator(b byte) bool {
+
+ if b == ANSI_BEL || b == 0x5C {
+ return true
+ }
+
+ return false
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/parser.go b/vendor/github.com/Azure/go-ansiterm/parser.go
new file mode 100644
index 00000000..03cec7ad
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/parser.go
@@ -0,0 +1,151 @@
+package ansiterm
+
+import (
+ "errors"
+ "log"
+ "os"
+)
+
+type AnsiParser struct {
+ currState state
+ eventHandler AnsiEventHandler
+ context *ansiContext
+ csiEntry state
+ csiParam state
+ dcsEntry state
+ escape state
+ escapeIntermediate state
+ error state
+ ground state
+ oscString state
+ stateMap []state
+
+ logf func(string, ...interface{})
+}
+
+type Option func(*AnsiParser)
+
+func WithLogf(f func(string, ...interface{})) Option {
+ return func(ap *AnsiParser) {
+ ap.logf = f
+ }
+}
+
+func CreateParser(initialState string, evtHandler AnsiEventHandler, opts ...Option) *AnsiParser {
+ ap := &AnsiParser{
+ eventHandler: evtHandler,
+ context: &ansiContext{},
+ }
+ for _, o := range opts {
+ o(ap)
+ }
+
+ if isDebugEnv := os.Getenv(LogEnv); isDebugEnv == "1" {
+ logFile, _ := os.Create("ansiParser.log")
+ logger := log.New(logFile, "", log.LstdFlags)
+ if ap.logf != nil {
+ l := ap.logf
+ ap.logf = func(s string, v ...interface{}) {
+ l(s, v...)
+ logger.Printf(s, v...)
+ }
+ } else {
+ ap.logf = logger.Printf
+ }
+ }
+
+ if ap.logf == nil {
+ ap.logf = func(string, ...interface{}) {}
+ }
+
+ ap.csiEntry = csiEntryState{baseState{name: "CsiEntry", parser: ap}}
+ ap.csiParam = csiParamState{baseState{name: "CsiParam", parser: ap}}
+ ap.dcsEntry = dcsEntryState{baseState{name: "DcsEntry", parser: ap}}
+ ap.escape = escapeState{baseState{name: "Escape", parser: ap}}
+ ap.escapeIntermediate = escapeIntermediateState{baseState{name: "EscapeIntermediate", parser: ap}}
+ ap.error = errorState{baseState{name: "Error", parser: ap}}
+ ap.ground = groundState{baseState{name: "Ground", parser: ap}}
+ ap.oscString = oscStringState{baseState{name: "OscString", parser: ap}}
+
+ ap.stateMap = []state{
+ ap.csiEntry,
+ ap.csiParam,
+ ap.dcsEntry,
+ ap.escape,
+ ap.escapeIntermediate,
+ ap.error,
+ ap.ground,
+ ap.oscString,
+ }
+
+ ap.currState = getState(initialState, ap.stateMap)
+
+ ap.logf("CreateParser: parser %p", ap)
+ return ap
+}
+
+func getState(name string, states []state) state {
+ for _, el := range states {
+ if el.Name() == name {
+ return el
+ }
+ }
+
+ return nil
+}
+
+func (ap *AnsiParser) Parse(bytes []byte) (int, error) {
+ for i, b := range bytes {
+ if err := ap.handle(b); err != nil {
+ return i, err
+ }
+ }
+
+ return len(bytes), ap.eventHandler.Flush()
+}
+
+func (ap *AnsiParser) handle(b byte) error {
+ ap.context.currentChar = b
+ newState, err := ap.currState.Handle(b)
+ if err != nil {
+ return err
+ }
+
+ if newState == nil {
+ ap.logf("WARNING: newState is nil")
+ return errors.New("New state of 'nil' is invalid.")
+ }
+
+ if newState != ap.currState {
+ if err := ap.changeState(newState); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (ap *AnsiParser) changeState(newState state) error {
+ ap.logf("ChangeState %s --> %s", ap.currState.Name(), newState.Name())
+
+ // Exit old state
+ if err := ap.currState.Exit(); err != nil {
+ ap.logf("Exit state '%s' failed with : '%v'", ap.currState.Name(), err)
+ return err
+ }
+
+ // Perform transition action
+ if err := ap.currState.Transition(newState); err != nil {
+ ap.logf("Transition from '%s' to '%s' failed with: '%v'", ap.currState.Name(), newState.Name, err)
+ return err
+ }
+
+ // Enter new state
+ if err := newState.Enter(); err != nil {
+ ap.logf("Enter state '%s' failed with: '%v'", newState.Name(), err)
+ return err
+ }
+
+ ap.currState = newState
+ return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go b/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go
new file mode 100644
index 00000000..de0a1f9c
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go
@@ -0,0 +1,99 @@
+package ansiterm
+
+import (
+ "strconv"
+)
+
+func parseParams(bytes []byte) ([]string, error) {
+ paramBuff := make([]byte, 0, 0)
+ params := []string{}
+
+ for _, v := range bytes {
+ if v == ';' {
+ if len(paramBuff) > 0 {
+ // Completed parameter, append it to the list
+ s := string(paramBuff)
+ params = append(params, s)
+ paramBuff = make([]byte, 0, 0)
+ }
+ } else {
+ paramBuff = append(paramBuff, v)
+ }
+ }
+
+ // Last parameter may not be terminated with ';'
+ if len(paramBuff) > 0 {
+ s := string(paramBuff)
+ params = append(params, s)
+ }
+
+ return params, nil
+}
+
+func parseCmd(context ansiContext) (string, error) {
+ return string(context.currentChar), nil
+}
+
+func getInt(params []string, dflt int) int {
+ i := getInts(params, 1, dflt)[0]
+ return i
+}
+
+func getInts(params []string, minCount int, dflt int) []int {
+ ints := []int{}
+
+ for _, v := range params {
+ i, _ := strconv.Atoi(v)
+ // Zero is mapped to the default value in VT100.
+ if i == 0 {
+ i = dflt
+ }
+ ints = append(ints, i)
+ }
+
+ if len(ints) < minCount {
+ remaining := minCount - len(ints)
+ for i := 0; i < remaining; i++ {
+ ints = append(ints, dflt)
+ }
+ }
+
+ return ints
+}
+
+func (ap *AnsiParser) modeDispatch(param string, set bool) error {
+ switch param {
+ case "?3":
+ return ap.eventHandler.DECCOLM(set)
+ case "?6":
+ return ap.eventHandler.DECOM(set)
+ case "?25":
+ return ap.eventHandler.DECTCEM(set)
+ }
+ return nil
+}
+
+func (ap *AnsiParser) hDispatch(params []string) error {
+ if len(params) == 1 {
+ return ap.modeDispatch(params[0], true)
+ }
+
+ return nil
+}
+
+func (ap *AnsiParser) lDispatch(params []string) error {
+ if len(params) == 1 {
+ return ap.modeDispatch(params[0], false)
+ }
+
+ return nil
+}
+
+func getEraseParam(params []string) int {
+ param := getInt(params, 0)
+ if param < 0 || 3 < param {
+ param = 0
+ }
+
+ return param
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/parser_actions.go b/vendor/github.com/Azure/go-ansiterm/parser_actions.go
new file mode 100644
index 00000000..0bb5e51e
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/parser_actions.go
@@ -0,0 +1,119 @@
+package ansiterm
+
+func (ap *AnsiParser) collectParam() error {
+ currChar := ap.context.currentChar
+ ap.logf("collectParam %#x", currChar)
+ ap.context.paramBuffer = append(ap.context.paramBuffer, currChar)
+ return nil
+}
+
+func (ap *AnsiParser) collectInter() error {
+ currChar := ap.context.currentChar
+ ap.logf("collectInter %#x", currChar)
+ ap.context.paramBuffer = append(ap.context.interBuffer, currChar)
+ return nil
+}
+
+func (ap *AnsiParser) escDispatch() error {
+ cmd, _ := parseCmd(*ap.context)
+ intermeds := ap.context.interBuffer
+ ap.logf("escDispatch currentChar: %#x", ap.context.currentChar)
+ ap.logf("escDispatch: %v(%v)", cmd, intermeds)
+
+ switch cmd {
+ case "D": // IND
+ return ap.eventHandler.IND()
+ case "E": // NEL, equivalent to CRLF
+ err := ap.eventHandler.Execute(ANSI_CARRIAGE_RETURN)
+ if err == nil {
+ err = ap.eventHandler.Execute(ANSI_LINE_FEED)
+ }
+ return err
+ case "M": // RI
+ return ap.eventHandler.RI()
+ }
+
+ return nil
+}
+
+func (ap *AnsiParser) csiDispatch() error {
+ cmd, _ := parseCmd(*ap.context)
+ params, _ := parseParams(ap.context.paramBuffer)
+ ap.logf("Parsed params: %v with length: %d", params, len(params))
+
+ ap.logf("csiDispatch: %v(%v)", cmd, params)
+
+ switch cmd {
+ case "@":
+ return ap.eventHandler.ICH(getInt(params, 1))
+ case "A":
+ return ap.eventHandler.CUU(getInt(params, 1))
+ case "B":
+ return ap.eventHandler.CUD(getInt(params, 1))
+ case "C":
+ return ap.eventHandler.CUF(getInt(params, 1))
+ case "D":
+ return ap.eventHandler.CUB(getInt(params, 1))
+ case "E":
+ return ap.eventHandler.CNL(getInt(params, 1))
+ case "F":
+ return ap.eventHandler.CPL(getInt(params, 1))
+ case "G":
+ return ap.eventHandler.CHA(getInt(params, 1))
+ case "H":
+ ints := getInts(params, 2, 1)
+ x, y := ints[0], ints[1]
+ return ap.eventHandler.CUP(x, y)
+ case "J":
+ param := getEraseParam(params)
+ return ap.eventHandler.ED(param)
+ case "K":
+ param := getEraseParam(params)
+ return ap.eventHandler.EL(param)
+ case "L":
+ return ap.eventHandler.IL(getInt(params, 1))
+ case "M":
+ return ap.eventHandler.DL(getInt(params, 1))
+ case "P":
+ return ap.eventHandler.DCH(getInt(params, 1))
+ case "S":
+ return ap.eventHandler.SU(getInt(params, 1))
+ case "T":
+ return ap.eventHandler.SD(getInt(params, 1))
+ case "c":
+ return ap.eventHandler.DA(params)
+ case "d":
+ return ap.eventHandler.VPA(getInt(params, 1))
+ case "f":
+ ints := getInts(params, 2, 1)
+ x, y := ints[0], ints[1]
+ return ap.eventHandler.HVP(x, y)
+ case "h":
+ return ap.hDispatch(params)
+ case "l":
+ return ap.lDispatch(params)
+ case "m":
+ return ap.eventHandler.SGR(getInts(params, 1, 0))
+ case "r":
+ ints := getInts(params, 2, 1)
+ top, bottom := ints[0], ints[1]
+ return ap.eventHandler.DECSTBM(top, bottom)
+ default:
+ ap.logf("ERROR: Unsupported CSI command: '%s', with full context: %v", cmd, ap.context)
+ return nil
+ }
+
+}
+
+func (ap *AnsiParser) print() error {
+ return ap.eventHandler.Print(ap.context.currentChar)
+}
+
+func (ap *AnsiParser) clear() error {
+ ap.context = &ansiContext{}
+ return nil
+}
+
+func (ap *AnsiParser) execute() error {
+ return ap.eventHandler.Execute(ap.context.currentChar)
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/states.go b/vendor/github.com/Azure/go-ansiterm/states.go
new file mode 100644
index 00000000..f2ea1fcd
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/states.go
@@ -0,0 +1,71 @@
+package ansiterm
+
+type stateID int
+
+type state interface {
+ Enter() error
+ Exit() error
+ Handle(byte) (state, error)
+ Name() string
+ Transition(state) error
+}
+
+type baseState struct {
+ name string
+ parser *AnsiParser
+}
+
+func (base baseState) Enter() error {
+ return nil
+}
+
+func (base baseState) Exit() error {
+ return nil
+}
+
+func (base baseState) Handle(b byte) (s state, e error) {
+
+ switch {
+ case b == CSI_ENTRY:
+ return base.parser.csiEntry, nil
+ case b == DCS_ENTRY:
+ return base.parser.dcsEntry, nil
+ case b == ANSI_ESCAPE_PRIMARY:
+ return base.parser.escape, nil
+ case b == OSC_STRING:
+ return base.parser.oscString, nil
+ case sliceContains(toGroundBytes, b):
+ return base.parser.ground, nil
+ }
+
+ return nil, nil
+}
+
+func (base baseState) Name() string {
+ return base.name
+}
+
+func (base baseState) Transition(s state) error {
+ if s == base.parser.ground {
+ execBytes := []byte{0x18}
+ execBytes = append(execBytes, 0x1A)
+ execBytes = append(execBytes, getByteRange(0x80, 0x8F)...)
+ execBytes = append(execBytes, getByteRange(0x91, 0x97)...)
+ execBytes = append(execBytes, 0x99)
+ execBytes = append(execBytes, 0x9A)
+
+ if sliceContains(execBytes, base.parser.context.currentChar) {
+ return base.parser.execute()
+ }
+ }
+
+ return nil
+}
+
+type dcsEntryState struct {
+ baseState
+}
+
+type errorState struct {
+ baseState
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/utilities.go b/vendor/github.com/Azure/go-ansiterm/utilities.go
new file mode 100644
index 00000000..39211449
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/utilities.go
@@ -0,0 +1,21 @@
+package ansiterm
+
+import (
+ "strconv"
+)
+
+func sliceContains(bytes []byte, b byte) bool {
+ for _, v := range bytes {
+ if v == b {
+ return true
+ }
+ }
+
+ return false
+}
+
+func convertBytesToInteger(bytes []byte) int {
+ s := string(bytes)
+ i, _ := strconv.Atoi(s)
+ return i
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go b/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go
new file mode 100644
index 00000000..5599082a
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go
@@ -0,0 +1,196 @@
+// +build windows
+
+package winterm
+
+import (
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+ "syscall"
+
+ "github.com/Azure/go-ansiterm"
+ windows "golang.org/x/sys/windows"
+)
+
+// Windows keyboard constants
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx.
+const (
+ VK_PRIOR = 0x21 // PAGE UP key
+ VK_NEXT = 0x22 // PAGE DOWN key
+ VK_END = 0x23 // END key
+ VK_HOME = 0x24 // HOME key
+ VK_LEFT = 0x25 // LEFT ARROW key
+ VK_UP = 0x26 // UP ARROW key
+ VK_RIGHT = 0x27 // RIGHT ARROW key
+ VK_DOWN = 0x28 // DOWN ARROW key
+ VK_SELECT = 0x29 // SELECT key
+ VK_PRINT = 0x2A // PRINT key
+ VK_EXECUTE = 0x2B // EXECUTE key
+ VK_SNAPSHOT = 0x2C // PRINT SCREEN key
+ VK_INSERT = 0x2D // INS key
+ VK_DELETE = 0x2E // DEL key
+ VK_HELP = 0x2F // HELP key
+ VK_F1 = 0x70 // F1 key
+ VK_F2 = 0x71 // F2 key
+ VK_F3 = 0x72 // F3 key
+ VK_F4 = 0x73 // F4 key
+ VK_F5 = 0x74 // F5 key
+ VK_F6 = 0x75 // F6 key
+ VK_F7 = 0x76 // F7 key
+ VK_F8 = 0x77 // F8 key
+ VK_F9 = 0x78 // F9 key
+ VK_F10 = 0x79 // F10 key
+ VK_F11 = 0x7A // F11 key
+ VK_F12 = 0x7B // F12 key
+
+ RIGHT_ALT_PRESSED = 0x0001
+ LEFT_ALT_PRESSED = 0x0002
+ RIGHT_CTRL_PRESSED = 0x0004
+ LEFT_CTRL_PRESSED = 0x0008
+ SHIFT_PRESSED = 0x0010
+ NUMLOCK_ON = 0x0020
+ SCROLLLOCK_ON = 0x0040
+ CAPSLOCK_ON = 0x0080
+ ENHANCED_KEY = 0x0100
+)
+
+type ansiCommand struct {
+ CommandBytes []byte
+ Command string
+ Parameters []string
+ IsSpecial bool
+}
+
+func newAnsiCommand(command []byte) *ansiCommand {
+
+ if isCharacterSelectionCmdChar(command[1]) {
+ // Is Character Set Selection commands
+ return &ansiCommand{
+ CommandBytes: command,
+ Command: string(command),
+ IsSpecial: true,
+ }
+ }
+
+ // last char is command character
+ lastCharIndex := len(command) - 1
+
+ ac := &ansiCommand{
+ CommandBytes: command,
+ Command: string(command[lastCharIndex]),
+ IsSpecial: false,
+ }
+
+ // more than a single escape
+ if lastCharIndex != 0 {
+ start := 1
+ // skip if double char escape sequence
+ if command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_ESCAPE_SECONDARY {
+ start++
+ }
+ // convert this to GetNextParam method
+ ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ansiterm.ANSI_PARAMETER_SEP)
+ }
+
+ return ac
+}
+
+func (ac *ansiCommand) paramAsSHORT(index int, defaultValue int16) int16 {
+ if index < 0 || index >= len(ac.Parameters) {
+ return defaultValue
+ }
+
+ param, err := strconv.ParseInt(ac.Parameters[index], 10, 16)
+ if err != nil {
+ return defaultValue
+ }
+
+ return int16(param)
+}
+
+func (ac *ansiCommand) String() string {
+ return fmt.Sprintf("0x%v \"%v\" (\"%v\")",
+ bytesToHex(ac.CommandBytes),
+ ac.Command,
+ strings.Join(ac.Parameters, "\",\""))
+}
+
+// isAnsiCommandChar returns true if the passed byte falls within the range of ANSI commands.
+// See http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html.
+func isAnsiCommandChar(b byte) bool {
+ switch {
+ case ansiterm.ANSI_COMMAND_FIRST <= b && b <= ansiterm.ANSI_COMMAND_LAST && b != ansiterm.ANSI_ESCAPE_SECONDARY:
+ return true
+ case b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_OSC || b == ansiterm.ANSI_CMD_DECPAM || b == ansiterm.ANSI_CMD_DECPNM:
+ // non-CSI escape sequence terminator
+ return true
+ case b == ansiterm.ANSI_CMD_STR_TERM || b == ansiterm.ANSI_BEL:
+ // String escape sequence terminator
+ return true
+ }
+ return false
+}
+
+func isXtermOscSequence(command []byte, current byte) bool {
+ return (len(command) >= 2 && command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_CMD_OSC && current != ansiterm.ANSI_BEL)
+}
+
+func isCharacterSelectionCmdChar(b byte) bool {
+ return (b == ansiterm.ANSI_CMD_G0 || b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_G2 || b == ansiterm.ANSI_CMD_G3)
+}
+
+// bytesToHex converts a slice of bytes to a human-readable string.
+func bytesToHex(b []byte) string {
+ hex := make([]string, len(b))
+ for i, ch := range b {
+ hex[i] = fmt.Sprintf("%X", ch)
+ }
+ return strings.Join(hex, "")
+}
+
+// ensureInRange adjusts the passed value, if necessary, to ensure it is within
+// the passed min / max range.
+func ensureInRange(n int16, min int16, max int16) int16 {
+ if n < min {
+ return min
+ } else if n > max {
+ return max
+ } else {
+ return n
+ }
+}
+
+func GetStdFile(nFile int) (*os.File, uintptr) {
+ var file *os.File
+
+ // syscall uses negative numbers
+ // windows package uses very big uint32
+ // Keep these switches split so we don't have to convert ints too much.
+ switch uint32(nFile) {
+ case windows.STD_INPUT_HANDLE:
+ file = os.Stdin
+ case windows.STD_OUTPUT_HANDLE:
+ file = os.Stdout
+ case windows.STD_ERROR_HANDLE:
+ file = os.Stderr
+ default:
+ switch nFile {
+ case syscall.STD_INPUT_HANDLE:
+ file = os.Stdin
+ case syscall.STD_OUTPUT_HANDLE:
+ file = os.Stdout
+ case syscall.STD_ERROR_HANDLE:
+ file = os.Stderr
+ default:
+ panic(fmt.Errorf("Invalid standard handle identifier: %v", nFile))
+ }
+ }
+
+ fd, err := syscall.GetStdHandle(nFile)
+ if err != nil {
+ panic(fmt.Errorf("Invalid standard handle identifier: %v -- %v", nFile, err))
+ }
+
+ return file, uintptr(fd)
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/api.go b/vendor/github.com/Azure/go-ansiterm/winterm/api.go
new file mode 100644
index 00000000..6055e33b
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/api.go
@@ -0,0 +1,327 @@
+// +build windows
+
+package winterm
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+//===========================================================================================================
+// IMPORTANT NOTE:
+//
+// The methods below make extensive use of the "unsafe" package to obtain the required pointers.
+// Beginning in Go 1.3, the garbage collector may release local variables (e.g., incoming arguments, stack
+// variables) the pointers reference *before* the API completes.
+//
+// As a result, in those cases, the code must hint that the variables remain in active by invoking the
+// dummy method "use" (see below). Newer versions of Go are planned to change the mechanism to no longer
+// require unsafe pointers.
+//
+// If you add or modify methods, ENSURE protection of local variables through the "use" builtin to inform
+// the garbage collector the variables remain in use if:
+//
+// -- The value is not a pointer (e.g., int32, struct)
+// -- The value is not referenced by the method after passing the pointer to Windows
+//
+// See http://golang.org/doc/go1.3.
+//===========================================================================================================
+
+var (
+ kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
+
+ getConsoleCursorInfoProc = kernel32DLL.NewProc("GetConsoleCursorInfo")
+ setConsoleCursorInfoProc = kernel32DLL.NewProc("SetConsoleCursorInfo")
+ setConsoleCursorPositionProc = kernel32DLL.NewProc("SetConsoleCursorPosition")
+ setConsoleModeProc = kernel32DLL.NewProc("SetConsoleMode")
+ getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo")
+ setConsoleScreenBufferSizeProc = kernel32DLL.NewProc("SetConsoleScreenBufferSize")
+ scrollConsoleScreenBufferProc = kernel32DLL.NewProc("ScrollConsoleScreenBufferA")
+ setConsoleTextAttributeProc = kernel32DLL.NewProc("SetConsoleTextAttribute")
+ setConsoleWindowInfoProc = kernel32DLL.NewProc("SetConsoleWindowInfo")
+ writeConsoleOutputProc = kernel32DLL.NewProc("WriteConsoleOutputW")
+ readConsoleInputProc = kernel32DLL.NewProc("ReadConsoleInputW")
+ waitForSingleObjectProc = kernel32DLL.NewProc("WaitForSingleObject")
+)
+
+// Windows Console constants
+const (
+ // Console modes
+ // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
+ ENABLE_PROCESSED_INPUT = 0x0001
+ ENABLE_LINE_INPUT = 0x0002
+ ENABLE_ECHO_INPUT = 0x0004
+ ENABLE_WINDOW_INPUT = 0x0008
+ ENABLE_MOUSE_INPUT = 0x0010
+ ENABLE_INSERT_MODE = 0x0020
+ ENABLE_QUICK_EDIT_MODE = 0x0040
+ ENABLE_EXTENDED_FLAGS = 0x0080
+ ENABLE_AUTO_POSITION = 0x0100
+ ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200
+
+ ENABLE_PROCESSED_OUTPUT = 0x0001
+ ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
+ ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
+ DISABLE_NEWLINE_AUTO_RETURN = 0x0008
+ ENABLE_LVB_GRID_WORLDWIDE = 0x0010
+
+ // Character attributes
+ // Note:
+ // -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan).
+ // Clearing all foreground or background colors results in black; setting all creates white.
+ // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes.
+ FOREGROUND_BLUE uint16 = 0x0001
+ FOREGROUND_GREEN uint16 = 0x0002
+ FOREGROUND_RED uint16 = 0x0004
+ FOREGROUND_INTENSITY uint16 = 0x0008
+ FOREGROUND_MASK uint16 = 0x000F
+
+ BACKGROUND_BLUE uint16 = 0x0010
+ BACKGROUND_GREEN uint16 = 0x0020
+ BACKGROUND_RED uint16 = 0x0040
+ BACKGROUND_INTENSITY uint16 = 0x0080
+ BACKGROUND_MASK uint16 = 0x00F0
+
+ COMMON_LVB_MASK uint16 = 0xFF00
+ COMMON_LVB_REVERSE_VIDEO uint16 = 0x4000
+ COMMON_LVB_UNDERSCORE uint16 = 0x8000
+
+ // Input event types
+ // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
+ KEY_EVENT = 0x0001
+ MOUSE_EVENT = 0x0002
+ WINDOW_BUFFER_SIZE_EVENT = 0x0004
+ MENU_EVENT = 0x0008
+ FOCUS_EVENT = 0x0010
+
+ // WaitForSingleObject return codes
+ WAIT_ABANDONED = 0x00000080
+ WAIT_FAILED = 0xFFFFFFFF
+ WAIT_SIGNALED = 0x0000000
+ WAIT_TIMEOUT = 0x00000102
+
+ // WaitForSingleObject wait duration
+ WAIT_INFINITE = 0xFFFFFFFF
+ WAIT_ONE_SECOND = 1000
+ WAIT_HALF_SECOND = 500
+ WAIT_QUARTER_SECOND = 250
+)
+
+// Windows API Console types
+// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682101(v=vs.85).aspx for Console specific types (e.g., COORD)
+// -- See https://msdn.microsoft.com/en-us/library/aa296569(v=vs.60).aspx for comments on alignment
+type (
+ CHAR_INFO struct {
+ UnicodeChar uint16
+ Attributes uint16
+ }
+
+ CONSOLE_CURSOR_INFO struct {
+ Size uint32
+ Visible int32
+ }
+
+ CONSOLE_SCREEN_BUFFER_INFO struct {
+ Size COORD
+ CursorPosition COORD
+ Attributes uint16
+ Window SMALL_RECT
+ MaximumWindowSize COORD
+ }
+
+ COORD struct {
+ X int16
+ Y int16
+ }
+
+ SMALL_RECT struct {
+ Left int16
+ Top int16
+ Right int16
+ Bottom int16
+ }
+
+ // INPUT_RECORD is a C/C++ union of which KEY_EVENT_RECORD is one case, it is also the largest
+ // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
+ INPUT_RECORD struct {
+ EventType uint16
+ KeyEvent KEY_EVENT_RECORD
+ }
+
+ KEY_EVENT_RECORD struct {
+ KeyDown int32
+ RepeatCount uint16
+ VirtualKeyCode uint16
+ VirtualScanCode uint16
+ UnicodeChar uint16
+ ControlKeyState uint32
+ }
+
+ WINDOW_BUFFER_SIZE struct {
+ Size COORD
+ }
+)
+
+// boolToBOOL converts a Go bool into a Windows int32.
+func boolToBOOL(f bool) int32 {
+ if f {
+ return int32(1)
+ } else {
+ return int32(0)
+ }
+}
+
+// GetConsoleCursorInfo retrieves information about the size and visiblity of the console cursor.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683163(v=vs.85).aspx.
+func GetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
+ r1, r2, err := getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
+ return checkError(r1, r2, err)
+}
+
+// SetConsoleCursorInfo sets the size and visiblity of the console cursor.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686019(v=vs.85).aspx.
+func SetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
+ r1, r2, err := setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
+ return checkError(r1, r2, err)
+}
+
+// SetConsoleCursorPosition location of the console cursor.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx.
+func SetConsoleCursorPosition(handle uintptr, coord COORD) error {
+ r1, r2, err := setConsoleCursorPositionProc.Call(handle, coordToPointer(coord))
+ use(coord)
+ return checkError(r1, r2, err)
+}
+
+// GetConsoleMode gets the console mode for given file descriptor
+// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx.
+func GetConsoleMode(handle uintptr) (mode uint32, err error) {
+ err = syscall.GetConsoleMode(syscall.Handle(handle), &mode)
+ return mode, err
+}
+
+// SetConsoleMode sets the console mode for given file descriptor
+// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
+func SetConsoleMode(handle uintptr, mode uint32) error {
+ r1, r2, err := setConsoleModeProc.Call(handle, uintptr(mode), 0)
+ use(mode)
+ return checkError(r1, r2, err)
+}
+
+// GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer.
+// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx.
+func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) {
+ info := CONSOLE_SCREEN_BUFFER_INFO{}
+ err := checkError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0))
+ if err != nil {
+ return nil, err
+ }
+ return &info, nil
+}
+
+func ScrollConsoleScreenBuffer(handle uintptr, scrollRect SMALL_RECT, clipRect SMALL_RECT, destOrigin COORD, char CHAR_INFO) error {
+ r1, r2, err := scrollConsoleScreenBufferProc.Call(handle, uintptr(unsafe.Pointer(&scrollRect)), uintptr(unsafe.Pointer(&clipRect)), coordToPointer(destOrigin), uintptr(unsafe.Pointer(&char)))
+ use(scrollRect)
+ use(clipRect)
+ use(destOrigin)
+ use(char)
+ return checkError(r1, r2, err)
+}
+
+// SetConsoleScreenBufferSize sets the size of the console screen buffer.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686044(v=vs.85).aspx.
+func SetConsoleScreenBufferSize(handle uintptr, coord COORD) error {
+ r1, r2, err := setConsoleScreenBufferSizeProc.Call(handle, coordToPointer(coord))
+ use(coord)
+ return checkError(r1, r2, err)
+}
+
+// SetConsoleTextAttribute sets the attributes of characters written to the
+// console screen buffer by the WriteFile or WriteConsole function.
+// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx.
+func SetConsoleTextAttribute(handle uintptr, attribute uint16) error {
+ r1, r2, err := setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0)
+ use(attribute)
+ return checkError(r1, r2, err)
+}
+
+// SetConsoleWindowInfo sets the size and position of the console screen buffer's window.
+// Note that the size and location must be within and no larger than the backing console screen buffer.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686125(v=vs.85).aspx.
+func SetConsoleWindowInfo(handle uintptr, isAbsolute bool, rect SMALL_RECT) error {
+ r1, r2, err := setConsoleWindowInfoProc.Call(handle, uintptr(boolToBOOL(isAbsolute)), uintptr(unsafe.Pointer(&rect)))
+ use(isAbsolute)
+ use(rect)
+ return checkError(r1, r2, err)
+}
+
+// WriteConsoleOutput writes the CHAR_INFOs from the provided buffer to the active console buffer.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687404(v=vs.85).aspx.
+func WriteConsoleOutput(handle uintptr, buffer []CHAR_INFO, bufferSize COORD, bufferCoord COORD, writeRegion *SMALL_RECT) error {
+ r1, r2, err := writeConsoleOutputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), coordToPointer(bufferSize), coordToPointer(bufferCoord), uintptr(unsafe.Pointer(writeRegion)))
+ use(buffer)
+ use(bufferSize)
+ use(bufferCoord)
+ return checkError(r1, r2, err)
+}
+
+// ReadConsoleInput reads (and removes) data from the console input buffer.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx.
+func ReadConsoleInput(handle uintptr, buffer []INPUT_RECORD, count *uint32) error {
+ r1, r2, err := readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), uintptr(len(buffer)), uintptr(unsafe.Pointer(count)))
+ use(buffer)
+ return checkError(r1, r2, err)
+}
+
+// WaitForSingleObject waits for the passed handle to be signaled.
+// It returns true if the handle was signaled; false otherwise.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx.
+func WaitForSingleObject(handle uintptr, msWait uint32) (bool, error) {
+ r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(uint32(msWait)))
+ switch r1 {
+ case WAIT_ABANDONED, WAIT_TIMEOUT:
+ return false, nil
+ case WAIT_SIGNALED:
+ return true, nil
+ }
+ use(msWait)
+ return false, err
+}
+
+// String helpers
+func (info CONSOLE_SCREEN_BUFFER_INFO) String() string {
+ return fmt.Sprintf("Size(%v) Cursor(%v) Window(%v) Max(%v)", info.Size, info.CursorPosition, info.Window, info.MaximumWindowSize)
+}
+
+func (coord COORD) String() string {
+ return fmt.Sprintf("%v,%v", coord.X, coord.Y)
+}
+
+func (rect SMALL_RECT) String() string {
+ return fmt.Sprintf("(%v,%v),(%v,%v)", rect.Left, rect.Top, rect.Right, rect.Bottom)
+}
+
+// checkError evaluates the results of a Windows API call and returns the error if it failed.
+func checkError(r1, r2 uintptr, err error) error {
+ // Windows APIs return non-zero to indicate success
+ if r1 != 0 {
+ return nil
+ }
+
+ // Return the error if provided, otherwise default to EINVAL
+ if err != nil {
+ return err
+ }
+ return syscall.EINVAL
+}
+
+// coordToPointer converts a COORD into a uintptr (by fooling the type system).
+func coordToPointer(c COORD) uintptr {
+ // Note: This code assumes the two SHORTs are correctly laid out; the "cast" to uint32 is just to get a pointer to pass.
+ return uintptr(*((*uint32)(unsafe.Pointer(&c))))
+}
+
+// use is a no-op, but the compiler cannot see that it is.
+// Calling use(p) ensures that p is kept live until that point.
+func use(p interface{}) {}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go b/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go
new file mode 100644
index 00000000..cbec8f72
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go
@@ -0,0 +1,100 @@
+// +build windows
+
+package winterm
+
+import "github.com/Azure/go-ansiterm"
+
+const (
+ FOREGROUND_COLOR_MASK = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
+ BACKGROUND_COLOR_MASK = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
+)
+
+// collectAnsiIntoWindowsAttributes modifies the passed Windows text mode flags to reflect the
+// request represented by the passed ANSI mode.
+func collectAnsiIntoWindowsAttributes(windowsMode uint16, inverted bool, baseMode uint16, ansiMode int16) (uint16, bool) {
+ switch ansiMode {
+
+ // Mode styles
+ case ansiterm.ANSI_SGR_BOLD:
+ windowsMode = windowsMode | FOREGROUND_INTENSITY
+
+ case ansiterm.ANSI_SGR_DIM, ansiterm.ANSI_SGR_BOLD_DIM_OFF:
+ windowsMode &^= FOREGROUND_INTENSITY
+
+ case ansiterm.ANSI_SGR_UNDERLINE:
+ windowsMode = windowsMode | COMMON_LVB_UNDERSCORE
+
+ case ansiterm.ANSI_SGR_REVERSE:
+ inverted = true
+
+ case ansiterm.ANSI_SGR_REVERSE_OFF:
+ inverted = false
+
+ case ansiterm.ANSI_SGR_UNDERLINE_OFF:
+ windowsMode &^= COMMON_LVB_UNDERSCORE
+
+ // Foreground colors
+ case ansiterm.ANSI_SGR_FOREGROUND_DEFAULT:
+ windowsMode = (windowsMode &^ FOREGROUND_MASK) | (baseMode & FOREGROUND_MASK)
+
+ case ansiterm.ANSI_SGR_FOREGROUND_BLACK:
+ windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK)
+
+ case ansiterm.ANSI_SGR_FOREGROUND_RED:
+ windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED
+
+ case ansiterm.ANSI_SGR_FOREGROUND_GREEN:
+ windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN
+
+ case ansiterm.ANSI_SGR_FOREGROUND_YELLOW:
+ windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN
+
+ case ansiterm.ANSI_SGR_FOREGROUND_BLUE:
+ windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_BLUE
+
+ case ansiterm.ANSI_SGR_FOREGROUND_MAGENTA:
+ windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_BLUE
+
+ case ansiterm.ANSI_SGR_FOREGROUND_CYAN:
+ windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE
+
+ case ansiterm.ANSI_SGR_FOREGROUND_WHITE:
+ windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
+
+ // Background colors
+ case ansiterm.ANSI_SGR_BACKGROUND_DEFAULT:
+ // Black with no intensity
+ windowsMode = (windowsMode &^ BACKGROUND_MASK) | (baseMode & BACKGROUND_MASK)
+
+ case ansiterm.ANSI_SGR_BACKGROUND_BLACK:
+ windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK)
+
+ case ansiterm.ANSI_SGR_BACKGROUND_RED:
+ windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED
+
+ case ansiterm.ANSI_SGR_BACKGROUND_GREEN:
+ windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN
+
+ case ansiterm.ANSI_SGR_BACKGROUND_YELLOW:
+ windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN
+
+ case ansiterm.ANSI_SGR_BACKGROUND_BLUE:
+ windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_BLUE
+
+ case ansiterm.ANSI_SGR_BACKGROUND_MAGENTA:
+ windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_BLUE
+
+ case ansiterm.ANSI_SGR_BACKGROUND_CYAN:
+ windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE
+
+ case ansiterm.ANSI_SGR_BACKGROUND_WHITE:
+ windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
+ }
+
+ return windowsMode, inverted
+}
+
+// invertAttributes inverts the foreground and background colors of a Windows attributes value
+func invertAttributes(windowsMode uint16) uint16 {
+ return (COMMON_LVB_MASK & windowsMode) | ((FOREGROUND_MASK & windowsMode) << 4) | ((BACKGROUND_MASK & windowsMode) >> 4)
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go b/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go
new file mode 100644
index 00000000..3ee06ea7
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go
@@ -0,0 +1,101 @@
+// +build windows
+
+package winterm
+
+const (
+ horizontal = iota
+ vertical
+)
+
+func (h *windowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_INFO) SMALL_RECT {
+ if h.originMode {
+ sr := h.effectiveSr(info.Window)
+ return SMALL_RECT{
+ Top: sr.top,
+ Bottom: sr.bottom,
+ Left: 0,
+ Right: info.Size.X - 1,
+ }
+ } else {
+ return SMALL_RECT{
+ Top: info.Window.Top,
+ Bottom: info.Window.Bottom,
+ Left: 0,
+ Right: info.Size.X - 1,
+ }
+ }
+}
+
+// setCursorPosition sets the cursor to the specified position, bounded to the screen size
+func (h *windowsAnsiEventHandler) setCursorPosition(position COORD, window SMALL_RECT) error {
+ position.X = ensureInRange(position.X, window.Left, window.Right)
+ position.Y = ensureInRange(position.Y, window.Top, window.Bottom)
+ err := SetConsoleCursorPosition(h.fd, position)
+ if err != nil {
+ return err
+ }
+ h.logf("Cursor position set: (%d, %d)", position.X, position.Y)
+ return err
+}
+
+func (h *windowsAnsiEventHandler) moveCursorVertical(param int) error {
+ return h.moveCursor(vertical, param)
+}
+
+func (h *windowsAnsiEventHandler) moveCursorHorizontal(param int) error {
+ return h.moveCursor(horizontal, param)
+}
+
+func (h *windowsAnsiEventHandler) moveCursor(moveMode int, param int) error {
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+
+ position := info.CursorPosition
+ switch moveMode {
+ case horizontal:
+ position.X += int16(param)
+ case vertical:
+ position.Y += int16(param)
+ }
+
+ if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (h *windowsAnsiEventHandler) moveCursorLine(param int) error {
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+
+ position := info.CursorPosition
+ position.X = 0
+ position.Y += int16(param)
+
+ if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (h *windowsAnsiEventHandler) moveCursorColumn(param int) error {
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+
+ position := info.CursorPosition
+ position.X = int16(param) - 1
+
+ if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go b/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go
new file mode 100644
index 00000000..244b5fa2
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go
@@ -0,0 +1,84 @@
+// +build windows
+
+package winterm
+
+import "github.com/Azure/go-ansiterm"
+
+func (h *windowsAnsiEventHandler) clearRange(attributes uint16, fromCoord COORD, toCoord COORD) error {
+ // Ignore an invalid (negative area) request
+ if toCoord.Y < fromCoord.Y {
+ return nil
+ }
+
+ var err error
+
+ var coordStart = COORD{}
+ var coordEnd = COORD{}
+
+ xCurrent, yCurrent := fromCoord.X, fromCoord.Y
+ xEnd, yEnd := toCoord.X, toCoord.Y
+
+ // Clear any partial initial line
+ if xCurrent > 0 {
+ coordStart.X, coordStart.Y = xCurrent, yCurrent
+ coordEnd.X, coordEnd.Y = xEnd, yCurrent
+
+ err = h.clearRect(attributes, coordStart, coordEnd)
+ if err != nil {
+ return err
+ }
+
+ xCurrent = 0
+ yCurrent += 1
+ }
+
+ // Clear intervening rectangular section
+ if yCurrent < yEnd {
+ coordStart.X, coordStart.Y = xCurrent, yCurrent
+ coordEnd.X, coordEnd.Y = xEnd, yEnd-1
+
+ err = h.clearRect(attributes, coordStart, coordEnd)
+ if err != nil {
+ return err
+ }
+
+ xCurrent = 0
+ yCurrent = yEnd
+ }
+
+ // Clear remaining partial ending line
+ coordStart.X, coordStart.Y = xCurrent, yCurrent
+ coordEnd.X, coordEnd.Y = xEnd, yEnd
+
+ err = h.clearRect(attributes, coordStart, coordEnd)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (h *windowsAnsiEventHandler) clearRect(attributes uint16, fromCoord COORD, toCoord COORD) error {
+ region := SMALL_RECT{Top: fromCoord.Y, Left: fromCoord.X, Bottom: toCoord.Y, Right: toCoord.X}
+ width := toCoord.X - fromCoord.X + 1
+ height := toCoord.Y - fromCoord.Y + 1
+ size := uint32(width) * uint32(height)
+
+ if size <= 0 {
+ return nil
+ }
+
+ buffer := make([]CHAR_INFO, size)
+
+ char := CHAR_INFO{ansiterm.FILL_CHARACTER, attributes}
+ for i := 0; i < int(size); i++ {
+ buffer[i] = char
+ }
+
+ err := WriteConsoleOutput(h.fd, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, ®ion)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go b/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go
new file mode 100644
index 00000000..2d27fa1d
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go
@@ -0,0 +1,118 @@
+// +build windows
+
+package winterm
+
+// effectiveSr gets the current effective scroll region in buffer coordinates
+func (h *windowsAnsiEventHandler) effectiveSr(window SMALL_RECT) scrollRegion {
+ top := addInRange(window.Top, h.sr.top, window.Top, window.Bottom)
+ bottom := addInRange(window.Top, h.sr.bottom, window.Top, window.Bottom)
+ if top >= bottom {
+ top = window.Top
+ bottom = window.Bottom
+ }
+ return scrollRegion{top: top, bottom: bottom}
+}
+
+func (h *windowsAnsiEventHandler) scrollUp(param int) error {
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+
+ sr := h.effectiveSr(info.Window)
+ return h.scroll(param, sr, info)
+}
+
+func (h *windowsAnsiEventHandler) scrollDown(param int) error {
+ return h.scrollUp(-param)
+}
+
+func (h *windowsAnsiEventHandler) deleteLines(param int) error {
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+
+ start := info.CursorPosition.Y
+ sr := h.effectiveSr(info.Window)
+ // Lines cannot be inserted or deleted outside the scrolling region.
+ if start >= sr.top && start <= sr.bottom {
+ sr.top = start
+ return h.scroll(param, sr, info)
+ } else {
+ return nil
+ }
+}
+
+func (h *windowsAnsiEventHandler) insertLines(param int) error {
+ return h.deleteLines(-param)
+}
+
+// scroll scrolls the provided scroll region by param lines. The scroll region is in buffer coordinates.
+func (h *windowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSOLE_SCREEN_BUFFER_INFO) error {
+ h.logf("scroll: scrollTop: %d, scrollBottom: %d", sr.top, sr.bottom)
+ h.logf("scroll: windowTop: %d, windowBottom: %d", info.Window.Top, info.Window.Bottom)
+
+ // Copy from and clip to the scroll region (full buffer width)
+ scrollRect := SMALL_RECT{
+ Top: sr.top,
+ Bottom: sr.bottom,
+ Left: 0,
+ Right: info.Size.X - 1,
+ }
+
+ // Origin to which area should be copied
+ destOrigin := COORD{
+ X: 0,
+ Y: sr.top - int16(param),
+ }
+
+ char := CHAR_INFO{
+ UnicodeChar: ' ',
+ Attributes: h.attributes,
+ }
+
+ if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (h *windowsAnsiEventHandler) deleteCharacters(param int) error {
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+ return h.scrollLine(param, info.CursorPosition, info)
+}
+
+func (h *windowsAnsiEventHandler) insertCharacters(param int) error {
+ return h.deleteCharacters(-param)
+}
+
+// scrollLine scrolls a line horizontally starting at the provided position by a number of columns.
+func (h *windowsAnsiEventHandler) scrollLine(columns int, position COORD, info *CONSOLE_SCREEN_BUFFER_INFO) error {
+ // Copy from and clip to the scroll region (full buffer width)
+ scrollRect := SMALL_RECT{
+ Top: position.Y,
+ Bottom: position.Y,
+ Left: position.X,
+ Right: info.Size.X - 1,
+ }
+
+ // Origin to which area should be copied
+ destOrigin := COORD{
+ X: position.X - int16(columns),
+ Y: position.Y,
+ }
+
+ char := CHAR_INFO{
+ UnicodeChar: ' ',
+ Attributes: h.attributes,
+ }
+
+ if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go b/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go
new file mode 100644
index 00000000..afa7635d
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go
@@ -0,0 +1,9 @@
+// +build windows
+
+package winterm
+
+// AddInRange increments a value by the passed quantity while ensuring the values
+// always remain within the supplied min / max range.
+func addInRange(n int16, increment int16, min int16, max int16) int16 {
+ return ensureInRange(n+increment, min, max)
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go b/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go
new file mode 100644
index 00000000..2d40fb75
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go
@@ -0,0 +1,743 @@
+// +build windows
+
+package winterm
+
+import (
+ "bytes"
+ "log"
+ "os"
+ "strconv"
+
+ "github.com/Azure/go-ansiterm"
+)
+
+type windowsAnsiEventHandler struct {
+ fd uintptr
+ file *os.File
+ infoReset *CONSOLE_SCREEN_BUFFER_INFO
+ sr scrollRegion
+ buffer bytes.Buffer
+ attributes uint16
+ inverted bool
+ wrapNext bool
+ drewMarginByte bool
+ originMode bool
+ marginByte byte
+ curInfo *CONSOLE_SCREEN_BUFFER_INFO
+ curPos COORD
+ logf func(string, ...interface{})
+}
+
+type Option func(*windowsAnsiEventHandler)
+
+func WithLogf(f func(string, ...interface{})) Option {
+ return func(w *windowsAnsiEventHandler) {
+ w.logf = f
+ }
+}
+
+func CreateWinEventHandler(fd uintptr, file *os.File, opts ...Option) ansiterm.AnsiEventHandler {
+ infoReset, err := GetConsoleScreenBufferInfo(fd)
+ if err != nil {
+ return nil
+ }
+
+ h := &windowsAnsiEventHandler{
+ fd: fd,
+ file: file,
+ infoReset: infoReset,
+ attributes: infoReset.Attributes,
+ }
+ for _, o := range opts {
+ o(h)
+ }
+
+ if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" {
+ logFile, _ := os.Create("winEventHandler.log")
+ logger := log.New(logFile, "", log.LstdFlags)
+ if h.logf != nil {
+ l := h.logf
+ h.logf = func(s string, v ...interface{}) {
+ l(s, v...)
+ logger.Printf(s, v...)
+ }
+ } else {
+ h.logf = logger.Printf
+ }
+ }
+
+ if h.logf == nil {
+ h.logf = func(string, ...interface{}) {}
+ }
+
+ return h
+}
+
+type scrollRegion struct {
+ top int16
+ bottom int16
+}
+
+// simulateLF simulates a LF or CR+LF by scrolling if necessary to handle the
+// current cursor position and scroll region settings, in which case it returns
+// true. If no special handling is necessary, then it does nothing and returns
+// false.
+//
+// In the false case, the caller should ensure that a carriage return
+// and line feed are inserted or that the text is otherwise wrapped.
+func (h *windowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) {
+ if h.wrapNext {
+ if err := h.Flush(); err != nil {
+ return false, err
+ }
+ h.clearWrap()
+ }
+ pos, info, err := h.getCurrentInfo()
+ if err != nil {
+ return false, err
+ }
+ sr := h.effectiveSr(info.Window)
+ if pos.Y == sr.bottom {
+ // Scrolling is necessary. Let Windows automatically scroll if the scrolling region
+ // is the full window.
+ if sr.top == info.Window.Top && sr.bottom == info.Window.Bottom {
+ if includeCR {
+ pos.X = 0
+ h.updatePos(pos)
+ }
+ return false, nil
+ }
+
+ // A custom scroll region is active. Scroll the window manually to simulate
+ // the LF.
+ if err := h.Flush(); err != nil {
+ return false, err
+ }
+ h.logf("Simulating LF inside scroll region")
+ if err := h.scrollUp(1); err != nil {
+ return false, err
+ }
+ if includeCR {
+ pos.X = 0
+ if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
+ return false, err
+ }
+ }
+ return true, nil
+
+ } else if pos.Y < info.Window.Bottom {
+ // Let Windows handle the LF.
+ pos.Y++
+ if includeCR {
+ pos.X = 0
+ }
+ h.updatePos(pos)
+ return false, nil
+ } else {
+ // The cursor is at the bottom of the screen but outside the scroll
+ // region. Skip the LF.
+ h.logf("Simulating LF outside scroll region")
+ if includeCR {
+ if err := h.Flush(); err != nil {
+ return false, err
+ }
+ pos.X = 0
+ if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
+ return false, err
+ }
+ }
+ return true, nil
+ }
+}
+
+// executeLF executes a LF without a CR.
+func (h *windowsAnsiEventHandler) executeLF() error {
+ handled, err := h.simulateLF(false)
+ if err != nil {
+ return err
+ }
+ if !handled {
+ // Windows LF will reset the cursor column position. Write the LF
+ // and restore the cursor position.
+ pos, _, err := h.getCurrentInfo()
+ if err != nil {
+ return err
+ }
+ h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED)
+ if pos.X != 0 {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("Resetting cursor position for LF without CR")
+ if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func (h *windowsAnsiEventHandler) Print(b byte) error {
+ if h.wrapNext {
+ h.buffer.WriteByte(h.marginByte)
+ h.clearWrap()
+ if _, err := h.simulateLF(true); err != nil {
+ return err
+ }
+ }
+ pos, info, err := h.getCurrentInfo()
+ if err != nil {
+ return err
+ }
+ if pos.X == info.Size.X-1 {
+ h.wrapNext = true
+ h.marginByte = b
+ } else {
+ pos.X++
+ h.updatePos(pos)
+ h.buffer.WriteByte(b)
+ }
+ return nil
+}
+
+func (h *windowsAnsiEventHandler) Execute(b byte) error {
+ switch b {
+ case ansiterm.ANSI_TAB:
+ h.logf("Execute(TAB)")
+ // Move to the next tab stop, but preserve auto-wrap if already set.
+ if !h.wrapNext {
+ pos, info, err := h.getCurrentInfo()
+ if err != nil {
+ return err
+ }
+ pos.X = (pos.X + 8) - pos.X%8
+ if pos.X >= info.Size.X {
+ pos.X = info.Size.X - 1
+ }
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case ansiterm.ANSI_BEL:
+ h.buffer.WriteByte(ansiterm.ANSI_BEL)
+ return nil
+
+ case ansiterm.ANSI_BACKSPACE:
+ if h.wrapNext {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.clearWrap()
+ }
+ pos, _, err := h.getCurrentInfo()
+ if err != nil {
+ return err
+ }
+ if pos.X > 0 {
+ pos.X--
+ h.updatePos(pos)
+ h.buffer.WriteByte(ansiterm.ANSI_BACKSPACE)
+ }
+ return nil
+
+ case ansiterm.ANSI_VERTICAL_TAB, ansiterm.ANSI_FORM_FEED:
+ // Treat as true LF.
+ return h.executeLF()
+
+ case ansiterm.ANSI_LINE_FEED:
+ // Simulate a CR and LF for now since there is no way in go-ansiterm
+ // to tell if the LF should include CR (and more things break when it's
+ // missing than when it's incorrectly added).
+ handled, err := h.simulateLF(true)
+ if handled || err != nil {
+ return err
+ }
+ return h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED)
+
+ case ansiterm.ANSI_CARRIAGE_RETURN:
+ if h.wrapNext {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.clearWrap()
+ }
+ pos, _, err := h.getCurrentInfo()
+ if err != nil {
+ return err
+ }
+ if pos.X != 0 {
+ pos.X = 0
+ h.updatePos(pos)
+ h.buffer.WriteByte(ansiterm.ANSI_CARRIAGE_RETURN)
+ }
+ return nil
+
+ default:
+ return nil
+ }
+}
+
+func (h *windowsAnsiEventHandler) CUU(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("CUU: [%v]", []string{strconv.Itoa(param)})
+ h.clearWrap()
+ return h.moveCursorVertical(-param)
+}
+
+func (h *windowsAnsiEventHandler) CUD(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("CUD: [%v]", []string{strconv.Itoa(param)})
+ h.clearWrap()
+ return h.moveCursorVertical(param)
+}
+
+func (h *windowsAnsiEventHandler) CUF(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("CUF: [%v]", []string{strconv.Itoa(param)})
+ h.clearWrap()
+ return h.moveCursorHorizontal(param)
+}
+
+func (h *windowsAnsiEventHandler) CUB(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("CUB: [%v]", []string{strconv.Itoa(param)})
+ h.clearWrap()
+ return h.moveCursorHorizontal(-param)
+}
+
+func (h *windowsAnsiEventHandler) CNL(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("CNL: [%v]", []string{strconv.Itoa(param)})
+ h.clearWrap()
+ return h.moveCursorLine(param)
+}
+
+func (h *windowsAnsiEventHandler) CPL(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("CPL: [%v]", []string{strconv.Itoa(param)})
+ h.clearWrap()
+ return h.moveCursorLine(-param)
+}
+
+func (h *windowsAnsiEventHandler) CHA(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("CHA: [%v]", []string{strconv.Itoa(param)})
+ h.clearWrap()
+ return h.moveCursorColumn(param)
+}
+
+func (h *windowsAnsiEventHandler) VPA(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("VPA: [[%d]]", param)
+ h.clearWrap()
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+ window := h.getCursorWindow(info)
+ position := info.CursorPosition
+ position.Y = window.Top + int16(param) - 1
+ return h.setCursorPosition(position, window)
+}
+
+func (h *windowsAnsiEventHandler) CUP(row int, col int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("CUP: [[%d %d]]", row, col)
+ h.clearWrap()
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+
+ window := h.getCursorWindow(info)
+ position := COORD{window.Left + int16(col) - 1, window.Top + int16(row) - 1}
+ return h.setCursorPosition(position, window)
+}
+
+func (h *windowsAnsiEventHandler) HVP(row int, col int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("HVP: [[%d %d]]", row, col)
+ h.clearWrap()
+ return h.CUP(row, col)
+}
+
+func (h *windowsAnsiEventHandler) DECTCEM(visible bool) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("DECTCEM: [%v]", []string{strconv.FormatBool(visible)})
+ h.clearWrap()
+ return nil
+}
+
+func (h *windowsAnsiEventHandler) DECOM(enable bool) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("DECOM: [%v]", []string{strconv.FormatBool(enable)})
+ h.clearWrap()
+ h.originMode = enable
+ return h.CUP(1, 1)
+}
+
+func (h *windowsAnsiEventHandler) DECCOLM(use132 bool) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("DECCOLM: [%v]", []string{strconv.FormatBool(use132)})
+ h.clearWrap()
+ if err := h.ED(2); err != nil {
+ return err
+ }
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+ targetWidth := int16(80)
+ if use132 {
+ targetWidth = 132
+ }
+ if info.Size.X < targetWidth {
+ if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
+ h.logf("set buffer failed: %v", err)
+ return err
+ }
+ }
+ window := info.Window
+ window.Left = 0
+ window.Right = targetWidth - 1
+ if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
+ h.logf("set window failed: %v", err)
+ return err
+ }
+ if info.Size.X > targetWidth {
+ if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
+ h.logf("set buffer failed: %v", err)
+ return err
+ }
+ }
+ return SetConsoleCursorPosition(h.fd, COORD{0, 0})
+}
+
+func (h *windowsAnsiEventHandler) ED(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("ED: [%v]", []string{strconv.Itoa(param)})
+ h.clearWrap()
+
+ // [J -- Erases from the cursor to the end of the screen, including the cursor position.
+ // [1J -- Erases from the beginning of the screen to the cursor, including the cursor position.
+ // [2J -- Erases the complete display. The cursor does not move.
+ // Notes:
+ // -- Clearing the entire buffer, versus just the Window, works best for Windows Consoles
+
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+
+ var start COORD
+ var end COORD
+
+ switch param {
+ case 0:
+ start = info.CursorPosition
+ end = COORD{info.Size.X - 1, info.Size.Y - 1}
+
+ case 1:
+ start = COORD{0, 0}
+ end = info.CursorPosition
+
+ case 2:
+ start = COORD{0, 0}
+ end = COORD{info.Size.X - 1, info.Size.Y - 1}
+ }
+
+ err = h.clearRange(h.attributes, start, end)
+ if err != nil {
+ return err
+ }
+
+ // If the whole buffer was cleared, move the window to the top while preserving
+ // the window-relative cursor position.
+ if param == 2 {
+ pos := info.CursorPosition
+ window := info.Window
+ pos.Y -= window.Top
+ window.Bottom -= window.Top
+ window.Top = 0
+ if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
+ return err
+ }
+ if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (h *windowsAnsiEventHandler) EL(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("EL: [%v]", strconv.Itoa(param))
+ h.clearWrap()
+
+ // [K -- Erases from the cursor to the end of the line, including the cursor position.
+ // [1K -- Erases from the beginning of the line to the cursor, including the cursor position.
+ // [2K -- Erases the complete line.
+
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+
+ var start COORD
+ var end COORD
+
+ switch param {
+ case 0:
+ start = info.CursorPosition
+ end = COORD{info.Size.X, info.CursorPosition.Y}
+
+ case 1:
+ start = COORD{0, info.CursorPosition.Y}
+ end = info.CursorPosition
+
+ case 2:
+ start = COORD{0, info.CursorPosition.Y}
+ end = COORD{info.Size.X, info.CursorPosition.Y}
+ }
+
+ err = h.clearRange(h.attributes, start, end)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (h *windowsAnsiEventHandler) IL(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("IL: [%v]", strconv.Itoa(param))
+ h.clearWrap()
+ return h.insertLines(param)
+}
+
+func (h *windowsAnsiEventHandler) DL(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("DL: [%v]", strconv.Itoa(param))
+ h.clearWrap()
+ return h.deleteLines(param)
+}
+
+func (h *windowsAnsiEventHandler) ICH(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("ICH: [%v]", strconv.Itoa(param))
+ h.clearWrap()
+ return h.insertCharacters(param)
+}
+
+func (h *windowsAnsiEventHandler) DCH(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("DCH: [%v]", strconv.Itoa(param))
+ h.clearWrap()
+ return h.deleteCharacters(param)
+}
+
+func (h *windowsAnsiEventHandler) SGR(params []int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ strings := []string{}
+ for _, v := range params {
+ strings = append(strings, strconv.Itoa(v))
+ }
+
+ h.logf("SGR: [%v]", strings)
+
+ if len(params) <= 0 {
+ h.attributes = h.infoReset.Attributes
+ h.inverted = false
+ } else {
+ for _, attr := range params {
+
+ if attr == ansiterm.ANSI_SGR_RESET {
+ h.attributes = h.infoReset.Attributes
+ h.inverted = false
+ continue
+ }
+
+ h.attributes, h.inverted = collectAnsiIntoWindowsAttributes(h.attributes, h.inverted, h.infoReset.Attributes, int16(attr))
+ }
+ }
+
+ attributes := h.attributes
+ if h.inverted {
+ attributes = invertAttributes(attributes)
+ }
+ err := SetConsoleTextAttribute(h.fd, attributes)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (h *windowsAnsiEventHandler) SU(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("SU: [%v]", []string{strconv.Itoa(param)})
+ h.clearWrap()
+ return h.scrollUp(param)
+}
+
+func (h *windowsAnsiEventHandler) SD(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("SD: [%v]", []string{strconv.Itoa(param)})
+ h.clearWrap()
+ return h.scrollDown(param)
+}
+
+func (h *windowsAnsiEventHandler) DA(params []string) error {
+ h.logf("DA: [%v]", params)
+ // DA cannot be implemented because it must send data on the VT100 input stream,
+ // which is not available to go-ansiterm.
+ return nil
+}
+
+func (h *windowsAnsiEventHandler) DECSTBM(top int, bottom int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("DECSTBM: [%d, %d]", top, bottom)
+
+ // Windows is 0 indexed, Linux is 1 indexed
+ h.sr.top = int16(top - 1)
+ h.sr.bottom = int16(bottom - 1)
+
+ // This command also moves the cursor to the origin.
+ h.clearWrap()
+ return h.CUP(1, 1)
+}
+
+func (h *windowsAnsiEventHandler) RI() error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("RI: []")
+ h.clearWrap()
+
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+
+ sr := h.effectiveSr(info.Window)
+ if info.CursorPosition.Y == sr.top {
+ return h.scrollDown(1)
+ }
+
+ return h.moveCursorVertical(-1)
+}
+
+func (h *windowsAnsiEventHandler) IND() error {
+ h.logf("IND: []")
+ return h.executeLF()
+}
+
+func (h *windowsAnsiEventHandler) Flush() error {
+ h.curInfo = nil
+ if h.buffer.Len() > 0 {
+ h.logf("Flush: [%s]", h.buffer.Bytes())
+ if _, err := h.buffer.WriteTo(h.file); err != nil {
+ return err
+ }
+ }
+
+ if h.wrapNext && !h.drewMarginByte {
+ h.logf("Flush: drawing margin byte '%c'", h.marginByte)
+
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+
+ charInfo := []CHAR_INFO{{UnicodeChar: uint16(h.marginByte), Attributes: info.Attributes}}
+ size := COORD{1, 1}
+ position := COORD{0, 0}
+ region := SMALL_RECT{Left: info.CursorPosition.X, Top: info.CursorPosition.Y, Right: info.CursorPosition.X, Bottom: info.CursorPosition.Y}
+ if err := WriteConsoleOutput(h.fd, charInfo, size, position, ®ion); err != nil {
+ return err
+ }
+ h.drewMarginByte = true
+ }
+ return nil
+}
+
+// cacheConsoleInfo ensures that the current console screen information has been queried
+// since the last call to Flush(). It must be called before accessing h.curInfo or h.curPos.
+func (h *windowsAnsiEventHandler) getCurrentInfo() (COORD, *CONSOLE_SCREEN_BUFFER_INFO, error) {
+ if h.curInfo == nil {
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return COORD{}, nil, err
+ }
+ h.curInfo = info
+ h.curPos = info.CursorPosition
+ }
+ return h.curPos, h.curInfo, nil
+}
+
+func (h *windowsAnsiEventHandler) updatePos(pos COORD) {
+ if h.curInfo == nil {
+ panic("failed to call getCurrentInfo before calling updatePos")
+ }
+ h.curPos = pos
+}
+
+// clearWrap clears the state where the cursor is in the margin
+// waiting for the next character before wrapping the line. This must
+// be done before most operations that act on the cursor.
+func (h *windowsAnsiEventHandler) clearWrap() {
+ h.wrapNext = false
+ h.drewMarginByte = false
+}
diff --git a/vendor/github.com/Nvveen/Gotty/LICENSE b/vendor/github.com/Nvveen/Gotty/LICENSE
new file mode 100644
index 00000000..0b71c973
--- /dev/null
+++ b/vendor/github.com/Nvveen/Gotty/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 2012, Neal van Veen (nealvanveen@gmail.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those
+of the authors and should not be interpreted as representing official policies,
+either expressed or implied, of the FreeBSD Project.
diff --git a/vendor/github.com/Nvveen/Gotty/README b/vendor/github.com/Nvveen/Gotty/README
new file mode 100644
index 00000000..a6b0d9a8
--- /dev/null
+++ b/vendor/github.com/Nvveen/Gotty/README
@@ -0,0 +1,5 @@
+Gotty is a library written in Go that determines and reads termcap database
+files to produce an interface for interacting with the capabilities of a
+terminal.
+See the godoc documentation or the source code for more information about
+function usage.
diff --git a/vendor/github.com/Nvveen/Gotty/TODO b/vendor/github.com/Nvveen/Gotty/TODO
new file mode 100644
index 00000000..47046053
--- /dev/null
+++ b/vendor/github.com/Nvveen/Gotty/TODO
@@ -0,0 +1,3 @@
+gotty.go:// TODO add more concurrency to name lookup, look for more opportunities.
+all:// TODO add more documentation, with function usage in a doc.go file.
+all:// TODO add more testing/benchmarking with go test.
diff --git a/vendor/github.com/Nvveen/Gotty/attributes.go b/vendor/github.com/Nvveen/Gotty/attributes.go
new file mode 100644
index 00000000..a4c005fa
--- /dev/null
+++ b/vendor/github.com/Nvveen/Gotty/attributes.go
@@ -0,0 +1,514 @@
+// Copyright 2012 Neal van Veen. All rights reserved.
+// Usage of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package gotty
+
+// Boolean capabilities
+var BoolAttr = [...]string{
+ "auto_left_margin", "bw",
+ "auto_right_margin", "am",
+ "no_esc_ctlc", "xsb",
+ "ceol_standout_glitch", "xhp",
+ "eat_newline_glitch", "xenl",
+ "erase_overstrike", "eo",
+ "generic_type", "gn",
+ "hard_copy", "hc",
+ "has_meta_key", "km",
+ "has_status_line", "hs",
+ "insert_null_glitch", "in",
+ "memory_above", "da",
+ "memory_below", "db",
+ "move_insert_mode", "mir",
+ "move_standout_mode", "msgr",
+ "over_strike", "os",
+ "status_line_esc_ok", "eslok",
+ "dest_tabs_magic_smso", "xt",
+ "tilde_glitch", "hz",
+ "transparent_underline", "ul",
+ "xon_xoff", "nxon",
+ "needs_xon_xoff", "nxon",
+ "prtr_silent", "mc5i",
+ "hard_cursor", "chts",
+ "non_rev_rmcup", "nrrmc",
+ "no_pad_char", "npc",
+ "non_dest_scroll_region", "ndscr",
+ "can_change", "ccc",
+ "back_color_erase", "bce",
+ "hue_lightness_saturation", "hls",
+ "col_addr_glitch", "xhpa",
+ "cr_cancels_micro_mode", "crxm",
+ "has_print_wheel", "daisy",
+ "row_addr_glitch", "xvpa",
+ "semi_auto_right_margin", "sam",
+ "cpi_changes_res", "cpix",
+ "lpi_changes_res", "lpix",
+ "backspaces_with_bs", "",
+ "crt_no_scrolling", "",
+ "no_correctly_working_cr", "",
+ "gnu_has_meta_key", "",
+ "linefeed_is_newline", "",
+ "has_hardware_tabs", "",
+ "return_does_clr_eol", "",
+}
+
+// Numerical capabilities
+var NumAttr = [...]string{
+ "columns", "cols",
+ "init_tabs", "it",
+ "lines", "lines",
+ "lines_of_memory", "lm",
+ "magic_cookie_glitch", "xmc",
+ "padding_baud_rate", "pb",
+ "virtual_terminal", "vt",
+ "width_status_line", "wsl",
+ "num_labels", "nlab",
+ "label_height", "lh",
+ "label_width", "lw",
+ "max_attributes", "ma",
+ "maximum_windows", "wnum",
+ "max_colors", "colors",
+ "max_pairs", "pairs",
+ "no_color_video", "ncv",
+ "buffer_capacity", "bufsz",
+ "dot_vert_spacing", "spinv",
+ "dot_horz_spacing", "spinh",
+ "max_micro_address", "maddr",
+ "max_micro_jump", "mjump",
+ "micro_col_size", "mcs",
+ "micro_line_size", "mls",
+ "number_of_pins", "npins",
+ "output_res_char", "orc",
+ "output_res_line", "orl",
+ "output_res_horz_inch", "orhi",
+ "output_res_vert_inch", "orvi",
+ "print_rate", "cps",
+ "wide_char_size", "widcs",
+ "buttons", "btns",
+ "bit_image_entwining", "bitwin",
+ "bit_image_type", "bitype",
+ "magic_cookie_glitch_ul", "",
+ "carriage_return_delay", "",
+ "new_line_delay", "",
+ "backspace_delay", "",
+ "horizontal_tab_delay", "",
+ "number_of_function_keys", "",
+}
+
+// String capabilities
+var StrAttr = [...]string{
+ "back_tab", "cbt",
+ "bell", "bel",
+ "carriage_return", "cr",
+ "change_scroll_region", "csr",
+ "clear_all_tabs", "tbc",
+ "clear_screen", "clear",
+ "clr_eol", "el",
+ "clr_eos", "ed",
+ "column_address", "hpa",
+ "command_character", "cmdch",
+ "cursor_address", "cup",
+ "cursor_down", "cud1",
+ "cursor_home", "home",
+ "cursor_invisible", "civis",
+ "cursor_left", "cub1",
+ "cursor_mem_address", "mrcup",
+ "cursor_normal", "cnorm",
+ "cursor_right", "cuf1",
+ "cursor_to_ll", "ll",
+ "cursor_up", "cuu1",
+ "cursor_visible", "cvvis",
+ "delete_character", "dch1",
+ "delete_line", "dl1",
+ "dis_status_line", "dsl",
+ "down_half_line", "hd",
+ "enter_alt_charset_mode", "smacs",
+ "enter_blink_mode", "blink",
+ "enter_bold_mode", "bold",
+ "enter_ca_mode", "smcup",
+ "enter_delete_mode", "smdc",
+ "enter_dim_mode", "dim",
+ "enter_insert_mode", "smir",
+ "enter_secure_mode", "invis",
+ "enter_protected_mode", "prot",
+ "enter_reverse_mode", "rev",
+ "enter_standout_mode", "smso",
+ "enter_underline_mode", "smul",
+ "erase_chars", "ech",
+ "exit_alt_charset_mode", "rmacs",
+ "exit_attribute_mode", "sgr0",
+ "exit_ca_mode", "rmcup",
+ "exit_delete_mode", "rmdc",
+ "exit_insert_mode", "rmir",
+ "exit_standout_mode", "rmso",
+ "exit_underline_mode", "rmul",
+ "flash_screen", "flash",
+ "form_feed", "ff",
+ "from_status_line", "fsl",
+ "init_1string", "is1",
+ "init_2string", "is2",
+ "init_3string", "is3",
+ "init_file", "if",
+ "insert_character", "ich1",
+ "insert_line", "il1",
+ "insert_padding", "ip",
+ "key_backspace", "kbs",
+ "key_catab", "ktbc",
+ "key_clear", "kclr",
+ "key_ctab", "kctab",
+ "key_dc", "kdch1",
+ "key_dl", "kdl1",
+ "key_down", "kcud1",
+ "key_eic", "krmir",
+ "key_eol", "kel",
+ "key_eos", "ked",
+ "key_f0", "kf0",
+ "key_f1", "kf1",
+ "key_f10", "kf10",
+ "key_f2", "kf2",
+ "key_f3", "kf3",
+ "key_f4", "kf4",
+ "key_f5", "kf5",
+ "key_f6", "kf6",
+ "key_f7", "kf7",
+ "key_f8", "kf8",
+ "key_f9", "kf9",
+ "key_home", "khome",
+ "key_ic", "kich1",
+ "key_il", "kil1",
+ "key_left", "kcub1",
+ "key_ll", "kll",
+ "key_npage", "knp",
+ "key_ppage", "kpp",
+ "key_right", "kcuf1",
+ "key_sf", "kind",
+ "key_sr", "kri",
+ "key_stab", "khts",
+ "key_up", "kcuu1",
+ "keypad_local", "rmkx",
+ "keypad_xmit", "smkx",
+ "lab_f0", "lf0",
+ "lab_f1", "lf1",
+ "lab_f10", "lf10",
+ "lab_f2", "lf2",
+ "lab_f3", "lf3",
+ "lab_f4", "lf4",
+ "lab_f5", "lf5",
+ "lab_f6", "lf6",
+ "lab_f7", "lf7",
+ "lab_f8", "lf8",
+ "lab_f9", "lf9",
+ "meta_off", "rmm",
+ "meta_on", "smm",
+ "newline", "_glitch",
+ "pad_char", "npc",
+ "parm_dch", "dch",
+ "parm_delete_line", "dl",
+ "parm_down_cursor", "cud",
+ "parm_ich", "ich",
+ "parm_index", "indn",
+ "parm_insert_line", "il",
+ "parm_left_cursor", "cub",
+ "parm_right_cursor", "cuf",
+ "parm_rindex", "rin",
+ "parm_up_cursor", "cuu",
+ "pkey_key", "pfkey",
+ "pkey_local", "pfloc",
+ "pkey_xmit", "pfx",
+ "print_screen", "mc0",
+ "prtr_off", "mc4",
+ "prtr_on", "mc5",
+ "repeat_char", "rep",
+ "reset_1string", "rs1",
+ "reset_2string", "rs2",
+ "reset_3string", "rs3",
+ "reset_file", "rf",
+ "restore_cursor", "rc",
+ "row_address", "mvpa",
+ "save_cursor", "row_address",
+ "scroll_forward", "ind",
+ "scroll_reverse", "ri",
+ "set_attributes", "sgr",
+ "set_tab", "hts",
+ "set_window", "wind",
+ "tab", "s_magic_smso",
+ "to_status_line", "tsl",
+ "underline_char", "uc",
+ "up_half_line", "hu",
+ "init_prog", "iprog",
+ "key_a1", "ka1",
+ "key_a3", "ka3",
+ "key_b2", "kb2",
+ "key_c1", "kc1",
+ "key_c3", "kc3",
+ "prtr_non", "mc5p",
+ "char_padding", "rmp",
+ "acs_chars", "acsc",
+ "plab_norm", "pln",
+ "key_btab", "kcbt",
+ "enter_xon_mode", "smxon",
+ "exit_xon_mode", "rmxon",
+ "enter_am_mode", "smam",
+ "exit_am_mode", "rmam",
+ "xon_character", "xonc",
+ "xoff_character", "xoffc",
+ "ena_acs", "enacs",
+ "label_on", "smln",
+ "label_off", "rmln",
+ "key_beg", "kbeg",
+ "key_cancel", "kcan",
+ "key_close", "kclo",
+ "key_command", "kcmd",
+ "key_copy", "kcpy",
+ "key_create", "kcrt",
+ "key_end", "kend",
+ "key_enter", "kent",
+ "key_exit", "kext",
+ "key_find", "kfnd",
+ "key_help", "khlp",
+ "key_mark", "kmrk",
+ "key_message", "kmsg",
+ "key_move", "kmov",
+ "key_next", "knxt",
+ "key_open", "kopn",
+ "key_options", "kopt",
+ "key_previous", "kprv",
+ "key_print", "kprt",
+ "key_redo", "krdo",
+ "key_reference", "kref",
+ "key_refresh", "krfr",
+ "key_replace", "krpl",
+ "key_restart", "krst",
+ "key_resume", "kres",
+ "key_save", "ksav",
+ "key_suspend", "kspd",
+ "key_undo", "kund",
+ "key_sbeg", "kBEG",
+ "key_scancel", "kCAN",
+ "key_scommand", "kCMD",
+ "key_scopy", "kCPY",
+ "key_screate", "kCRT",
+ "key_sdc", "kDC",
+ "key_sdl", "kDL",
+ "key_select", "kslt",
+ "key_send", "kEND",
+ "key_seol", "kEOL",
+ "key_sexit", "kEXT",
+ "key_sfind", "kFND",
+ "key_shelp", "kHLP",
+ "key_shome", "kHOM",
+ "key_sic", "kIC",
+ "key_sleft", "kLFT",
+ "key_smessage", "kMSG",
+ "key_smove", "kMOV",
+ "key_snext", "kNXT",
+ "key_soptions", "kOPT",
+ "key_sprevious", "kPRV",
+ "key_sprint", "kPRT",
+ "key_sredo", "kRDO",
+ "key_sreplace", "kRPL",
+ "key_sright", "kRIT",
+ "key_srsume", "kRES",
+ "key_ssave", "kSAV",
+ "key_ssuspend", "kSPD",
+ "key_sundo", "kUND",
+ "req_for_input", "rfi",
+ "key_f11", "kf11",
+ "key_f12", "kf12",
+ "key_f13", "kf13",
+ "key_f14", "kf14",
+ "key_f15", "kf15",
+ "key_f16", "kf16",
+ "key_f17", "kf17",
+ "key_f18", "kf18",
+ "key_f19", "kf19",
+ "key_f20", "kf20",
+ "key_f21", "kf21",
+ "key_f22", "kf22",
+ "key_f23", "kf23",
+ "key_f24", "kf24",
+ "key_f25", "kf25",
+ "key_f26", "kf26",
+ "key_f27", "kf27",
+ "key_f28", "kf28",
+ "key_f29", "kf29",
+ "key_f30", "kf30",
+ "key_f31", "kf31",
+ "key_f32", "kf32",
+ "key_f33", "kf33",
+ "key_f34", "kf34",
+ "key_f35", "kf35",
+ "key_f36", "kf36",
+ "key_f37", "kf37",
+ "key_f38", "kf38",
+ "key_f39", "kf39",
+ "key_f40", "kf40",
+ "key_f41", "kf41",
+ "key_f42", "kf42",
+ "key_f43", "kf43",
+ "key_f44", "kf44",
+ "key_f45", "kf45",
+ "key_f46", "kf46",
+ "key_f47", "kf47",
+ "key_f48", "kf48",
+ "key_f49", "kf49",
+ "key_f50", "kf50",
+ "key_f51", "kf51",
+ "key_f52", "kf52",
+ "key_f53", "kf53",
+ "key_f54", "kf54",
+ "key_f55", "kf55",
+ "key_f56", "kf56",
+ "key_f57", "kf57",
+ "key_f58", "kf58",
+ "key_f59", "kf59",
+ "key_f60", "kf60",
+ "key_f61", "kf61",
+ "key_f62", "kf62",
+ "key_f63", "kf63",
+ "clr_bol", "el1",
+ "clear_margins", "mgc",
+ "set_left_margin", "smgl",
+ "set_right_margin", "smgr",
+ "label_format", "fln",
+ "set_clock", "sclk",
+ "display_clock", "dclk",
+ "remove_clock", "rmclk",
+ "create_window", "cwin",
+ "goto_window", "wingo",
+ "hangup", "hup",
+ "dial_phone", "dial",
+ "quick_dial", "qdial",
+ "tone", "tone",
+ "pulse", "pulse",
+ "flash_hook", "hook",
+ "fixed_pause", "pause",
+ "wait_tone", "wait",
+ "user0", "u0",
+ "user1", "u1",
+ "user2", "u2",
+ "user3", "u3",
+ "user4", "u4",
+ "user5", "u5",
+ "user6", "u6",
+ "user7", "u7",
+ "user8", "u8",
+ "user9", "u9",
+ "orig_pair", "op",
+ "orig_colors", "oc",
+ "initialize_color", "initc",
+ "initialize_pair", "initp",
+ "set_color_pair", "scp",
+ "set_foreground", "setf",
+ "set_background", "setb",
+ "change_char_pitch", "cpi",
+ "change_line_pitch", "lpi",
+ "change_res_horz", "chr",
+ "change_res_vert", "cvr",
+ "define_char", "defc",
+ "enter_doublewide_mode", "swidm",
+ "enter_draft_quality", "sdrfq",
+ "enter_italics_mode", "sitm",
+ "enter_leftward_mode", "slm",
+ "enter_micro_mode", "smicm",
+ "enter_near_letter_quality", "snlq",
+ "enter_normal_quality", "snrmq",
+ "enter_shadow_mode", "sshm",
+ "enter_subscript_mode", "ssubm",
+ "enter_superscript_mode", "ssupm",
+ "enter_upward_mode", "sum",
+ "exit_doublewide_mode", "rwidm",
+ "exit_italics_mode", "ritm",
+ "exit_leftward_mode", "rlm",
+ "exit_micro_mode", "rmicm",
+ "exit_shadow_mode", "rshm",
+ "exit_subscript_mode", "rsubm",
+ "exit_superscript_mode", "rsupm",
+ "exit_upward_mode", "rum",
+ "micro_column_address", "mhpa",
+ "micro_down", "mcud1",
+ "micro_left", "mcub1",
+ "micro_right", "mcuf1",
+ "micro_row_address", "mvpa",
+ "micro_up", "mcuu1",
+ "order_of_pins", "porder",
+ "parm_down_micro", "mcud",
+ "parm_left_micro", "mcub",
+ "parm_right_micro", "mcuf",
+ "parm_up_micro", "mcuu",
+ "select_char_set", "scs",
+ "set_bottom_margin", "smgb",
+ "set_bottom_margin_parm", "smgbp",
+ "set_left_margin_parm", "smglp",
+ "set_right_margin_parm", "smgrp",
+ "set_top_margin", "smgt",
+ "set_top_margin_parm", "smgtp",
+ "start_bit_image", "sbim",
+ "start_char_set_def", "scsd",
+ "stop_bit_image", "rbim",
+ "stop_char_set_def", "rcsd",
+ "subscript_characters", "subcs",
+ "superscript_characters", "supcs",
+ "these_cause_cr", "docr",
+ "zero_motion", "zerom",
+ "char_set_names", "csnm",
+ "key_mouse", "kmous",
+ "mouse_info", "minfo",
+ "req_mouse_pos", "reqmp",
+ "get_mouse", "getm",
+ "set_a_foreground", "setaf",
+ "set_a_background", "setab",
+ "pkey_plab", "pfxl",
+ "device_type", "devt",
+ "code_set_init", "csin",
+ "set0_des_seq", "s0ds",
+ "set1_des_seq", "s1ds",
+ "set2_des_seq", "s2ds",
+ "set3_des_seq", "s3ds",
+ "set_lr_margin", "smglr",
+ "set_tb_margin", "smgtb",
+ "bit_image_repeat", "birep",
+ "bit_image_newline", "binel",
+ "bit_image_carriage_return", "bicr",
+ "color_names", "colornm",
+ "define_bit_image_region", "defbi",
+ "end_bit_image_region", "endbi",
+ "set_color_band", "setcolor",
+ "set_page_length", "slines",
+ "display_pc_char", "dispc",
+ "enter_pc_charset_mode", "smpch",
+ "exit_pc_charset_mode", "rmpch",
+ "enter_scancode_mode", "smsc",
+ "exit_scancode_mode", "rmsc",
+ "pc_term_options", "pctrm",
+ "scancode_escape", "scesc",
+ "alt_scancode_esc", "scesa",
+ "enter_horizontal_hl_mode", "ehhlm",
+ "enter_left_hl_mode", "elhlm",
+ "enter_low_hl_mode", "elohlm",
+ "enter_right_hl_mode", "erhlm",
+ "enter_top_hl_mode", "ethlm",
+ "enter_vertical_hl_mode", "evhlm",
+ "set_a_attributes", "sgr1",
+ "set_pglen_inch", "slength",
+ "termcap_init2", "",
+ "termcap_reset", "",
+ "linefeed_if_not_lf", "",
+ "backspace_if_not_bs", "",
+ "other_non_function_keys", "",
+ "arrow_key_map", "",
+ "acs_ulcorner", "",
+ "acs_llcorner", "",
+ "acs_urcorner", "",
+ "acs_lrcorner", "",
+ "acs_ltee", "",
+ "acs_rtee", "",
+ "acs_btee", "",
+ "acs_ttee", "",
+ "acs_hline", "",
+ "acs_vline", "",
+ "acs_plus", "",
+ "memory_lock", "",
+ "memory_unlock", "",
+ "box_chars_1", "",
+}
diff --git a/vendor/github.com/Nvveen/Gotty/gotty.go b/vendor/github.com/Nvveen/Gotty/gotty.go
new file mode 100644
index 00000000..093cbf37
--- /dev/null
+++ b/vendor/github.com/Nvveen/Gotty/gotty.go
@@ -0,0 +1,238 @@
+// Copyright 2012 Neal van Veen. All rights reserved.
+// Usage of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Gotty is a Go-package for reading and parsing the terminfo database
+package gotty
+
+// TODO add more concurrency to name lookup, look for more opportunities.
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "os"
+ "reflect"
+ "strings"
+ "sync"
+)
+
+// Open a terminfo file by the name given and construct a TermInfo object.
+// If something went wrong reading the terminfo database file, an error is
+// returned.
+func OpenTermInfo(termName string) (*TermInfo, error) {
+ var term *TermInfo
+ var err error
+ // Find the environment variables
+ termloc := os.Getenv("TERMINFO")
+ if len(termloc) == 0 {
+ // Search like ncurses
+ locations := []string{os.Getenv("HOME") + "/.terminfo/", "/etc/terminfo/",
+ "/lib/terminfo/", "/usr/share/terminfo/"}
+ var path string
+ for _, str := range locations {
+ // Construct path
+ path = str + string(termName[0]) + "/" + termName
+ // Check if path can be opened
+ file, _ := os.Open(path)
+ if file != nil {
+ // Path can open, fall out and use current path
+ file.Close()
+ break
+ }
+ }
+ if len(path) > 0 {
+ term, err = readTermInfo(path)
+ } else {
+ err = errors.New(fmt.Sprintf("No terminfo file(-location) found"))
+ }
+ }
+ return term, err
+}
+
+// Open a terminfo file from the environment variable containing the current
+// terminal name and construct a TermInfo object. If something went wrong
+// reading the terminfo database file, an error is returned.
+func OpenTermInfoEnv() (*TermInfo, error) {
+ termenv := os.Getenv("TERM")
+ return OpenTermInfo(termenv)
+}
+
+// Return an attribute by the name attr provided. If none can be found,
+// an error is returned.
+func (term *TermInfo) GetAttribute(attr string) (stacker, error) {
+ // Channel to store the main value in.
+ var value stacker
+ // Add a blocking WaitGroup
+ var block sync.WaitGroup
+ // Keep track of variable being written.
+ written := false
+ // Function to put into goroutine.
+ f := func(ats interface{}) {
+ var ok bool
+ var v stacker
+ // Switch on type of map to use and assign value to it.
+ switch reflect.TypeOf(ats).Elem().Kind() {
+ case reflect.Bool:
+ v, ok = ats.(map[string]bool)[attr]
+ case reflect.Int16:
+ v, ok = ats.(map[string]int16)[attr]
+ case reflect.String:
+ v, ok = ats.(map[string]string)[attr]
+ }
+ // If ok, a value is found, so we can write.
+ if ok {
+ value = v
+ written = true
+ }
+ // Goroutine is done
+ block.Done()
+ }
+ block.Add(3)
+ // Go for all 3 attribute lists.
+ go f(term.boolAttributes)
+ go f(term.numAttributes)
+ go f(term.strAttributes)
+ // Wait until every goroutine is done.
+ block.Wait()
+ // If a value has been written, return it.
+ if written {
+ return value, nil
+ }
+ // Otherwise, error.
+ return nil, fmt.Errorf("Erorr finding attribute")
+}
+
+// Return an attribute by the name attr provided. If none can be found,
+// an error is returned. A name is first converted to its termcap value.
+func (term *TermInfo) GetAttributeName(name string) (stacker, error) {
+ tc := GetTermcapName(name)
+ return term.GetAttribute(tc)
+}
+
+// A utility function that finds and returns the termcap equivalent of a
+// variable name.
+func GetTermcapName(name string) string {
+ // Termcap name
+ var tc string
+ // Blocking group
+ var wait sync.WaitGroup
+ // Function to put into a goroutine
+ f := func(attrs []string) {
+ // Find the string corresponding to the name
+ for i, s := range attrs {
+ if s == name {
+ tc = attrs[i+1]
+ }
+ }
+ // Goroutine is finished
+ wait.Done()
+ }
+ wait.Add(3)
+ // Go for all 3 attribute lists
+ go f(BoolAttr[:])
+ go f(NumAttr[:])
+ go f(StrAttr[:])
+ // Wait until every goroutine is done
+ wait.Wait()
+ // Return the termcap name
+ return tc
+}
+
+// This function takes a path to a terminfo file and reads it in binary
+// form to construct the actual TermInfo file.
+func readTermInfo(path string) (*TermInfo, error) {
+ // Open the terminfo file
+ file, err := os.Open(path)
+ defer file.Close()
+ if err != nil {
+ return nil, err
+ }
+
+ // magic, nameSize, boolSize, nrSNum, nrOffsetsStr, strSize
+ // Header is composed of the magic 0432 octal number, size of the name
+ // section, size of the boolean section, the amount of number values,
+ // the number of offsets of strings, and the size of the string section.
+ var header [6]int16
+ // Byte array is used to read in byte values
+ var byteArray []byte
+ // Short array is used to read in short values
+ var shArray []int16
+ // TermInfo object to store values
+ var term TermInfo
+
+ // Read in the header
+ err = binary.Read(file, binary.LittleEndian, &header)
+ if err != nil {
+ return nil, err
+ }
+ // If magic number isn't there or isn't correct, we have the wrong filetype
+ if header[0] != 0432 {
+ return nil, errors.New(fmt.Sprintf("Wrong filetype"))
+ }
+
+ // Read in the names
+ byteArray = make([]byte, header[1])
+ err = binary.Read(file, binary.LittleEndian, &byteArray)
+ if err != nil {
+ return nil, err
+ }
+ term.Names = strings.Split(string(byteArray), "|")
+
+ // Read in the booleans
+ byteArray = make([]byte, header[2])
+ err = binary.Read(file, binary.LittleEndian, &byteArray)
+ if err != nil {
+ return nil, err
+ }
+ term.boolAttributes = make(map[string]bool)
+ for i, b := range byteArray {
+ if b == 1 {
+ term.boolAttributes[BoolAttr[i*2+1]] = true
+ }
+ }
+ // If the number of bytes read is not even, a byte for alignment is added
+ if len(byteArray)%2 != 0 {
+ err = binary.Read(file, binary.LittleEndian, make([]byte, 1))
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ // Read in shorts
+ shArray = make([]int16, header[3])
+ err = binary.Read(file, binary.LittleEndian, &shArray)
+ if err != nil {
+ return nil, err
+ }
+ term.numAttributes = make(map[string]int16)
+ for i, n := range shArray {
+ if n != 0377 && n > -1 {
+ term.numAttributes[NumAttr[i*2+1]] = n
+ }
+ }
+
+ // Read the offsets into the short array
+ shArray = make([]int16, header[4])
+ err = binary.Read(file, binary.LittleEndian, &shArray)
+ if err != nil {
+ return nil, err
+ }
+ // Read the actual strings in the byte array
+ byteArray = make([]byte, header[5])
+ err = binary.Read(file, binary.LittleEndian, &byteArray)
+ if err != nil {
+ return nil, err
+ }
+ term.strAttributes = make(map[string]string)
+ // We get an offset, and then iterate until the string is null-terminated
+ for i, offset := range shArray {
+ if offset > -1 {
+ r := offset
+ for ; byteArray[r] != 0; r++ {
+ }
+ term.strAttributes[StrAttr[i*2+1]] = string(byteArray[offset:r])
+ }
+ }
+ return &term, nil
+}
diff --git a/vendor/github.com/Nvveen/Gotty/parser.go b/vendor/github.com/Nvveen/Gotty/parser.go
new file mode 100644
index 00000000..a9d5d23c
--- /dev/null
+++ b/vendor/github.com/Nvveen/Gotty/parser.go
@@ -0,0 +1,362 @@
+// Copyright 2012 Neal van Veen. All rights reserved.
+// Usage of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package gotty
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+var exp = [...]string{
+ "%%",
+ "%c",
+ "%s",
+ "%p(\\d)",
+ "%P([A-z])",
+ "%g([A-z])",
+ "%'(.)'",
+ "%{([0-9]+)}",
+ "%l",
+ "%\\+|%-|%\\*|%/|%m",
+ "%&|%\\||%\\^",
+ "%=|%>|%<",
+ "%A|%O",
+ "%!|%~",
+ "%i",
+ "%(:[\\ #\\-\\+]{0,4})?(\\d+\\.\\d+|\\d+)?[doxXs]",
+ "%\\?(.*?);",
+}
+
+var regex *regexp.Regexp
+var staticVar map[byte]stacker
+
+// Parses the attribute that is received with name attr and parameters params.
+func (term *TermInfo) Parse(attr string, params ...interface{}) (string, error) {
+ // Get the attribute name first.
+ iface, err := term.GetAttribute(attr)
+ str, ok := iface.(string)
+ if err != nil {
+ return "", err
+ }
+ if !ok {
+ return str, errors.New("Only string capabilities can be parsed.")
+ }
+ // Construct the hidden parser struct so we can use a recursive stack based
+ // parser.
+ ps := &parser{}
+ // Dynamic variables only exist in this context.
+ ps.dynamicVar = make(map[byte]stacker, 26)
+ ps.parameters = make([]stacker, len(params))
+ // Convert the parameters to insert them into the parser struct.
+ for i, x := range params {
+ ps.parameters[i] = x
+ }
+ // Recursively walk and return.
+ result, err := ps.walk(str)
+ return result, err
+}
+
+// Parses the attribute that is received with name attr and parameters params.
+// Only works on full name of a capability that is given, which it uses to
+// search for the termcap name.
+func (term *TermInfo) ParseName(attr string, params ...interface{}) (string, error) {
+ tc := GetTermcapName(attr)
+ return term.Parse(tc, params)
+}
+
+// Identify each token in a stack based manner and do the actual parsing.
+func (ps *parser) walk(attr string) (string, error) {
+ // We use a buffer to get the modified string.
+ var buf bytes.Buffer
+ // Next, find and identify all tokens by their indices and strings.
+ tokens := regex.FindAllStringSubmatch(attr, -1)
+ if len(tokens) == 0 {
+ return attr, nil
+ }
+ indices := regex.FindAllStringIndex(attr, -1)
+ q := 0 // q counts the matches of one token
+ // Iterate through the string per character.
+ for i := 0; i < len(attr); i++ {
+ // If the current position is an identified token, execute the following
+ // steps.
+ if q < len(indices) && i >= indices[q][0] && i < indices[q][1] {
+ // Switch on token.
+ switch {
+ case tokens[q][0][:2] == "%%":
+ // Literal percentage character.
+ buf.WriteByte('%')
+ case tokens[q][0][:2] == "%c":
+ // Pop a character.
+ c, err := ps.st.pop()
+ if err != nil {
+ return buf.String(), err
+ }
+ buf.WriteByte(c.(byte))
+ case tokens[q][0][:2] == "%s":
+ // Pop a string.
+ str, err := ps.st.pop()
+ if err != nil {
+ return buf.String(), err
+ }
+ if _, ok := str.(string); !ok {
+ return buf.String(), errors.New("Stack head is not a string")
+ }
+ buf.WriteString(str.(string))
+ case tokens[q][0][:2] == "%p":
+ // Push a parameter on the stack.
+ index, err := strconv.ParseInt(tokens[q][1], 10, 8)
+ index--
+ if err != nil {
+ return buf.String(), err
+ }
+ if int(index) >= len(ps.parameters) {
+ return buf.String(), errors.New("Parameters index out of bound")
+ }
+ ps.st.push(ps.parameters[index])
+ case tokens[q][0][:2] == "%P":
+ // Pop a variable from the stack as a dynamic or static variable.
+ val, err := ps.st.pop()
+ if err != nil {
+ return buf.String(), err
+ }
+ index := tokens[q][2]
+ if len(index) > 1 {
+ errorStr := fmt.Sprintf("%s is not a valid dynamic variables index",
+ index)
+ return buf.String(), errors.New(errorStr)
+ }
+ // Specify either dynamic or static.
+ if index[0] >= 'a' && index[0] <= 'z' {
+ ps.dynamicVar[index[0]] = val
+ } else if index[0] >= 'A' && index[0] <= 'Z' {
+ staticVar[index[0]] = val
+ }
+ case tokens[q][0][:2] == "%g":
+ // Push a variable from the stack as a dynamic or static variable.
+ index := tokens[q][3]
+ if len(index) > 1 {
+ errorStr := fmt.Sprintf("%s is not a valid static variables index",
+ index)
+ return buf.String(), errors.New(errorStr)
+ }
+ var val stacker
+ if index[0] >= 'a' && index[0] <= 'z' {
+ val = ps.dynamicVar[index[0]]
+ } else if index[0] >= 'A' && index[0] <= 'Z' {
+ val = staticVar[index[0]]
+ }
+ ps.st.push(val)
+ case tokens[q][0][:2] == "%'":
+ // Push a character constant.
+ con := tokens[q][4]
+ if len(con) > 1 {
+ errorStr := fmt.Sprintf("%s is not a valid character constant", con)
+ return buf.String(), errors.New(errorStr)
+ }
+ ps.st.push(con[0])
+ case tokens[q][0][:2] == "%{":
+ // Push an integer constant.
+ con, err := strconv.ParseInt(tokens[q][5], 10, 32)
+ if err != nil {
+ return buf.String(), err
+ }
+ ps.st.push(con)
+ case tokens[q][0][:2] == "%l":
+ // Push the length of the string that is popped from the stack.
+ popStr, err := ps.st.pop()
+ if err != nil {
+ return buf.String(), err
+ }
+ if _, ok := popStr.(string); !ok {
+ errStr := fmt.Sprintf("Stack head is not a string")
+ return buf.String(), errors.New(errStr)
+ }
+ ps.st.push(len(popStr.(string)))
+ case tokens[q][0][:2] == "%?":
+ // If-then-else construct. First, the whole string is identified and
+ // then inside this substring, we can specify which parts to switch on.
+ ifReg, _ := regexp.Compile("%\\?(.*)%t(.*)%e(.*);|%\\?(.*)%t(.*);")
+ ifTokens := ifReg.FindStringSubmatch(tokens[q][0])
+ var (
+ ifStr string
+ err error
+ )
+ // Parse the if-part to determine if-else.
+ if len(ifTokens[1]) > 0 {
+ ifStr, err = ps.walk(ifTokens[1])
+ } else { // else
+ ifStr, err = ps.walk(ifTokens[4])
+ }
+ // Return any errors
+ if err != nil {
+ return buf.String(), err
+ } else if len(ifStr) > 0 {
+ // Self-defined limitation, not sure if this is correct, but didn't
+ // seem like it.
+ return buf.String(), errors.New("If-clause cannot print statements")
+ }
+ var thenStr string
+ // Pop the first value that is set by parsing the if-clause.
+ choose, err := ps.st.pop()
+ if err != nil {
+ return buf.String(), err
+ }
+ // Switch to if or else.
+ if choose.(int) == 0 && len(ifTokens[1]) > 0 {
+ thenStr, err = ps.walk(ifTokens[3])
+ } else if choose.(int) != 0 {
+ if len(ifTokens[1]) > 0 {
+ thenStr, err = ps.walk(ifTokens[2])
+ } else {
+ thenStr, err = ps.walk(ifTokens[5])
+ }
+ }
+ if err != nil {
+ return buf.String(), err
+ }
+ buf.WriteString(thenStr)
+ case tokens[q][0][len(tokens[q][0])-1] == 'd': // Fallthrough for printing
+ fallthrough
+ case tokens[q][0][len(tokens[q][0])-1] == 'o': // digits.
+ fallthrough
+ case tokens[q][0][len(tokens[q][0])-1] == 'x':
+ fallthrough
+ case tokens[q][0][len(tokens[q][0])-1] == 'X':
+ fallthrough
+ case tokens[q][0][len(tokens[q][0])-1] == 's':
+ token := tokens[q][0]
+ // Remove the : that comes before a flag.
+ if token[1] == ':' {
+ token = token[:1] + token[2:]
+ }
+ digit, err := ps.st.pop()
+ if err != nil {
+ return buf.String(), err
+ }
+ // The rest is determined like the normal formatted prints.
+ digitStr := fmt.Sprintf(token, digit.(int))
+ buf.WriteString(digitStr)
+ case tokens[q][0][:2] == "%i":
+ // Increment the parameters by one.
+ if len(ps.parameters) < 2 {
+ return buf.String(), errors.New("Not enough parameters to increment.")
+ }
+ val1, val2 := ps.parameters[0].(int), ps.parameters[1].(int)
+ val1++
+ val2++
+ ps.parameters[0], ps.parameters[1] = val1, val2
+ default:
+ // The rest of the tokens is a special case, where two values are
+ // popped and then operated on by the token that comes after them.
+ op1, err := ps.st.pop()
+ if err != nil {
+ return buf.String(), err
+ }
+ op2, err := ps.st.pop()
+ if err != nil {
+ return buf.String(), err
+ }
+ var result stacker
+ switch tokens[q][0][:2] {
+ case "%+":
+ // Addition
+ result = op2.(int) + op1.(int)
+ case "%-":
+ // Subtraction
+ result = op2.(int) - op1.(int)
+ case "%*":
+ // Multiplication
+ result = op2.(int) * op1.(int)
+ case "%/":
+ // Division
+ result = op2.(int) / op1.(int)
+ case "%m":
+ // Modulo
+ result = op2.(int) % op1.(int)
+ case "%&":
+ // Bitwise AND
+ result = op2.(int) & op1.(int)
+ case "%|":
+ // Bitwise OR
+ result = op2.(int) | op1.(int)
+ case "%^":
+ // Bitwise XOR
+ result = op2.(int) ^ op1.(int)
+ case "%=":
+ // Equals
+ result = op2 == op1
+ case "%>":
+ // Greater-than
+ result = op2.(int) > op1.(int)
+ case "%<":
+ // Lesser-than
+ result = op2.(int) < op1.(int)
+ case "%A":
+ // Logical AND
+ result = op2.(bool) && op1.(bool)
+ case "%O":
+ // Logical OR
+ result = op2.(bool) || op1.(bool)
+ case "%!":
+ // Logical complement
+ result = !op1.(bool)
+ case "%~":
+ // Bitwise complement
+ result = ^(op1.(int))
+ }
+ ps.st.push(result)
+ }
+
+ i = indices[q][1] - 1
+ q++
+ } else {
+ // We are not "inside" a token, so just skip until the end or the next
+ // token, and add all characters to the buffer.
+ j := i
+ if q != len(indices) {
+ for !(j >= indices[q][0] && j < indices[q][1]) {
+ j++
+ }
+ } else {
+ j = len(attr)
+ }
+ buf.WriteString(string(attr[i:j]))
+ i = j
+ }
+ }
+ // Return the buffer as a string.
+ return buf.String(), nil
+}
+
+// Push a stacker-value onto the stack.
+func (st *stack) push(s stacker) {
+ *st = append(*st, s)
+}
+
+// Pop a stacker-value from the stack.
+func (st *stack) pop() (stacker, error) {
+ if len(*st) == 0 {
+ return nil, errors.New("Stack is empty.")
+ }
+ newStack := make(stack, len(*st)-1)
+ val := (*st)[len(*st)-1]
+ copy(newStack, (*st)[:len(*st)-1])
+ *st = newStack
+ return val, nil
+}
+
+// Initialize regexes and the static vars (that don't get changed between
+// calls.
+func init() {
+ // Initialize the main regex.
+ expStr := strings.Join(exp[:], "|")
+ regex, _ = regexp.Compile(expStr)
+ // Initialize the static variables.
+ staticVar = make(map[byte]stacker, 26)
+}
diff --git a/vendor/github.com/Nvveen/Gotty/types.go b/vendor/github.com/Nvveen/Gotty/types.go
new file mode 100644
index 00000000..9bcc65e9
--- /dev/null
+++ b/vendor/github.com/Nvveen/Gotty/types.go
@@ -0,0 +1,23 @@
+// Copyright 2012 Neal van Veen. All rights reserved.
+// Usage of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package gotty
+
+type TermInfo struct {
+ boolAttributes map[string]bool
+ numAttributes map[string]int16
+ strAttributes map[string]string
+ // The various names of the TermInfo file.
+ Names []string
+}
+
+type stacker interface {
+}
+type stack []stacker
+
+type parser struct {
+ st stack
+ parameters []stacker
+ dynamicVar map[byte]stacker
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/.gitignore b/vendor/github.com/cenkalti/backoff/v4/.gitignore
new file mode 100644
index 00000000..50d95c54
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/.gitignore
@@ -0,0 +1,25 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+
+# IDEs
+.idea/
diff --git a/vendor/github.com/cenkalti/backoff/v4/LICENSE b/vendor/github.com/cenkalti/backoff/v4/LICENSE
new file mode 100644
index 00000000..89b81799
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Cenk Altı
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/cenkalti/backoff/v4/README.md b/vendor/github.com/cenkalti/backoff/v4/README.md
new file mode 100644
index 00000000..9433004a
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/README.md
@@ -0,0 +1,30 @@
+# Exponential Backoff [![GoDoc][godoc image]][godoc] [![Coverage Status][coveralls image]][coveralls]
+
+This is a Go port of the exponential backoff algorithm from [Google's HTTP Client Library for Java][google-http-java-client].
+
+[Exponential backoff][exponential backoff wiki]
+is an algorithm that uses feedback to multiplicatively decrease the rate of some process,
+in order to gradually find an acceptable rate.
+The retries exponentially increase and stop increasing when a certain threshold is met.
+
+## Usage
+
+Import path is `github.com/cenkalti/backoff/v4`. Please note the version part at the end.
+
+Use https://pkg.go.dev/github.com/cenkalti/backoff/v4 to view the documentation.
+
+## Contributing
+
+* I would like to keep this library as small as possible.
+* Please don't send a PR without opening an issue and discussing it first.
+* If proposed change is not a common use case, I will probably not accept it.
+
+[godoc]: https://pkg.go.dev/github.com/cenkalti/backoff/v4
+[godoc image]: https://godoc.org/github.com/cenkalti/backoff?status.png
+[coveralls]: https://coveralls.io/github/cenkalti/backoff?branch=master
+[coveralls image]: https://coveralls.io/repos/github/cenkalti/backoff/badge.svg?branch=master
+
+[google-http-java-client]: https://github.com/google/google-http-java-client/blob/da1aa993e90285ec18579f1553339b00e19b3ab5/google-http-client/src/main/java/com/google/api/client/util/ExponentialBackOff.java
+[exponential backoff wiki]: http://en.wikipedia.org/wiki/Exponential_backoff
+
+[advanced example]: https://pkg.go.dev/github.com/cenkalti/backoff/v4?tab=doc#pkg-examples
diff --git a/vendor/github.com/cenkalti/backoff/v4/backoff.go b/vendor/github.com/cenkalti/backoff/v4/backoff.go
new file mode 100644
index 00000000..3676ee40
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/backoff.go
@@ -0,0 +1,66 @@
+// Package backoff implements backoff algorithms for retrying operations.
+//
+// Use Retry function for retrying operations that may fail.
+// If Retry does not meet your needs,
+// copy/paste the function into your project and modify as you wish.
+//
+// There is also Ticker type similar to time.Ticker.
+// You can use it if you need to work with channels.
+//
+// See Examples section below for usage examples.
+package backoff
+
+import "time"
+
+// BackOff is a backoff policy for retrying an operation.
+type BackOff interface {
+ // NextBackOff returns the duration to wait before retrying the operation,
+ // or backoff. Stop to indicate that no more retries should be made.
+ //
+ // Example usage:
+ //
+ // duration := backoff.NextBackOff();
+ // if (duration == backoff.Stop) {
+ // // Do not retry operation.
+ // } else {
+ // // Sleep for duration and retry operation.
+ // }
+ //
+ NextBackOff() time.Duration
+
+ // Reset to initial state.
+ Reset()
+}
+
+// Stop indicates that no more retries should be made for use in NextBackOff().
+const Stop time.Duration = -1
+
+// ZeroBackOff is a fixed backoff policy whose backoff time is always zero,
+// meaning that the operation is retried immediately without waiting, indefinitely.
+type ZeroBackOff struct{}
+
+func (b *ZeroBackOff) Reset() {}
+
+func (b *ZeroBackOff) NextBackOff() time.Duration { return 0 }
+
+// StopBackOff is a fixed backoff policy that always returns backoff.Stop for
+// NextBackOff(), meaning that the operation should never be retried.
+type StopBackOff struct{}
+
+func (b *StopBackOff) Reset() {}
+
+func (b *StopBackOff) NextBackOff() time.Duration { return Stop }
+
+// ConstantBackOff is a backoff policy that always returns the same backoff delay.
+// This is in contrast to an exponential backoff policy,
+// which returns a delay that grows longer as you call NextBackOff() over and over again.
+type ConstantBackOff struct {
+ Interval time.Duration
+}
+
+func (b *ConstantBackOff) Reset() {}
+func (b *ConstantBackOff) NextBackOff() time.Duration { return b.Interval }
+
+func NewConstantBackOff(d time.Duration) *ConstantBackOff {
+ return &ConstantBackOff{Interval: d}
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/context.go b/vendor/github.com/cenkalti/backoff/v4/context.go
new file mode 100644
index 00000000..48482330
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/context.go
@@ -0,0 +1,62 @@
+package backoff
+
+import (
+ "context"
+ "time"
+)
+
+// BackOffContext is a backoff policy that stops retrying after the context
+// is canceled.
+type BackOffContext interface { // nolint: golint
+ BackOff
+ Context() context.Context
+}
+
+type backOffContext struct {
+ BackOff
+ ctx context.Context
+}
+
+// WithContext returns a BackOffContext with context ctx
+//
+// ctx must not be nil
+func WithContext(b BackOff, ctx context.Context) BackOffContext { // nolint: golint
+ if ctx == nil {
+ panic("nil context")
+ }
+
+ if b, ok := b.(*backOffContext); ok {
+ return &backOffContext{
+ BackOff: b.BackOff,
+ ctx: ctx,
+ }
+ }
+
+ return &backOffContext{
+ BackOff: b,
+ ctx: ctx,
+ }
+}
+
+func getContext(b BackOff) context.Context {
+ if cb, ok := b.(BackOffContext); ok {
+ return cb.Context()
+ }
+ if tb, ok := b.(*backOffTries); ok {
+ return getContext(tb.delegate)
+ }
+ return context.Background()
+}
+
+func (b *backOffContext) Context() context.Context {
+ return b.ctx
+}
+
+func (b *backOffContext) NextBackOff() time.Duration {
+ select {
+ case <-b.ctx.Done():
+ return Stop
+ default:
+ return b.BackOff.NextBackOff()
+ }
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/exponential.go b/vendor/github.com/cenkalti/backoff/v4/exponential.go
new file mode 100644
index 00000000..aac99f19
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/exponential.go
@@ -0,0 +1,216 @@
+package backoff
+
+import (
+ "math/rand"
+ "time"
+)
+
+/*
+ExponentialBackOff is a backoff implementation that increases the backoff
+period for each retry attempt using a randomization function that grows exponentially.
+
+NextBackOff() is calculated using the following formula:
+
+ randomized interval =
+ RetryInterval * (random value in range [1 - RandomizationFactor, 1 + RandomizationFactor])
+
+In other words NextBackOff() will range between the randomization factor
+percentage below and above the retry interval.
+
+For example, given the following parameters:
+
+ RetryInterval = 2
+ RandomizationFactor = 0.5
+ Multiplier = 2
+
+the actual backoff period used in the next retry attempt will range between 1 and 3 seconds,
+multiplied by the exponential, that is, between 2 and 6 seconds.
+
+Note: MaxInterval caps the RetryInterval and not the randomized interval.
+
+If the time elapsed since an ExponentialBackOff instance is created goes past the
+MaxElapsedTime, then the method NextBackOff() starts returning backoff.Stop.
+
+The elapsed time can be reset by calling Reset().
+
+Example: Given the following default arguments, for 10 tries the sequence will be,
+and assuming we go over the MaxElapsedTime on the 10th try:
+
+ Request # RetryInterval (seconds) Randomized Interval (seconds)
+
+ 1 0.5 [0.25, 0.75]
+ 2 0.75 [0.375, 1.125]
+ 3 1.125 [0.562, 1.687]
+ 4 1.687 [0.8435, 2.53]
+ 5 2.53 [1.265, 3.795]
+ 6 3.795 [1.897, 5.692]
+ 7 5.692 [2.846, 8.538]
+ 8 8.538 [4.269, 12.807]
+ 9 12.807 [6.403, 19.210]
+ 10 19.210 backoff.Stop
+
+Note: Implementation is not thread-safe.
+*/
+type ExponentialBackOff struct {
+ InitialInterval time.Duration
+ RandomizationFactor float64
+ Multiplier float64
+ MaxInterval time.Duration
+ // After MaxElapsedTime the ExponentialBackOff returns Stop.
+ // It never stops if MaxElapsedTime == 0.
+ MaxElapsedTime time.Duration
+ Stop time.Duration
+ Clock Clock
+
+ currentInterval time.Duration
+ startTime time.Time
+}
+
+// Clock is an interface that returns current time for BackOff.
+type Clock interface {
+ Now() time.Time
+}
+
+// ExponentialBackOffOpts is a function type used to configure ExponentialBackOff options.
+type ExponentialBackOffOpts func(*ExponentialBackOff)
+
+// Default values for ExponentialBackOff.
+const (
+ DefaultInitialInterval = 500 * time.Millisecond
+ DefaultRandomizationFactor = 0.5
+ DefaultMultiplier = 1.5
+ DefaultMaxInterval = 60 * time.Second
+ DefaultMaxElapsedTime = 15 * time.Minute
+)
+
+// NewExponentialBackOff creates an instance of ExponentialBackOff using default values.
+func NewExponentialBackOff(opts ...ExponentialBackOffOpts) *ExponentialBackOff {
+ b := &ExponentialBackOff{
+ InitialInterval: DefaultInitialInterval,
+ RandomizationFactor: DefaultRandomizationFactor,
+ Multiplier: DefaultMultiplier,
+ MaxInterval: DefaultMaxInterval,
+ MaxElapsedTime: DefaultMaxElapsedTime,
+ Stop: Stop,
+ Clock: SystemClock,
+ }
+ for _, fn := range opts {
+ fn(b)
+ }
+ b.Reset()
+ return b
+}
+
+// WithInitialInterval sets the initial interval between retries.
+func WithInitialInterval(duration time.Duration) ExponentialBackOffOpts {
+ return func(ebo *ExponentialBackOff) {
+ ebo.InitialInterval = duration
+ }
+}
+
+// WithRandomizationFactor sets the randomization factor to add jitter to intervals.
+func WithRandomizationFactor(randomizationFactor float64) ExponentialBackOffOpts {
+ return func(ebo *ExponentialBackOff) {
+ ebo.RandomizationFactor = randomizationFactor
+ }
+}
+
+// WithMultiplier sets the multiplier for increasing the interval after each retry.
+func WithMultiplier(multiplier float64) ExponentialBackOffOpts {
+ return func(ebo *ExponentialBackOff) {
+ ebo.Multiplier = multiplier
+ }
+}
+
+// WithMaxInterval sets the maximum interval between retries.
+func WithMaxInterval(duration time.Duration) ExponentialBackOffOpts {
+ return func(ebo *ExponentialBackOff) {
+ ebo.MaxInterval = duration
+ }
+}
+
+// WithMaxElapsedTime sets the maximum total time for retries.
+func WithMaxElapsedTime(duration time.Duration) ExponentialBackOffOpts {
+ return func(ebo *ExponentialBackOff) {
+ ebo.MaxElapsedTime = duration
+ }
+}
+
+// WithRetryStopDuration sets the duration after which retries should stop.
+func WithRetryStopDuration(duration time.Duration) ExponentialBackOffOpts {
+ return func(ebo *ExponentialBackOff) {
+ ebo.Stop = duration
+ }
+}
+
+// WithClockProvider sets the clock used to measure time.
+func WithClockProvider(clock Clock) ExponentialBackOffOpts {
+ return func(ebo *ExponentialBackOff) {
+ ebo.Clock = clock
+ }
+}
+
+type systemClock struct{}
+
+func (t systemClock) Now() time.Time {
+ return time.Now()
+}
+
+// SystemClock implements Clock interface that uses time.Now().
+var SystemClock = systemClock{}
+
+// Reset the interval back to the initial retry interval and restarts the timer.
+// Reset must be called before using b.
+func (b *ExponentialBackOff) Reset() {
+ b.currentInterval = b.InitialInterval
+ b.startTime = b.Clock.Now()
+}
+
+// NextBackOff calculates the next backoff interval using the formula:
+// Randomized interval = RetryInterval * (1 ± RandomizationFactor)
+func (b *ExponentialBackOff) NextBackOff() time.Duration {
+ // Make sure we have not gone over the maximum elapsed time.
+ elapsed := b.GetElapsedTime()
+ next := getRandomValueFromInterval(b.RandomizationFactor, rand.Float64(), b.currentInterval)
+ b.incrementCurrentInterval()
+ if b.MaxElapsedTime != 0 && elapsed+next > b.MaxElapsedTime {
+ return b.Stop
+ }
+ return next
+}
+
+// GetElapsedTime returns the elapsed time since an ExponentialBackOff instance
+// is created and is reset when Reset() is called.
+//
+// The elapsed time is computed using time.Now().UnixNano(). It is
+// safe to call even while the backoff policy is used by a running
+// ticker.
+func (b *ExponentialBackOff) GetElapsedTime() time.Duration {
+ return b.Clock.Now().Sub(b.startTime)
+}
+
+// Increments the current interval by multiplying it with the multiplier.
+func (b *ExponentialBackOff) incrementCurrentInterval() {
+ // Check for overflow, if overflow is detected set the current interval to the max interval.
+ if float64(b.currentInterval) >= float64(b.MaxInterval)/b.Multiplier {
+ b.currentInterval = b.MaxInterval
+ } else {
+ b.currentInterval = time.Duration(float64(b.currentInterval) * b.Multiplier)
+ }
+}
+
+// Returns a random value from the following interval:
+// [currentInterval - randomizationFactor * currentInterval, currentInterval + randomizationFactor * currentInterval].
+func getRandomValueFromInterval(randomizationFactor, random float64, currentInterval time.Duration) time.Duration {
+ if randomizationFactor == 0 {
+ return currentInterval // make sure no randomness is used when randomizationFactor is 0.
+ }
+ var delta = randomizationFactor * float64(currentInterval)
+ var minInterval = float64(currentInterval) - delta
+ var maxInterval = float64(currentInterval) + delta
+
+ // Get a random value from the range [minInterval, maxInterval].
+ // The formula used below has a +1 because if the minInterval is 1 and the maxInterval is 3 then
+ // we want a 33% chance for selecting either 1, 2 or 3.
+ return time.Duration(minInterval + (random * (maxInterval - minInterval + 1)))
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/retry.go b/vendor/github.com/cenkalti/backoff/v4/retry.go
new file mode 100644
index 00000000..b9c0c51c
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/retry.go
@@ -0,0 +1,146 @@
+package backoff
+
+import (
+ "errors"
+ "time"
+)
+
+// An OperationWithData is executing by RetryWithData() or RetryNotifyWithData().
+// The operation will be retried using a backoff policy if it returns an error.
+type OperationWithData[T any] func() (T, error)
+
+// An Operation is executing by Retry() or RetryNotify().
+// The operation will be retried using a backoff policy if it returns an error.
+type Operation func() error
+
+func (o Operation) withEmptyData() OperationWithData[struct{}] {
+ return func() (struct{}, error) {
+ return struct{}{}, o()
+ }
+}
+
+// Notify is a notify-on-error function. It receives an operation error and
+// backoff delay if the operation failed (with an error).
+//
+// NOTE that if the backoff policy stated to stop retrying,
+// the notify function isn't called.
+type Notify func(error, time.Duration)
+
+// Retry the operation o until it does not return error or BackOff stops.
+// o is guaranteed to be run at least once.
+//
+// If o returns a *PermanentError, the operation is not retried, and the
+// wrapped error is returned.
+//
+// Retry sleeps the goroutine for the duration returned by BackOff after a
+// failed operation returns.
+func Retry(o Operation, b BackOff) error {
+ return RetryNotify(o, b, nil)
+}
+
+// RetryWithData is like Retry but returns data in the response too.
+func RetryWithData[T any](o OperationWithData[T], b BackOff) (T, error) {
+ return RetryNotifyWithData(o, b, nil)
+}
+
+// RetryNotify calls notify function with the error and wait duration
+// for each failed attempt before sleep.
+func RetryNotify(operation Operation, b BackOff, notify Notify) error {
+ return RetryNotifyWithTimer(operation, b, notify, nil)
+}
+
+// RetryNotifyWithData is like RetryNotify but returns data in the response too.
+func RetryNotifyWithData[T any](operation OperationWithData[T], b BackOff, notify Notify) (T, error) {
+ return doRetryNotify(operation, b, notify, nil)
+}
+
+// RetryNotifyWithTimer calls notify function with the error and wait duration using the given Timer
+// for each failed attempt before sleep.
+// A default timer that uses system timer is used when nil is passed.
+func RetryNotifyWithTimer(operation Operation, b BackOff, notify Notify, t Timer) error {
+ _, err := doRetryNotify(operation.withEmptyData(), b, notify, t)
+ return err
+}
+
+// RetryNotifyWithTimerAndData is like RetryNotifyWithTimer but returns data in the response too.
+func RetryNotifyWithTimerAndData[T any](operation OperationWithData[T], b BackOff, notify Notify, t Timer) (T, error) {
+ return doRetryNotify(operation, b, notify, t)
+}
+
+func doRetryNotify[T any](operation OperationWithData[T], b BackOff, notify Notify, t Timer) (T, error) {
+ var (
+ err error
+ next time.Duration
+ res T
+ )
+ if t == nil {
+ t = &defaultTimer{}
+ }
+
+ defer func() {
+ t.Stop()
+ }()
+
+ ctx := getContext(b)
+
+ b.Reset()
+ for {
+ res, err = operation()
+ if err == nil {
+ return res, nil
+ }
+
+ var permanent *PermanentError
+ if errors.As(err, &permanent) {
+ return res, permanent.Err
+ }
+
+ if next = b.NextBackOff(); next == Stop {
+ if cerr := ctx.Err(); cerr != nil {
+ return res, cerr
+ }
+
+ return res, err
+ }
+
+ if notify != nil {
+ notify(err, next)
+ }
+
+ t.Start(next)
+
+ select {
+ case <-ctx.Done():
+ return res, ctx.Err()
+ case <-t.C():
+ }
+ }
+}
+
+// PermanentError signals that the operation should not be retried.
+type PermanentError struct {
+ Err error
+}
+
+func (e *PermanentError) Error() string {
+ return e.Err.Error()
+}
+
+func (e *PermanentError) Unwrap() error {
+ return e.Err
+}
+
+func (e *PermanentError) Is(target error) bool {
+ _, ok := target.(*PermanentError)
+ return ok
+}
+
+// Permanent wraps the given err in a *PermanentError.
+func Permanent(err error) error {
+ if err == nil {
+ return nil
+ }
+ return &PermanentError{
+ Err: err,
+ }
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/ticker.go b/vendor/github.com/cenkalti/backoff/v4/ticker.go
new file mode 100644
index 00000000..df9d68bc
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/ticker.go
@@ -0,0 +1,97 @@
+package backoff
+
+import (
+ "context"
+ "sync"
+ "time"
+)
+
+// Ticker holds a channel that delivers `ticks' of a clock at times reported by a BackOff.
+//
+// Ticks will continue to arrive when the previous operation is still running,
+// so operations that take a while to fail could run in quick succession.
+type Ticker struct {
+ C <-chan time.Time
+ c chan time.Time
+ b BackOff
+ ctx context.Context
+ timer Timer
+ stop chan struct{}
+ stopOnce sync.Once
+}
+
+// NewTicker returns a new Ticker containing a channel that will send
+// the time at times specified by the BackOff argument. Ticker is
+// guaranteed to tick at least once. The channel is closed when Stop
+// method is called or BackOff stops. It is not safe to manipulate the
+// provided backoff policy (notably calling NextBackOff or Reset)
+// while the ticker is running.
+func NewTicker(b BackOff) *Ticker {
+ return NewTickerWithTimer(b, &defaultTimer{})
+}
+
+// NewTickerWithTimer returns a new Ticker with a custom timer.
+// A default timer that uses system timer is used when nil is passed.
+func NewTickerWithTimer(b BackOff, timer Timer) *Ticker {
+ if timer == nil {
+ timer = &defaultTimer{}
+ }
+ c := make(chan time.Time)
+ t := &Ticker{
+ C: c,
+ c: c,
+ b: b,
+ ctx: getContext(b),
+ timer: timer,
+ stop: make(chan struct{}),
+ }
+ t.b.Reset()
+ go t.run()
+ return t
+}
+
+// Stop turns off a ticker. After Stop, no more ticks will be sent.
+func (t *Ticker) Stop() {
+ t.stopOnce.Do(func() { close(t.stop) })
+}
+
+func (t *Ticker) run() {
+ c := t.c
+ defer close(c)
+
+ // Ticker is guaranteed to tick at least once.
+ afterC := t.send(time.Now())
+
+ for {
+ if afterC == nil {
+ return
+ }
+
+ select {
+ case tick := <-afterC:
+ afterC = t.send(tick)
+ case <-t.stop:
+ t.c = nil // Prevent future ticks from being sent to the channel.
+ return
+ case <-t.ctx.Done():
+ return
+ }
+ }
+}
+
+func (t *Ticker) send(tick time.Time) <-chan time.Time {
+ select {
+ case t.c <- tick:
+ case <-t.stop:
+ return nil
+ }
+
+ next := t.b.NextBackOff()
+ if next == Stop {
+ t.Stop()
+ return nil
+ }
+
+ t.timer.Start(next)
+ return t.timer.C()
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/timer.go b/vendor/github.com/cenkalti/backoff/v4/timer.go
new file mode 100644
index 00000000..8120d021
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/timer.go
@@ -0,0 +1,35 @@
+package backoff
+
+import "time"
+
+type Timer interface {
+ Start(duration time.Duration)
+ Stop()
+ C() <-chan time.Time
+}
+
+// defaultTimer implements Timer interface using time.Timer
+type defaultTimer struct {
+ timer *time.Timer
+}
+
+// C returns the timers channel which receives the current time when the timer fires.
+func (t *defaultTimer) C() <-chan time.Time {
+ return t.timer.C
+}
+
+// Start starts the timer to fire after the given duration
+func (t *defaultTimer) Start(duration time.Duration) {
+ if t.timer == nil {
+ t.timer = time.NewTimer(duration)
+ } else {
+ t.timer.Reset(duration)
+ }
+}
+
+// Stop is called when the timer is not used anymore and resources may be freed.
+func (t *defaultTimer) Stop() {
+ if t.timer != nil {
+ t.timer.Stop()
+ }
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/tries.go b/vendor/github.com/cenkalti/backoff/v4/tries.go
new file mode 100644
index 00000000..28d58ca3
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/tries.go
@@ -0,0 +1,38 @@
+package backoff
+
+import "time"
+
+/*
+WithMaxRetries creates a wrapper around another BackOff, which will
+return Stop if NextBackOff() has been called too many times since
+the last time Reset() was called
+
+Note: Implementation is not thread-safe.
+*/
+func WithMaxRetries(b BackOff, max uint64) BackOff {
+ return &backOffTries{delegate: b, maxTries: max}
+}
+
+type backOffTries struct {
+ delegate BackOff
+ maxTries uint64
+ numTries uint64
+}
+
+func (b *backOffTries) NextBackOff() time.Duration {
+ if b.maxTries == 0 {
+ return Stop
+ }
+ if b.maxTries > 0 {
+ if b.maxTries <= b.numTries {
+ return Stop
+ }
+ b.numTries++
+ }
+ return b.delegate.NextBackOff()
+}
+
+func (b *backOffTries) Reset() {
+ b.numTries = 0
+ b.delegate.Reset()
+}
diff --git a/vendor/github.com/containerd/continuity/AUTHORS b/vendor/github.com/containerd/continuity/AUTHORS
new file mode 100644
index 00000000..0b4a03cd
--- /dev/null
+++ b/vendor/github.com/containerd/continuity/AUTHORS
@@ -0,0 +1,40 @@
+Aaron Lehmann
+Akash Gupta
+Akihiro Suda
+Andrew Pennebaker
+Brandon Philips
+Brian Goff
+Christopher Jones
+Daniel, Dao Quang Minh
+Darren Stahl
+Derek McGowan
+Edward Pilatowicz
+Fu Wei
+Gabriel Adrian Samfira
+Hajime Tazaki
+Ian Campbell
+Ivan Markin
+Jacob Blain Christen
+Justin Cormack
+Justin Cummins
+Kasper Fabæch Brandt
+Kazuyoshi Kato
+Kir Kolyshkin
+Michael Crosby
+Michael Wan
+Mike Brown
+Niels de Vos
+Phil Estes
+Sam Whited
+Samuel Karp
+Sebastiaan van Stijn
+Shengjing Zhu
+Stephen J Day
+Tibor Vass
+Tobias Klauser
+Tom Faulhaber
+Tonis Tiigi
+Trevor Porter
+Wei Fu
+Wilbert van de Ridder
+Xiaodong Ye
diff --git a/vendor/github.com/containerd/continuity/LICENSE b/vendor/github.com/containerd/continuity/LICENSE
new file mode 100644
index 00000000..584149b6
--- /dev/null
+++ b/vendor/github.com/containerd/continuity/LICENSE
@@ -0,0 +1,191 @@
+
+ Apache License
+ Version 2.0, January 2004
+ https://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ Copyright The containerd Authors
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/containerd/continuity/pathdriver/path_driver.go b/vendor/github.com/containerd/continuity/pathdriver/path_driver.go
new file mode 100644
index 00000000..b0d5a6b5
--- /dev/null
+++ b/vendor/github.com/containerd/continuity/pathdriver/path_driver.go
@@ -0,0 +1,101 @@
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package pathdriver
+
+import (
+ "path/filepath"
+)
+
+// PathDriver provides all of the path manipulation functions in a common
+// interface. The context should call these and never use the `filepath`
+// package or any other package to manipulate paths.
+type PathDriver interface {
+ Join(paths ...string) string
+ IsAbs(path string) bool
+ Rel(base, target string) (string, error)
+ Base(path string) string
+ Dir(path string) string
+ Clean(path string) string
+ Split(path string) (dir, file string)
+ Separator() byte
+ Abs(path string) (string, error)
+ Walk(string, filepath.WalkFunc) error
+ FromSlash(path string) string
+ ToSlash(path string) string
+ Match(pattern, name string) (matched bool, err error)
+}
+
+// pathDriver is a simple default implementation calls the filepath package.
+type pathDriver struct{}
+
+// LocalPathDriver is the exported pathDriver struct for convenience.
+var LocalPathDriver PathDriver = &pathDriver{}
+
+func (*pathDriver) Join(paths ...string) string {
+ return filepath.Join(paths...)
+}
+
+func (*pathDriver) IsAbs(path string) bool {
+ return filepath.IsAbs(path)
+}
+
+func (*pathDriver) Rel(base, target string) (string, error) {
+ return filepath.Rel(base, target)
+}
+
+func (*pathDriver) Base(path string) string {
+ return filepath.Base(path)
+}
+
+func (*pathDriver) Dir(path string) string {
+ return filepath.Dir(path)
+}
+
+func (*pathDriver) Clean(path string) string {
+ return filepath.Clean(path)
+}
+
+func (*pathDriver) Split(path string) (dir, file string) {
+ return filepath.Split(path)
+}
+
+func (*pathDriver) Separator() byte {
+ return filepath.Separator
+}
+
+func (*pathDriver) Abs(path string) (string, error) {
+ return filepath.Abs(path)
+}
+
+// Note that filepath.Walk calls os.Stat, so if the context wants to
+// to call Driver.Stat() for Walk, they need to create a new struct that
+// overrides this method.
+func (*pathDriver) Walk(root string, walkFn filepath.WalkFunc) error {
+ return filepath.Walk(root, walkFn)
+}
+
+func (*pathDriver) FromSlash(path string) string {
+ return filepath.FromSlash(path)
+}
+
+func (*pathDriver) ToSlash(path string) string {
+ return filepath.ToSlash(path)
+}
+
+func (*pathDriver) Match(pattern, name string) (bool, error) {
+ return filepath.Match(pattern, name)
+}
diff --git a/vendor/github.com/docker/cli/AUTHORS b/vendor/github.com/docker/cli/AUTHORS
new file mode 100644
index 00000000..ad1abd49
--- /dev/null
+++ b/vendor/github.com/docker/cli/AUTHORS
@@ -0,0 +1,910 @@
+# File @generated by scripts/docs/generate-authors.sh. DO NOT EDIT.
+# This file lists all contributors to the repository.
+# See scripts/docs/generate-authors.sh to make modifications.
+
+A. Lester Buck III
+Aanand Prasad
+Aaron L. Xu
+Aaron Lehmann
+Aaron.L.Xu
+Abdur Rehman
+Abhinandan Prativadi
+Abin Shahab
+Abreto FU
+Ace Tang
+Addam Hardy
+Adolfo Ochagavía
+Adrian Plata
+Adrien Duermael
+Adrien Folie
+Adyanth Hosavalike
+Ahmet Alp Balkan
+Aidan Feldman
+Aidan Hobson Sayers
+AJ Bowen
+Akhil Mohan
+Akihiro Suda
+Akim Demaille
+Alan Thompson
+Alano Terblanche
+Albert Callarisa
+Alberto Roura
+Albin Kerouanton
+Aleksa Sarai
+Aleksander Piotrowski
+Alessandro Boch
+Alex Couture-Beil
+Alex Mavrogiannis
+Alex Mayer
+Alexander Boyd
+Alexander Chneerov
+Alexander Larsson
+Alexander Morozov
+Alexander Ryabov
+Alexandre González
+Alexey Igrychev
+Alexis Couvreur
+Alfred Landrum
+Ali Rostami
+Alicia Lauerman
+Allen Sun
+Alvin Deng
+Amen Belayneh
+Amey Shrivastava <72866602+AmeyShrivastava@users.noreply.github.com>
+Amir Goldstein
+Amit Krishnan
+Amit Shukla
+Amy Lindburg
+Anca Iordache
+Anda Xu
+Andrea Luzzardi
+Andreas Köhler
+Andres G. Aragoneses
+Andres Leon Rangel
+Andrew France
+Andrew Hsu
+Andrew Macpherson
+Andrew McDonnell
+Andrew Po
+Andrew-Zipperer
+Andrey Petrov
+Andrii Berehuliak
+André Martins
+Andy Goldstein
+Andy Rothfusz
+Anil Madhavapeddy
+Ankush Agarwal
+Anne Henmi
+Anton Polonskiy
+Antonio Murdaca
+Antonis Kalipetis
+Anusha Ragunathan
+Ao Li
+Arash Deshmeh
+Arko Dasgupta
+Arnaud Porterie
+Arnaud Rebillout
+Arthur Peka
+Ashly Mathew
+Ashwini Oruganti
+Aslam Ahemad
+Azat Khuyiyakhmetov
+Bardia Keyoumarsi
+Barnaby Gray
+Bastiaan Bakker
+BastianHofmann
+Ben Bodenmiller
+Ben Bonnefoy
+Ben Creasy
+Ben Firshman
+Benjamin Boudreau
+Benjamin Böhmke
+Benjamin Nater
+Benoit Sigoure
+Bhumika Bayani
+Bill Wang
+Bin Liu
+Bingshen Wang
+Bishal Das
+Bjorn Neergaard
+Boaz Shuster
+Boban Acimovic
+Bogdan Anton
+Boris Pruessmann
+Brad Baker
+Bradley Cicenas
+Brandon Mitchell
+Brandon Philips
+Brent Salisbury
+Bret Fisher
+Brian (bex) Exelbierd
+Brian Goff
+Brian Tracy
+Brian Wieder
+Bruno Sousa
+Bryan Bess
+Bryan Boreham
+Bryan Murphy
+bryfry
+Calvin Liu
+Cameron Spear
+Cao Weiwei
+Carlo Mion
+Carlos Alexandro Becker
+Carlos de Paula
+Casey Korver
+Ce Gao
+Cedric Davies
+Cezar Sa Espinola
+Chad Faragher
+Chao Wang
+Charles Chan
+Charles Law
+Charles Smith
+Charlie Drage
+Charlotte Mach
+ChaYoung You
+Chee Hau Lim
+Chen Chuanliang
+Chen Hanxiao
+Chen Mingjie
+Chen Qiu
+Chris Chinchilla
+Chris Couzens
+Chris Gavin
+Chris Gibson
+Chris McKinnel
+Chris Snow
+Chris Vermilion
+Chris Weyl
+Christian Persson
+Christian Stefanescu
+Christophe Robin
+Christophe Vidal
+Christopher Biscardi
+Christopher Crone
+Christopher Jones
+Christopher Petito <47751006+krissetto@users.noreply.github.com>
+Christopher Petito
+Christopher Svensson
+Christy Norman
+Chun Chen
+Clinton Kitson
+Coenraad Loubser
+Colin Hebert
+Collin Guarino
+Colm Hally
+Comical Derskeal <27731088+derskeal@users.noreply.github.com>
+Conner Crosby
+Corey Farrell
+Corey Quon
+Cory Bennet
+Cory Snider
+Craig Osterhout
+Craig Wilhite
+Cristian Staretu
+Daehyeok Mun
+Dafydd Crosby
+Daisuke Ito
+dalanlan
+Damien Nadé
+Dan Cotora
+Danial Gharib
+Daniel Artine
+Daniel Cassidy
+Daniel Dao
+Daniel Farrell
+Daniel Gasienica
+Daniel Goosen
+Daniel Helfand
+Daniel Hiltgen
+Daniel J Walsh
+Daniel Nephin
+Daniel Norberg
+Daniel Watkins
+Daniel Zhang
+Daniil Nikolenko
+Danny Berger
+Darren Shepherd
+Darren Stahl
+Dattatraya Kumbhar
+Dave Goodchild
+Dave Henderson
+Dave Tucker
+David Alvarez
+David Beitey
+David Calavera
+David Cramer
+David Dooling
+David Gageot
+David Karlsson
+David le Blanc