From aca1f29e113cc7cdceaa344b2fb6f7d480b62821 Mon Sep 17 00:00:00 2001 From: Maxence Maireaux Date: Mon, 15 Jan 2024 16:41:32 +0100 Subject: [PATCH] feat: Sync witch stack repository => 3cd23436c03ddc6f9f78fbd48ce1449f3a48e9a7 --- .goreleaser.ledger.yml | 2 - .goreleaser.yml | 4 +- Earthfile | 2 +- benchmarks/ledger_test.go | 3 +- cmd/container.go | 2 + cmd/root.go | 2 + go.mod | 20 +- go.sum | 42 ++- internal/account.go | 2 +- internal/account_test.go | 25 ++ internal/api/module.go | 7 +- internal/api/router.go | 6 +- internal/api/v1/controllers_accounts_test.go | 9 +- internal/api/v1/controllers_balances.go | 2 +- internal/api/v1/controllers_balances_test.go | 3 +- internal/api/v1/controllers_config_test.go | 3 +- internal/api/v1/controllers_info_test.go | 7 +- .../api/v1/controllers_transactions_test.go | 15 +- internal/api/v1/routes.go | 11 +- internal/api/v2/controllers_accounts_test.go | 9 +- internal/api/v2/controllers_balances_test.go | 3 +- internal/api/v2/controllers_bulk_test.go | 3 +- internal/api/v2/controllers_config_test.go | 3 +- .../api/v2/controllers_create_ledger_test.go | 3 +- .../api/v2/controllers_get_ledger_test.go | 3 +- internal/api/v2/controllers_info_test.go | 7 +- .../api/v2/controllers_transactions_test.go | 13 +- internal/api/v2/routes.go | 5 +- internal/machine/script/NumScript.g4 | 4 +- internal/machine/script/compiler/source.go | 2 +- .../script/parser/NumScriptLexer.interp | 2 +- .../machine/script/parser/numscript_lexer.go | 325 +++++++++--------- internal/machine/vm/machine_test.go | 45 ++- internal/storage/systemstore/migrations.go | 14 + libs/Earthfile | 4 +- libs/api/link.go | 6 + libs/auth/auth.go | 122 +++++++ libs/auth/cli.go | 33 ++ libs/auth/middleware.go | 28 ++ libs/auth/module.go | 40 +++ libs/auth/no_auth.go | 13 + libs/bun/bunconnect/connect.go | 9 +- libs/collectionutils/map.go | 15 + libs/collectionutils/slice.go | 14 +- libs/go.mod | 24 +- libs/go.sum | 50 ++- libs/publish/messages.go | 27 +- libs/publish/module_test.go | 29 +- openapi.yaml | 41 +++ openapi/v1.yaml | 20 ++ openapi/v2.yaml | 21 ++ scratch.Dockerfile | 9 + 52 files changed, 849 insertions(+), 264 deletions(-) create mode 100644 libs/api/link.go create mode 100644 libs/auth/auth.go create mode 100644 libs/auth/cli.go create mode 100644 libs/auth/middleware.go create mode 100644 libs/auth/module.go create mode 100644 libs/auth/no_auth.go create mode 100644 scratch.Dockerfile diff --git a/.goreleaser.ledger.yml b/.goreleaser.ledger.yml index e6a399643..dc1d297f1 100644 --- a/.goreleaser.ledger.yml +++ b/.goreleaser.ledger.yml @@ -100,8 +100,6 @@ changelog: release: prerelease: auto - extra_files: - - glob: openapi.yaml footer: | ## What to do next? - Read the [documentation](https://docs.formance.com/) diff --git a/.goreleaser.yml b/.goreleaser.yml index 4e18acdaa..670e6c03d 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,6 +1,6 @@ project_name: ledger monorepo: - tag_prefix: components/ledger/ + tag_prefix: v dir: ./ includes: @@ -26,8 +26,6 @@ builds: release: prerelease: auto - extra_files: - - glob: openapi.yaml footer: | ## What to do next? - Read the [documentation](https://docs.formance.com/) diff --git a/Earthfile b/Earthfile index 90c2af7a9..71dcc9283 100644 --- a/Earthfile +++ b/Earthfile @@ -1,6 +1,6 @@ VERSION --pass-args --arg-scope-and-set 0.7 -ARG core=github.com/formancehq/earthly:v0.5.2 +ARG core=github.com/formancehq/earthly:v0.6.0 IMPORT $core AS core IMPORT ../.. AS stack IMPORT .. AS components diff --git a/benchmarks/ledger_test.go b/benchmarks/ledger_test.go index 6dc1042dd..6d4808d6f 100644 --- a/benchmarks/ledger_test.go +++ b/benchmarks/ledger_test.go @@ -21,6 +21,7 @@ import ( "github.com/formancehq/ledger/internal/opentelemetry/metrics" "github.com/formancehq/ledger/internal/storage/storagetesting" "github.com/formancehq/stack/libs/go-libs/api" + "github.com/formancehq/stack/libs/go-libs/auth" "github.com/formancehq/stack/libs/go-libs/logging" "github.com/google/uuid" "github.com/stretchr/testify/require" @@ -40,7 +41,7 @@ func BenchmarkParallelWrites(b *testing.B) { ledgerName := uuid.NewString() backend := backend.NewDefaultBackend(driver, "latest", resolver) - router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := logging.ContextWithLogger(r.Context(), logging.FromContext(ctx)) router.ServeHTTP(w, r.WithContext(ctx)) diff --git a/cmd/container.go b/cmd/container.go index 50308b755..33ec92412 100644 --- a/cmd/container.go +++ b/cmd/container.go @@ -6,6 +6,7 @@ import ( "github.com/formancehq/ledger/cmd/internal" "github.com/formancehq/ledger/internal/engine" driver "github.com/formancehq/ledger/internal/storage/driver" + "github.com/formancehq/stack/libs/go-libs/auth" "github.com/formancehq/stack/libs/go-libs/otlp/otlpmetrics" "github.com/formancehq/stack/libs/go-libs/otlp/otlptraces" "github.com/formancehq/stack/libs/go-libs/publish" @@ -27,6 +28,7 @@ func resolveOptions(output io.Writer, userOptions ...fx.Option) []fx.Option { publish.CLIPublisherModule(v, ServiceName), otlptraces.CLITracesModule(v), otlpmetrics.CLIMetricsModule(v), + auth.CLIAuthModule(v), driver.CLIModule(v, output, debug), internal.NewAnalyticsModule(v, Version), engine.Module(engine.Configuration{ diff --git a/cmd/root.go b/cmd/root.go index 30bab3dd7..6f68701a8 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -6,6 +6,7 @@ import ( "github.com/formancehq/ledger/cmd/internal" "github.com/formancehq/ledger/internal/storage/driver" + "github.com/formancehq/stack/libs/go-libs/auth" "github.com/formancehq/stack/libs/go-libs/otlp/otlpmetrics" "github.com/formancehq/stack/libs/go-libs/otlp/otlptraces" "github.com/formancehq/stack/libs/go-libs/publish" @@ -53,6 +54,7 @@ func NewRootCommand() *cobra.Command { otlpmetrics.InitOTLPMetricsFlags(root.PersistentFlags()) otlptraces.InitOTLPTracesFlags(root.PersistentFlags()) + auth.InitAuthFlags(root.PersistentFlags()) internal.InitAnalyticsFlags(root, DefaultSegmentWriteKey) publish.InitCLIFlags(root) driver.InitCLIFlags(root) diff --git a/go.mod b/go.mod index 8246b3003..b83535376 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/go-chi/chi/v5 v5.0.8 github.com/go-chi/cors v1.2.1 github.com/google/go-cmp v0.5.9 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.3.1 github.com/jackc/pgx/v5 v5.3.0 github.com/lib/pq v1.10.7 github.com/logrusorgru/aurora v2.0.3+incompatible @@ -20,7 +20,7 @@ require ( github.com/pborman/uuid v1.2.1 github.com/pkg/errors v0.9.1 github.com/riandyrn/otelchi v0.5.1 - github.com/sirupsen/logrus v1.9.0 + github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.6.1 github.com/spf13/viper v1.15.0 github.com/stretchr/testify v1.8.4 @@ -64,9 +64,14 @@ require ( github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/gorilla/mux v1.8.0 // indirect + github.com/gorilla/schema v1.2.0 // indirect + github.com/gorilla/securecookie v1.1.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-retryablehttp v0.7.2 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.13 // indirect @@ -85,6 +90,8 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect + github.com/muhlemmer/gu v0.3.1 // indirect + github.com/muhlemmer/httpforwarded v0.1.0 // indirect github.com/nats-io/nats.go v1.28.0 // indirect github.com/nats-io/nkeys v0.4.6 // indirect github.com/nats-io/nuid v1.0.1 // indirect @@ -98,6 +105,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect + github.com/rs/cors v1.10.0 // indirect github.com/segmentio/backo-go v1.0.1 // indirect github.com/shirou/gopsutil/v3 v3.23.4 // indirect github.com/shoenig/go-m1cpu v0.1.5 // indirect @@ -123,6 +131,7 @@ require ( github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect + github.com/zitadel/oidc/v2 v2.11.0 // indirect go.opentelemetry.io/contrib v1.0.0 // indirect go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama v0.42.0 // indirect go.opentelemetry.io/contrib/instrumentation/host v0.42.0 // indirect @@ -148,14 +157,17 @@ require ( go.uber.org/zap v1.24.0 // indirect golang.org/x/crypto v0.14.0 // indirect golang.org/x/mod v0.11.0 // indirect - golang.org/x/net v0.10.0 // indirect + golang.org/x/net v0.15.0 // indirect + golang.org/x/oauth2 v0.12.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/tools v0.6.0 // indirect + google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/grpc v1.56.3 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 417aa21cc..f9fe2f77c 100644 --- a/go.sum +++ b/go.sum @@ -184,6 +184,7 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -239,11 +240,16 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= +github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= @@ -253,9 +259,15 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0/go.mod h1:YDZoGHuwE+ov0c8smSH4 github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= +github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -288,6 +300,7 @@ github.com/jcmturner/gokrb5/v8 v8.4.3 h1:iTonLeSJOn7MVUtyMT+arAn5AKAPrkilzhGw8wE github.com/jcmturner/gokrb5/v8 v8.4.3/go.mod h1:dqRwJGXznQrzw6cWmyo6kH+E7jksEQG/CyVWsJEsJO0= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jeremija/gosubmit v0.2.7 h1:At0OhGCFGPXyjPYAsCchoBUhE099pcBXmsb4iZqROIc= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -331,6 +344,10 @@ github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6U github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/muhlemmer/gu v0.3.1 h1:7EAqmFrW7n3hETvuAdmFmn4hS8W+z3LgKtrnow+YzNM= +github.com/muhlemmer/gu v0.3.1/go.mod h1:YHtHR+gxM+bKEIIs7Hmi9sPT3ZDUvTN/i88wQpZkrdM= +github.com/muhlemmer/httpforwarded v0.1.0 h1:x4DLrzXdliq8mprgUMR0olDvHGkou5BJsK/vWUetyzY= +github.com/muhlemmer/httpforwarded v0.1.0/go.mod h1:yo9czKedo2pdZhoXe+yDkGVbU0TJ0q9oQ90BVoDEtw0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nats-io/jwt/v2 v2.5.0 h1:WQQ40AAlqqfx+f6ku+i0pOVm+ASirD4fUh+oQsiE9Ak= github.com/nats-io/nats-server/v2 v2.9.23 h1:6Wj6H6QpP9FMlpCyWUaNu2yeZ/qGj+mdRkZ1wbikExU= @@ -384,6 +401,8 @@ github.com/riandyrn/otelchi v0.5.1/go.mod h1:ZxVxNEl+jQ9uHseRYIxKWRb3OY8YXFEu+Ek github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rs/cors v1.10.0 h1:62NOS1h+r8p1mW6FM0FSB0exioXLhd/sh15KpjWBZ+8= +github.com/rs/cors v1.10.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= @@ -398,8 +417,8 @@ github.com/shoenig/test v0.6.3/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnj github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= @@ -482,6 +501,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/zitadel/oidc/v2 v2.11.0 h1:Am4/yQr4iiM5bznRgF3FOp+wLdKx2gzSU73uyI9vvBE= +github.com/zitadel/oidc/v2 v2.11.0/go.mod h1:enFSVBQI6aE0TEB1ntjXs9r6O6DEosxX4uhEBLBVD8o= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -633,8 +654,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220725212005-46097bf591d3/go.mod h1:AaygXjzTFtRAg2ttMY5RMuhpJ3cNnI0XpyFJD1iQRSM= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -645,6 +666,8 @@ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= +golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -815,6 +838,7 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -891,8 +915,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -902,6 +926,8 @@ gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/segmentio/analytics-go.v3 v3.1.0 h1:UzxH1uaGZRpMKDhJyBz0pexz6yUoBU3x8bJsRk/HV6U= gopkg.in/segmentio/analytics-go.v3 v3.1.0/go.mod h1:4QqqlTlSSpVlWA9/9nDcPw+FkM2yv1NQoYjUbL9/JAw= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internal/account.go b/internal/account.go index ca5ec4a38..0ea974880 100644 --- a/internal/account.go +++ b/internal/account.go @@ -52,7 +52,7 @@ func (v ExpandedAccount) Copy() ExpandedAccount { return v } -const AccountSegmentRegex = "[a-zA-Z0-9_]+" +const AccountSegmentRegex = "[a-zA-Z0-9_]+(?:-[a-zA-Z0-9_]+)*" const AccountPattern = "^" + AccountSegmentRegex + "(:" + AccountSegmentRegex + ")*$" var AccountRegexp = regexp.MustCompile(AccountPattern) diff --git a/internal/account_test.go b/internal/account_test.go index 61f699540..3a6834cd9 100644 --- a/internal/account_test.go +++ b/internal/account_test.go @@ -46,6 +46,31 @@ func TestValidateAddress(t *testing.T) { address: "a:", shouldBeOk: false, }, + { + name: "using single dash", + address: "-", + shouldBeOk: false, + }, + { + name: "using dash without alphanum before", + address: "-toto", + shouldBeOk: false, + }, + { + name: "using dash without alphanum after", + address: "toto-", + shouldBeOk: false, + }, + { + name: "using dash", + address: "toto-titi", + shouldBeOk: true, + }, + { + name: "using dash multi segment", + address: "toto-titi:tata-tutu", + shouldBeOk: true, + }, } for _, testCase := range testsCases { diff --git a/internal/api/module.go b/internal/api/module.go index 484a035c8..6dfce8f92 100644 --- a/internal/api/module.go +++ b/internal/api/module.go @@ -9,6 +9,7 @@ import ( "github.com/formancehq/ledger/internal/engine" "github.com/formancehq/ledger/internal/opentelemetry/metrics" "github.com/formancehq/ledger/internal/storage/driver" + "github.com/formancehq/stack/libs/go-libs/auth" "github.com/formancehq/stack/libs/go-libs/health" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric/noop" @@ -25,8 +26,10 @@ func Module(cfg Config) fx.Option { fx.Provide(func( backend backend.Backend, healthController *health.HealthController, - globalMetricsRegistry metrics.GlobalRegistry) chi.Router { - return NewRouter(backend, healthController, globalMetricsRegistry, cfg.ReadOnly) + globalMetricsRegistry metrics.GlobalRegistry, + a auth.Auth, + ) chi.Router { + return NewRouter(backend, healthController, globalMetricsRegistry, a, cfg.ReadOnly) }), fx.Provide(func(storageDriver *driver.Driver, resolver *engine.Resolver) backend.Backend { return backend.NewDefaultBackend(storageDriver, cfg.Version, resolver) diff --git a/internal/api/router.go b/internal/api/router.go index 7181b91ba..449d5f59a 100644 --- a/internal/api/router.go +++ b/internal/api/router.go @@ -7,6 +7,7 @@ import ( v1 "github.com/formancehq/ledger/internal/api/v1" v2 "github.com/formancehq/ledger/internal/api/v2" "github.com/formancehq/ledger/internal/opentelemetry/metrics" + "github.com/formancehq/stack/libs/go-libs/auth" "github.com/formancehq/stack/libs/go-libs/health" "github.com/go-chi/chi/v5" ) @@ -15,6 +16,7 @@ func NewRouter( backend backend.Backend, healthController *health.HealthController, globalMetricsRegistry metrics.GlobalRegistry, + a auth.Auth, readOnly bool, ) chi.Router { mux := chi.NewRouter() @@ -27,12 +29,12 @@ func NewRouter( if readOnly { mux.Use(ReadOnly) } - v2Router := v2.NewRouter(backend, healthController, globalMetricsRegistry) + v2Router := v2.NewRouter(backend, healthController, globalMetricsRegistry, a) mux.Handle("/v2*", http.StripPrefix("/v2", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { chi.RouteContext(r.Context()).Reset() v2Router.ServeHTTP(w, r) }))) - mux.Handle("/*", v1.NewRouter(backend, healthController, globalMetricsRegistry)) + mux.Handle("/*", v1.NewRouter(backend, healthController, globalMetricsRegistry, a)) return mux } diff --git a/internal/api/v1/controllers_accounts_test.go b/internal/api/v1/controllers_accounts_test.go index cd434e783..a10956a27 100644 --- a/internal/api/v1/controllers_accounts_test.go +++ b/internal/api/v1/controllers_accounts_test.go @@ -6,6 +6,7 @@ import ( "net/url" "testing" + "github.com/formancehq/stack/libs/go-libs/auth" "github.com/formancehq/stack/libs/go-libs/bun/bunpaginate" ledger "github.com/formancehq/ledger/internal" @@ -123,7 +124,7 @@ func TestGetAccounts(t *testing.T) { Return(&expectedCursor, nil) } - router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodGet, "/xxx/accounts", nil) rec := httptest.NewRecorder() @@ -159,7 +160,7 @@ func TestGetAccount(t *testing.T) { GetAccountWithVolumes(gomock.Any(), ledgerstore.NewGetAccountQuery("foo").WithExpandVolumes()). Return(&account, nil) - router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodGet, "/xxx/accounts/foo", nil) rec := httptest.NewRecorder() @@ -193,7 +194,7 @@ func TestPostAccountMetadata(t *testing.T) { }, { name: "invalid account address format", - account: "invalid-acc", + account: "invalid--acc", expectStatusCode: http.StatusBadRequest, expectedErrorCode: v1.ErrValidation, }, @@ -220,7 +221,7 @@ func TestPostAccountMetadata(t *testing.T) { Return(nil) } - router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodPost, "/xxx/accounts/"+testCase.account+"/metadata", sharedapi.Buffer(t, testCase.body)) rec := httptest.NewRecorder() diff --git a/internal/api/v1/controllers_balances.go b/internal/api/v1/controllers_balances.go index 5d7b2404a..a351ba84e 100644 --- a/internal/api/v1/controllers_balances.go +++ b/internal/api/v1/controllers_balances.go @@ -57,7 +57,7 @@ func getBalances(w http.ResponseWriter, r *http.Request) { return } - cursor, err := l.GetAccountsWithVolumes(r.Context(), *q) + cursor, err := l.GetAccountsWithVolumes(r.Context(), q.WithExpandVolumes()) if err != nil { sharedapi.InternalServerError(w, r, err) return diff --git a/internal/api/v1/controllers_balances_test.go b/internal/api/v1/controllers_balances_test.go index fbbccd473..82aa8283e 100644 --- a/internal/api/v1/controllers_balances_test.go +++ b/internal/api/v1/controllers_balances_test.go @@ -12,6 +12,7 @@ import ( "github.com/formancehq/ledger/internal/opentelemetry/metrics" "github.com/formancehq/ledger/internal/storage/ledgerstore" sharedapi "github.com/formancehq/stack/libs/go-libs/api" + "github.com/formancehq/stack/libs/go-libs/auth" "github.com/formancehq/stack/libs/go-libs/query" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" @@ -52,7 +53,7 @@ func TestGetBalancesAggregated(t *testing.T) { GetAggregatedBalances(gomock.Any(), ledgerstore.NewGetAggregatedBalancesQuery(testCase.expectQuery)). Return(expectedBalances, nil) - router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodGet, "/xxx/aggregate/balances", nil) rec := httptest.NewRecorder() diff --git a/internal/api/v1/controllers_config_test.go b/internal/api/v1/controllers_config_test.go index 0659d02b0..179ba1914 100644 --- a/internal/api/v1/controllers_config_test.go +++ b/internal/api/v1/controllers_config_test.go @@ -7,6 +7,7 @@ import ( v1 "github.com/formancehq/ledger/internal/api/v1" sharedapi "github.com/formancehq/stack/libs/go-libs/api" + "github.com/formancehq/stack/libs/go-libs/auth" "github.com/formancehq/ledger/internal/storage/systemstore" @@ -19,7 +20,7 @@ func TestGetInfo(t *testing.T) { t.Parallel() backend, _ := newTestingBackend(t, false) - router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) backend. EXPECT(). diff --git a/internal/api/v1/controllers_info_test.go b/internal/api/v1/controllers_info_test.go index 3ac05bdd5..64c1bebef 100644 --- a/internal/api/v1/controllers_info_test.go +++ b/internal/api/v1/controllers_info_test.go @@ -8,6 +8,7 @@ import ( "testing" "time" + "github.com/formancehq/stack/libs/go-libs/auth" "github.com/formancehq/stack/libs/go-libs/bun/bunpaginate" ledger "github.com/formancehq/ledger/internal" @@ -27,7 +28,7 @@ func TestGetLedgerInfo(t *testing.T) { t.Parallel() backend, mock := newTestingBackend(t, false) - router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) migrationInfo := []migrations.Info{ { @@ -70,7 +71,7 @@ func TestGetStats(t *testing.T) { t.Parallel() backend, mock := newTestingBackend(t, true) - router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) expectedStats := engine.Stats{ Transactions: 10, @@ -164,7 +165,7 @@ func TestGetLogs(t *testing.T) { Return(&expectedCursor, nil) } - router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodGet, "/xxx/logs", nil) rec := httptest.NewRecorder() diff --git a/internal/api/v1/controllers_transactions_test.go b/internal/api/v1/controllers_transactions_test.go index e0a8e1d40..5fa158ac8 100644 --- a/internal/api/v1/controllers_transactions_test.go +++ b/internal/api/v1/controllers_transactions_test.go @@ -7,6 +7,7 @@ import ( "net/url" "testing" + "github.com/formancehq/stack/libs/go-libs/auth" "github.com/formancehq/stack/libs/go-libs/bun/bunpaginate" ledger "github.com/formancehq/ledger/internal" @@ -232,7 +233,7 @@ func TestPostTransactions(t *testing.T) { Return(expectedTx, nil) } - router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodPost, "/xxx/transactions", sharedapi.Buffer(t, testCase.payload)) rec := httptest.NewRecorder() @@ -294,7 +295,7 @@ func TestPostTransactionMetadata(t *testing.T) { Return(nil) } - router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodPost, "/xxx/transactions/0/metadata", sharedapi.Buffer(t, testCase.body)) rec := httptest.NewRecorder() @@ -327,7 +328,7 @@ func TestGetTransaction(t *testing.T) { GetTransactionWithVolumes(gomock.Any(), ledgerstore.NewGetTransactionQuery(big.NewInt(0))). Return(&tx, nil) - router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodGet, "/xxx/transactions/0", nil) rec := httptest.NewRecorder() @@ -470,7 +471,7 @@ func TestGetTransactions(t *testing.T) { Return(&expectedCursor, nil) } - router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodGet, "/xxx/transactions", nil) rec := httptest.NewRecorder() @@ -580,7 +581,7 @@ func TestCountTransactions(t *testing.T) { Return(10, nil) } - router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodHead, "/xxx/transactions", nil) rec := httptest.NewRecorder() @@ -612,7 +613,7 @@ func TestRevertTransaction(t *testing.T) { RevertTransaction(gomock.Any(), command.Parameters{}, big.NewInt(0), false). Return(expectedTx, nil) - router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodPost, "/xxx/transactions/0/revert", nil) rec := httptest.NewRecorder() @@ -637,7 +638,7 @@ func TestForceRevertTransaction(t *testing.T) { RevertTransaction(gomock.Any(), command.Parameters{}, big.NewInt(0), true). Return(expectedTx, nil) - router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v1.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodPost, "/xxx/transactions/0/revert?disableChecks=true", nil) rec := httptest.NewRecorder() diff --git a/internal/api/v1/routes.go b/internal/api/v1/routes.go index e1346a79d..c0b525c1d 100644 --- a/internal/api/v1/routes.go +++ b/internal/api/v1/routes.go @@ -5,6 +5,7 @@ import ( "github.com/formancehq/ledger/internal/api/backend" "github.com/formancehq/ledger/internal/opentelemetry/metrics" + "github.com/formancehq/stack/libs/go-libs/auth" "github.com/formancehq/stack/libs/go-libs/health" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" @@ -12,7 +13,12 @@ import ( "github.com/riandyrn/otelchi" ) -func NewRouter(b backend.Backend, healthController *health.HealthController, globalMetricsRegistry metrics.GlobalRegistry) chi.Router { +func NewRouter( + b backend.Backend, + healthController *health.HealthController, + globalMetricsRegistry metrics.GlobalRegistry, + a auth.Auth, +) chi.Router { router := chi.NewMux() router.Use( @@ -27,10 +33,11 @@ func NewRouter(b backend.Backend, healthController *health.HealthController, glo ) router.Get("/_healthcheck", healthController.Check) + router.Get("/_info", getInfo(b)) router.Group(func(router chi.Router) { + router.Use(auth.Middleware(a)) router.Use(otelchi.Middleware("ledger")) - router.Get("/_info", getInfo(b)) router.Route("/{ledger}", func(router chi.Router) { router.Use(func(handler http.Handler) http.Handler { diff --git a/internal/api/v2/controllers_accounts_test.go b/internal/api/v2/controllers_accounts_test.go index 88b4f0a0b..bd7c33db8 100644 --- a/internal/api/v2/controllers_accounts_test.go +++ b/internal/api/v2/controllers_accounts_test.go @@ -8,6 +8,7 @@ import ( "testing" "time" + "github.com/formancehq/stack/libs/go-libs/auth" "github.com/formancehq/stack/libs/go-libs/bun/bunpaginate" ledger "github.com/formancehq/ledger/internal" @@ -146,7 +147,7 @@ func TestGetAccounts(t *testing.T) { Return(&expectedCursor, nil) } - router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodGet, "/xxx/accounts?pit="+before.Format(time.RFC3339Nano), bytes.NewBufferString(testCase.body)) rec := httptest.NewRecorder() @@ -191,7 +192,7 @@ func TestGetAccount(t *testing.T) { GetAccountWithVolumes(gomock.Any(), query). Return(&account, nil) - router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodGet, "/xxx/accounts/foo?pit="+now.Format(time.RFC3339Nano), nil) rec := httptest.NewRecorder() @@ -225,7 +226,7 @@ func TestPostAccountMetadata(t *testing.T) { }, { name: "invalid account address format", - account: "invalid-acc", + account: "invalid--acc", expectStatusCode: http.StatusBadRequest, expectedErrorCode: v2.ErrValidation, }, @@ -252,7 +253,7 @@ func TestPostAccountMetadata(t *testing.T) { Return(nil) } - router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodPost, "/xxx/accounts/"+testCase.account+"/metadata", sharedapi.Buffer(t, testCase.body)) rec := httptest.NewRecorder() diff --git a/internal/api/v2/controllers_balances_test.go b/internal/api/v2/controllers_balances_test.go index 0723d3ea1..8758ac18f 100644 --- a/internal/api/v2/controllers_balances_test.go +++ b/internal/api/v2/controllers_balances_test.go @@ -14,6 +14,7 @@ import ( "github.com/formancehq/ledger/internal/opentelemetry/metrics" "github.com/formancehq/ledger/internal/storage/ledgerstore" sharedapi "github.com/formancehq/stack/libs/go-libs/api" + "github.com/formancehq/stack/libs/go-libs/auth" "github.com/formancehq/stack/libs/go-libs/query" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" @@ -59,7 +60,7 @@ func TestGetBalancesAggregated(t *testing.T) { GetAggregatedBalances(gomock.Any(), ledgerstore.NewGetAggregatedBalancesQuery(testCase.expectQuery)). Return(expectedBalances, nil) - router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodGet, "/xxx/aggregate/balances?pit="+before.Format(time.RFC3339Nano), bytes.NewBufferString(testCase.body)) rec := httptest.NewRecorder() diff --git a/internal/api/v2/controllers_bulk_test.go b/internal/api/v2/controllers_bulk_test.go index c855179ac..3d701f29a 100644 --- a/internal/api/v2/controllers_bulk_test.go +++ b/internal/api/v2/controllers_bulk_test.go @@ -16,6 +16,7 @@ import ( "github.com/formancehq/ledger/internal/engine/command" "github.com/formancehq/ledger/internal/opentelemetry/metrics" sharedapi "github.com/formancehq/stack/libs/go-libs/api" + "github.com/formancehq/stack/libs/go-libs/auth" "github.com/formancehq/stack/libs/go-libs/metadata" "github.com/pkg/errors" "github.com/stretchr/testify/require" @@ -307,7 +308,7 @@ func TestBulk(t *testing.T) { backend, mock := newTestingBackend(t, true) testCase.expectations(mock) - router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodPost, "/xxx/_bulk", bytes.NewBufferString(testCase.body)) rec := httptest.NewRecorder() diff --git a/internal/api/v2/controllers_config_test.go b/internal/api/v2/controllers_config_test.go index 884dd63e0..3c6afada9 100644 --- a/internal/api/v2/controllers_config_test.go +++ b/internal/api/v2/controllers_config_test.go @@ -8,6 +8,7 @@ import ( v2 "github.com/formancehq/ledger/internal/api/v2" "github.com/formancehq/ledger/internal/opentelemetry/metrics" + "github.com/formancehq/stack/libs/go-libs/auth" "github.com/stretchr/testify/require" ) @@ -15,7 +16,7 @@ func TestGetInfo(t *testing.T) { t.Parallel() backend, _ := newTestingBackend(t, false) - router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) backend. EXPECT(). diff --git a/internal/api/v2/controllers_create_ledger_test.go b/internal/api/v2/controllers_create_ledger_test.go index 5c98114a4..87fd9617d 100644 --- a/internal/api/v2/controllers_create_ledger_test.go +++ b/internal/api/v2/controllers_create_ledger_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/formancehq/ledger/internal/storage/driver" + "github.com/formancehq/stack/libs/go-libs/auth" v2 "github.com/formancehq/ledger/internal/api/v2" "github.com/formancehq/ledger/internal/opentelemetry/metrics" @@ -19,7 +20,7 @@ func TestConfigureLedger(t *testing.T) { t.Parallel() b, _ := newTestingBackend(t, false) - router := v2.NewRouter(b, nil, metrics.NewNoOpRegistry()) + router := v2.NewRouter(b, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) name := uuid.NewString() b. diff --git a/internal/api/v2/controllers_get_ledger_test.go b/internal/api/v2/controllers_get_ledger_test.go index b56a294df..4eef92e16 100644 --- a/internal/api/v2/controllers_get_ledger_test.go +++ b/internal/api/v2/controllers_get_ledger_test.go @@ -8,6 +8,7 @@ import ( ledger "github.com/formancehq/ledger/internal" "github.com/formancehq/ledger/internal/storage/systemstore" "github.com/formancehq/stack/libs/go-libs/api" + "github.com/formancehq/stack/libs/go-libs/auth" v2 "github.com/formancehq/ledger/internal/api/v2" "github.com/formancehq/ledger/internal/opentelemetry/metrics" @@ -20,7 +21,7 @@ func TestGetLedger(t *testing.T) { t.Parallel() b, _ := newTestingBackend(t, false) - router := v2.NewRouter(b, nil, metrics.NewNoOpRegistry()) + router := v2.NewRouter(b, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) name := uuid.NewString() now := ledger.Now() diff --git a/internal/api/v2/controllers_info_test.go b/internal/api/v2/controllers_info_test.go index 3f5894ce8..32e1a035a 100644 --- a/internal/api/v2/controllers_info_test.go +++ b/internal/api/v2/controllers_info_test.go @@ -10,6 +10,7 @@ import ( "testing" "time" + "github.com/formancehq/stack/libs/go-libs/auth" "github.com/formancehq/stack/libs/go-libs/bun/bunpaginate" ledger "github.com/formancehq/ledger/internal" @@ -29,7 +30,7 @@ func TestGetLedgerInfo(t *testing.T) { t.Parallel() backend, mock := newTestingBackend(t, false) - router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) migrationInfo := []migrations.Info{ { @@ -72,7 +73,7 @@ func TestGetStats(t *testing.T) { t.Parallel() backend, mock := newTestingBackend(t, true) - router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) expectedStats := engine.Stats{ Transactions: 10, @@ -163,7 +164,7 @@ func TestGetLogs(t *testing.T) { Return(&expectedCursor, nil) } - router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodGet, "/xxx/logs", bytes.NewBufferString(testCase.body)) rec := httptest.NewRecorder() diff --git a/internal/api/v2/controllers_transactions_test.go b/internal/api/v2/controllers_transactions_test.go index 06af6b325..ed9075f3f 100644 --- a/internal/api/v2/controllers_transactions_test.go +++ b/internal/api/v2/controllers_transactions_test.go @@ -10,6 +10,7 @@ import ( "testing" "time" + "github.com/formancehq/stack/libs/go-libs/auth" "github.com/formancehq/stack/libs/go-libs/bun/bunpaginate" "github.com/formancehq/ledger/internal/api/backend" @@ -444,7 +445,7 @@ func TestPostTransactions(t *testing.T) { } } - router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodPost, "/xxx/transactions", sharedapi.Buffer(t, testCase.payload)) rec := httptest.NewRecorder() @@ -507,7 +508,7 @@ func TestPostTransactionMetadata(t *testing.T) { Return(nil) } - router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodPost, "/xxx/transactions/0/metadata", sharedapi.Buffer(t, testCase.body)) rec := httptest.NewRecorder() @@ -545,7 +546,7 @@ func TestGetTransaction(t *testing.T) { GetTransactionWithVolumes(gomock.Any(), query). Return(&tx, nil) - router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodGet, "/xxx/transactions/0?pit="+now.Format(time.RFC3339Nano), nil) rec := httptest.NewRecorder() @@ -713,7 +714,7 @@ func TestGetTransactions(t *testing.T) { Return(&expectedCursor, nil) } - router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodGet, "/xxx/transactions", bytes.NewBufferString(testCase.body)) rec := httptest.NewRecorder() @@ -849,7 +850,7 @@ func TestCountTransactions(t *testing.T) { Return(10, nil) } - router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodHead, "/xxx/transactions?pit="+before.Format(time.RFC3339Nano), bytes.NewBufferString(testCase.body)) rec := httptest.NewRecorder() @@ -943,7 +944,7 @@ func TestRevert(t *testing.T) { RevertTransaction(gomock.Any(), command.Parameters{}, big.NewInt(0), tc.expectForce). Return(tc.returnTx, tc.returnErr) - router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry()) + router := v2.NewRouter(backend, nil, metrics.NewNoOpRegistry(), auth.NewNoAuth()) req := httptest.NewRequest(http.MethodPost, "/xxx/transactions/0/revert", nil) if tc.queryParams != nil { diff --git a/internal/api/v2/routes.go b/internal/api/v2/routes.go index 443ce94e0..1c3cfcef0 100644 --- a/internal/api/v2/routes.go +++ b/internal/api/v2/routes.go @@ -5,6 +5,7 @@ import ( "github.com/formancehq/ledger/internal/api/backend" "github.com/formancehq/ledger/internal/opentelemetry/metrics" + "github.com/formancehq/stack/libs/go-libs/auth" "github.com/formancehq/stack/libs/go-libs/health" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" @@ -16,6 +17,7 @@ func NewRouter( b backend.Backend, healthController *health.HealthController, globalMetricsRegistry metrics.GlobalRegistry, + a auth.Auth, ) chi.Router { router := chi.NewMux() @@ -31,10 +33,11 @@ func NewRouter( ) router.Get("/_healthcheck", healthController.Check) + router.Get("/_info", getInfo(b)) router.Group(func(router chi.Router) { + router.Use(auth.Middleware(a)) router.Use(otelchi.Middleware("ledger")) - router.Get("/_info", getInfo(b)) router.Get("/", listLedgers(b)) router.Route("/{ledger}", func(router chi.Router) { diff --git a/internal/machine/script/NumScript.g4 b/internal/machine/script/NumScript.g4 index 685f6b763..6354f0a79 100644 --- a/internal/machine/script/NumScript.g4 +++ b/internal/machine/script/NumScript.g4 @@ -45,7 +45,9 @@ SAVE: 'save'; NUMBER: [0-9]+; PERCENT: '%'; VARIABLE_NAME: '$' [a-z_]+ [a-z0-9_]*; -ACCOUNT: '@' [a-zA-Z0-9_]+ [a-zA-Z0-9_:]*; +ACCOUNT : '@'[a-zA-Z0-9_]+(('-'|':')[a-zA-Z0-9_]+)*; + + ASSET: [A-Z/0-9]+; monetary: LBRACK asset=expression amt=NUMBER RBRACK; diff --git a/internal/machine/script/compiler/source.go b/internal/machine/script/compiler/source.go index c1a0fcf98..9db97a8d4 100644 --- a/internal/machine/script/compiler/source.go +++ b/internal/machine/script/compiler/source.go @@ -190,7 +190,7 @@ func (p *parseVisitor) VisitSource(c parser.ISourceContext, pushAsset func(), is if err != nil { return nil, nil, nil, LogicError(c, err) } - p.AppendInstruction(program.OP_TAKE_ALL) + p.AppendInstruction(program.OP_TAKE_ALWAYS) err = p.PushInteger(machine.NewNumber(2)) if err != nil { return nil, nil, nil, LogicError(c, err) diff --git a/internal/machine/script/parser/NumScriptLexer.interp b/internal/machine/script/parser/NumScriptLexer.interp index 7f1577d18..86b8f1fe2 100644 --- a/internal/machine/script/parser/NumScriptLexer.interp +++ b/internal/machine/script/parser/NumScriptLexer.interp @@ -155,4 +155,4 @@ mode names: DEFAULT_MODE atn: -[4, 0, 47, 457, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 4, 4, 155, 8, 4, 11, 4, 12, 4, 156, 1, 5, 4, 5, 160, 8, 5, 11, 5, 12, 5, 161, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 5, 6, 171, 8, 6, 10, 6, 12, 6, 174, 9, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 5, 7, 185, 8, 7, 10, 7, 12, 7, 188, 9, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 22, 1, 22, 1, 23, 1, 23, 1, 24, 1, 24, 1, 25, 1, 25, 1, 26, 1, 26, 1, 27, 1, 27, 1, 28, 1, 28, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 5, 36, 354, 8, 36, 10, 36, 12, 36, 357, 9, 36, 1, 36, 1, 36, 1, 37, 4, 37, 362, 8, 37, 11, 37, 12, 37, 363, 1, 37, 3, 37, 367, 8, 37, 1, 37, 1, 37, 3, 37, 371, 8, 37, 1, 37, 4, 37, 374, 8, 37, 11, 37, 12, 37, 375, 1, 37, 4, 37, 379, 8, 37, 11, 37, 12, 37, 380, 1, 37, 1, 37, 4, 37, 385, 8, 37, 11, 37, 12, 37, 386, 3, 37, 389, 8, 37, 1, 37, 3, 37, 392, 8, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 42, 4, 42, 423, 8, 42, 11, 42, 12, 42, 424, 1, 43, 1, 43, 1, 44, 1, 44, 4, 44, 431, 8, 44, 11, 44, 12, 44, 432, 1, 44, 5, 44, 436, 8, 44, 10, 44, 12, 44, 439, 9, 44, 1, 45, 1, 45, 4, 45, 443, 8, 45, 11, 45, 12, 45, 444, 1, 45, 5, 45, 448, 8, 45, 10, 45, 12, 45, 451, 9, 45, 1, 46, 4, 46, 454, 8, 46, 11, 46, 12, 46, 455, 2, 172, 186, 0, 47, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41, 21, 43, 22, 45, 23, 47, 24, 49, 25, 51, 26, 53, 27, 55, 28, 57, 29, 59, 30, 61, 31, 63, 32, 65, 33, 67, 34, 69, 35, 71, 36, 73, 37, 75, 38, 77, 39, 79, 40, 81, 41, 83, 42, 85, 43, 87, 44, 89, 45, 91, 46, 93, 47, 1, 0, 10, 2, 0, 10, 10, 13, 13, 2, 0, 9, 9, 32, 32, 6, 0, 32, 32, 45, 45, 48, 57, 65, 90, 95, 95, 97, 122, 1, 0, 48, 57, 1, 0, 32, 32, 2, 0, 95, 95, 97, 122, 3, 0, 48, 57, 95, 95, 97, 122, 4, 0, 48, 57, 65, 90, 95, 95, 97, 122, 4, 0, 48, 58, 65, 90, 95, 95, 97, 122, 2, 0, 47, 57, 65, 90, 476, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0, 0, 0, 63, 1, 0, 0, 0, 0, 65, 1, 0, 0, 0, 0, 67, 1, 0, 0, 0, 0, 69, 1, 0, 0, 0, 0, 71, 1, 0, 0, 0, 0, 73, 1, 0, 0, 0, 0, 75, 1, 0, 0, 0, 0, 77, 1, 0, 0, 0, 0, 79, 1, 0, 0, 0, 0, 81, 1, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 85, 1, 0, 0, 0, 0, 87, 1, 0, 0, 0, 0, 89, 1, 0, 0, 0, 0, 91, 1, 0, 0, 0, 0, 93, 1, 0, 0, 0, 1, 95, 1, 0, 0, 0, 3, 97, 1, 0, 0, 0, 5, 122, 1, 0, 0, 0, 7, 151, 1, 0, 0, 0, 9, 154, 1, 0, 0, 0, 11, 159, 1, 0, 0, 0, 13, 165, 1, 0, 0, 0, 15, 180, 1, 0, 0, 0, 17, 193, 1, 0, 0, 0, 19, 198, 1, 0, 0, 0, 21, 203, 1, 0, 0, 0, 23, 215, 1, 0, 0, 0, 25, 232, 1, 0, 0, 0, 27, 238, 1, 0, 0, 0, 29, 243, 1, 0, 0, 0, 31, 248, 1, 0, 0, 0, 33, 255, 1, 0, 0, 0, 35, 260, 1, 0, 0, 0, 37, 264, 1, 0, 0, 0, 39, 276, 1, 0, 0, 0, 41, 279, 1, 0, 0, 0, 43, 288, 1, 0, 0, 0, 45, 290, 1, 0, 0, 0, 47, 292, 1, 0, 0, 0, 49, 294, 1, 0, 0, 0, 51, 296, 1, 0, 0, 0, 53, 298, 1, 0, 0, 0, 55, 300, 1, 0, 0, 0, 57, 302, 1, 0, 0, 0, 59, 304, 1, 0, 0, 0, 61, 306, 1, 0, 0, 0, 63, 314, 1, 0, 0, 0, 65, 320, 1, 0, 0, 0, 67, 327, 1, 0, 0, 0, 69, 336, 1, 0, 0, 0, 71, 344, 1, 0, 0, 0, 73, 351, 1, 0, 0, 0, 75, 391, 1, 0, 0, 0, 77, 393, 1, 0, 0, 0, 79, 403, 1, 0, 0, 0, 81, 408, 1, 0, 0, 0, 83, 416, 1, 0, 0, 0, 85, 422, 1, 0, 0, 0, 87, 426, 1, 0, 0, 0, 89, 428, 1, 0, 0, 0, 91, 440, 1, 0, 0, 0, 93, 453, 1, 0, 0, 0, 95, 96, 5, 42, 0, 0, 96, 2, 1, 0, 0, 0, 97, 98, 5, 97, 0, 0, 98, 99, 5, 108, 0, 0, 99, 100, 5, 108, 0, 0, 100, 101, 5, 111, 0, 0, 101, 102, 5, 119, 0, 0, 102, 103, 5, 105, 0, 0, 103, 104, 5, 110, 0, 0, 104, 105, 5, 103, 0, 0, 105, 106, 5, 32, 0, 0, 106, 107, 5, 111, 0, 0, 107, 108, 5, 118, 0, 0, 108, 109, 5, 101, 0, 0, 109, 110, 5, 114, 0, 0, 110, 111, 5, 100, 0, 0, 111, 112, 5, 114, 0, 0, 112, 113, 5, 97, 0, 0, 113, 114, 5, 102, 0, 0, 114, 115, 5, 116, 0, 0, 115, 116, 5, 32, 0, 0, 116, 117, 5, 117, 0, 0, 117, 118, 5, 112, 0, 0, 118, 119, 5, 32, 0, 0, 119, 120, 5, 116, 0, 0, 120, 121, 5, 111, 0, 0, 121, 4, 1, 0, 0, 0, 122, 123, 5, 97, 0, 0, 123, 124, 5, 108, 0, 0, 124, 125, 5, 108, 0, 0, 125, 126, 5, 111, 0, 0, 126, 127, 5, 119, 0, 0, 127, 128, 5, 105, 0, 0, 128, 129, 5, 110, 0, 0, 129, 130, 5, 103, 0, 0, 130, 131, 5, 32, 0, 0, 131, 132, 5, 117, 0, 0, 132, 133, 5, 110, 0, 0, 133, 134, 5, 98, 0, 0, 134, 135, 5, 111, 0, 0, 135, 136, 5, 117, 0, 0, 136, 137, 5, 110, 0, 0, 137, 138, 5, 100, 0, 0, 138, 139, 5, 101, 0, 0, 139, 140, 5, 100, 0, 0, 140, 141, 5, 32, 0, 0, 141, 142, 5, 111, 0, 0, 142, 143, 5, 118, 0, 0, 143, 144, 5, 101, 0, 0, 144, 145, 5, 114, 0, 0, 145, 146, 5, 100, 0, 0, 146, 147, 5, 114, 0, 0, 147, 148, 5, 97, 0, 0, 148, 149, 5, 102, 0, 0, 149, 150, 5, 116, 0, 0, 150, 6, 1, 0, 0, 0, 151, 152, 5, 44, 0, 0, 152, 8, 1, 0, 0, 0, 153, 155, 7, 0, 0, 0, 154, 153, 1, 0, 0, 0, 155, 156, 1, 0, 0, 0, 156, 154, 1, 0, 0, 0, 156, 157, 1, 0, 0, 0, 157, 10, 1, 0, 0, 0, 158, 160, 7, 1, 0, 0, 159, 158, 1, 0, 0, 0, 160, 161, 1, 0, 0, 0, 161, 159, 1, 0, 0, 0, 161, 162, 1, 0, 0, 0, 162, 163, 1, 0, 0, 0, 163, 164, 6, 5, 0, 0, 164, 12, 1, 0, 0, 0, 165, 166, 5, 47, 0, 0, 166, 167, 5, 42, 0, 0, 167, 172, 1, 0, 0, 0, 168, 171, 3, 13, 6, 0, 169, 171, 9, 0, 0, 0, 170, 168, 1, 0, 0, 0, 170, 169, 1, 0, 0, 0, 171, 174, 1, 0, 0, 0, 172, 173, 1, 0, 0, 0, 172, 170, 1, 0, 0, 0, 173, 175, 1, 0, 0, 0, 174, 172, 1, 0, 0, 0, 175, 176, 5, 42, 0, 0, 176, 177, 5, 47, 0, 0, 177, 178, 1, 0, 0, 0, 178, 179, 6, 6, 0, 0, 179, 14, 1, 0, 0, 0, 180, 181, 5, 47, 0, 0, 181, 182, 5, 47, 0, 0, 182, 186, 1, 0, 0, 0, 183, 185, 9, 0, 0, 0, 184, 183, 1, 0, 0, 0, 185, 188, 1, 0, 0, 0, 186, 187, 1, 0, 0, 0, 186, 184, 1, 0, 0, 0, 187, 189, 1, 0, 0, 0, 188, 186, 1, 0, 0, 0, 189, 190, 3, 9, 4, 0, 190, 191, 1, 0, 0, 0, 191, 192, 6, 7, 0, 0, 192, 16, 1, 0, 0, 0, 193, 194, 5, 118, 0, 0, 194, 195, 5, 97, 0, 0, 195, 196, 5, 114, 0, 0, 196, 197, 5, 115, 0, 0, 197, 18, 1, 0, 0, 0, 198, 199, 5, 109, 0, 0, 199, 200, 5, 101, 0, 0, 200, 201, 5, 116, 0, 0, 201, 202, 5, 97, 0, 0, 202, 20, 1, 0, 0, 0, 203, 204, 5, 115, 0, 0, 204, 205, 5, 101, 0, 0, 205, 206, 5, 116, 0, 0, 206, 207, 5, 95, 0, 0, 207, 208, 5, 116, 0, 0, 208, 209, 5, 120, 0, 0, 209, 210, 5, 95, 0, 0, 210, 211, 5, 109, 0, 0, 211, 212, 5, 101, 0, 0, 212, 213, 5, 116, 0, 0, 213, 214, 5, 97, 0, 0, 214, 22, 1, 0, 0, 0, 215, 216, 5, 115, 0, 0, 216, 217, 5, 101, 0, 0, 217, 218, 5, 116, 0, 0, 218, 219, 5, 95, 0, 0, 219, 220, 5, 97, 0, 0, 220, 221, 5, 99, 0, 0, 221, 222, 5, 99, 0, 0, 222, 223, 5, 111, 0, 0, 223, 224, 5, 117, 0, 0, 224, 225, 5, 110, 0, 0, 225, 226, 5, 116, 0, 0, 226, 227, 5, 95, 0, 0, 227, 228, 5, 109, 0, 0, 228, 229, 5, 101, 0, 0, 229, 230, 5, 116, 0, 0, 230, 231, 5, 97, 0, 0, 231, 24, 1, 0, 0, 0, 232, 233, 5, 112, 0, 0, 233, 234, 5, 114, 0, 0, 234, 235, 5, 105, 0, 0, 235, 236, 5, 110, 0, 0, 236, 237, 5, 116, 0, 0, 237, 26, 1, 0, 0, 0, 238, 239, 5, 102, 0, 0, 239, 240, 5, 97, 0, 0, 240, 241, 5, 105, 0, 0, 241, 242, 5, 108, 0, 0, 242, 28, 1, 0, 0, 0, 243, 244, 5, 115, 0, 0, 244, 245, 5, 101, 0, 0, 245, 246, 5, 110, 0, 0, 246, 247, 5, 100, 0, 0, 247, 30, 1, 0, 0, 0, 248, 249, 5, 115, 0, 0, 249, 250, 5, 111, 0, 0, 250, 251, 5, 117, 0, 0, 251, 252, 5, 114, 0, 0, 252, 253, 5, 99, 0, 0, 253, 254, 5, 101, 0, 0, 254, 32, 1, 0, 0, 0, 255, 256, 5, 102, 0, 0, 256, 257, 5, 114, 0, 0, 257, 258, 5, 111, 0, 0, 258, 259, 5, 109, 0, 0, 259, 34, 1, 0, 0, 0, 260, 261, 5, 109, 0, 0, 261, 262, 5, 97, 0, 0, 262, 263, 5, 120, 0, 0, 263, 36, 1, 0, 0, 0, 264, 265, 5, 100, 0, 0, 265, 266, 5, 101, 0, 0, 266, 267, 5, 115, 0, 0, 267, 268, 5, 116, 0, 0, 268, 269, 5, 105, 0, 0, 269, 270, 5, 110, 0, 0, 270, 271, 5, 97, 0, 0, 271, 272, 5, 116, 0, 0, 272, 273, 5, 105, 0, 0, 273, 274, 5, 111, 0, 0, 274, 275, 5, 110, 0, 0, 275, 38, 1, 0, 0, 0, 276, 277, 5, 116, 0, 0, 277, 278, 5, 111, 0, 0, 278, 40, 1, 0, 0, 0, 279, 280, 5, 97, 0, 0, 280, 281, 5, 108, 0, 0, 281, 282, 5, 108, 0, 0, 282, 283, 5, 111, 0, 0, 283, 284, 5, 99, 0, 0, 284, 285, 5, 97, 0, 0, 285, 286, 5, 116, 0, 0, 286, 287, 5, 101, 0, 0, 287, 42, 1, 0, 0, 0, 288, 289, 5, 43, 0, 0, 289, 44, 1, 0, 0, 0, 290, 291, 5, 45, 0, 0, 291, 46, 1, 0, 0, 0, 292, 293, 5, 40, 0, 0, 293, 48, 1, 0, 0, 0, 294, 295, 5, 41, 0, 0, 295, 50, 1, 0, 0, 0, 296, 297, 5, 91, 0, 0, 297, 52, 1, 0, 0, 0, 298, 299, 5, 93, 0, 0, 299, 54, 1, 0, 0, 0, 300, 301, 5, 123, 0, 0, 301, 56, 1, 0, 0, 0, 302, 303, 5, 125, 0, 0, 303, 58, 1, 0, 0, 0, 304, 305, 5, 61, 0, 0, 305, 60, 1, 0, 0, 0, 306, 307, 5, 97, 0, 0, 307, 308, 5, 99, 0, 0, 308, 309, 5, 99, 0, 0, 309, 310, 5, 111, 0, 0, 310, 311, 5, 117, 0, 0, 311, 312, 5, 110, 0, 0, 312, 313, 5, 116, 0, 0, 313, 62, 1, 0, 0, 0, 314, 315, 5, 97, 0, 0, 315, 316, 5, 115, 0, 0, 316, 317, 5, 115, 0, 0, 317, 318, 5, 101, 0, 0, 318, 319, 5, 116, 0, 0, 319, 64, 1, 0, 0, 0, 320, 321, 5, 110, 0, 0, 321, 322, 5, 117, 0, 0, 322, 323, 5, 109, 0, 0, 323, 324, 5, 98, 0, 0, 324, 325, 5, 101, 0, 0, 325, 326, 5, 114, 0, 0, 326, 66, 1, 0, 0, 0, 327, 328, 5, 109, 0, 0, 328, 329, 5, 111, 0, 0, 329, 330, 5, 110, 0, 0, 330, 331, 5, 101, 0, 0, 331, 332, 5, 116, 0, 0, 332, 333, 5, 97, 0, 0, 333, 334, 5, 114, 0, 0, 334, 335, 5, 121, 0, 0, 335, 68, 1, 0, 0, 0, 336, 337, 5, 112, 0, 0, 337, 338, 5, 111, 0, 0, 338, 339, 5, 114, 0, 0, 339, 340, 5, 116, 0, 0, 340, 341, 5, 105, 0, 0, 341, 342, 5, 111, 0, 0, 342, 343, 5, 110, 0, 0, 343, 70, 1, 0, 0, 0, 344, 345, 5, 115, 0, 0, 345, 346, 5, 116, 0, 0, 346, 347, 5, 114, 0, 0, 347, 348, 5, 105, 0, 0, 348, 349, 5, 110, 0, 0, 349, 350, 5, 103, 0, 0, 350, 72, 1, 0, 0, 0, 351, 355, 5, 34, 0, 0, 352, 354, 7, 2, 0, 0, 353, 352, 1, 0, 0, 0, 354, 357, 1, 0, 0, 0, 355, 353, 1, 0, 0, 0, 355, 356, 1, 0, 0, 0, 356, 358, 1, 0, 0, 0, 357, 355, 1, 0, 0, 0, 358, 359, 5, 34, 0, 0, 359, 74, 1, 0, 0, 0, 360, 362, 7, 3, 0, 0, 361, 360, 1, 0, 0, 0, 362, 363, 1, 0, 0, 0, 363, 361, 1, 0, 0, 0, 363, 364, 1, 0, 0, 0, 364, 366, 1, 0, 0, 0, 365, 367, 7, 4, 0, 0, 366, 365, 1, 0, 0, 0, 366, 367, 1, 0, 0, 0, 367, 368, 1, 0, 0, 0, 368, 370, 5, 47, 0, 0, 369, 371, 7, 4, 0, 0, 370, 369, 1, 0, 0, 0, 370, 371, 1, 0, 0, 0, 371, 373, 1, 0, 0, 0, 372, 374, 7, 3, 0, 0, 373, 372, 1, 0, 0, 0, 374, 375, 1, 0, 0, 0, 375, 373, 1, 0, 0, 0, 375, 376, 1, 0, 0, 0, 376, 392, 1, 0, 0, 0, 377, 379, 7, 3, 0, 0, 378, 377, 1, 0, 0, 0, 379, 380, 1, 0, 0, 0, 380, 378, 1, 0, 0, 0, 380, 381, 1, 0, 0, 0, 381, 388, 1, 0, 0, 0, 382, 384, 5, 46, 0, 0, 383, 385, 7, 3, 0, 0, 384, 383, 1, 0, 0, 0, 385, 386, 1, 0, 0, 0, 386, 384, 1, 0, 0, 0, 386, 387, 1, 0, 0, 0, 387, 389, 1, 0, 0, 0, 388, 382, 1, 0, 0, 0, 388, 389, 1, 0, 0, 0, 389, 390, 1, 0, 0, 0, 390, 392, 5, 37, 0, 0, 391, 361, 1, 0, 0, 0, 391, 378, 1, 0, 0, 0, 392, 76, 1, 0, 0, 0, 393, 394, 5, 114, 0, 0, 394, 395, 5, 101, 0, 0, 395, 396, 5, 109, 0, 0, 396, 397, 5, 97, 0, 0, 397, 398, 5, 105, 0, 0, 398, 399, 5, 110, 0, 0, 399, 400, 5, 105, 0, 0, 400, 401, 5, 110, 0, 0, 401, 402, 5, 103, 0, 0, 402, 78, 1, 0, 0, 0, 403, 404, 5, 107, 0, 0, 404, 405, 5, 101, 0, 0, 405, 406, 5, 112, 0, 0, 406, 407, 5, 116, 0, 0, 407, 80, 1, 0, 0, 0, 408, 409, 5, 98, 0, 0, 409, 410, 5, 97, 0, 0, 410, 411, 5, 108, 0, 0, 411, 412, 5, 97, 0, 0, 412, 413, 5, 110, 0, 0, 413, 414, 5, 99, 0, 0, 414, 415, 5, 101, 0, 0, 415, 82, 1, 0, 0, 0, 416, 417, 5, 115, 0, 0, 417, 418, 5, 97, 0, 0, 418, 419, 5, 118, 0, 0, 419, 420, 5, 101, 0, 0, 420, 84, 1, 0, 0, 0, 421, 423, 7, 3, 0, 0, 422, 421, 1, 0, 0, 0, 423, 424, 1, 0, 0, 0, 424, 422, 1, 0, 0, 0, 424, 425, 1, 0, 0, 0, 425, 86, 1, 0, 0, 0, 426, 427, 5, 37, 0, 0, 427, 88, 1, 0, 0, 0, 428, 430, 5, 36, 0, 0, 429, 431, 7, 5, 0, 0, 430, 429, 1, 0, 0, 0, 431, 432, 1, 0, 0, 0, 432, 430, 1, 0, 0, 0, 432, 433, 1, 0, 0, 0, 433, 437, 1, 0, 0, 0, 434, 436, 7, 6, 0, 0, 435, 434, 1, 0, 0, 0, 436, 439, 1, 0, 0, 0, 437, 435, 1, 0, 0, 0, 437, 438, 1, 0, 0, 0, 438, 90, 1, 0, 0, 0, 439, 437, 1, 0, 0, 0, 440, 442, 5, 64, 0, 0, 441, 443, 7, 7, 0, 0, 442, 441, 1, 0, 0, 0, 443, 444, 1, 0, 0, 0, 444, 442, 1, 0, 0, 0, 444, 445, 1, 0, 0, 0, 445, 449, 1, 0, 0, 0, 446, 448, 7, 8, 0, 0, 447, 446, 1, 0, 0, 0, 448, 451, 1, 0, 0, 0, 449, 447, 1, 0, 0, 0, 449, 450, 1, 0, 0, 0, 450, 92, 1, 0, 0, 0, 451, 449, 1, 0, 0, 0, 452, 454, 7, 9, 0, 0, 453, 452, 1, 0, 0, 0, 454, 455, 1, 0, 0, 0, 455, 453, 1, 0, 0, 0, 455, 456, 1, 0, 0, 0, 456, 94, 1, 0, 0, 0, 21, 0, 156, 161, 170, 172, 186, 355, 363, 366, 370, 375, 380, 386, 388, 391, 424, 432, 437, 444, 449, 455, 1, 6, 0, 0] \ No newline at end of file +[4, 0, 47, 462, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 4, 4, 155, 8, 4, 11, 4, 12, 4, 156, 1, 5, 4, 5, 160, 8, 5, 11, 5, 12, 5, 161, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 5, 6, 171, 8, 6, 10, 6, 12, 6, 174, 9, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 5, 7, 185, 8, 7, 10, 7, 12, 7, 188, 9, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 22, 1, 22, 1, 23, 1, 23, 1, 24, 1, 24, 1, 25, 1, 25, 1, 26, 1, 26, 1, 27, 1, 27, 1, 28, 1, 28, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 5, 36, 354, 8, 36, 10, 36, 12, 36, 357, 9, 36, 1, 36, 1, 36, 1, 37, 4, 37, 362, 8, 37, 11, 37, 12, 37, 363, 1, 37, 3, 37, 367, 8, 37, 1, 37, 1, 37, 3, 37, 371, 8, 37, 1, 37, 4, 37, 374, 8, 37, 11, 37, 12, 37, 375, 1, 37, 4, 37, 379, 8, 37, 11, 37, 12, 37, 380, 1, 37, 1, 37, 4, 37, 385, 8, 37, 11, 37, 12, 37, 386, 3, 37, 389, 8, 37, 1, 37, 3, 37, 392, 8, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 42, 4, 42, 423, 8, 42, 11, 42, 12, 42, 424, 1, 43, 1, 43, 1, 44, 1, 44, 4, 44, 431, 8, 44, 11, 44, 12, 44, 432, 1, 44, 5, 44, 436, 8, 44, 10, 44, 12, 44, 439, 9, 44, 1, 45, 1, 45, 4, 45, 443, 8, 45, 11, 45, 12, 45, 444, 1, 45, 1, 45, 4, 45, 449, 8, 45, 11, 45, 12, 45, 450, 5, 45, 453, 8, 45, 10, 45, 12, 45, 456, 9, 45, 1, 46, 4, 46, 459, 8, 46, 11, 46, 12, 46, 460, 2, 172, 186, 0, 47, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41, 21, 43, 22, 45, 23, 47, 24, 49, 25, 51, 26, 53, 27, 55, 28, 57, 29, 59, 30, 61, 31, 63, 32, 65, 33, 67, 34, 69, 35, 71, 36, 73, 37, 75, 38, 77, 39, 79, 40, 81, 41, 83, 42, 85, 43, 87, 44, 89, 45, 91, 46, 93, 47, 1, 0, 10, 2, 0, 10, 10, 13, 13, 2, 0, 9, 9, 32, 32, 6, 0, 32, 32, 45, 45, 48, 57, 65, 90, 95, 95, 97, 122, 1, 0, 48, 57, 1, 0, 32, 32, 2, 0, 95, 95, 97, 122, 3, 0, 48, 57, 95, 95, 97, 122, 4, 0, 48, 57, 65, 90, 95, 95, 97, 122, 2, 0, 45, 45, 58, 58, 2, 0, 47, 57, 65, 90, 482, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0, 0, 0, 63, 1, 0, 0, 0, 0, 65, 1, 0, 0, 0, 0, 67, 1, 0, 0, 0, 0, 69, 1, 0, 0, 0, 0, 71, 1, 0, 0, 0, 0, 73, 1, 0, 0, 0, 0, 75, 1, 0, 0, 0, 0, 77, 1, 0, 0, 0, 0, 79, 1, 0, 0, 0, 0, 81, 1, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 85, 1, 0, 0, 0, 0, 87, 1, 0, 0, 0, 0, 89, 1, 0, 0, 0, 0, 91, 1, 0, 0, 0, 0, 93, 1, 0, 0, 0, 1, 95, 1, 0, 0, 0, 3, 97, 1, 0, 0, 0, 5, 122, 1, 0, 0, 0, 7, 151, 1, 0, 0, 0, 9, 154, 1, 0, 0, 0, 11, 159, 1, 0, 0, 0, 13, 165, 1, 0, 0, 0, 15, 180, 1, 0, 0, 0, 17, 193, 1, 0, 0, 0, 19, 198, 1, 0, 0, 0, 21, 203, 1, 0, 0, 0, 23, 215, 1, 0, 0, 0, 25, 232, 1, 0, 0, 0, 27, 238, 1, 0, 0, 0, 29, 243, 1, 0, 0, 0, 31, 248, 1, 0, 0, 0, 33, 255, 1, 0, 0, 0, 35, 260, 1, 0, 0, 0, 37, 264, 1, 0, 0, 0, 39, 276, 1, 0, 0, 0, 41, 279, 1, 0, 0, 0, 43, 288, 1, 0, 0, 0, 45, 290, 1, 0, 0, 0, 47, 292, 1, 0, 0, 0, 49, 294, 1, 0, 0, 0, 51, 296, 1, 0, 0, 0, 53, 298, 1, 0, 0, 0, 55, 300, 1, 0, 0, 0, 57, 302, 1, 0, 0, 0, 59, 304, 1, 0, 0, 0, 61, 306, 1, 0, 0, 0, 63, 314, 1, 0, 0, 0, 65, 320, 1, 0, 0, 0, 67, 327, 1, 0, 0, 0, 69, 336, 1, 0, 0, 0, 71, 344, 1, 0, 0, 0, 73, 351, 1, 0, 0, 0, 75, 391, 1, 0, 0, 0, 77, 393, 1, 0, 0, 0, 79, 403, 1, 0, 0, 0, 81, 408, 1, 0, 0, 0, 83, 416, 1, 0, 0, 0, 85, 422, 1, 0, 0, 0, 87, 426, 1, 0, 0, 0, 89, 428, 1, 0, 0, 0, 91, 440, 1, 0, 0, 0, 93, 458, 1, 0, 0, 0, 95, 96, 5, 42, 0, 0, 96, 2, 1, 0, 0, 0, 97, 98, 5, 97, 0, 0, 98, 99, 5, 108, 0, 0, 99, 100, 5, 108, 0, 0, 100, 101, 5, 111, 0, 0, 101, 102, 5, 119, 0, 0, 102, 103, 5, 105, 0, 0, 103, 104, 5, 110, 0, 0, 104, 105, 5, 103, 0, 0, 105, 106, 5, 32, 0, 0, 106, 107, 5, 111, 0, 0, 107, 108, 5, 118, 0, 0, 108, 109, 5, 101, 0, 0, 109, 110, 5, 114, 0, 0, 110, 111, 5, 100, 0, 0, 111, 112, 5, 114, 0, 0, 112, 113, 5, 97, 0, 0, 113, 114, 5, 102, 0, 0, 114, 115, 5, 116, 0, 0, 115, 116, 5, 32, 0, 0, 116, 117, 5, 117, 0, 0, 117, 118, 5, 112, 0, 0, 118, 119, 5, 32, 0, 0, 119, 120, 5, 116, 0, 0, 120, 121, 5, 111, 0, 0, 121, 4, 1, 0, 0, 0, 122, 123, 5, 97, 0, 0, 123, 124, 5, 108, 0, 0, 124, 125, 5, 108, 0, 0, 125, 126, 5, 111, 0, 0, 126, 127, 5, 119, 0, 0, 127, 128, 5, 105, 0, 0, 128, 129, 5, 110, 0, 0, 129, 130, 5, 103, 0, 0, 130, 131, 5, 32, 0, 0, 131, 132, 5, 117, 0, 0, 132, 133, 5, 110, 0, 0, 133, 134, 5, 98, 0, 0, 134, 135, 5, 111, 0, 0, 135, 136, 5, 117, 0, 0, 136, 137, 5, 110, 0, 0, 137, 138, 5, 100, 0, 0, 138, 139, 5, 101, 0, 0, 139, 140, 5, 100, 0, 0, 140, 141, 5, 32, 0, 0, 141, 142, 5, 111, 0, 0, 142, 143, 5, 118, 0, 0, 143, 144, 5, 101, 0, 0, 144, 145, 5, 114, 0, 0, 145, 146, 5, 100, 0, 0, 146, 147, 5, 114, 0, 0, 147, 148, 5, 97, 0, 0, 148, 149, 5, 102, 0, 0, 149, 150, 5, 116, 0, 0, 150, 6, 1, 0, 0, 0, 151, 152, 5, 44, 0, 0, 152, 8, 1, 0, 0, 0, 153, 155, 7, 0, 0, 0, 154, 153, 1, 0, 0, 0, 155, 156, 1, 0, 0, 0, 156, 154, 1, 0, 0, 0, 156, 157, 1, 0, 0, 0, 157, 10, 1, 0, 0, 0, 158, 160, 7, 1, 0, 0, 159, 158, 1, 0, 0, 0, 160, 161, 1, 0, 0, 0, 161, 159, 1, 0, 0, 0, 161, 162, 1, 0, 0, 0, 162, 163, 1, 0, 0, 0, 163, 164, 6, 5, 0, 0, 164, 12, 1, 0, 0, 0, 165, 166, 5, 47, 0, 0, 166, 167, 5, 42, 0, 0, 167, 172, 1, 0, 0, 0, 168, 171, 3, 13, 6, 0, 169, 171, 9, 0, 0, 0, 170, 168, 1, 0, 0, 0, 170, 169, 1, 0, 0, 0, 171, 174, 1, 0, 0, 0, 172, 173, 1, 0, 0, 0, 172, 170, 1, 0, 0, 0, 173, 175, 1, 0, 0, 0, 174, 172, 1, 0, 0, 0, 175, 176, 5, 42, 0, 0, 176, 177, 5, 47, 0, 0, 177, 178, 1, 0, 0, 0, 178, 179, 6, 6, 0, 0, 179, 14, 1, 0, 0, 0, 180, 181, 5, 47, 0, 0, 181, 182, 5, 47, 0, 0, 182, 186, 1, 0, 0, 0, 183, 185, 9, 0, 0, 0, 184, 183, 1, 0, 0, 0, 185, 188, 1, 0, 0, 0, 186, 187, 1, 0, 0, 0, 186, 184, 1, 0, 0, 0, 187, 189, 1, 0, 0, 0, 188, 186, 1, 0, 0, 0, 189, 190, 3, 9, 4, 0, 190, 191, 1, 0, 0, 0, 191, 192, 6, 7, 0, 0, 192, 16, 1, 0, 0, 0, 193, 194, 5, 118, 0, 0, 194, 195, 5, 97, 0, 0, 195, 196, 5, 114, 0, 0, 196, 197, 5, 115, 0, 0, 197, 18, 1, 0, 0, 0, 198, 199, 5, 109, 0, 0, 199, 200, 5, 101, 0, 0, 200, 201, 5, 116, 0, 0, 201, 202, 5, 97, 0, 0, 202, 20, 1, 0, 0, 0, 203, 204, 5, 115, 0, 0, 204, 205, 5, 101, 0, 0, 205, 206, 5, 116, 0, 0, 206, 207, 5, 95, 0, 0, 207, 208, 5, 116, 0, 0, 208, 209, 5, 120, 0, 0, 209, 210, 5, 95, 0, 0, 210, 211, 5, 109, 0, 0, 211, 212, 5, 101, 0, 0, 212, 213, 5, 116, 0, 0, 213, 214, 5, 97, 0, 0, 214, 22, 1, 0, 0, 0, 215, 216, 5, 115, 0, 0, 216, 217, 5, 101, 0, 0, 217, 218, 5, 116, 0, 0, 218, 219, 5, 95, 0, 0, 219, 220, 5, 97, 0, 0, 220, 221, 5, 99, 0, 0, 221, 222, 5, 99, 0, 0, 222, 223, 5, 111, 0, 0, 223, 224, 5, 117, 0, 0, 224, 225, 5, 110, 0, 0, 225, 226, 5, 116, 0, 0, 226, 227, 5, 95, 0, 0, 227, 228, 5, 109, 0, 0, 228, 229, 5, 101, 0, 0, 229, 230, 5, 116, 0, 0, 230, 231, 5, 97, 0, 0, 231, 24, 1, 0, 0, 0, 232, 233, 5, 112, 0, 0, 233, 234, 5, 114, 0, 0, 234, 235, 5, 105, 0, 0, 235, 236, 5, 110, 0, 0, 236, 237, 5, 116, 0, 0, 237, 26, 1, 0, 0, 0, 238, 239, 5, 102, 0, 0, 239, 240, 5, 97, 0, 0, 240, 241, 5, 105, 0, 0, 241, 242, 5, 108, 0, 0, 242, 28, 1, 0, 0, 0, 243, 244, 5, 115, 0, 0, 244, 245, 5, 101, 0, 0, 245, 246, 5, 110, 0, 0, 246, 247, 5, 100, 0, 0, 247, 30, 1, 0, 0, 0, 248, 249, 5, 115, 0, 0, 249, 250, 5, 111, 0, 0, 250, 251, 5, 117, 0, 0, 251, 252, 5, 114, 0, 0, 252, 253, 5, 99, 0, 0, 253, 254, 5, 101, 0, 0, 254, 32, 1, 0, 0, 0, 255, 256, 5, 102, 0, 0, 256, 257, 5, 114, 0, 0, 257, 258, 5, 111, 0, 0, 258, 259, 5, 109, 0, 0, 259, 34, 1, 0, 0, 0, 260, 261, 5, 109, 0, 0, 261, 262, 5, 97, 0, 0, 262, 263, 5, 120, 0, 0, 263, 36, 1, 0, 0, 0, 264, 265, 5, 100, 0, 0, 265, 266, 5, 101, 0, 0, 266, 267, 5, 115, 0, 0, 267, 268, 5, 116, 0, 0, 268, 269, 5, 105, 0, 0, 269, 270, 5, 110, 0, 0, 270, 271, 5, 97, 0, 0, 271, 272, 5, 116, 0, 0, 272, 273, 5, 105, 0, 0, 273, 274, 5, 111, 0, 0, 274, 275, 5, 110, 0, 0, 275, 38, 1, 0, 0, 0, 276, 277, 5, 116, 0, 0, 277, 278, 5, 111, 0, 0, 278, 40, 1, 0, 0, 0, 279, 280, 5, 97, 0, 0, 280, 281, 5, 108, 0, 0, 281, 282, 5, 108, 0, 0, 282, 283, 5, 111, 0, 0, 283, 284, 5, 99, 0, 0, 284, 285, 5, 97, 0, 0, 285, 286, 5, 116, 0, 0, 286, 287, 5, 101, 0, 0, 287, 42, 1, 0, 0, 0, 288, 289, 5, 43, 0, 0, 289, 44, 1, 0, 0, 0, 290, 291, 5, 45, 0, 0, 291, 46, 1, 0, 0, 0, 292, 293, 5, 40, 0, 0, 293, 48, 1, 0, 0, 0, 294, 295, 5, 41, 0, 0, 295, 50, 1, 0, 0, 0, 296, 297, 5, 91, 0, 0, 297, 52, 1, 0, 0, 0, 298, 299, 5, 93, 0, 0, 299, 54, 1, 0, 0, 0, 300, 301, 5, 123, 0, 0, 301, 56, 1, 0, 0, 0, 302, 303, 5, 125, 0, 0, 303, 58, 1, 0, 0, 0, 304, 305, 5, 61, 0, 0, 305, 60, 1, 0, 0, 0, 306, 307, 5, 97, 0, 0, 307, 308, 5, 99, 0, 0, 308, 309, 5, 99, 0, 0, 309, 310, 5, 111, 0, 0, 310, 311, 5, 117, 0, 0, 311, 312, 5, 110, 0, 0, 312, 313, 5, 116, 0, 0, 313, 62, 1, 0, 0, 0, 314, 315, 5, 97, 0, 0, 315, 316, 5, 115, 0, 0, 316, 317, 5, 115, 0, 0, 317, 318, 5, 101, 0, 0, 318, 319, 5, 116, 0, 0, 319, 64, 1, 0, 0, 0, 320, 321, 5, 110, 0, 0, 321, 322, 5, 117, 0, 0, 322, 323, 5, 109, 0, 0, 323, 324, 5, 98, 0, 0, 324, 325, 5, 101, 0, 0, 325, 326, 5, 114, 0, 0, 326, 66, 1, 0, 0, 0, 327, 328, 5, 109, 0, 0, 328, 329, 5, 111, 0, 0, 329, 330, 5, 110, 0, 0, 330, 331, 5, 101, 0, 0, 331, 332, 5, 116, 0, 0, 332, 333, 5, 97, 0, 0, 333, 334, 5, 114, 0, 0, 334, 335, 5, 121, 0, 0, 335, 68, 1, 0, 0, 0, 336, 337, 5, 112, 0, 0, 337, 338, 5, 111, 0, 0, 338, 339, 5, 114, 0, 0, 339, 340, 5, 116, 0, 0, 340, 341, 5, 105, 0, 0, 341, 342, 5, 111, 0, 0, 342, 343, 5, 110, 0, 0, 343, 70, 1, 0, 0, 0, 344, 345, 5, 115, 0, 0, 345, 346, 5, 116, 0, 0, 346, 347, 5, 114, 0, 0, 347, 348, 5, 105, 0, 0, 348, 349, 5, 110, 0, 0, 349, 350, 5, 103, 0, 0, 350, 72, 1, 0, 0, 0, 351, 355, 5, 34, 0, 0, 352, 354, 7, 2, 0, 0, 353, 352, 1, 0, 0, 0, 354, 357, 1, 0, 0, 0, 355, 353, 1, 0, 0, 0, 355, 356, 1, 0, 0, 0, 356, 358, 1, 0, 0, 0, 357, 355, 1, 0, 0, 0, 358, 359, 5, 34, 0, 0, 359, 74, 1, 0, 0, 0, 360, 362, 7, 3, 0, 0, 361, 360, 1, 0, 0, 0, 362, 363, 1, 0, 0, 0, 363, 361, 1, 0, 0, 0, 363, 364, 1, 0, 0, 0, 364, 366, 1, 0, 0, 0, 365, 367, 7, 4, 0, 0, 366, 365, 1, 0, 0, 0, 366, 367, 1, 0, 0, 0, 367, 368, 1, 0, 0, 0, 368, 370, 5, 47, 0, 0, 369, 371, 7, 4, 0, 0, 370, 369, 1, 0, 0, 0, 370, 371, 1, 0, 0, 0, 371, 373, 1, 0, 0, 0, 372, 374, 7, 3, 0, 0, 373, 372, 1, 0, 0, 0, 374, 375, 1, 0, 0, 0, 375, 373, 1, 0, 0, 0, 375, 376, 1, 0, 0, 0, 376, 392, 1, 0, 0, 0, 377, 379, 7, 3, 0, 0, 378, 377, 1, 0, 0, 0, 379, 380, 1, 0, 0, 0, 380, 378, 1, 0, 0, 0, 380, 381, 1, 0, 0, 0, 381, 388, 1, 0, 0, 0, 382, 384, 5, 46, 0, 0, 383, 385, 7, 3, 0, 0, 384, 383, 1, 0, 0, 0, 385, 386, 1, 0, 0, 0, 386, 384, 1, 0, 0, 0, 386, 387, 1, 0, 0, 0, 387, 389, 1, 0, 0, 0, 388, 382, 1, 0, 0, 0, 388, 389, 1, 0, 0, 0, 389, 390, 1, 0, 0, 0, 390, 392, 5, 37, 0, 0, 391, 361, 1, 0, 0, 0, 391, 378, 1, 0, 0, 0, 392, 76, 1, 0, 0, 0, 393, 394, 5, 114, 0, 0, 394, 395, 5, 101, 0, 0, 395, 396, 5, 109, 0, 0, 396, 397, 5, 97, 0, 0, 397, 398, 5, 105, 0, 0, 398, 399, 5, 110, 0, 0, 399, 400, 5, 105, 0, 0, 400, 401, 5, 110, 0, 0, 401, 402, 5, 103, 0, 0, 402, 78, 1, 0, 0, 0, 403, 404, 5, 107, 0, 0, 404, 405, 5, 101, 0, 0, 405, 406, 5, 112, 0, 0, 406, 407, 5, 116, 0, 0, 407, 80, 1, 0, 0, 0, 408, 409, 5, 98, 0, 0, 409, 410, 5, 97, 0, 0, 410, 411, 5, 108, 0, 0, 411, 412, 5, 97, 0, 0, 412, 413, 5, 110, 0, 0, 413, 414, 5, 99, 0, 0, 414, 415, 5, 101, 0, 0, 415, 82, 1, 0, 0, 0, 416, 417, 5, 115, 0, 0, 417, 418, 5, 97, 0, 0, 418, 419, 5, 118, 0, 0, 419, 420, 5, 101, 0, 0, 420, 84, 1, 0, 0, 0, 421, 423, 7, 3, 0, 0, 422, 421, 1, 0, 0, 0, 423, 424, 1, 0, 0, 0, 424, 422, 1, 0, 0, 0, 424, 425, 1, 0, 0, 0, 425, 86, 1, 0, 0, 0, 426, 427, 5, 37, 0, 0, 427, 88, 1, 0, 0, 0, 428, 430, 5, 36, 0, 0, 429, 431, 7, 5, 0, 0, 430, 429, 1, 0, 0, 0, 431, 432, 1, 0, 0, 0, 432, 430, 1, 0, 0, 0, 432, 433, 1, 0, 0, 0, 433, 437, 1, 0, 0, 0, 434, 436, 7, 6, 0, 0, 435, 434, 1, 0, 0, 0, 436, 439, 1, 0, 0, 0, 437, 435, 1, 0, 0, 0, 437, 438, 1, 0, 0, 0, 438, 90, 1, 0, 0, 0, 439, 437, 1, 0, 0, 0, 440, 442, 5, 64, 0, 0, 441, 443, 7, 7, 0, 0, 442, 441, 1, 0, 0, 0, 443, 444, 1, 0, 0, 0, 444, 442, 1, 0, 0, 0, 444, 445, 1, 0, 0, 0, 445, 454, 1, 0, 0, 0, 446, 448, 7, 8, 0, 0, 447, 449, 7, 7, 0, 0, 448, 447, 1, 0, 0, 0, 449, 450, 1, 0, 0, 0, 450, 448, 1, 0, 0, 0, 450, 451, 1, 0, 0, 0, 451, 453, 1, 0, 0, 0, 452, 446, 1, 0, 0, 0, 453, 456, 1, 0, 0, 0, 454, 452, 1, 0, 0, 0, 454, 455, 1, 0, 0, 0, 455, 92, 1, 0, 0, 0, 456, 454, 1, 0, 0, 0, 457, 459, 7, 9, 0, 0, 458, 457, 1, 0, 0, 0, 459, 460, 1, 0, 0, 0, 460, 458, 1, 0, 0, 0, 460, 461, 1, 0, 0, 0, 461, 94, 1, 0, 0, 0, 22, 0, 156, 161, 170, 172, 186, 355, 363, 366, 370, 375, 380, 386, 388, 391, 424, 432, 437, 444, 450, 454, 460, 1, 6, 0, 0] \ No newline at end of file diff --git a/internal/machine/script/parser/numscript_lexer.go b/internal/machine/script/parser/numscript_lexer.go index cf2cac296..6d5c285dd 100644 --- a/internal/machine/script/parser/numscript_lexer.go +++ b/internal/machine/script/parser/numscript_lexer.go @@ -73,7 +73,7 @@ func numscriptlexerLexerInit() { } staticData.predictionContextCache = antlr.NewPredictionContextCache() staticData.serializedATN = []int32{ - 4, 0, 47, 457, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, + 4, 0, 47, 462, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, @@ -116,166 +116,169 @@ func numscriptlexerLexerInit() { 1, 40, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 42, 4, 42, 423, 8, 42, 11, 42, 12, 42, 424, 1, 43, 1, 43, 1, 44, 1, 44, 4, 44, 431, 8, 44, 11, 44, 12, 44, 432, 1, 44, 5, 44, 436, 8, 44, 10, 44, 12, 44, 439, 9, 44, 1, 45, - 1, 45, 4, 45, 443, 8, 45, 11, 45, 12, 45, 444, 1, 45, 5, 45, 448, 8, 45, - 10, 45, 12, 45, 451, 9, 45, 1, 46, 4, 46, 454, 8, 46, 11, 46, 12, 46, 455, - 2, 172, 186, 0, 47, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, - 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, - 35, 18, 37, 19, 39, 20, 41, 21, 43, 22, 45, 23, 47, 24, 49, 25, 51, 26, - 53, 27, 55, 28, 57, 29, 59, 30, 61, 31, 63, 32, 65, 33, 67, 34, 69, 35, - 71, 36, 73, 37, 75, 38, 77, 39, 79, 40, 81, 41, 83, 42, 85, 43, 87, 44, - 89, 45, 91, 46, 93, 47, 1, 0, 10, 2, 0, 10, 10, 13, 13, 2, 0, 9, 9, 32, - 32, 6, 0, 32, 32, 45, 45, 48, 57, 65, 90, 95, 95, 97, 122, 1, 0, 48, 57, - 1, 0, 32, 32, 2, 0, 95, 95, 97, 122, 3, 0, 48, 57, 95, 95, 97, 122, 4, - 0, 48, 57, 65, 90, 95, 95, 97, 122, 4, 0, 48, 58, 65, 90, 95, 95, 97, 122, - 2, 0, 47, 57, 65, 90, 476, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, - 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, - 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, - 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, - 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, - 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, - 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, - 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, - 1, 0, 0, 0, 0, 61, 1, 0, 0, 0, 0, 63, 1, 0, 0, 0, 0, 65, 1, 0, 0, 0, 0, - 67, 1, 0, 0, 0, 0, 69, 1, 0, 0, 0, 0, 71, 1, 0, 0, 0, 0, 73, 1, 0, 0, 0, - 0, 75, 1, 0, 0, 0, 0, 77, 1, 0, 0, 0, 0, 79, 1, 0, 0, 0, 0, 81, 1, 0, 0, - 0, 0, 83, 1, 0, 0, 0, 0, 85, 1, 0, 0, 0, 0, 87, 1, 0, 0, 0, 0, 89, 1, 0, - 0, 0, 0, 91, 1, 0, 0, 0, 0, 93, 1, 0, 0, 0, 1, 95, 1, 0, 0, 0, 3, 97, 1, - 0, 0, 0, 5, 122, 1, 0, 0, 0, 7, 151, 1, 0, 0, 0, 9, 154, 1, 0, 0, 0, 11, - 159, 1, 0, 0, 0, 13, 165, 1, 0, 0, 0, 15, 180, 1, 0, 0, 0, 17, 193, 1, - 0, 0, 0, 19, 198, 1, 0, 0, 0, 21, 203, 1, 0, 0, 0, 23, 215, 1, 0, 0, 0, - 25, 232, 1, 0, 0, 0, 27, 238, 1, 0, 0, 0, 29, 243, 1, 0, 0, 0, 31, 248, - 1, 0, 0, 0, 33, 255, 1, 0, 0, 0, 35, 260, 1, 0, 0, 0, 37, 264, 1, 0, 0, - 0, 39, 276, 1, 0, 0, 0, 41, 279, 1, 0, 0, 0, 43, 288, 1, 0, 0, 0, 45, 290, - 1, 0, 0, 0, 47, 292, 1, 0, 0, 0, 49, 294, 1, 0, 0, 0, 51, 296, 1, 0, 0, - 0, 53, 298, 1, 0, 0, 0, 55, 300, 1, 0, 0, 0, 57, 302, 1, 0, 0, 0, 59, 304, - 1, 0, 0, 0, 61, 306, 1, 0, 0, 0, 63, 314, 1, 0, 0, 0, 65, 320, 1, 0, 0, - 0, 67, 327, 1, 0, 0, 0, 69, 336, 1, 0, 0, 0, 71, 344, 1, 0, 0, 0, 73, 351, - 1, 0, 0, 0, 75, 391, 1, 0, 0, 0, 77, 393, 1, 0, 0, 0, 79, 403, 1, 0, 0, - 0, 81, 408, 1, 0, 0, 0, 83, 416, 1, 0, 0, 0, 85, 422, 1, 0, 0, 0, 87, 426, - 1, 0, 0, 0, 89, 428, 1, 0, 0, 0, 91, 440, 1, 0, 0, 0, 93, 453, 1, 0, 0, - 0, 95, 96, 5, 42, 0, 0, 96, 2, 1, 0, 0, 0, 97, 98, 5, 97, 0, 0, 98, 99, - 5, 108, 0, 0, 99, 100, 5, 108, 0, 0, 100, 101, 5, 111, 0, 0, 101, 102, - 5, 119, 0, 0, 102, 103, 5, 105, 0, 0, 103, 104, 5, 110, 0, 0, 104, 105, - 5, 103, 0, 0, 105, 106, 5, 32, 0, 0, 106, 107, 5, 111, 0, 0, 107, 108, - 5, 118, 0, 0, 108, 109, 5, 101, 0, 0, 109, 110, 5, 114, 0, 0, 110, 111, - 5, 100, 0, 0, 111, 112, 5, 114, 0, 0, 112, 113, 5, 97, 0, 0, 113, 114, - 5, 102, 0, 0, 114, 115, 5, 116, 0, 0, 115, 116, 5, 32, 0, 0, 116, 117, - 5, 117, 0, 0, 117, 118, 5, 112, 0, 0, 118, 119, 5, 32, 0, 0, 119, 120, - 5, 116, 0, 0, 120, 121, 5, 111, 0, 0, 121, 4, 1, 0, 0, 0, 122, 123, 5, - 97, 0, 0, 123, 124, 5, 108, 0, 0, 124, 125, 5, 108, 0, 0, 125, 126, 5, - 111, 0, 0, 126, 127, 5, 119, 0, 0, 127, 128, 5, 105, 0, 0, 128, 129, 5, - 110, 0, 0, 129, 130, 5, 103, 0, 0, 130, 131, 5, 32, 0, 0, 131, 132, 5, - 117, 0, 0, 132, 133, 5, 110, 0, 0, 133, 134, 5, 98, 0, 0, 134, 135, 5, - 111, 0, 0, 135, 136, 5, 117, 0, 0, 136, 137, 5, 110, 0, 0, 137, 138, 5, - 100, 0, 0, 138, 139, 5, 101, 0, 0, 139, 140, 5, 100, 0, 0, 140, 141, 5, - 32, 0, 0, 141, 142, 5, 111, 0, 0, 142, 143, 5, 118, 0, 0, 143, 144, 5, - 101, 0, 0, 144, 145, 5, 114, 0, 0, 145, 146, 5, 100, 0, 0, 146, 147, 5, - 114, 0, 0, 147, 148, 5, 97, 0, 0, 148, 149, 5, 102, 0, 0, 149, 150, 5, - 116, 0, 0, 150, 6, 1, 0, 0, 0, 151, 152, 5, 44, 0, 0, 152, 8, 1, 0, 0, - 0, 153, 155, 7, 0, 0, 0, 154, 153, 1, 0, 0, 0, 155, 156, 1, 0, 0, 0, 156, - 154, 1, 0, 0, 0, 156, 157, 1, 0, 0, 0, 157, 10, 1, 0, 0, 0, 158, 160, 7, - 1, 0, 0, 159, 158, 1, 0, 0, 0, 160, 161, 1, 0, 0, 0, 161, 159, 1, 0, 0, - 0, 161, 162, 1, 0, 0, 0, 162, 163, 1, 0, 0, 0, 163, 164, 6, 5, 0, 0, 164, - 12, 1, 0, 0, 0, 165, 166, 5, 47, 0, 0, 166, 167, 5, 42, 0, 0, 167, 172, - 1, 0, 0, 0, 168, 171, 3, 13, 6, 0, 169, 171, 9, 0, 0, 0, 170, 168, 1, 0, - 0, 0, 170, 169, 1, 0, 0, 0, 171, 174, 1, 0, 0, 0, 172, 173, 1, 0, 0, 0, - 172, 170, 1, 0, 0, 0, 173, 175, 1, 0, 0, 0, 174, 172, 1, 0, 0, 0, 175, - 176, 5, 42, 0, 0, 176, 177, 5, 47, 0, 0, 177, 178, 1, 0, 0, 0, 178, 179, - 6, 6, 0, 0, 179, 14, 1, 0, 0, 0, 180, 181, 5, 47, 0, 0, 181, 182, 5, 47, - 0, 0, 182, 186, 1, 0, 0, 0, 183, 185, 9, 0, 0, 0, 184, 183, 1, 0, 0, 0, - 185, 188, 1, 0, 0, 0, 186, 187, 1, 0, 0, 0, 186, 184, 1, 0, 0, 0, 187, - 189, 1, 0, 0, 0, 188, 186, 1, 0, 0, 0, 189, 190, 3, 9, 4, 0, 190, 191, - 1, 0, 0, 0, 191, 192, 6, 7, 0, 0, 192, 16, 1, 0, 0, 0, 193, 194, 5, 118, - 0, 0, 194, 195, 5, 97, 0, 0, 195, 196, 5, 114, 0, 0, 196, 197, 5, 115, - 0, 0, 197, 18, 1, 0, 0, 0, 198, 199, 5, 109, 0, 0, 199, 200, 5, 101, 0, - 0, 200, 201, 5, 116, 0, 0, 201, 202, 5, 97, 0, 0, 202, 20, 1, 0, 0, 0, - 203, 204, 5, 115, 0, 0, 204, 205, 5, 101, 0, 0, 205, 206, 5, 116, 0, 0, - 206, 207, 5, 95, 0, 0, 207, 208, 5, 116, 0, 0, 208, 209, 5, 120, 0, 0, - 209, 210, 5, 95, 0, 0, 210, 211, 5, 109, 0, 0, 211, 212, 5, 101, 0, 0, - 212, 213, 5, 116, 0, 0, 213, 214, 5, 97, 0, 0, 214, 22, 1, 0, 0, 0, 215, - 216, 5, 115, 0, 0, 216, 217, 5, 101, 0, 0, 217, 218, 5, 116, 0, 0, 218, - 219, 5, 95, 0, 0, 219, 220, 5, 97, 0, 0, 220, 221, 5, 99, 0, 0, 221, 222, - 5, 99, 0, 0, 222, 223, 5, 111, 0, 0, 223, 224, 5, 117, 0, 0, 224, 225, - 5, 110, 0, 0, 225, 226, 5, 116, 0, 0, 226, 227, 5, 95, 0, 0, 227, 228, - 5, 109, 0, 0, 228, 229, 5, 101, 0, 0, 229, 230, 5, 116, 0, 0, 230, 231, - 5, 97, 0, 0, 231, 24, 1, 0, 0, 0, 232, 233, 5, 112, 0, 0, 233, 234, 5, - 114, 0, 0, 234, 235, 5, 105, 0, 0, 235, 236, 5, 110, 0, 0, 236, 237, 5, - 116, 0, 0, 237, 26, 1, 0, 0, 0, 238, 239, 5, 102, 0, 0, 239, 240, 5, 97, - 0, 0, 240, 241, 5, 105, 0, 0, 241, 242, 5, 108, 0, 0, 242, 28, 1, 0, 0, - 0, 243, 244, 5, 115, 0, 0, 244, 245, 5, 101, 0, 0, 245, 246, 5, 110, 0, - 0, 246, 247, 5, 100, 0, 0, 247, 30, 1, 0, 0, 0, 248, 249, 5, 115, 0, 0, - 249, 250, 5, 111, 0, 0, 250, 251, 5, 117, 0, 0, 251, 252, 5, 114, 0, 0, - 252, 253, 5, 99, 0, 0, 253, 254, 5, 101, 0, 0, 254, 32, 1, 0, 0, 0, 255, - 256, 5, 102, 0, 0, 256, 257, 5, 114, 0, 0, 257, 258, 5, 111, 0, 0, 258, - 259, 5, 109, 0, 0, 259, 34, 1, 0, 0, 0, 260, 261, 5, 109, 0, 0, 261, 262, - 5, 97, 0, 0, 262, 263, 5, 120, 0, 0, 263, 36, 1, 0, 0, 0, 264, 265, 5, - 100, 0, 0, 265, 266, 5, 101, 0, 0, 266, 267, 5, 115, 0, 0, 267, 268, 5, - 116, 0, 0, 268, 269, 5, 105, 0, 0, 269, 270, 5, 110, 0, 0, 270, 271, 5, - 97, 0, 0, 271, 272, 5, 116, 0, 0, 272, 273, 5, 105, 0, 0, 273, 274, 5, - 111, 0, 0, 274, 275, 5, 110, 0, 0, 275, 38, 1, 0, 0, 0, 276, 277, 5, 116, - 0, 0, 277, 278, 5, 111, 0, 0, 278, 40, 1, 0, 0, 0, 279, 280, 5, 97, 0, - 0, 280, 281, 5, 108, 0, 0, 281, 282, 5, 108, 0, 0, 282, 283, 5, 111, 0, - 0, 283, 284, 5, 99, 0, 0, 284, 285, 5, 97, 0, 0, 285, 286, 5, 116, 0, 0, - 286, 287, 5, 101, 0, 0, 287, 42, 1, 0, 0, 0, 288, 289, 5, 43, 0, 0, 289, - 44, 1, 0, 0, 0, 290, 291, 5, 45, 0, 0, 291, 46, 1, 0, 0, 0, 292, 293, 5, - 40, 0, 0, 293, 48, 1, 0, 0, 0, 294, 295, 5, 41, 0, 0, 295, 50, 1, 0, 0, - 0, 296, 297, 5, 91, 0, 0, 297, 52, 1, 0, 0, 0, 298, 299, 5, 93, 0, 0, 299, - 54, 1, 0, 0, 0, 300, 301, 5, 123, 0, 0, 301, 56, 1, 0, 0, 0, 302, 303, - 5, 125, 0, 0, 303, 58, 1, 0, 0, 0, 304, 305, 5, 61, 0, 0, 305, 60, 1, 0, - 0, 0, 306, 307, 5, 97, 0, 0, 307, 308, 5, 99, 0, 0, 308, 309, 5, 99, 0, - 0, 309, 310, 5, 111, 0, 0, 310, 311, 5, 117, 0, 0, 311, 312, 5, 110, 0, - 0, 312, 313, 5, 116, 0, 0, 313, 62, 1, 0, 0, 0, 314, 315, 5, 97, 0, 0, - 315, 316, 5, 115, 0, 0, 316, 317, 5, 115, 0, 0, 317, 318, 5, 101, 0, 0, - 318, 319, 5, 116, 0, 0, 319, 64, 1, 0, 0, 0, 320, 321, 5, 110, 0, 0, 321, - 322, 5, 117, 0, 0, 322, 323, 5, 109, 0, 0, 323, 324, 5, 98, 0, 0, 324, - 325, 5, 101, 0, 0, 325, 326, 5, 114, 0, 0, 326, 66, 1, 0, 0, 0, 327, 328, - 5, 109, 0, 0, 328, 329, 5, 111, 0, 0, 329, 330, 5, 110, 0, 0, 330, 331, - 5, 101, 0, 0, 331, 332, 5, 116, 0, 0, 332, 333, 5, 97, 0, 0, 333, 334, - 5, 114, 0, 0, 334, 335, 5, 121, 0, 0, 335, 68, 1, 0, 0, 0, 336, 337, 5, - 112, 0, 0, 337, 338, 5, 111, 0, 0, 338, 339, 5, 114, 0, 0, 339, 340, 5, - 116, 0, 0, 340, 341, 5, 105, 0, 0, 341, 342, 5, 111, 0, 0, 342, 343, 5, - 110, 0, 0, 343, 70, 1, 0, 0, 0, 344, 345, 5, 115, 0, 0, 345, 346, 5, 116, - 0, 0, 346, 347, 5, 114, 0, 0, 347, 348, 5, 105, 0, 0, 348, 349, 5, 110, - 0, 0, 349, 350, 5, 103, 0, 0, 350, 72, 1, 0, 0, 0, 351, 355, 5, 34, 0, - 0, 352, 354, 7, 2, 0, 0, 353, 352, 1, 0, 0, 0, 354, 357, 1, 0, 0, 0, 355, - 353, 1, 0, 0, 0, 355, 356, 1, 0, 0, 0, 356, 358, 1, 0, 0, 0, 357, 355, - 1, 0, 0, 0, 358, 359, 5, 34, 0, 0, 359, 74, 1, 0, 0, 0, 360, 362, 7, 3, - 0, 0, 361, 360, 1, 0, 0, 0, 362, 363, 1, 0, 0, 0, 363, 361, 1, 0, 0, 0, - 363, 364, 1, 0, 0, 0, 364, 366, 1, 0, 0, 0, 365, 367, 7, 4, 0, 0, 366, - 365, 1, 0, 0, 0, 366, 367, 1, 0, 0, 0, 367, 368, 1, 0, 0, 0, 368, 370, - 5, 47, 0, 0, 369, 371, 7, 4, 0, 0, 370, 369, 1, 0, 0, 0, 370, 371, 1, 0, - 0, 0, 371, 373, 1, 0, 0, 0, 372, 374, 7, 3, 0, 0, 373, 372, 1, 0, 0, 0, - 374, 375, 1, 0, 0, 0, 375, 373, 1, 0, 0, 0, 375, 376, 1, 0, 0, 0, 376, - 392, 1, 0, 0, 0, 377, 379, 7, 3, 0, 0, 378, 377, 1, 0, 0, 0, 379, 380, - 1, 0, 0, 0, 380, 378, 1, 0, 0, 0, 380, 381, 1, 0, 0, 0, 381, 388, 1, 0, - 0, 0, 382, 384, 5, 46, 0, 0, 383, 385, 7, 3, 0, 0, 384, 383, 1, 0, 0, 0, - 385, 386, 1, 0, 0, 0, 386, 384, 1, 0, 0, 0, 386, 387, 1, 0, 0, 0, 387, - 389, 1, 0, 0, 0, 388, 382, 1, 0, 0, 0, 388, 389, 1, 0, 0, 0, 389, 390, - 1, 0, 0, 0, 390, 392, 5, 37, 0, 0, 391, 361, 1, 0, 0, 0, 391, 378, 1, 0, - 0, 0, 392, 76, 1, 0, 0, 0, 393, 394, 5, 114, 0, 0, 394, 395, 5, 101, 0, - 0, 395, 396, 5, 109, 0, 0, 396, 397, 5, 97, 0, 0, 397, 398, 5, 105, 0, - 0, 398, 399, 5, 110, 0, 0, 399, 400, 5, 105, 0, 0, 400, 401, 5, 110, 0, - 0, 401, 402, 5, 103, 0, 0, 402, 78, 1, 0, 0, 0, 403, 404, 5, 107, 0, 0, - 404, 405, 5, 101, 0, 0, 405, 406, 5, 112, 0, 0, 406, 407, 5, 116, 0, 0, - 407, 80, 1, 0, 0, 0, 408, 409, 5, 98, 0, 0, 409, 410, 5, 97, 0, 0, 410, - 411, 5, 108, 0, 0, 411, 412, 5, 97, 0, 0, 412, 413, 5, 110, 0, 0, 413, - 414, 5, 99, 0, 0, 414, 415, 5, 101, 0, 0, 415, 82, 1, 0, 0, 0, 416, 417, - 5, 115, 0, 0, 417, 418, 5, 97, 0, 0, 418, 419, 5, 118, 0, 0, 419, 420, - 5, 101, 0, 0, 420, 84, 1, 0, 0, 0, 421, 423, 7, 3, 0, 0, 422, 421, 1, 0, - 0, 0, 423, 424, 1, 0, 0, 0, 424, 422, 1, 0, 0, 0, 424, 425, 1, 0, 0, 0, - 425, 86, 1, 0, 0, 0, 426, 427, 5, 37, 0, 0, 427, 88, 1, 0, 0, 0, 428, 430, - 5, 36, 0, 0, 429, 431, 7, 5, 0, 0, 430, 429, 1, 0, 0, 0, 431, 432, 1, 0, - 0, 0, 432, 430, 1, 0, 0, 0, 432, 433, 1, 0, 0, 0, 433, 437, 1, 0, 0, 0, - 434, 436, 7, 6, 0, 0, 435, 434, 1, 0, 0, 0, 436, 439, 1, 0, 0, 0, 437, - 435, 1, 0, 0, 0, 437, 438, 1, 0, 0, 0, 438, 90, 1, 0, 0, 0, 439, 437, 1, - 0, 0, 0, 440, 442, 5, 64, 0, 0, 441, 443, 7, 7, 0, 0, 442, 441, 1, 0, 0, - 0, 443, 444, 1, 0, 0, 0, 444, 442, 1, 0, 0, 0, 444, 445, 1, 0, 0, 0, 445, - 449, 1, 0, 0, 0, 446, 448, 7, 8, 0, 0, 447, 446, 1, 0, 0, 0, 448, 451, - 1, 0, 0, 0, 449, 447, 1, 0, 0, 0, 449, 450, 1, 0, 0, 0, 450, 92, 1, 0, - 0, 0, 451, 449, 1, 0, 0, 0, 452, 454, 7, 9, 0, 0, 453, 452, 1, 0, 0, 0, - 454, 455, 1, 0, 0, 0, 455, 453, 1, 0, 0, 0, 455, 456, 1, 0, 0, 0, 456, - 94, 1, 0, 0, 0, 21, 0, 156, 161, 170, 172, 186, 355, 363, 366, 370, 375, - 380, 386, 388, 391, 424, 432, 437, 444, 449, 455, 1, 6, 0, 0, + 1, 45, 4, 45, 443, 8, 45, 11, 45, 12, 45, 444, 1, 45, 1, 45, 4, 45, 449, + 8, 45, 11, 45, 12, 45, 450, 5, 45, 453, 8, 45, 10, 45, 12, 45, 456, 9, + 45, 1, 46, 4, 46, 459, 8, 46, 11, 46, 12, 46, 460, 2, 172, 186, 0, 47, + 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, + 23, 12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, + 41, 21, 43, 22, 45, 23, 47, 24, 49, 25, 51, 26, 53, 27, 55, 28, 57, 29, + 59, 30, 61, 31, 63, 32, 65, 33, 67, 34, 69, 35, 71, 36, 73, 37, 75, 38, + 77, 39, 79, 40, 81, 41, 83, 42, 85, 43, 87, 44, 89, 45, 91, 46, 93, 47, + 1, 0, 10, 2, 0, 10, 10, 13, 13, 2, 0, 9, 9, 32, 32, 6, 0, 32, 32, 45, 45, + 48, 57, 65, 90, 95, 95, 97, 122, 1, 0, 48, 57, 1, 0, 32, 32, 2, 0, 95, + 95, 97, 122, 3, 0, 48, 57, 95, 95, 97, 122, 4, 0, 48, 57, 65, 90, 95, 95, + 97, 122, 2, 0, 45, 45, 58, 58, 2, 0, 47, 57, 65, 90, 482, 0, 1, 1, 0, 0, + 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, + 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, + 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, + 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, + 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, + 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, + 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, + 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0, 0, 0, 63, 1, 0, + 0, 0, 0, 65, 1, 0, 0, 0, 0, 67, 1, 0, 0, 0, 0, 69, 1, 0, 0, 0, 0, 71, 1, + 0, 0, 0, 0, 73, 1, 0, 0, 0, 0, 75, 1, 0, 0, 0, 0, 77, 1, 0, 0, 0, 0, 79, + 1, 0, 0, 0, 0, 81, 1, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 85, 1, 0, 0, 0, 0, + 87, 1, 0, 0, 0, 0, 89, 1, 0, 0, 0, 0, 91, 1, 0, 0, 0, 0, 93, 1, 0, 0, 0, + 1, 95, 1, 0, 0, 0, 3, 97, 1, 0, 0, 0, 5, 122, 1, 0, 0, 0, 7, 151, 1, 0, + 0, 0, 9, 154, 1, 0, 0, 0, 11, 159, 1, 0, 0, 0, 13, 165, 1, 0, 0, 0, 15, + 180, 1, 0, 0, 0, 17, 193, 1, 0, 0, 0, 19, 198, 1, 0, 0, 0, 21, 203, 1, + 0, 0, 0, 23, 215, 1, 0, 0, 0, 25, 232, 1, 0, 0, 0, 27, 238, 1, 0, 0, 0, + 29, 243, 1, 0, 0, 0, 31, 248, 1, 0, 0, 0, 33, 255, 1, 0, 0, 0, 35, 260, + 1, 0, 0, 0, 37, 264, 1, 0, 0, 0, 39, 276, 1, 0, 0, 0, 41, 279, 1, 0, 0, + 0, 43, 288, 1, 0, 0, 0, 45, 290, 1, 0, 0, 0, 47, 292, 1, 0, 0, 0, 49, 294, + 1, 0, 0, 0, 51, 296, 1, 0, 0, 0, 53, 298, 1, 0, 0, 0, 55, 300, 1, 0, 0, + 0, 57, 302, 1, 0, 0, 0, 59, 304, 1, 0, 0, 0, 61, 306, 1, 0, 0, 0, 63, 314, + 1, 0, 0, 0, 65, 320, 1, 0, 0, 0, 67, 327, 1, 0, 0, 0, 69, 336, 1, 0, 0, + 0, 71, 344, 1, 0, 0, 0, 73, 351, 1, 0, 0, 0, 75, 391, 1, 0, 0, 0, 77, 393, + 1, 0, 0, 0, 79, 403, 1, 0, 0, 0, 81, 408, 1, 0, 0, 0, 83, 416, 1, 0, 0, + 0, 85, 422, 1, 0, 0, 0, 87, 426, 1, 0, 0, 0, 89, 428, 1, 0, 0, 0, 91, 440, + 1, 0, 0, 0, 93, 458, 1, 0, 0, 0, 95, 96, 5, 42, 0, 0, 96, 2, 1, 0, 0, 0, + 97, 98, 5, 97, 0, 0, 98, 99, 5, 108, 0, 0, 99, 100, 5, 108, 0, 0, 100, + 101, 5, 111, 0, 0, 101, 102, 5, 119, 0, 0, 102, 103, 5, 105, 0, 0, 103, + 104, 5, 110, 0, 0, 104, 105, 5, 103, 0, 0, 105, 106, 5, 32, 0, 0, 106, + 107, 5, 111, 0, 0, 107, 108, 5, 118, 0, 0, 108, 109, 5, 101, 0, 0, 109, + 110, 5, 114, 0, 0, 110, 111, 5, 100, 0, 0, 111, 112, 5, 114, 0, 0, 112, + 113, 5, 97, 0, 0, 113, 114, 5, 102, 0, 0, 114, 115, 5, 116, 0, 0, 115, + 116, 5, 32, 0, 0, 116, 117, 5, 117, 0, 0, 117, 118, 5, 112, 0, 0, 118, + 119, 5, 32, 0, 0, 119, 120, 5, 116, 0, 0, 120, 121, 5, 111, 0, 0, 121, + 4, 1, 0, 0, 0, 122, 123, 5, 97, 0, 0, 123, 124, 5, 108, 0, 0, 124, 125, + 5, 108, 0, 0, 125, 126, 5, 111, 0, 0, 126, 127, 5, 119, 0, 0, 127, 128, + 5, 105, 0, 0, 128, 129, 5, 110, 0, 0, 129, 130, 5, 103, 0, 0, 130, 131, + 5, 32, 0, 0, 131, 132, 5, 117, 0, 0, 132, 133, 5, 110, 0, 0, 133, 134, + 5, 98, 0, 0, 134, 135, 5, 111, 0, 0, 135, 136, 5, 117, 0, 0, 136, 137, + 5, 110, 0, 0, 137, 138, 5, 100, 0, 0, 138, 139, 5, 101, 0, 0, 139, 140, + 5, 100, 0, 0, 140, 141, 5, 32, 0, 0, 141, 142, 5, 111, 0, 0, 142, 143, + 5, 118, 0, 0, 143, 144, 5, 101, 0, 0, 144, 145, 5, 114, 0, 0, 145, 146, + 5, 100, 0, 0, 146, 147, 5, 114, 0, 0, 147, 148, 5, 97, 0, 0, 148, 149, + 5, 102, 0, 0, 149, 150, 5, 116, 0, 0, 150, 6, 1, 0, 0, 0, 151, 152, 5, + 44, 0, 0, 152, 8, 1, 0, 0, 0, 153, 155, 7, 0, 0, 0, 154, 153, 1, 0, 0, + 0, 155, 156, 1, 0, 0, 0, 156, 154, 1, 0, 0, 0, 156, 157, 1, 0, 0, 0, 157, + 10, 1, 0, 0, 0, 158, 160, 7, 1, 0, 0, 159, 158, 1, 0, 0, 0, 160, 161, 1, + 0, 0, 0, 161, 159, 1, 0, 0, 0, 161, 162, 1, 0, 0, 0, 162, 163, 1, 0, 0, + 0, 163, 164, 6, 5, 0, 0, 164, 12, 1, 0, 0, 0, 165, 166, 5, 47, 0, 0, 166, + 167, 5, 42, 0, 0, 167, 172, 1, 0, 0, 0, 168, 171, 3, 13, 6, 0, 169, 171, + 9, 0, 0, 0, 170, 168, 1, 0, 0, 0, 170, 169, 1, 0, 0, 0, 171, 174, 1, 0, + 0, 0, 172, 173, 1, 0, 0, 0, 172, 170, 1, 0, 0, 0, 173, 175, 1, 0, 0, 0, + 174, 172, 1, 0, 0, 0, 175, 176, 5, 42, 0, 0, 176, 177, 5, 47, 0, 0, 177, + 178, 1, 0, 0, 0, 178, 179, 6, 6, 0, 0, 179, 14, 1, 0, 0, 0, 180, 181, 5, + 47, 0, 0, 181, 182, 5, 47, 0, 0, 182, 186, 1, 0, 0, 0, 183, 185, 9, 0, + 0, 0, 184, 183, 1, 0, 0, 0, 185, 188, 1, 0, 0, 0, 186, 187, 1, 0, 0, 0, + 186, 184, 1, 0, 0, 0, 187, 189, 1, 0, 0, 0, 188, 186, 1, 0, 0, 0, 189, + 190, 3, 9, 4, 0, 190, 191, 1, 0, 0, 0, 191, 192, 6, 7, 0, 0, 192, 16, 1, + 0, 0, 0, 193, 194, 5, 118, 0, 0, 194, 195, 5, 97, 0, 0, 195, 196, 5, 114, + 0, 0, 196, 197, 5, 115, 0, 0, 197, 18, 1, 0, 0, 0, 198, 199, 5, 109, 0, + 0, 199, 200, 5, 101, 0, 0, 200, 201, 5, 116, 0, 0, 201, 202, 5, 97, 0, + 0, 202, 20, 1, 0, 0, 0, 203, 204, 5, 115, 0, 0, 204, 205, 5, 101, 0, 0, + 205, 206, 5, 116, 0, 0, 206, 207, 5, 95, 0, 0, 207, 208, 5, 116, 0, 0, + 208, 209, 5, 120, 0, 0, 209, 210, 5, 95, 0, 0, 210, 211, 5, 109, 0, 0, + 211, 212, 5, 101, 0, 0, 212, 213, 5, 116, 0, 0, 213, 214, 5, 97, 0, 0, + 214, 22, 1, 0, 0, 0, 215, 216, 5, 115, 0, 0, 216, 217, 5, 101, 0, 0, 217, + 218, 5, 116, 0, 0, 218, 219, 5, 95, 0, 0, 219, 220, 5, 97, 0, 0, 220, 221, + 5, 99, 0, 0, 221, 222, 5, 99, 0, 0, 222, 223, 5, 111, 0, 0, 223, 224, 5, + 117, 0, 0, 224, 225, 5, 110, 0, 0, 225, 226, 5, 116, 0, 0, 226, 227, 5, + 95, 0, 0, 227, 228, 5, 109, 0, 0, 228, 229, 5, 101, 0, 0, 229, 230, 5, + 116, 0, 0, 230, 231, 5, 97, 0, 0, 231, 24, 1, 0, 0, 0, 232, 233, 5, 112, + 0, 0, 233, 234, 5, 114, 0, 0, 234, 235, 5, 105, 0, 0, 235, 236, 5, 110, + 0, 0, 236, 237, 5, 116, 0, 0, 237, 26, 1, 0, 0, 0, 238, 239, 5, 102, 0, + 0, 239, 240, 5, 97, 0, 0, 240, 241, 5, 105, 0, 0, 241, 242, 5, 108, 0, + 0, 242, 28, 1, 0, 0, 0, 243, 244, 5, 115, 0, 0, 244, 245, 5, 101, 0, 0, + 245, 246, 5, 110, 0, 0, 246, 247, 5, 100, 0, 0, 247, 30, 1, 0, 0, 0, 248, + 249, 5, 115, 0, 0, 249, 250, 5, 111, 0, 0, 250, 251, 5, 117, 0, 0, 251, + 252, 5, 114, 0, 0, 252, 253, 5, 99, 0, 0, 253, 254, 5, 101, 0, 0, 254, + 32, 1, 0, 0, 0, 255, 256, 5, 102, 0, 0, 256, 257, 5, 114, 0, 0, 257, 258, + 5, 111, 0, 0, 258, 259, 5, 109, 0, 0, 259, 34, 1, 0, 0, 0, 260, 261, 5, + 109, 0, 0, 261, 262, 5, 97, 0, 0, 262, 263, 5, 120, 0, 0, 263, 36, 1, 0, + 0, 0, 264, 265, 5, 100, 0, 0, 265, 266, 5, 101, 0, 0, 266, 267, 5, 115, + 0, 0, 267, 268, 5, 116, 0, 0, 268, 269, 5, 105, 0, 0, 269, 270, 5, 110, + 0, 0, 270, 271, 5, 97, 0, 0, 271, 272, 5, 116, 0, 0, 272, 273, 5, 105, + 0, 0, 273, 274, 5, 111, 0, 0, 274, 275, 5, 110, 0, 0, 275, 38, 1, 0, 0, + 0, 276, 277, 5, 116, 0, 0, 277, 278, 5, 111, 0, 0, 278, 40, 1, 0, 0, 0, + 279, 280, 5, 97, 0, 0, 280, 281, 5, 108, 0, 0, 281, 282, 5, 108, 0, 0, + 282, 283, 5, 111, 0, 0, 283, 284, 5, 99, 0, 0, 284, 285, 5, 97, 0, 0, 285, + 286, 5, 116, 0, 0, 286, 287, 5, 101, 0, 0, 287, 42, 1, 0, 0, 0, 288, 289, + 5, 43, 0, 0, 289, 44, 1, 0, 0, 0, 290, 291, 5, 45, 0, 0, 291, 46, 1, 0, + 0, 0, 292, 293, 5, 40, 0, 0, 293, 48, 1, 0, 0, 0, 294, 295, 5, 41, 0, 0, + 295, 50, 1, 0, 0, 0, 296, 297, 5, 91, 0, 0, 297, 52, 1, 0, 0, 0, 298, 299, + 5, 93, 0, 0, 299, 54, 1, 0, 0, 0, 300, 301, 5, 123, 0, 0, 301, 56, 1, 0, + 0, 0, 302, 303, 5, 125, 0, 0, 303, 58, 1, 0, 0, 0, 304, 305, 5, 61, 0, + 0, 305, 60, 1, 0, 0, 0, 306, 307, 5, 97, 0, 0, 307, 308, 5, 99, 0, 0, 308, + 309, 5, 99, 0, 0, 309, 310, 5, 111, 0, 0, 310, 311, 5, 117, 0, 0, 311, + 312, 5, 110, 0, 0, 312, 313, 5, 116, 0, 0, 313, 62, 1, 0, 0, 0, 314, 315, + 5, 97, 0, 0, 315, 316, 5, 115, 0, 0, 316, 317, 5, 115, 0, 0, 317, 318, + 5, 101, 0, 0, 318, 319, 5, 116, 0, 0, 319, 64, 1, 0, 0, 0, 320, 321, 5, + 110, 0, 0, 321, 322, 5, 117, 0, 0, 322, 323, 5, 109, 0, 0, 323, 324, 5, + 98, 0, 0, 324, 325, 5, 101, 0, 0, 325, 326, 5, 114, 0, 0, 326, 66, 1, 0, + 0, 0, 327, 328, 5, 109, 0, 0, 328, 329, 5, 111, 0, 0, 329, 330, 5, 110, + 0, 0, 330, 331, 5, 101, 0, 0, 331, 332, 5, 116, 0, 0, 332, 333, 5, 97, + 0, 0, 333, 334, 5, 114, 0, 0, 334, 335, 5, 121, 0, 0, 335, 68, 1, 0, 0, + 0, 336, 337, 5, 112, 0, 0, 337, 338, 5, 111, 0, 0, 338, 339, 5, 114, 0, + 0, 339, 340, 5, 116, 0, 0, 340, 341, 5, 105, 0, 0, 341, 342, 5, 111, 0, + 0, 342, 343, 5, 110, 0, 0, 343, 70, 1, 0, 0, 0, 344, 345, 5, 115, 0, 0, + 345, 346, 5, 116, 0, 0, 346, 347, 5, 114, 0, 0, 347, 348, 5, 105, 0, 0, + 348, 349, 5, 110, 0, 0, 349, 350, 5, 103, 0, 0, 350, 72, 1, 0, 0, 0, 351, + 355, 5, 34, 0, 0, 352, 354, 7, 2, 0, 0, 353, 352, 1, 0, 0, 0, 354, 357, + 1, 0, 0, 0, 355, 353, 1, 0, 0, 0, 355, 356, 1, 0, 0, 0, 356, 358, 1, 0, + 0, 0, 357, 355, 1, 0, 0, 0, 358, 359, 5, 34, 0, 0, 359, 74, 1, 0, 0, 0, + 360, 362, 7, 3, 0, 0, 361, 360, 1, 0, 0, 0, 362, 363, 1, 0, 0, 0, 363, + 361, 1, 0, 0, 0, 363, 364, 1, 0, 0, 0, 364, 366, 1, 0, 0, 0, 365, 367, + 7, 4, 0, 0, 366, 365, 1, 0, 0, 0, 366, 367, 1, 0, 0, 0, 367, 368, 1, 0, + 0, 0, 368, 370, 5, 47, 0, 0, 369, 371, 7, 4, 0, 0, 370, 369, 1, 0, 0, 0, + 370, 371, 1, 0, 0, 0, 371, 373, 1, 0, 0, 0, 372, 374, 7, 3, 0, 0, 373, + 372, 1, 0, 0, 0, 374, 375, 1, 0, 0, 0, 375, 373, 1, 0, 0, 0, 375, 376, + 1, 0, 0, 0, 376, 392, 1, 0, 0, 0, 377, 379, 7, 3, 0, 0, 378, 377, 1, 0, + 0, 0, 379, 380, 1, 0, 0, 0, 380, 378, 1, 0, 0, 0, 380, 381, 1, 0, 0, 0, + 381, 388, 1, 0, 0, 0, 382, 384, 5, 46, 0, 0, 383, 385, 7, 3, 0, 0, 384, + 383, 1, 0, 0, 0, 385, 386, 1, 0, 0, 0, 386, 384, 1, 0, 0, 0, 386, 387, + 1, 0, 0, 0, 387, 389, 1, 0, 0, 0, 388, 382, 1, 0, 0, 0, 388, 389, 1, 0, + 0, 0, 389, 390, 1, 0, 0, 0, 390, 392, 5, 37, 0, 0, 391, 361, 1, 0, 0, 0, + 391, 378, 1, 0, 0, 0, 392, 76, 1, 0, 0, 0, 393, 394, 5, 114, 0, 0, 394, + 395, 5, 101, 0, 0, 395, 396, 5, 109, 0, 0, 396, 397, 5, 97, 0, 0, 397, + 398, 5, 105, 0, 0, 398, 399, 5, 110, 0, 0, 399, 400, 5, 105, 0, 0, 400, + 401, 5, 110, 0, 0, 401, 402, 5, 103, 0, 0, 402, 78, 1, 0, 0, 0, 403, 404, + 5, 107, 0, 0, 404, 405, 5, 101, 0, 0, 405, 406, 5, 112, 0, 0, 406, 407, + 5, 116, 0, 0, 407, 80, 1, 0, 0, 0, 408, 409, 5, 98, 0, 0, 409, 410, 5, + 97, 0, 0, 410, 411, 5, 108, 0, 0, 411, 412, 5, 97, 0, 0, 412, 413, 5, 110, + 0, 0, 413, 414, 5, 99, 0, 0, 414, 415, 5, 101, 0, 0, 415, 82, 1, 0, 0, + 0, 416, 417, 5, 115, 0, 0, 417, 418, 5, 97, 0, 0, 418, 419, 5, 118, 0, + 0, 419, 420, 5, 101, 0, 0, 420, 84, 1, 0, 0, 0, 421, 423, 7, 3, 0, 0, 422, + 421, 1, 0, 0, 0, 423, 424, 1, 0, 0, 0, 424, 422, 1, 0, 0, 0, 424, 425, + 1, 0, 0, 0, 425, 86, 1, 0, 0, 0, 426, 427, 5, 37, 0, 0, 427, 88, 1, 0, + 0, 0, 428, 430, 5, 36, 0, 0, 429, 431, 7, 5, 0, 0, 430, 429, 1, 0, 0, 0, + 431, 432, 1, 0, 0, 0, 432, 430, 1, 0, 0, 0, 432, 433, 1, 0, 0, 0, 433, + 437, 1, 0, 0, 0, 434, 436, 7, 6, 0, 0, 435, 434, 1, 0, 0, 0, 436, 439, + 1, 0, 0, 0, 437, 435, 1, 0, 0, 0, 437, 438, 1, 0, 0, 0, 438, 90, 1, 0, + 0, 0, 439, 437, 1, 0, 0, 0, 440, 442, 5, 64, 0, 0, 441, 443, 7, 7, 0, 0, + 442, 441, 1, 0, 0, 0, 443, 444, 1, 0, 0, 0, 444, 442, 1, 0, 0, 0, 444, + 445, 1, 0, 0, 0, 445, 454, 1, 0, 0, 0, 446, 448, 7, 8, 0, 0, 447, 449, + 7, 7, 0, 0, 448, 447, 1, 0, 0, 0, 449, 450, 1, 0, 0, 0, 450, 448, 1, 0, + 0, 0, 450, 451, 1, 0, 0, 0, 451, 453, 1, 0, 0, 0, 452, 446, 1, 0, 0, 0, + 453, 456, 1, 0, 0, 0, 454, 452, 1, 0, 0, 0, 454, 455, 1, 0, 0, 0, 455, + 92, 1, 0, 0, 0, 456, 454, 1, 0, 0, 0, 457, 459, 7, 9, 0, 0, 458, 457, 1, + 0, 0, 0, 459, 460, 1, 0, 0, 0, 460, 458, 1, 0, 0, 0, 460, 461, 1, 0, 0, + 0, 461, 94, 1, 0, 0, 0, 22, 0, 156, 161, 170, 172, 186, 355, 363, 366, + 370, 375, 380, 386, 388, 391, 424, 432, 437, 444, 450, 454, 460, 1, 6, + 0, 0, } deserializer := antlr.NewATNDeserializer(nil) staticData.atn = deserializer.Deserialize(staticData.serializedATN) diff --git a/internal/machine/vm/machine_test.go b/internal/machine/vm/machine_test.go index 43a720220..f9f34fcc6 100644 --- a/internal/machine/vm/machine_test.go +++ b/internal/machine/vm/machine_test.go @@ -1292,8 +1292,16 @@ func TestVariablesParsing(t *testing.T) { "acc": "valid:acc", })) + require.NoError(t, m.SetVarsFromJSON(map[string]string{ + "acc": "valid-acc", + })) + + require.NoError(t, m.SetVarsFromJSON(map[string]string{ + "acc": "account:valid-acc", + })) + require.Error(t, m.SetVarsFromJSON(map[string]string{ - "acc": "invalid-acc", + "acc": "account:invalid--acc", })) require.NoError(t, m.SetVarsFromJSON(map[string]string{ @@ -1301,7 +1309,7 @@ func TestVariablesParsing(t *testing.T) { })) require.Error(t, m.SetVarsFromJSON(map[string]string{ - "acc": "invalid-acc", + "acc": "invalid--acc", })) }) @@ -1552,9 +1560,9 @@ func TestSetVarsFromJSON(t *testing.T) { destination = $dest )`, vars: map[string]string{ - "dest": "invalid-acc", + "dest": "invalid--acc", }, - expectedError: fmt.Errorf("invalid JSON value for variable $dest of type account: value invalid-acc: accounts should respect pattern ^[a-zA-Z0-9_]+(:[a-zA-Z0-9_]+)*$"), + expectedError: fmt.Errorf("invalid JSON value for variable $dest of type account: value invalid--acc: accounts should respect pattern ^[a-zA-Z0-9_]+(?:-[a-zA-Z0-9_]+)*(:[a-zA-Z0-9_]+(?:-[a-zA-Z0-9_]+)*)*$"), }, } { tc := tc @@ -2139,3 +2147,32 @@ send [B 100] ( } test(t, tc) } + +func TestMaxWithUnboundedOverdraft(t *testing.T) { + tc := NewTestCase() + tc.compile(t, ` +send [COIN 100] ( + source = { + max [COIN 10] from @account1 allowing unbounded overdraft + @account2 + } + destination = @world +)`) + tc.setBalance("account1", "COIN", 10000) + tc.setBalance("account2", "COIN", 10000) + tc.expected = CaseResult{ + Printed: []machine.Value{}, + Postings: []Posting{{ + Source: "account1", + Destination: "world", + Amount: machine.NewMonetaryInt(10), + Asset: "COIN", + }, { + Source: "account2", + Destination: "world", + Amount: machine.NewMonetaryInt(90), + Asset: "COIN", + }}, + } + test(t, tc) +} diff --git a/internal/storage/systemstore/migrations.go b/internal/storage/systemstore/migrations.go index 27ab83fc1..5a1f3149c 100644 --- a/internal/storage/systemstore/migrations.go +++ b/internal/storage/systemstore/migrations.go @@ -60,6 +60,20 @@ func Migrate(ctx context.Context, db bun.IDB) error { return sqlutils.PostgresError(err) }, }, + migrations.Migration{ + Name: "Add ledger, bucket naming constraints 63 chars", + UpWithContext: func(ctx context.Context, tx bun.Tx) error { + _, err := tx.ExecContext(ctx, ` + alter table ledgers + alter column ledger type varchar(63), + alter column bucket type varchar(63); + `) + if err != nil { + return err + } + return nil + }, + }, ) return migrator.Up(ctx, db) } diff --git a/libs/Earthfile b/libs/Earthfile index 883aeef19..05a75dd3e 100644 --- a/libs/Earthfile +++ b/libs/Earthfile @@ -1,6 +1,6 @@ -VERSION --arg-scope-and-set --pass-args 0.7 +VERSION --arg-scope-and-set --pass-args --use-function-keyword 0.7 -ARG core=github.com/formancehq/earthly:v0.5.2 +ARG core=github.com/formancehq/earthly:v0.6.0 IMPORT $core AS core FROM core+base-image diff --git a/libs/api/link.go b/libs/api/link.go new file mode 100644 index 000000000..410ffb417 --- /dev/null +++ b/libs/api/link.go @@ -0,0 +1,6 @@ +package api + +type Link struct { + Name string `json:"name"` + URI string `json:"uri"` +} diff --git a/libs/auth/auth.go b/libs/auth/auth.go new file mode 100644 index 000000000..289db2c98 --- /dev/null +++ b/libs/auth/auth.go @@ -0,0 +1,122 @@ +package auth + +import ( + "context" + "fmt" + "net/http" + "os" + "strings" + + "github.com/formancehq/stack/libs/go-libs/collectionutils" + "github.com/formancehq/stack/libs/go-libs/logging" + "github.com/hashicorp/go-retryablehttp" + "github.com/zitadel/oidc/v2/pkg/client/rp" + "github.com/zitadel/oidc/v2/pkg/oidc" + "github.com/zitadel/oidc/v2/pkg/op" + "go.uber.org/zap" +) + +type jwtAuth struct { + logger logging.Logger + httpClient *http.Client + accessTokenVerifier op.AccessTokenVerifier + + issuer string + checkScopes bool + service string +} + +func newOtlpHttpClient(maxRetries int) *http.Client { + retryClient := retryablehttp.NewClient() + retryClient.RetryMax = maxRetries + return retryClient.StandardClient() +} + +func newJWTAuth( + logger logging.Logger, + readKeySetMaxRetries int, + issuer string, + service string, + checkScopes bool, +) *jwtAuth { + return &jwtAuth{ + logger: logger, + httpClient: newOtlpHttpClient(readKeySetMaxRetries), + accessTokenVerifier: nil, + issuer: issuer, + checkScopes: checkScopes, + service: service, + } +} + +// Authenticate validates the JWT in the request and returns the user, if valid. +func (ja *jwtAuth) Authenticate(w http.ResponseWriter, r *http.Request) (bool, error) { + authHeader := r.Header.Get("authorization") + if authHeader == "" { + ja.logger.Error("no authorization header") + return false, fmt.Errorf("no authorization header") + } + + if !strings.HasPrefix(authHeader, strings.ToLower(oidc.PrefixBearer)) && + !strings.HasPrefix(authHeader, oidc.PrefixBearer) { + ja.logger.Error("malformed authorization header") + return false, fmt.Errorf("malformed authorization header") + } + + token := strings.TrimPrefix(authHeader, strings.ToLower(oidc.PrefixBearer)) + token = strings.TrimPrefix(token, oidc.PrefixBearer) + + accessTokenVerifier, err := ja.getAccessTokenVerifier(r.Context()) + if err != nil { + ja.logger.Error("unable to create access token verifier", zap.Error(err)) + return false, fmt.Errorf("unable to create access token verifier: %w", err) + } + + claims, err := op.VerifyAccessToken[*oidc.AccessTokenClaims](r.Context(), token, accessTokenVerifier) + if err != nil { + ja.logger.Error("unable to verify access token", zap.Error(err)) + return false, fmt.Errorf("unable to verify access token: %w", err) + } + + if ja.checkScopes { + scope := claims.Scopes + + allowed := true + switch r.Method { + case http.MethodOptions, http.MethodGet, http.MethodHead, http.MethodTrace: + allowed = allowed && (collectionutils.Contains(scope, ja.service+":read") || collectionutils.Contains(scope, ja.service+":write")) + default: + allowed = allowed && collectionutils.Contains(scope, ja.service+":write") + } + + if !allowed { + ja.logger.Info("not enough scopes") + return false, fmt.Errorf("missing access, found scopes: '%s' need %s:read|write", strings.Join(scope, ", "), ja.service) + } + } + + return true, nil +} + +func (ja *jwtAuth) getAccessTokenVerifier(ctx context.Context) (op.AccessTokenVerifier, error) { + if ja.accessTokenVerifier == nil { + //discoveryConfiguration, err := client.Discover(ja.Issuer, ja.httpClient) + //if err != nil { + // return nil, err + //} + + // todo: ugly quick fix + authServicePort := "8080" + if fromEnv := os.Getenv("AUTH_SERVICE_PORT"); fromEnv != "" { + authServicePort = fromEnv + } + keySet := rp.NewRemoteKeySet(ja.httpClient, fmt.Sprintf("http://auth:%s/keys", authServicePort)) + + ja.accessTokenVerifier = op.NewAccessTokenVerifier( + os.Getenv("STACK_PUBLIC_URL")+"/api/auth", + keySet, + ) + } + + return ja.accessTokenVerifier, nil +} diff --git a/libs/auth/cli.go b/libs/auth/cli.go new file mode 100644 index 000000000..dbb4b6df3 --- /dev/null +++ b/libs/auth/cli.go @@ -0,0 +1,33 @@ +package auth + +import ( + flag "github.com/spf13/pflag" + "github.com/spf13/viper" + "go.uber.org/fx" +) + +const ( + AuthEnabled = "auth-enabled" + AuthIssuerFlag = "auth-issuer" + AuthReadKeySetMaxRetriesFlag = "auth-read-key-set-max-retries" + AuthCheckScopesFlag = "auth-check-scopes" + AuthServiceFlag = "auth-service" +) + +func InitAuthFlags(flags *flag.FlagSet) { + flags.Bool(AuthEnabled, false, "Enable auth") + flags.String(AuthIssuerFlag, "", "Issuer") + flags.Int(AuthReadKeySetMaxRetriesFlag, 10, "ReadKeySetMaxRetries") + flags.Bool(AuthCheckScopesFlag, false, "CheckScopes") + flags.String(AuthServiceFlag, "", "Service") +} + +func CLIAuthModule(v *viper.Viper) fx.Option { + return Module(ModuleConfig{ + Enabled: v.GetBool(AuthEnabled), + Issuer: v.GetString(AuthIssuerFlag), + ReadKeySetMaxRetries: v.GetInt(AuthReadKeySetMaxRetriesFlag), + CheckScopes: v.GetBool(AuthCheckScopesFlag), + Service: v.GetString(AuthServiceFlag), + }) +} diff --git a/libs/auth/middleware.go b/libs/auth/middleware.go new file mode 100644 index 000000000..da4f81bd9 --- /dev/null +++ b/libs/auth/middleware.go @@ -0,0 +1,28 @@ +package auth + +import ( + "net/http" +) + +type Auth interface { + Authenticate(w http.ResponseWriter, r *http.Request) (bool, error) +} + +func Middleware(ja Auth) func(handler http.Handler) http.Handler { + return func(handler http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + authenticated, err := ja.Authenticate(w, r) + if err != nil { + w.WriteHeader(http.StatusUnauthorized) + return + } + + if !authenticated { + w.WriteHeader(http.StatusUnauthorized) + return + } + + handler.ServeHTTP(w, r) + }) + } +} diff --git a/libs/auth/module.go b/libs/auth/module.go new file mode 100644 index 000000000..7bc29379b --- /dev/null +++ b/libs/auth/module.go @@ -0,0 +1,40 @@ +package auth + +import ( + "github.com/formancehq/stack/libs/go-libs/logging" + "go.uber.org/fx" +) + +type ModuleConfig struct { + Enabled bool + Issuer string + ReadKeySetMaxRetries int + CheckScopes bool + Service string +} + +func Module(cfg ModuleConfig) fx.Option { + options := make([]fx.Option, 0) + + options = append(options, + fx.Provide(func() Auth { + return NewNoAuth() + }), + ) + + if cfg.Enabled { + options = append(options, + fx.Decorate(func(logger logging.Logger) Auth { + return newJWTAuth( + logger, + cfg.ReadKeySetMaxRetries, + cfg.Issuer, + cfg.Service, + cfg.CheckScopes, + ) + }), + ) + } + + return fx.Options(options...) +} diff --git a/libs/auth/no_auth.go b/libs/auth/no_auth.go new file mode 100644 index 000000000..4323b7847 --- /dev/null +++ b/libs/auth/no_auth.go @@ -0,0 +1,13 @@ +package auth + +import "net/http" + +type noAuth struct{} + +func (a noAuth) Authenticate(w http.ResponseWriter, r *http.Request) (bool, error) { + return true, nil +} + +func NewNoAuth() *noAuth { + return &noAuth{} +} diff --git a/libs/bun/bunconnect/connect.go b/libs/bun/bunconnect/connect.go index 217a0999f..aacbf043d 100644 --- a/libs/bun/bunconnect/connect.go +++ b/libs/bun/bunconnect/connect.go @@ -3,13 +3,14 @@ package bunconnect import ( "database/sql" "fmt" + "io" + "net/url" + "time" + "github.com/formancehq/stack/libs/go-libs/bun/bundebug" "github.com/uptrace/bun" "github.com/uptrace/bun/dialect/pgdialect" "github.com/uptrace/bun/extra/bunotel" - "io" - "net/url" - "time" ) type ConnectionOptions struct { @@ -64,7 +65,7 @@ func OpenDBWithSchema(connectionOptions ConnectionOptions, schema string, hooks } query := parsedConnectionParams.Query() - query.Set("search_path", schema) + query.Set("search_path", fmt.Sprintf(`"%s"`, schema)) parsedConnectionParams.RawQuery = query.Encode() connectionOptions.DatabaseSourceName = parsedConnectionParams.String() diff --git a/libs/collectionutils/map.go b/libs/collectionutils/map.go index 54d0eb475..04a63aea6 100644 --- a/libs/collectionutils/map.go +++ b/libs/collectionutils/map.go @@ -18,6 +18,21 @@ func ConvertMap[K comparable, FROM any, TO any](m map[K]FROM, mapper func(v FROM return ret } +func MergeMaps[K comparable, V any](m1, m2 map[K]V) map[K]V { + ret := make(map[K]V) + if m1 != nil { + for k, v := range m1 { + ret[k] = v + } + } + if m2 != nil { + for k, v := range m2 { + ret[k] = v + } + } + return ret +} + func ToAny[V any](v V) any { return v } diff --git a/libs/collectionutils/slice.go b/libs/collectionutils/slice.go index 58d2faead..087d9358b 100644 --- a/libs/collectionutils/slice.go +++ b/libs/collectionutils/slice.go @@ -70,8 +70,10 @@ func Contains[T any](slice []T, t T) bool { type Set[T comparable] map[T]struct{} -func (s Set[T]) Put(t T) { - s[t] = struct{}{} +func (s Set[T]) Put(t ...T) { + for _, t2 := range t { + s[t2] = struct{}{} + } } func (s Set[T]) Contains(t T) bool { @@ -79,6 +81,14 @@ func (s Set[T]) Contains(t T) bool { return ok } +func (s Set[T]) ToSlice() []T { + ret := make([]T, 0) + for k := range s { + ret = append(ret, k) + } + return ret +} + func NewSet[T comparable]() Set[T] { return make(Set[T], 0) } diff --git a/libs/go.mod b/libs/go.mod index b14e9d5f1..e9a650376 100644 --- a/libs/go.mod +++ b/libs/go.mod @@ -10,7 +10,8 @@ require ( github.com/ThreeDotsLabs/watermill-nats/v2 v2.0.0 github.com/coreos/go-semver v0.3.0 github.com/dgraph-io/ristretto v0.1.1 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.3.1 + github.com/hashicorp/go-retryablehttp v0.7.2 github.com/imdario/mergo v0.3.13 github.com/jackc/pgx/v5 v5.3.0 github.com/lib/pq v1.10.7 @@ -20,7 +21,7 @@ require ( github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 github.com/pkg/errors v0.9.1 github.com/segmentio/analytics-go v3.1.0+incompatible - github.com/sirupsen/logrus v1.9.0 + github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.6.1 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.15.0 @@ -31,6 +32,7 @@ require ( github.com/uptrace/bun/extra/bunotel v1.1.16 github.com/uptrace/opentelemetry-go-extra/otellogrus v0.1.21 github.com/xdg-go/scram v1.1.2 + github.com/zitadel/oidc/v2 v2.11.0 go.opentelemetry.io/contrib/instrumentation/host v0.42.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 go.opentelemetry.io/contrib/instrumentation/runtime v0.42.0 @@ -84,8 +86,12 @@ require ( github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/gorilla/mux v1.8.0 // indirect + github.com/gorilla/schema v1.2.0 // indirect + github.com/gorilla/securecookie v1.1.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/hcl v1.0.0 // indirect @@ -107,6 +113,8 @@ require ( github.com/minio/highwayhash v1.0.2 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect + github.com/muhlemmer/gu v0.3.1 // indirect + github.com/muhlemmer/httpforwarded v0.1.0 // indirect github.com/nats-io/jwt/v2 v2.5.0 // indirect github.com/nats-io/nkeys v0.4.4 // indirect github.com/nats-io/nuid v1.0.1 // indirect @@ -119,6 +127,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect + github.com/rs/cors v1.10.0 // indirect github.com/segmentio/backo-go v1.0.1 // indirect github.com/shirou/gopsutil/v3 v3.23.4 // indirect github.com/shoenig/go-m1cpu v0.1.5 // indirect @@ -147,17 +156,20 @@ require ( go.uber.org/atomic v1.10.0 // indirect go.uber.org/dig v1.16.1 // indirect go.uber.org/multierr v1.9.0 // indirect - golang.org/x/crypto v0.12.0 // indirect + golang.org/x/crypto v0.13.0 // indirect golang.org/x/mod v0.8.0 // indirect - golang.org/x/net v0.10.0 // indirect + golang.org/x/net v0.15.0 // indirect + golang.org/x/oauth2 v0.12.0 // indirect golang.org/x/sys v0.12.0 // indirect - golang.org/x/text v0.12.0 // indirect + golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.6.0 // indirect + google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/grpc v1.56.3 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/libs/go.sum b/libs/go.sum index 655b4bea6..05752001a 100644 --- a/libs/go.sum +++ b/libs/go.sum @@ -183,6 +183,7 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -237,11 +238,16 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= +github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= @@ -251,9 +257,15 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0/go.mod h1:YDZoGHuwE+ov0c8smSH4 github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= +github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -286,6 +298,7 @@ github.com/jcmturner/gokrb5/v8 v8.4.3 h1:iTonLeSJOn7MVUtyMT+arAn5AKAPrkilzhGw8wE github.com/jcmturner/gokrb5/v8 v8.4.3/go.mod h1:dqRwJGXznQrzw6cWmyo6kH+E7jksEQG/CyVWsJEsJO0= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jeremija/gosubmit v0.2.7 h1:At0OhGCFGPXyjPYAsCchoBUhE099pcBXmsb4iZqROIc= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -331,6 +344,10 @@ github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6U github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/muhlemmer/gu v0.3.1 h1:7EAqmFrW7n3hETvuAdmFmn4hS8W+z3LgKtrnow+YzNM= +github.com/muhlemmer/gu v0.3.1/go.mod h1:YHtHR+gxM+bKEIIs7Hmi9sPT3ZDUvTN/i88wQpZkrdM= +github.com/muhlemmer/httpforwarded v0.1.0 h1:x4DLrzXdliq8mprgUMR0olDvHGkou5BJsK/vWUetyzY= +github.com/muhlemmer/httpforwarded v0.1.0/go.mod h1:yo9czKedo2pdZhoXe+yDkGVbU0TJ0q9oQ90BVoDEtw0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nats-io/jwt/v2 v2.5.0 h1:WQQ40AAlqqfx+f6ku+i0pOVm+ASirD4fUh+oQsiE9Ak= github.com/nats-io/jwt/v2 v2.5.0/go.mod h1:24BeQtRwxRV8ruvC4CojXlx/WQ/VjuwlYiH+vu/+ibI= @@ -382,6 +399,8 @@ github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqn github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rs/cors v1.10.0 h1:62NOS1h+r8p1mW6FM0FSB0exioXLhd/sh15KpjWBZ+8= +github.com/rs/cors v1.10.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= @@ -398,8 +417,8 @@ github.com/shoenig/test v0.6.3/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnj github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= @@ -483,6 +502,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/zitadel/oidc/v2 v2.11.0 h1:Am4/yQr4iiM5bznRgF3FOp+wLdKx2gzSU73uyI9vvBE= +github.com/zitadel/oidc/v2 v2.11.0/go.mod h1:enFSVBQI6aE0TEB1ntjXs9r6O6DEosxX4uhEBLBVD8o= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -553,8 +574,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -627,8 +648,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220725212005-46097bf591d3/go.mod h1:AaygXjzTFtRAg2ttMY5RMuhpJ3cNnI0XpyFJD1iQRSM= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -639,6 +660,8 @@ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= +golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -724,8 +747,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -814,6 +837,7 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -890,8 +914,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -899,6 +923,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/libs/publish/messages.go b/libs/publish/messages.go index acf580861..4f08e3817 100644 --- a/libs/publish/messages.go +++ b/libs/publish/messages.go @@ -3,19 +3,33 @@ package publish import ( "context" "encoding/json" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/propagation" + "go.opentelemetry.io/otel/trace" "time" "github.com/ThreeDotsLabs/watermill/message" "github.com/google/uuid" ) -func NewMessage(ctx context.Context, m any) *message.Message { +const ( + otelContextKey = "otel-context" +) + +func NewMessage(ctx context.Context, m EventMessage) *message.Message { data, err := json.Marshal(m) if err != nil { panic(err) } + + carrier := propagation.MapCarrier{} + otel.GetTextMapPropagator().Inject(ctx, carrier) + otelContext, _ := json.Marshal(carrier) + msg := message.NewMessage(uuid.NewString(), data) msg.SetContext(ctx) + msg.Metadata[otelContextKey] = string(otelContext) + return msg } @@ -27,10 +41,15 @@ type EventMessage struct { Payload any `json:"payload"` } -func UnmarshalMessage(msg *message.Message) (*EventMessage, error) { +func UnmarshalMessage(msg *message.Message) (trace.Span, *EventMessage, error) { ev := &EventMessage{} if err := json.Unmarshal(msg.Payload, ev); err != nil { - return nil, err + return nil, nil, err + } + carrier := propagation.MapCarrier{} + ctx := context.TODO() + if err := json.Unmarshal([]byte(msg.Metadata[otelContextKey]), &carrier); err == nil { + ctx = otel.GetTextMapPropagator().Extract(msg.Context(), carrier) } - return ev, nil + return trace.SpanFromContext(ctx), ev, nil } diff --git a/libs/publish/module_test.go b/libs/publish/module_test.go index 80fa28f5a..a14ad0cb9 100644 --- a/libs/publish/module_test.go +++ b/libs/publish/module_test.go @@ -3,6 +3,10 @@ package publish import ( "context" "fmt" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/propagation" + tracesdk "go.opentelemetry.io/otel/sdk/trace" + "go.opentelemetry.io/otel/trace" "io" "os" "testing" @@ -80,6 +84,10 @@ func createRedpandaServer(t *testing.T) string { func TestModule(t *testing.T) { t.Parallel() + tracerProvider := tracesdk.NewTracerProvider() + otel.SetTracerProvider(tracerProvider) + otel.SetTextMapPropagator(propagation.TraceContext{}) + type moduleTestCase struct { name string setup func(t *testing.T) fx.Option @@ -130,10 +138,12 @@ func TestModule(t *testing.T) { Host: "0.0.0.0", Port: 4322, JetStream: true, + StoreDir: os.TempDir(), }) require.NoError(t, err) server.Start() + require.Eventually(t, server.Running, 3*time.Second, 10*time.Millisecond) t.Cleanup(server.Shutdown) @@ -152,7 +162,7 @@ func TestModule(t *testing.T) { var ( publisher message.Publisher router *message.Router - messageHandled = make(chan struct{}) + messageHandled = make(chan *message.Message, 1) ) options := []fx.Option{ Module(tc.topicMapping), @@ -161,7 +171,7 @@ func TestModule(t *testing.T) { fx.Supply(fx.Annotate(logging.Testing(), fx.As(new(logging.Logger)))), fx.Invoke(func(r *message.Router, subscriber message.Subscriber) { r.AddNoPublisherHandler("testing", tc.topic, subscriber, func(msg *message.Message) error { - require.Equal(t, "\"baz\"", string(msg.Payload)) + messageHandled <- msg close(messageHandled) return nil }) @@ -178,11 +188,22 @@ func TestModule(t *testing.T) { <-router.Running() - msg := NewMessage(context.TODO(), "baz") + tracer := otel.Tracer("main") + ctx, span := tracer.Start(context.TODO(), "main") + t.Cleanup(func() { + span.End() + }) + require.True(t, trace.SpanFromContext(ctx).SpanContext().IsValid()) + msg := NewMessage(ctx, EventMessage{}) require.NoError(t, publisher.Publish(tc.topic, msg)) select { - case <-messageHandled: + case msg := <-messageHandled: + span, event, err := UnmarshalMessage(msg) + require.NoError(t, err) + require.NotNil(t, event) + require.NotNil(t, ctx) + require.True(t, span.SpanContext().IsValid()) case <-time.After(10 * time.Second): t.Fatal("timeout waiting message") } diff --git a/openapi.yaml b/openapi.yaml index dfe056e66..314d34d0a 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -9,6 +9,7 @@ paths: tags: - Ledger - Server + x-speakeasy-group: ledger summary: Show server information operationId: getInfo responses: @@ -30,6 +31,7 @@ paths: operationId: getLedgerInfo tags: - Ledger + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -58,6 +60,7 @@ paths: tags: - Ledger - Accounts + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -103,6 +106,7 @@ paths: tags: - Ledger - Accounts + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -238,6 +242,7 @@ paths: tags: - Ledger - Accounts + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -277,6 +282,7 @@ paths: tags: - Ledger - Accounts + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -330,6 +336,7 @@ paths: tags: - Ledger - Mapping + x-speakeasy-group: ledger operationId: getMapping summary: Get the mapping of a ledger parameters: @@ -357,6 +364,7 @@ paths: tags: - Ledger - Mapping + x-speakeasy-group: ledger operationId: updateMapping summary: Update the mapping of a ledger parameters: @@ -392,6 +400,7 @@ paths: tags: - Ledger - Script + x-speakeasy-group: ledger operationId: runScript summary: Execute a Numscript description: | @@ -434,6 +443,7 @@ paths: tags: - Ledger - Stats + x-speakeasy-group: ledger operationId: readStats summary: Get statistics from a ledger description: | @@ -464,6 +474,7 @@ paths: tags: - Ledger - Transactions + x-speakeasy-group: ledger summary: Count the transactions from a ledger operationId: countTransactions parameters: @@ -564,6 +575,7 @@ paths: tags: - Ledger - Transactions + x-speakeasy-group: ledger summary: List transactions from a ledger description: List transactions from a ledger, sorted by txid in descending order. operationId: listTransactions @@ -716,6 +728,7 @@ paths: tags: - Ledger - Transactions + x-speakeasy-group: ledger summary: Create a new transaction to a ledger operationId: createTransaction parameters: @@ -766,6 +779,7 @@ paths: tags: - Ledger - Transactions + x-speakeasy-group: ledger summary: Get transaction from a ledger by its ID operationId: getTransaction parameters: @@ -803,6 +817,7 @@ paths: tags: - Ledger - Transactions + x-speakeasy-group: ledger summary: Set the metadata of a transaction by its ID operationId: addMetadataOnTransaction parameters: @@ -843,6 +858,7 @@ paths: tags: - Ledger - Transactions + x-speakeasy-group: ledger operationId: revertTransaction summary: Revert a ledger transaction by its ID parameters: @@ -886,6 +902,7 @@ paths: tags: - Ledger - Transactions + x-speakeasy-group: ledger summary: Create a new batch of transactions to a ledger operationId: CreateTransactions parameters: @@ -920,6 +937,7 @@ paths: tags: - Ledger - Balances + x-speakeasy-group: ledger summary: Get the balances from a ledger's account operationId: getBalances parameters: @@ -982,6 +1000,7 @@ paths: tags: - Ledger - Balances + x-speakeasy-group: ledger summary: Get the aggregated balances from selected accounts operationId: getBalancesAggregated parameters: @@ -1016,6 +1035,7 @@ paths: tags: - Ledger - Logs + x-speakeasy-group: ledger summary: List the logs from a ledger description: List the logs from a ledger, sorted by ID in descending order. operationId: listLogs @@ -1136,6 +1156,7 @@ paths: get: tags: - Ledger + x-speakeasy-group: ledger summary: Show server information operationId: v2GetInfo responses: @@ -1178,6 +1199,7 @@ paths: example: aHR0cHM6Ly9nLnBhZ2UvTmVrby1SYW1lbj9zaGFyZQ== tags: - Ledger + x-speakeasy-group: ledger responses: "200": description: OK @@ -1205,6 +1227,7 @@ paths: operationId: v2GetLedger tags: - Ledger + x-speakeasy-group: ledger responses: "200": description: OK @@ -1223,6 +1246,7 @@ paths: operationId: v2CreateLedger tags: - Ledger + x-speakeasy-group: ledger requestBody: content: application/json: @@ -1249,6 +1273,7 @@ paths: operationId: v2GetLedgerInfo tags: - Ledger + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -1280,6 +1305,7 @@ paths: operationId: v2CreateBulk tags: - Ledger + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -1318,6 +1344,7 @@ paths: operationId: v2CountAccounts tags: - Ledger + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -1359,6 +1386,7 @@ paths: operationId: v2ListAccounts tags: - Ledger + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -1430,6 +1458,7 @@ paths: operationId: v2GetAccount tags: - Ledger + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -1480,6 +1509,7 @@ paths: operationId: v2AddMetadataToAccount tags: - Ledger + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -1545,6 +1575,7 @@ paths: operationId: v2DeleteAccountMetadata tags: - Ledger + x-speakeasy-group: ledger summary: Delete metadata by key parameters: - name: ledger @@ -1575,6 +1606,7 @@ paths: get: tags: - Ledger + x-speakeasy-group: ledger operationId: v2ReadStats summary: Get statistics from a ledger description: | @@ -1604,6 +1636,7 @@ paths: head: tags: - Ledger + x-speakeasy-group: ledger summary: Count the transactions from a ledger operationId: v2CountTransactions parameters: @@ -1644,6 +1677,7 @@ paths: get: tags: - Ledger + x-speakeasy-group: ledger summary: List transactions from a ledger description: List transactions from a ledger, sorted by id in descending order. operationId: v2ListTransactions @@ -1721,6 +1755,7 @@ paths: post: tags: - Ledger + x-speakeasy-group: ledger summary: Create a new transaction to a ledger operationId: v2CreateTransaction parameters: @@ -1775,6 +1810,7 @@ paths: get: tags: - Ledger + x-speakeasy-group: ledger summary: Get transaction from a ledger by its ID operationId: v2GetTransaction parameters: @@ -1829,6 +1865,7 @@ paths: post: tags: - Ledger + x-speakeasy-group: ledger summary: Set the metadata of a transaction by its ID operationId: v2AddMetadataOnTransaction parameters: @@ -1894,6 +1931,7 @@ paths: summary: Delete metadata by key tags: - Ledger + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -1938,6 +1976,7 @@ paths: post: tags: - Ledger + x-speakeasy-group: ledger operationId: v2RevertTransaction summary: Revert a ledger transaction by its ID parameters: @@ -1986,6 +2025,7 @@ paths: get: tags: - Ledger + x-speakeasy-group: ledger summary: Get the aggregated balances from selected accounts operationId: v2GetBalancesAggregated parameters: @@ -2025,6 +2065,7 @@ paths: get: tags: - Ledger + x-speakeasy-group: ledger summary: List the logs from a ledger description: List the logs from a ledger, sorted by ID in descending order. operationId: v2ListLogs diff --git a/openapi/v1.yaml b/openapi/v1.yaml index b97420e07..19b3e2b61 100644 --- a/openapi/v1.yaml +++ b/openapi/v1.yaml @@ -10,6 +10,7 @@ paths: tags: - Ledger - Server + x-speakeasy-group: ledger summary: Show server information operationId: getInfo responses: @@ -32,6 +33,7 @@ paths: operationId: getLedgerInfo tags: - Ledger + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -61,6 +63,7 @@ paths: tags: - Ledger - Accounts + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -107,6 +110,7 @@ paths: tags: - Ledger - Accounts + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -231,6 +235,7 @@ paths: tags: - Ledger - Accounts + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -271,6 +276,7 @@ paths: tags: - Ledger - Accounts + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -328,6 +334,7 @@ paths: tags: - Ledger - Mapping + x-speakeasy-group: ledger operationId: getMapping summary: Get the mapping of a ledger parameters: @@ -356,6 +363,7 @@ paths: tags: - Ledger - Mapping + x-speakeasy-group: ledger operationId: updateMapping summary: Update the mapping of a ledger parameters: @@ -392,6 +400,7 @@ paths: tags: - Ledger - Script + x-speakeasy-group: ledger operationId: runScript summary: Execute a Numscript description: > @@ -436,6 +445,7 @@ paths: tags: - Ledger - Stats + x-speakeasy-group: ledger operationId: readStats summary: Get statistics from a ledger description: | @@ -467,6 +477,7 @@ paths: tags: - Ledger - Transactions + x-speakeasy-group: ledger summary: Count the transactions from a ledger operationId: countTransactions parameters: @@ -569,6 +580,7 @@ paths: tags: - Ledger - Transactions + x-speakeasy-group: ledger summary: List transactions from a ledger description: List transactions from a ledger, sorted by txid in descending order. operationId: listTransactions @@ -724,6 +736,7 @@ paths: tags: - Ledger - Transactions + x-speakeasy-group: ledger summary: Create a new transaction to a ledger operationId: createTransaction parameters: @@ -777,6 +790,7 @@ paths: tags: - Ledger - Transactions + x-speakeasy-group: ledger summary: Get transaction from a ledger by its ID operationId: getTransaction parameters: @@ -815,6 +829,7 @@ paths: tags: - Ledger - Transactions + x-speakeasy-group: ledger summary: Set the metadata of a transaction by its ID operationId: addMetadataOnTransaction parameters: @@ -856,6 +871,7 @@ paths: tags: - Ledger - Transactions + x-speakeasy-group: ledger operationId: revertTransaction summary: Revert a ledger transaction by its ID parameters: @@ -900,6 +916,7 @@ paths: tags: - Ledger - Transactions + x-speakeasy-group: ledger summary: Create a new batch of transactions to a ledger operationId: CreateTransactions parameters: @@ -935,6 +952,7 @@ paths: tags: - Ledger - Balances + x-speakeasy-group: ledger summary: Get the balances from a ledger's account operationId: getBalances parameters: @@ -999,6 +1017,7 @@ paths: tags: - Ledger - Balances + x-speakeasy-group: ledger summary: Get the aggregated balances from selected accounts operationId: getBalancesAggregated parameters: @@ -1035,6 +1054,7 @@ paths: tags: - Ledger - Logs + x-speakeasy-group: ledger summary: List the logs from a ledger description: List the logs from a ledger, sorted by ID in descending order. operationId: listLogs diff --git a/openapi/v2.yaml b/openapi/v2.yaml index 4261c55e2..1e79cb55b 100644 --- a/openapi/v2.yaml +++ b/openapi/v2.yaml @@ -9,6 +9,7 @@ paths: get: tags: - Ledger + x-speakeasy-group: ledger summary: Show server information operationId: v2GetInfo responses: @@ -52,6 +53,7 @@ paths: example: aHR0cHM6Ly9nLnBhZ2UvTmVrby1SYW1lbj9zaGFyZQ== tags: - Ledger + x-speakeasy-group: ledger responses: "200": description: OK @@ -81,6 +83,7 @@ paths: operationId: v2GetLedger tags: - Ledger + x-speakeasy-group: ledger responses: "200": description: OK @@ -100,6 +103,7 @@ paths: operationId: v2CreateLedger tags: - Ledger + x-speakeasy-group: ledger requestBody: content: application/json: @@ -129,6 +133,7 @@ paths: operationId: v2GetLedgerInfo tags: - Ledger + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -161,6 +166,7 @@ paths: operationId: v2CreateBulk tags: - Ledger + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -200,6 +206,7 @@ paths: operationId: v2CountAccounts tags: - Ledger + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -242,6 +249,7 @@ paths: operationId: v2ListAccounts tags: - Ledger + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -316,6 +324,7 @@ paths: operationId: v2GetAccount tags: - Ledger + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -367,6 +376,7 @@ paths: operationId: v2AddMetadataToAccount tags: - Ledger + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -436,6 +446,7 @@ paths: operationId: v2DeleteAccountMetadata tags: - Ledger + x-speakeasy-group: ledger summary: Delete metadata by key parameters: - name: ledger @@ -467,6 +478,7 @@ paths: get: tags: - Ledger + x-speakeasy-group: ledger operationId: v2ReadStats summary: Get statistics from a ledger description: | @@ -497,6 +509,7 @@ paths: head: tags: - Ledger + x-speakeasy-group: ledger summary: Count the transactions from a ledger operationId: v2CountTransactions parameters: @@ -538,6 +551,7 @@ paths: get: tags: - Ledger + x-speakeasy-group: ledger summary: List transactions from a ledger description: List transactions from a ledger, sorted by id in descending order. operationId: v2ListTransactions @@ -619,6 +633,7 @@ paths: post: tags: - Ledger + x-speakeasy-group: ledger summary: Create a new transaction to a ledger operationId: v2CreateTransaction parameters: @@ -674,6 +689,7 @@ paths: get: tags: - Ledger + x-speakeasy-group: ledger summary: Get transaction from a ledger by its ID operationId: v2GetTransaction parameters: @@ -731,6 +747,7 @@ paths: post: tags: - Ledger + x-speakeasy-group: ledger summary: Set the metadata of a transaction by its ID operationId: v2AddMetadataOnTransaction parameters: @@ -800,6 +817,7 @@ paths: summary: Delete metadata by key tags: - Ledger + x-speakeasy-group: ledger parameters: - name: ledger in: path @@ -847,6 +865,7 @@ paths: post: tags: - Ledger + x-speakeasy-group: ledger operationId: v2RevertTransaction summary: Revert a ledger transaction by its ID parameters: @@ -897,6 +916,7 @@ paths: get: tags: - Ledger + x-speakeasy-group: ledger summary: Get the aggregated balances from selected accounts operationId: v2GetBalancesAggregated parameters: @@ -937,6 +957,7 @@ paths: get: tags: - Ledger + x-speakeasy-group: ledger summary: List the logs from a ledger description: List the logs from a ledger, sorted by ID in descending order. operationId: v2ListLogs diff --git a/scratch.Dockerfile b/scratch.Dockerfile new file mode 100644 index 000000000..2193c52c3 --- /dev/null +++ b/scratch.Dockerfile @@ -0,0 +1,9 @@ +FROM alpine:latest as certs +RUN apk --update add ca-certificates + +FROM scratch +COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt +COPY ledger /usr/bin/ledger +ENV OTEL_SERVICE_NAME ledger +ENTRYPOINT ["/usr/bin/ledger"] +CMD ["serve"]