diff --git a/.gitignore b/.gitignore index 503a584..2beff0b 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,9 @@ # Go workspace file go.work -.idea/ +bin/ +__debug_* -fly.toml \ No newline at end of file +fly.toml +settings.env +config.toml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..49cda6d --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,12 @@ + + + + + postgresql + true + org.postgresql.Driver + jdbc:postgresql://postgresql.lauka-home.net/go-test + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/go-urlsh.iml b/.idea/go-urlsh.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/.idea/go-urlsh.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..68928a7 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/.idea/jsonSchemas.xml b/.idea/jsonSchemas.xml new file mode 100644 index 0000000..1e8bfb0 --- /dev/null +++ b/.idea/jsonSchemas.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..ee1a5eb --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml new file mode 100644 index 0000000..ad4d8f5 --- /dev/null +++ b/.idea/sqldialects.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..9bb2b2d --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,18 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "debug go-urlsh", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}", + "envFile": "${workspaceFolder}/settings.env" + } + + + ] +} diff --git a/.woodpecker/deploy-docker.yml b/.woodpecker/deploy-docker.yml index acee694..32cc763 100644 --- a/.woodpecker/deploy-docker.yml +++ b/.woodpecker/deploy-docker.yml @@ -7,9 +7,9 @@ steps: settings: dockerfile: Dockerfile platforms: linux/arm/v7,linux/arm64/v8,linux/amd64 - repo: codeberg.org/lauralani/go-urlsh + repo: code.lila.network/adoralaura/go-urlsh registry: codeberg.org - tags: latest + tags: develop username: lauralani password: from_secret: codeberg_token @@ -22,9 +22,9 @@ steps: settings: dockerfile: Dockerfile platforms: linux/arm/v7,linux/arm64/v8,linux/amd64 - repo: codeberg.org/lauralani/go-urlsh + repo: code.lila.network/adoralaura/go-urlsh registry: codeberg.org auto_tag: true username: lauralani password: - from_secret: codeberg_token \ No newline at end of file + from_secret: codeberg_token diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d99fa6..4524afc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] @@ -11,23 +11,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - added Changelog - Ability to change the url and description of shortlinks - /api/v1/users/me endpoint to get user details -- Account page for user overview and later use +- User account page +- Two Factor Authentication (#6) ### Changed +- update to Go 1.22 - License changed to MIT +- Main development repo is now at https://code.lila.network/adoralaura/go-urlsh ### Removed - Docker image support for linux/ppc64le +- Remember login switch (login cookie lasts 30 days now by default) ### Fixed - Login sessions now actually get cleaned up -## [0.1.2] - 2014-08-09 +## [0.1.2] - 2023-08-09 ### Fixed - fixed wrong javascript file linked in link add page -## [0.1.1] - 2014-07-10 +## [0.1.1] - 2023-07-10 ### Changed - Consolidated frontend javascript functions into one file @@ -40,7 +44,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Ability to add and delete short links -[unreleased]: https://codeberg.org/lauralani/go-urlsh/compare/0.1.2...HEAD -[0.1.2]: https://codeberg.org/lauralani/go-urlsh/compare/0.1.1...0.1.2 -[0.1.1]: https://codeberg.org/lauralani/go-urlsh/compare/0.1.0...0.1.1 -[0.1.0]: https://codeberg.org/lauralani/go-urlsh/releases/tag/0.1.0 +[unreleased]: https://code.lila.network/adoralaura/go-urlsh/compare/0.1.2...HEAD +[0.1.2]: https://code.lila.network/adoralaura/go-urlsh/compare/0.1.1...0.1.2 +[0.1.1]: https://code.lila.network/adoralaura/go-urlsh/compare/0.1.0...0.1.1 +[0.1.0]: https://code.lila.network/adoralaura/go-urlsh/releases/tag/0.1.0 diff --git a/Dockerfile b/Dockerfile index 3c6eac3..c33b9e4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.20-alpine AS dev +FROM golang:1.22-alpine AS dev COPY . /var/app WORKDIR /var/app @@ -27,4 +27,4 @@ COPY --from=build /var/app/views /var/app/views EXPOSE 80 ENTRYPOINT ["/var/app/go-urlsh"] -CMD "" \ No newline at end of file +CMD "" diff --git a/README.md b/README.md index f741876..71eac8c 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ URL Shortener in Go ## Changelog -You can find the Changelog here: [Changelog](https://codeberg.org/lauralani/go-urlsh/src/branch/main/CHANGELOG.md) +You can find the Changelog here: [Changelog](https://code.lila.network/adoralaura/go-urlsh/src/branch/main/CHANGELOG.md) ## License `go-urlsh` is available under the MIT license. See the LICENSE file for more info. diff --git a/cmd/go-urlsh/go-urlsh.go b/cmd/go-urlsh/go-urlsh.go index c59d4af..c2f1e21 100644 --- a/cmd/go-urlsh/go-urlsh.go +++ b/cmd/go-urlsh/go-urlsh.go @@ -1,23 +1,30 @@ package app import ( - "codeberg.org/lauralani/go-urlsh/internal/app" - "codeberg.org/lauralani/go-urlsh/internal/db" + "flag" "fmt" - "log" + + "code.lila.network/adoralaura/go-urlsh/internal/app" + "code.lila.network/adoralaura/go-urlsh/internal/config" + "code.lila.network/adoralaura/go-urlsh/internal/db" + "github.com/rs/zerolog" ) func Run() error { - err := db.InitializeDB() - if err != nil { - log.Fatalln(err) - } + configPath := flag.String("config", "", "location of the config file to use (default: /etc/go-urlsh/config.toml or $pwd/config.toml)") + flag.Parse() - go app.CleanupLogins() - go app.CleanupLoginsCronJob() + cfg := config.NewConfig(*configPath) - err = app.SetupFiber() + logger := config.NewLogger(zerolog.Level(cfg.LogLevel)) + + database := db.InitializeDB(cfg, logger) + + go app.CleanupLogins(database, logger) + go app.CleanupLoginsCronJob(database, logger) + + err := app.SetupFiber(database, logger, cfg) if err != nil { return fmt.Errorf("couldn't start webserver: %v", err.Error()) } diff --git a/go-urlsh b/go-urlsh new file mode 100755 index 0000000..f3a7f4c Binary files /dev/null and b/go-urlsh differ diff --git a/go.mod b/go.mod index f5fe3d6..376cd47 100644 --- a/go.mod +++ b/go.mod @@ -1,38 +1,56 @@ -module codeberg.org/lauralani/go-urlsh +module code.lila.network/adoralaura/go-urlsh -go 1.20 +go 1.22 require ( - github.com/gofiber/fiber/v2 v2.46.0 - github.com/gofiber/template v1.8.2 - github.com/google/uuid v1.3.0 + github.com/gofiber/fiber/v2 v2.52.4 + github.com/gofiber/template/html/v2 v2.1.1 github.com/jasonlvhit/gocron v0.0.1 - github.com/uptrace/bun v1.1.14 - github.com/uptrace/bun/dialect/pgdialect v1.1.14 - github.com/uptrace/bun/driver/pgdriver v1.1.14 + github.com/pquerna/otp v1.4.0 + github.com/uptrace/bun v1.1.8 + github.com/uptrace/bun/dialect/pgdialect v1.1.8 + github.com/uptrace/bun/driver/pgdriver v1.1.8 ) require ( - github.com/andybalholm/brotli v1.0.5 // indirect + github.com/andybalholm/brotli v1.1.0 // indirect + github.com/boombuler/barcode v1.0.1 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gofiber/template v1.8.3 // indirect + github.com/gofiber/utils v1.1.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect - github.com/klauspost/compress v1.16.6 // indirect + github.com/klauspost/compress v1.17.8 // indirect + github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect - github.com/mattn/go-runewidth v0.0.14 // indirect - github.com/philhofer/fwd v1.1.2 // indirect - github.com/rivo/uniseg v0.4.4 // indirect - github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect - github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect - github.com/tinylib/msgp v1.1.8 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/rs/zerolog v1.32.0 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.18.2 // indirect + github.com/subosito/gotenv v1.6.0 // indirect github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.47.0 // indirect + github.com/valyala/fasthttp v1.52.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect - github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect + github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect - golang.org/x/crypto v0.10.0 // indirect - golang.org/x/mod v0.7.0 // indirect - golang.org/x/sys v0.9.0 // indirect - golang.org/x/tools v0.4.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/crypto v0.22.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/sys v0.19.0 // indirect + golang.org/x/text v0.14.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect mellium.im/sasl v0.3.1 // indirect ) diff --git a/go.sum b/go.sum index dff9734..edd70f4 100644 --- a/go.sum +++ b/go.sum @@ -1,899 +1,149 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= -github.com/CloudyKit/jet/v6 v6.2.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4= -github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= -github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aymerick/raymond v2.0.2+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/cbroglie/mustache v1.4.0/go.mod h1:SS1FTIghy0sjse4DUVGV1k/40B1qE1XkD9DtDsHo9iM= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= -github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs= +github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/go-redis/redis v6.15.5+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gofiber/fiber/v2 v2.44.0 h1:Z90bEvPcJM5GFJnu1py0E1ojoerkyew3iiNJ78MQCM8= -github.com/gofiber/fiber/v2 v2.44.0/go.mod h1:VTMtb/au8g01iqvHyaCzftuM/xmZgKOZCtFzz6CdV9w= -github.com/gofiber/fiber/v2 v2.46.0 h1:wkkWotblsGVlLjXj2dpgKQAYHtXumsK/HyFugQM68Ns= -github.com/gofiber/fiber/v2 v2.46.0/go.mod h1:DNl0/c37WLe0g92U6lx1VMQuxGUQY5V7EIaVoEsUffc= -github.com/gofiber/template v1.8.1 h1:KLnNtXqH3LTzquU0NsLMqX3YGd3pD562UhSNaIca5HI= -github.com/gofiber/template v1.8.1/go.mod h1:+2x8bRo2TAXnqp0RUN2MdyKshUi+BulPoUCOHstFLqE= -github.com/gofiber/template v1.8.2 h1:PIv9s/7Uq6m+Fm2MDNd20pAFFKt5wWs7ZBd8iV9pWwk= -github.com/gofiber/template v1.8.2/go.mod h1:bs/2n0pSNPOkRa5VJ8zTIvedcI/lEYxzV3+YPXdBvq8= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/gofiber/fiber/v2 v2.52.4 h1:P+T+4iK7VaqUsq2PALYEfBBo6bJZ4q3FP8cZ84EggTM= +github.com/gofiber/fiber/v2 v2.52.4/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= +github.com/gofiber/template v1.8.3 h1:hzHdvMwMo/T2kouz2pPCA0zGiLCeMnoGsQZBTSYgZxc= +github.com/gofiber/template v1.8.3/go.mod h1:bs/2n0pSNPOkRa5VJ8zTIvedcI/lEYxzV3+YPXdBvq8= +github.com/gofiber/template/html/v2 v2.1.1 h1:QEy3O3EBkvwDthy5bXVGUseOyO6ldJoiDxlF4+MJiV8= +github.com/gofiber/template/html/v2 v2.1.1/go.mod h1:2G0GHHOUx70C1LDncoBpe4T6maQbNa4x1CVNFW0wju0= +github.com/gofiber/utils v1.1.0 h1:vdEBpn7AzIUJRhe+CiTOJdUcTg4Q9RK+pEa0KPbLdrM= +github.com/gofiber/utils v1.1.0/go.mod h1:poZpsnhBykfnY1Mc0KeEa6mSHrS3dV0+oBWyeQmb2e0= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= -github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= -github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= -github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= -github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jasonlvhit/gocron v0.0.1 h1:qTt5qF3b3srDjeOIR4Le1LfeyvoYzJlYpqvG7tJX5YU= github.com/jasonlvhit/gocron v0.0.1/go.mod h1:k9a3TV8VcU73XZxfVHCHWMWF9SOqgoku0/QlY2yvlA4= 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= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= -github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk= -github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= -github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= -github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= -github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-slim v0.0.4/go.mod h1:kXIwPrQbAZrhungtweoDO6qQQpUem6XkBg/mXykpoO0= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= -github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= -github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= +github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg= +github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= -github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= -github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 h1:rmMl4fXJhKMNWl+K+r/fq4FbbKI+Ia2m9hYBLm2h4G4= -github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94/go.mod h1:90zrgN3D/WJsDd1iXHT96alCoN2KJo6/4x1DZC3wZs8= -github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4= -github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk= -github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= +github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw= -github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= -github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo= github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= -github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/uptrace/bun v1.1.12 h1:sOjDVHxNTuM6dNGaba0wUuz7KvDE1BmNu9Gqs2gJSXQ= -github.com/uptrace/bun v1.1.12/go.mod h1:NPG6JGULBeQ9IU6yHp7YGELRa5Agmd7ATZdz4tGZ6z0= -github.com/uptrace/bun v1.1.14 h1:S5vvNnjEynJ0CvnrBOD7MIRW7q/WbtvFXrdfy0lddAM= -github.com/uptrace/bun v1.1.14/go.mod h1:RHk6DrIisO62dv10pUOJCz5MphXThuOTpVNYEYv7NI8= -github.com/uptrace/bun/dialect/pgdialect v1.1.12 h1:m/CM1UfOkoBTglGO5CUTKnIKKOApOYxkcP2qn0F9tJk= -github.com/uptrace/bun/dialect/pgdialect v1.1.12/go.mod h1:Ij6WIxQILxLlL2frUBxUBOZJtLElD2QQNDcu/PWDHTc= -github.com/uptrace/bun/dialect/pgdialect v1.1.14 h1:b7+V1KDJPQSFYgkG/6YLXCl2uvwEY3kf/GSM7hTHRDY= -github.com/uptrace/bun/dialect/pgdialect v1.1.14/go.mod h1:v6YiaXmnKQ2FlhRD2c0ZfKd+QXH09pYn4H8ojaavkKk= -github.com/uptrace/bun/driver/pgdriver v1.1.12 h1:3rRWB1GK0psTJrHwxzNfEij2MLibggiLdTqjTtfHc1w= -github.com/uptrace/bun/driver/pgdriver v1.1.12/go.mod h1:ssYUP+qwSEgeDDS1xm2XBip9el1y9Mi5mTAvLoiADLM= -github.com/uptrace/bun/driver/pgdriver v1.1.14 h1:V2Etm7mLGS3mhx8ddxZcUnwZLX02Jmq9JTlo0sNVDhA= -github.com/uptrace/bun/driver/pgdriver v1.1.14/go.mod h1:D4FjWV9arDYct6sjMJhFoyU71SpllZRHXFRRP2Kd0Kw= +github.com/uptrace/bun v1.1.8 h1:slxuaP4LYWFbPRUmTtQhfJN+6eX/6ar2HDKYTcI50SA= +github.com/uptrace/bun v1.1.8/go.mod h1:iT89ESdV3uMupD9ixt6Khidht+BK0STabK/LeZE+B84= +github.com/uptrace/bun v1.2.1 h1:2ENAcfeCfaY5+2e7z5pXrzFKy3vS8VXvkCag6N2Yzfk= +github.com/uptrace/bun v1.2.1/go.mod h1:cNg+pWBUMmJ8rHnETgf65CEvn3aIKErrwOD6IA8e+Ec= +github.com/uptrace/bun/dialect/pgdialect v1.1.8 h1:wayJhjYDPGv8tgOBLolbBtSFQ0TihFoo8E1T129UdA8= +github.com/uptrace/bun/dialect/pgdialect v1.1.8/go.mod h1:nNbU8PHTjTUM+CRtGmqyBb9zcuRAB8I680/qoFSmBUk= +github.com/uptrace/bun/dialect/pgdialect v1.2.1 h1:ceP99r03u+s8ylaDE/RzgcajwGiC76Jz3nS2ZgyPQ4M= +github.com/uptrace/bun/dialect/pgdialect v1.2.1/go.mod h1:mv6B12cisvSc6bwKm9q9wcrr26awkZK8QXM+nso9n2U= +github.com/uptrace/bun/driver/pgdriver v1.1.8 h1:gyL22axRQfjJS2Umq0erzJnp0bLOdUE8/USKZHPQB8o= +github.com/uptrace/bun/driver/pgdriver v1.1.8/go.mod h1:4tHK0h7a/UoldBoe9J3GU4tEYjr3mkd62U3Kq3PVk3E= +github.com/uptrace/bun/driver/pgdriver v1.2.1 h1:Cp6c1tKzbTIyL8o0cGT6cOhTsmQZdsUNhgcV51dsmLU= +github.com/uptrace/bun/driver/pgdriver v1.2.1/go.mod h1:jEd3WGx74hWLat3/IkesOoWNjrFNUDADK3nkyOFOOJM= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.45.0 h1:zPkkzpIn8tdHZUrVa6PzYd0i5verqiPSkgTd3bSUcpA= -github.com/valyala/fasthttp v1.45.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= -github.com/valyala/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK9c= -github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= +github.com/valyala/fasthttp v1.52.0 h1:wqBQpxH71XW0e2g+Og4dzQM8pk34aFYlA1Ga8db7gU0= +github.com/valyala/fasthttp v1.52.0/go.mod h1:hf5C4QnVMkNXMspnsUlfM3WitlgYflyhHYoKol/szxQ= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= -github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= -github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= +github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= -github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= -golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4= -golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +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/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 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= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= mellium.im/sasl v0.3.1 h1:wE0LW6g7U83vhvxjC1IY8DnXM+EU095yeo8XClvCdfo= mellium.im/sasl v0.3.1/go.mod h1:xm59PUYpZHhgQ9ZqoJ5QaCqzWMi8IeS49dhp6plPCzw= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/internal/api/apikeys.go b/internal/api/apikeys.go index 23adb79..e84ce62 100644 --- a/internal/api/apikeys.go +++ b/internal/api/apikeys.go @@ -2,14 +2,14 @@ package api import "github.com/gofiber/fiber/v2" -func HandleApiKeysGetAll(c *fiber.Ctx) error { - return nil +func (am APIRouteManager) HandleApiKeysGetAll(c *fiber.Ctx) error { + return fiber.NewError(501, "Not Implemented") } -func HandleApiKeysPost(c *fiber.Ctx) error { - return nil +func (am APIRouteManager) HandleApiKeysPost(c *fiber.Ctx) error { + return fiber.NewError(501, "Not Implemented") } -func HandleApiKeysDelete(c *fiber.Ctx) error { - return nil +func (am APIRouteManager) HandleApiKeysDelete(c *fiber.Ctx) error { + return fiber.NewError(501, "Not Implemented") } diff --git a/internal/api/links.go b/internal/api/links.go index b7ae6e2..fc2199e 100644 --- a/internal/api/links.go +++ b/internal/api/links.go @@ -1,26 +1,28 @@ package api import ( - "codeberg.org/lauralani/go-urlsh/internal/db" - "codeberg.org/lauralani/go-urlsh/internal/misc" - "codeberg.org/lauralani/go-urlsh/models" "context" "database/sql" "encoding/json" "fmt" - "github.com/gofiber/fiber/v2" "log" "time" + + "code.lila.network/adoralaura/go-urlsh/internal/constants" + "code.lila.network/adoralaura/go-urlsh/internal/db" + "code.lila.network/adoralaura/go-urlsh/internal/misc" + "code.lila.network/adoralaura/go-urlsh/models" + "github.com/gofiber/fiber/v2" ) -func HandleLinkGetAll(c *fiber.Ctx) error { - if !db.IsCookieValid(c.Cookies(misc.CookieName, "")) && !db.IsApiKeyValid(c.GetRespHeader("x-api-key", "")) { +func (am APIRouteManager) HandleLinkGetAll(c *fiber.Ctx) error { + if !db.IsCookieValid(c.Cookies(constants.LoginCookieName, "")) && !db.IsApiKeyValid(c.GetRespHeader("x-api-key", "")) { return fiber.NewError(fiber.StatusUnauthorized, "401 Unauthorized") } var links []models.Link - err := models.DB.NewSelect().Model(&links).Scan(context.Background()) + err := am.db.NewSelect().Model(&links).Scan(context.Background()) if err != nil { return fmt.Errorf("error querying links: %v", err.Error()) } @@ -35,12 +37,12 @@ func HandleLinkGetAll(c *fiber.Ctx) error { return nil } -func HandleLinkGet(c *fiber.Ctx) error { +func (am APIRouteManager) HandleLinkGet(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusNotImplemented, "501 Not Implemented") } -func HandleLinkPost(c *fiber.Ctx) error { - if !db.IsCookieValid(c.Cookies(misc.CookieName, "")) && !db.IsApiKeyValid(c.GetRespHeader("x-api-key", "")) { +func (am APIRouteManager) HandleLinkPost(c *fiber.Ctx) error { + if !db.IsCookieValid(c.Cookies(constants.LoginCookieName, "")) && !db.IsApiKeyValid(c.GetRespHeader("x-api-key", "")) { return fiber.NewError(fiber.StatusUnauthorized, "401 Unauthorized") } @@ -61,7 +63,7 @@ func HandleLinkPost(c *fiber.Ctx) error { newlink.Created = now newlink.Modified = now - _, err = models.DB.NewInsert().Model(&newlink).Exec(context.Background()) + _, err = am.db.NewInsert().Model(&newlink).Exec(context.Background()) if err != nil { return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error: "+err.Error()) } @@ -77,8 +79,8 @@ func HandleLinkPost(c *fiber.Ctx) error { return nil } -func HandleLinkPut(c *fiber.Ctx) error { - if !db.IsCookieValid(c.Cookies(misc.CookieName, "")) && !db.IsApiKeyValid(c.GetRespHeader("x-api-key", "")) { +func (am APIRouteManager) HandleLinkPut(c *fiber.Ctx) error { + if !db.IsCookieValid(c.Cookies(constants.LoginCookieName, "")) && !db.IsApiKeyValid(c.GetRespHeader("x-api-key", "")) { return fiber.NewError(fiber.StatusUnauthorized, "401 Unauthorized") } @@ -90,7 +92,7 @@ func HandleLinkPut(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, "400 Bad Request") } - err := models.DB.NewSelect().Model(&dblink).Where("id = ?", id).Scan(context.Background()) + err := am.db.NewSelect().Model(&dblink).Where("id = ?", id).Scan(context.Background()) if err != nil { if err == sql.ErrNoRows { @@ -111,7 +113,7 @@ func HandleLinkPut(c *fiber.Ctx) error { dblink.URL = editlink.URL dblink.Modified = time.Now() - _, err = models.DB.NewUpdate().Model(&dblink).WherePK().Exec(context.Background()) + _, err = am.db.NewUpdate().Model(&dblink).WherePK().Exec(context.Background()) if err != nil { return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error: "+err.Error()) } @@ -122,14 +124,14 @@ func HandleLinkPut(c *fiber.Ctx) error { return nil } -func HandleLinkDelete(c *fiber.Ctx) error { +func (am APIRouteManager) HandleLinkDelete(c *fiber.Ctx) error { id := c.Params("id") if id == "" { return fiber.NewError(fiber.StatusBadRequest, "400 Bad Request") } - numrows, err := models.DB.NewSelect().Model((*models.Link)(nil)).Where("id = ?", id).Count(context.Background()) + numrows, err := am.db.NewSelect().Model((*models.Link)(nil)).Where("id = ?", id).Count(context.Background()) if err != nil { log.Println(err.Error()) return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") @@ -139,7 +141,7 @@ func HandleLinkDelete(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusNotFound, "404 Not Found") } - _, err = models.DB.NewDelete().Model((*models.Link)(nil)).Where("id = ?", id).Exec(context.Background()) + _, err = am.db.NewDelete().Model((*models.Link)(nil)).Where("id = ?", id).Exec(context.Background()) if err != nil { log.Println(err.Error()) return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") diff --git a/internal/api/model.go b/internal/api/model.go new file mode 100644 index 0000000..71dcd2e --- /dev/null +++ b/internal/api/model.go @@ -0,0 +1,26 @@ +package api + +import ( + "code.lila.network/adoralaura/go-urlsh/internal/config" + "github.com/rs/zerolog" + "github.com/uptrace/bun" +) + +// APIRouteManager is a model that provides db, logger and config access +// to API routes +type APIRouteManager struct { + db *bun.DB + logger *zerolog.Logger + config *config.Config +} + +// NewAPIRouteManager creates a new Instance of an APIRouteManager +// and initializes it with the given DB, Logger and Config +func NewAPIRouteManager(db *bun.DB, logger *zerolog.Logger, config *config.Config) *APIRouteManager { + manager := new(APIRouteManager) + manager.db = db + manager.logger = logger + manager.config = config + + return manager +} diff --git a/internal/api/users.go b/internal/api/users.go index 4e92ec2..3055763 100644 --- a/internal/api/users.go +++ b/internal/api/users.go @@ -1,20 +1,22 @@ package api import ( - "codeberg.org/lauralani/go-urlsh/internal/db" - "codeberg.org/lauralani/go-urlsh/internal/misc" - "codeberg.org/lauralani/go-urlsh/models" "context" "crypto/sha256" "database/sql" "encoding/hex" "encoding/json" - "github.com/gofiber/fiber/v2" "log" "time" + + "code.lila.network/adoralaura/go-urlsh/internal/constants" + "code.lila.network/adoralaura/go-urlsh/internal/db" + "code.lila.network/adoralaura/go-urlsh/internal/misc" + "code.lila.network/adoralaura/go-urlsh/models" + "github.com/gofiber/fiber/v2" ) -func HandleUserPost(c *fiber.Ctx) error { +func (am APIRouteManager) HandleUserPost(c *fiber.Ctx) error { var newuser models.LoginRequest err := json.Unmarshal(c.Body(), &newuser) @@ -23,7 +25,7 @@ func HandleUserPost(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, "400 Bad Request") } - usercount, err := models.DB.NewSelect().Model((*models.User)(nil)).Count(context.Background()) + usercount, err := am.db.NewSelect().Model((*models.User)(nil)).Count(context.Background()) if err != nil { log.Printf("[POST /api/v1/users] Error querying database for users: %v\n", err.Error()) return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") @@ -44,13 +46,13 @@ func HandleUserPost(c *fiber.Ctx) error { user.PasswordHash = hash user.Created = created - _, err = models.DB.NewInsert().Model(user).Exec(context.Background()) + _, err = am.db.NewInsert().Model(user).Exec(context.Background()) if err != nil { log.Printf("[POST /api/v1/users] Error adding user %v to database : %v\n", newuser.Username, err.Error()) return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") } - userresponse := models.UserResponse{UserName: newuser.Username, Created: created} + userresponse := models.UserResponse{UserName: newuser.Username, Created: created, MFAEnabled: false} c.Status(fiber.StatusCreated) err = c.JSON(userresponse) @@ -61,12 +63,12 @@ func HandleUserPost(c *fiber.Ctx) error { } } -func HandleUserMe(c *fiber.Ctx) error { - if !db.IsCookieValid(c.Cookies(misc.CookieName, "")) && !db.IsApiKeyValid(c.GetRespHeader("x-api-key", "")) { +func (am APIRouteManager) HandleUserMe(c *fiber.Ctx) error { + if !db.IsCookieValid(c.Cookies(constants.LoginCookieName, "")) && !db.IsApiKeyValid(c.GetRespHeader("x-api-key", "")) { return fiber.NewError(fiber.StatusUnauthorized, "401 Unauthorized") } - cookie := c.Cookies(misc.CookieName, "") + cookie := c.Cookies(constants.LoginCookieName, "") apikey := c.GetRespHeader("x-api-key", "") var authmethod string @@ -81,37 +83,37 @@ func HandleUserMe(c *fiber.Ctx) error { switch authmethod { case "cookie": var session models.Session - err := models.DB.NewSelect().Model(&session).Where("cookie = ?", cookie).Scan(context.Background()) + err := am.db.NewSelect().Model(&session).Where("cookie = ?", cookie).Scan(context.Background()) if err != nil { if err == sql.ErrNoRows { - log.Printf("[HandleUserMe] Session %v not found\n", cookie) + log.Printf("[GET /api/v1/users/me] Session %v not found\n", cookie) } else { - log.Printf("[HandleUserMe] Error querying session %v from database: %v\n", cookie, err) + log.Printf("[GET /api/v1/users/me] Error querying session %v from database: %v\n", cookie, err) } return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") } - err = models.DB.NewSelect().Model(&user).Where("username = ?", session.UserName).Scan(context.Background()) + err = am.db.NewSelect().Model(&user).Where("username = ?", session.UserName).Scan(context.Background()) if err != nil { - log.Printf("[HandleUserMe] Error querying user %v from database: %v\n", session.UserName, err) + log.Printf("[GET /api/v1/users/me] Error querying user %v from database: %v\n", session.UserName, err) return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") } case "apikey": var key models.ApiKey - err := models.DB.NewSelect().Model(&key).Where("key = ?", apikey).Scan(context.Background()) + err := am.db.NewSelect().Model(&key).Where("key = ?", apikey).Scan(context.Background()) if err != nil { if err == sql.ErrNoRows { - log.Printf("[HandleUserMe] ApiKey %v not found\n", apikey) + log.Printf("[GET /api/v1/users/me] ApiKey %v not found\n", apikey) } else { - log.Printf("[HandleUserMe] Error querying apikey %v from database: %v\n", apikey, err) + log.Printf("[GET /api/v1/users/me] Error querying apikey %v from database: %v\n", apikey, err) } return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") } - err = models.DB.NewSelect().Model(&user).Where("username = ?", key.UserName).Scan(context.Background()) + err = am.db.NewSelect().Model(&user).Where("username = ?", key.UserName).Scan(context.Background()) if err != nil { - log.Printf("[HandleUserMe] Error querying user %v from database: %v\n", key.UserName, err) + log.Printf("[GET /api/v1/users/me] Error querying user %v from database: %v\n", key.UserName, err) return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") } } @@ -120,9 +122,17 @@ func HandleUserMe(c *fiber.Ctx) error { userresponse.UserName = user.UserName userresponse.Created = user.Created - err := c.JSON(userresponse) + hasmfa, err := db.UserHasMFA(user) if err != nil { - return err + log.Printf("[GET /api/v1/users/me] Error checking MFA status: %q\n", err) + return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") + } + userresponse.MFAEnabled = hasmfa + + err = c.JSON(userresponse) + if err != nil { + log.Printf("[GET /api/v1/users/me] Error marshaling JSON response: %q\n", err) + return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") } return nil } diff --git a/internal/app/error.go b/internal/app/error.go deleted file mode 100644 index c4748fc..0000000 --- a/internal/app/error.go +++ /dev/null @@ -1,23 +0,0 @@ -package app - -import ( - "errors" - "github.com/gofiber/fiber/v2" -) - -func HandleError(c *fiber.Ctx, err error) error { - code := fiber.StatusInternalServerError - - // Retrieve the custom status code if it's a *fiber.Error - var e *fiber.Error - if errors.As(err, &e) { - code = e.Code - } - - // Set Content-Type: text/plain; charset=utf-8 - c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8) - - // Return status code with error message - return c.Status(code).SendString(err.Error()) - -} diff --git a/internal/app/fiber.go b/internal/app/fiber.go index d06c24c..e8a1e72 100644 --- a/internal/app/fiber.go +++ b/internal/app/fiber.go @@ -1,88 +1,47 @@ package app import ( - "codeberg.org/lauralani/go-urlsh/internal/api" - "codeberg.org/lauralani/go-urlsh/internal/web" + "strconv" + + "code.lila.network/adoralaura/go-urlsh/internal/config" + "code.lila.network/adoralaura/go-urlsh/internal/misc" + "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/compress" "github.com/gofiber/fiber/v2/middleware/cors" "github.com/gofiber/fiber/v2/middleware/etag" - "github.com/gofiber/fiber/v2/middleware/logger" "github.com/gofiber/fiber/v2/middleware/recover" - "github.com/gofiber/template/html" - "os" + "github.com/gofiber/template/html/v2" + "github.com/rs/zerolog" + "github.com/uptrace/bun" ) -func SetupFiber() error { +func SetupFiber(db *bun.DB, logger *zerolog.Logger, config *config.Config) error { var prod = false - var port = "3000" - var ip = "" - var proxyheader = "X-Forwarded-For" var template_engine = html.New("./views", ".tmpl") - if os.Getenv("PROD") == "true" { - prod = true - } - - if os.Getenv("PORT") != "" { - port = os.Getenv("PORT") - } - - if os.Getenv("LISTEN") != "" { - ip = os.Getenv("LISTEN") - } - - if os.Getenv("PROXYHEADER") != "" { - proxyheader = os.Getenv("PROXYHEADER") - } - fiberapp := fiber.New(fiber.Config{ AppName: "go-urlsh", - ProxyHeader: proxyheader, + ProxyHeader: config.ProxyHeader, Prefork: prod, - ErrorHandler: HandleError, + ErrorHandler: misc.HandleError, Views: template_engine, CompressedFileSuffix: ".gz", }) - fiberapp.Use(logger.New(logger.Config{Format: "[${ip}]:${port} ${status} ${method} ${path}\n"})) fiberapp.Use(etag.New(etag.Config{Weak: false})) fiberapp.Use(compress.New()) fiberapp.Use(recover.New()) - fiberapp.Get("/admin/", web.HandleAdminLinkIndexGet) - - fiberapp.Get("/admin/account/", web.HandleAdminAccountGet) - - fiberapp.Get("/admin/login", web.HandleAdminLoginGet) - fiberapp.Post("/admin/login", web.HandleAdminLoginPost) - - fiberapp.Get("/admin/", web.HandleAdminLinkIndexGet) - fiberapp.Get("/admin/links/new", web.HandleAdminLinkNewGet) - fiberapp.Get("/admin/links/edit/:id", web.HandleAdminLinkEditGet) - - fiberapp.Static("/admin/", "./web") - - fiberapp.Get("/", web.HandleRootGet) - fiberapp.Get("/:id", web.HandleRootGet) + addWebRoutes(fiberapp) v1 := fiberapp.Group("/api/v1") v1.Use(cors.New(cors.Config{AllowOrigins: "*"})) - v1.Get("/links", api.HandleLinkGetAll) - v1.Get("/links/:id", api.HandleLinkGet) - v1.Put("/links/:id", api.HandleLinkPut) - v1.Post("/links", api.HandleLinkPost) - v1.Delete("/links/:id", api.HandleLinkDelete) + addApiRoutes(v1, db, logger, config) - v1.Get("/apikeys", api.HandleApiKeysGetAll) - v1.Post("/apikeys", api.HandleApiKeysPost) - v1.Delete("/apikeys/:id", api.HandleApiKeysPost) - - v1.Post("/users", api.HandleUserPost) - - listenerr := fiberapp.Listen(ip + ":" + port) + listenerr := fiberapp.Listen(config.HostIP.String() + ":" + strconv.Itoa(config.HostPort)) if listenerr != nil { return listenerr } diff --git a/internal/app/routes.go b/internal/app/routes.go new file mode 100644 index 0000000..422d827 --- /dev/null +++ b/internal/app/routes.go @@ -0,0 +1,57 @@ +package app + +import ( + "code.lila.network/adoralaura/go-urlsh/internal/api" + "code.lila.network/adoralaura/go-urlsh/internal/config" + "code.lila.network/adoralaura/go-urlsh/internal/web" + "github.com/gofiber/fiber/v2" + "github.com/rs/zerolog" + "github.com/uptrace/bun" +) + +func addWebRoutes( + f *fiber.App) { + + f.Get("/admin/", web.HandleAdminLinkIndexGet) + + f.Get("/admin/account/", web.HandleAdminAccountGet) + f.Get("/admin/account/setup-multifactor", web.HandleAdminAccountMFASetupGet) + f.Post("/admin/account/mfa/confirm", web.HandleAdminAccountMFASetupPost) + f.Delete("/admin/account/mfa", web.HandleAdminAccountMFARemove) + + f.Get("/admin/login", web.HandleAdminLoginGet) + f.Post("/admin/login", web.HandleAdminLoginPost) + + f.Get("/admin/login/multifactor", web.HandleAdminLoginMFAGet) + f.Post("/admin/login/multifactor", web.HandleAdminLoginMFAPost) + + f.Get("/admin/", web.HandleAdminLinkIndexGet) + f.Get("/admin/links/new", web.HandleAdminLinkNewGet) + f.Get("/admin/links/edit/:id", web.HandleAdminLinkEditGet) + + f.Static("/admin/", "./web") + + f.Get("/", web.HandleIndexGet) + f.Get("/:id", web.HandleIndexGet) + +} + +func addApiRoutes( + r fiber.Router, + db *bun.DB, + logger *zerolog.Logger, + config *config.Config) { + am := api.NewAPIRouteManager(db, logger, config) + + r.Get("/links", am.HandleLinkGetAll) + r.Get("/links/:id", am.HandleLinkGet) + r.Put("/links/:id", am.HandleLinkPut) + r.Post("/links", am.HandleLinkPost) + r.Delete("/links/:id", am.HandleLinkDelete) + + r.Get("/apikeys", am.HandleApiKeysGetAll) + r.Post("/apikeys", am.HandleApiKeysPost) + r.Delete("/apikeys/:id", am.HandleApiKeysPost) + + r.Post("/users", am.HandleUserPost) +} diff --git a/internal/app/routines.go b/internal/app/routines.go index 76c3c11..2a764e0 100644 --- a/internal/app/routines.go +++ b/internal/app/routines.go @@ -1,24 +1,43 @@ package app import ( - "codeberg.org/lauralani/go-urlsh/models" "context" - "github.com/jasonlvhit/gocron" "log" + + "github.com/jasonlvhit/gocron" + "github.com/rs/zerolog" + "github.com/uptrace/bun" ) -func CleanupLoginsCronJob() { - err := gocron.Every(1).Hours().Do(CleanupLogins) +func CleanupLoginsCronJob(db *bun.DB, logger *zerolog.Logger) { + err := gocron.Every(5).Minutes().Do(CleanupLogins, db, logger) if err != nil { return } <-gocron.Start() } -func CleanupLogins() { - _, err := models.DB.NewDelete().Table("logins").Where("expires < NOW()").Exec(context.Background()) +func CleanupLogins(db *bun.DB, logger *zerolog.Logger) { + res, err := db.NewDelete().Table("logins").Where("expires < NOW()").Exec(context.Background()) if err != nil { log.Printf("[CleanupLogins] Error deleting logins: %v\n", err) } - log.Printf("Cleaned up logins") + + numdeleted, _ := res.RowsAffected() + logger.Debug().Int64("logins", numdeleted).Msg("cleaned up logins from DB") + + res, err = db.NewDelete().Table("logintransactions").Where("expires < NOW()").Exec(context.Background()) + if err != nil { + log.Printf("[CleanupLogins] Error deleting login transactions: %v\n", err) + } + numdeleted, _ = res.RowsAffected() + logger.Debug().Int64("transactions", numdeleted).Msg("cleaned up transactions from DB") + + res, err = db.NewDelete().Table("multifactor").Where("expires_at < NOW()").Where("active = false").Exec(context.Background()) + if err != nil { + log.Printf("[CleanupLogins] Error deleting 2fa transactions: %v\n", err) + } + + numdeleted, _ = res.RowsAffected() + logger.Debug().Int64("mfatransactions", numdeleted).Msg("cleaned up 2fa transactions from DB") } diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000..0a78062 --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,144 @@ +package config + +import ( + "net/netip" + "slices" + "strconv" + + "github.com/rs/zerolog" + "github.com/spf13/viper" +) + +type Config struct { + DatabaseDSN string + + // panic = 5, + // fatal = 4, + // error = 3, + // warn = 2, + // info = 1, + // debug = 0, + // trace = -1 + LogLevel int + HostIP netip.Addr + HostPort int + HostURL string + ProxyHeader string + AccessLog bool +} + +func NewConfig(configPath string) *Config { + logger := NewLogger(zerolog.InfoLevel) + + loadConfigFile(configPath, logger) + + cfg := new(Config) + exit := false + + // handle Database DSN + if viper.GetString("database.url") != "" { + cfg.DatabaseDSN = viper.GetString("database.url") + } else { + dsn := "postgres://" + if viper.GetString("database.username") == "" { + exit = true + logger.Error().Msg("If database.url is not set, database.username must not be empty!") + } else { + dsn = dsn + viper.GetString("database.username") + } + + if viper.GetString("database.password") == "" { + exit = true + logger.Error().Msg("If database.url is not set, database.password must not be empty!") + } else { + dsn = dsn + ":" + viper.GetString("database.password") + } + + if viper.GetString("database.address") == "" { + exit = true + logger.Error().Msg("If database.url is not set, database.address must not be empty!") + } else { + dsn = dsn + "@" + viper.GetString("database.address") + } + + if viper.GetString("database.port") != "" { + dsn = dsn + ":" + strconv.Itoa(viper.GetInt("database.port")) + } + + if viper.GetString("database.database") == "" { + exit = true + logger.Error().Msg("If database.url is not set, database.database must not be empty!") + } else { + dsn = dsn + "/" + viper.GetString("database.database") + } + + if slices.Contains([]string{"disable", "require", "verify-full", ""}, viper.GetString("database.ssl-mode")) { + if viper.GetString("database.ssl-mode") == "" { + cfg.DatabaseDSN = dsn + "?sslmode=disable" + } else { + cfg.DatabaseDSN = dsn + "?sslmode=" + viper.GetString("database.ssl-mode") + } + } else { + logger.Error().Msg(`If database.url is not set, database.ssl-mode must be either "disable", "require", "verify-full" or empty!`) + } + } + + // Handle Logging + switch logLevel := viper.GetString("logging.level"); logLevel { + case "panic": + cfg.LogLevel = 5 + case "fatal": + cfg.LogLevel = 4 + case "error": + cfg.LogLevel = 3 + case "warn": + cfg.LogLevel = 2 + case "info": + cfg.LogLevel = 1 + case "debug": + cfg.LogLevel = 0 + case "trace": + cfg.LogLevel = -1 + + default: + exit = true + logger.Error().Str("value", logLevel).Msg(`Value of logging.level is invalid!`) + } + + cfg.HostURL = viper.GetString("application.base-url") + + if viper.GetString("application.listen") != "" { + ip, err := netip.ParseAddr(viper.GetString("application.listen")) + if err != nil { + exit = true + logger.Error().Str("value", viper.GetString("application.listen")).Msg(`Value of application.listen is not a valid IP address!`) + } else { + cfg.HostIP = ip + } + } else { + cfg.HostIP = netip.MustParseAddr("127.0.0.1") + } + + if viper.GetInt("application.port") != 0 { + // if port is a valid port number + if viper.GetInt("application.port") <= 65535 && viper.GetInt("application.port") > 0 { + cfg.HostPort = viper.GetInt("application.port") + } else { + logger.Error().Str("value", viper.GetString("application.port")).Msg(`Value of application.port is not a valid port number!`) + } + } else { + cfg.HostPort = 3000 + } + + if viper.GetString("application.proxy-header") == "" { + cfg.ProxyHeader = "X-Forwarded-For" + } else { + cfg.ProxyHeader = viper.GetString("application.proxy-header") + } + + if exit { + logger.Fatal().Msg("There were errors reading the config file. See errors above!") + } + + return cfg +} diff --git a/internal/config/file.go b/internal/config/file.go new file mode 100644 index 0000000..c34c004 --- /dev/null +++ b/internal/config/file.go @@ -0,0 +1,30 @@ +package config + +import ( + "os" + + "github.com/rs/zerolog" + "github.com/spf13/viper" +) + +// loadConfigFile reads the config file from given string OR +// from either $WorkDir/config.* or from /etc/go-urlsh/config.* +// Returns map[string]any with the specified config files. +// Panics if it can't read any config file. +func loadConfigFile(filepath string, logger *zerolog.Logger) { + if filepath == "" { + path, err := os.Executable() + if err != nil { + logger.Fatal().Err(err).Msg("error getting current working dir") + } + viper.SetConfigName("config") + viper.AddConfigPath("/etc/go-urlsh/") + viper.AddConfigPath(path) + } else { + viper.SetConfigFile(filepath) + } + err := viper.ReadInConfig() + if err != nil { + logger.Fatal().Err(err).Msg("failed to open config file") + } +} diff --git a/internal/config/file_test.go b/internal/config/file_test.go new file mode 100644 index 0000000..c4725c3 --- /dev/null +++ b/internal/config/file_test.go @@ -0,0 +1,60 @@ +package config + +import ( + "os" + "testing" + + "github.com/rs/zerolog" + "github.com/spf13/viper" +) + +// writeTestConfigFile creates a test config file at given filename location +func writeTestConfigFile(t *testing.T, filename string) { + testdata := []byte("[application]\nlisten = \"127.0.0.1\"\n[database]\nport = 54321\ntestbool = false") + err := os.WriteFile(filename, testdata, 0644) + if err != nil { + t.Fatalf("Can't write test file %q: %v", filename, err) + } +} + +// removeTestConfigFile removes given config file +func removeTestConfigFile(t *testing.T, filename string) { + err := os.Remove(filename) + if err != nil { + t.Fatalf("Can't remove test file %q: %v", filename, err) + } +} + +// TestLoadConfigFile calls config.loadConfigFile +// to check if a valid Configuration can be loaded. +func TestLoadConfigFile(t *testing.T) { + logger := NewLogger(zerolog.InfoLevel) + dir, err := os.Getwd() + if err != nil { + t.Fatalf("Can't get current working directory") + } + + testFile := dir + "/" + "config_unittest.toml" + + writeTestConfigFile(t, testFile) + + defer removeTestConfigFile(t, testFile) + + loadConfigFile(testFile, logger) + + if viper.GetString("application.listen") != "127.0.0.1" { + t.Fatalf(`viper.GetString("application.listen") = %q, want "127.0.0.1"`, viper.GetString("application.listen")) + } + + if viper.GetInt("database.port") != 54321 { + t.Fatalf(`viper.GetInt("database.port") = %q, want 54321`, viper.GetInt("database.port")) + } + + if viper.GetBool("database.testbool") != false { + t.Fatalf(`viper.GetBool("database.testbool") = true, want false`) + } + + if viper.GetString("invalid.config.value") != "" { + t.Fatalf(`viper.GetString("invalid.config.value") = %q, want ""`, viper.GetString("invalid.config.value")) + } +} diff --git a/internal/config/logger.go b/internal/config/logger.go new file mode 100644 index 0000000..38f2b9f --- /dev/null +++ b/internal/config/logger.go @@ -0,0 +1,17 @@ +package config + +import ( + "os" + "time" + + "github.com/rs/zerolog" +) + +// NewLogger creates and initializes a new *zerolog.Logger with the given +// log level. +func NewLogger(level zerolog.Level) *zerolog.Logger { + output := zerolog.ConsoleWriter{Out: os.Stdout, NoColor: false, TimeFormat: time.RFC3339} + logger := zerolog.New(output).With().Timestamp().Logger() + + return &logger +} diff --git a/internal/constants/constants.go b/internal/constants/constants.go new file mode 100644 index 0000000..23ba572 --- /dev/null +++ b/internal/constants/constants.go @@ -0,0 +1,10 @@ +package constants + +import "time" + +var LoginCookieName = "gourlsh_auth" +var MFAFlowCookieName = "gourlsh_mfa_key" +var MFASetupCookieName = "gourlsh_mfa_setup" + +var LoginCookieLength = 40 +var LoginCookieExpiryDuration = 30 * 24 * time.Hour diff --git a/internal/db/apikey.go b/internal/db/apikey.go index 197370b..b8b3bb4 100644 --- a/internal/db/apikey.go +++ b/internal/db/apikey.go @@ -1,9 +1,10 @@ package db import ( - "codeberg.org/lauralani/go-urlsh/models" "context" "log" + + "code.lila.network/adoralaura/go-urlsh/models" ) // IsApiKeyValid checks the database if ApiKey val is valid. diff --git a/internal/db/cookie.go b/internal/db/cookie.go index 1affab1..b0bafdb 100644 --- a/internal/db/cookie.go +++ b/internal/db/cookie.go @@ -1,9 +1,12 @@ package db import ( - "codeberg.org/lauralani/go-urlsh/models" "context" + "database/sql" + "fmt" "log" + + "code.lila.network/adoralaura/go-urlsh/models" ) // IsCookieValid checks the database if Cookie val is valid. @@ -25,3 +28,40 @@ func IsCookieValid(val string) bool { return true } } + +func GetUserFromCookie(cookie string) (models.User, error) { + var session models.Session + var user models.User + err := models.DB.NewSelect().Model(&session).Where("cookie = ?", cookie).Scan(context.Background()) + if err != nil { + if err == sql.ErrNoRows { + return models.User{}, fmt.Errorf("[GetUserFromCookie] Session %v not found", cookie) + } else { + return models.User{}, fmt.Errorf("[GetUserFromCookie] Error querying session %v from database: %v", cookie, err) + } + } + err = models.DB.NewSelect().Model(&user).Where("username = ?", session.UserName).Scan(context.Background()) + if err != nil { + return models.User{}, fmt.Errorf("[GetUserFromCookie] Error querying user %v from database: %v", session.UserName, err) + } + return user, nil +} + +func GetUserFromMFACookie(cookie string) (models.User, error) { + var transaction models.MFALoginTransaction + var user models.User + err := models.DB.NewSelect().Model(&transaction).Where("sessionkey = ?", cookie).Scan(context.Background()) + if err != nil { + if err == sql.ErrNoRows { + return models.User{}, fmt.Errorf("[GetUserFromMFACookie] MFA Transaction %v not found", cookie) + } else { + return models.User{}, fmt.Errorf("[GetUserFromMFACookie] Error querying MFA Transaction %v from database: %v", cookie, err) + } + } + err = models.DB.NewSelect().Model(&user).Where("username = ?", transaction.UserName).Scan(context.Background()) + if err != nil { + return models.User{}, fmt.Errorf("[GetUserFromMFACookie] Error querying user %v from database: %v", transaction.UserName, err) + } + return user, nil + +} diff --git a/internal/db/cookie_test.go b/internal/db/cookie_test.go new file mode 100644 index 0000000..7c37c4e --- /dev/null +++ b/internal/db/cookie_test.go @@ -0,0 +1,26 @@ +package db + +// +//import ( +// "database/sql" +// "regexp" +// "testing" +//) +// + +//var db sql.DB +// +//func init() { +// +//} + +// TestHelloName calls greetings.Hello with a name, checking +// for a valid return value. +//func TestCookieValidation(t *testing.T) { +// name := "Gladys" +// want := regexp.MustCompile(`\b` + name + `\b`) +// msg, err := Hello("Gladys") +// if !want.MatchString(msg) || err != nil { +// t.Fatalf(`Hello("Gladys") = %q, %v, want match for %#q, nil`, msg, err, want) +// } +//} diff --git a/internal/db/errors.go b/internal/db/errors.go new file mode 100644 index 0000000..03dab9f --- /dev/null +++ b/internal/db/errors.go @@ -0,0 +1,11 @@ +package db + +import "fmt" + +type DatabaseInsertError struct { + message string +} + +func (e *DatabaseInsertError) Error() string { + return fmt.Sprintf("%d - %s", e.arg, e.message) +} diff --git a/internal/db/global.go b/internal/db/global.go new file mode 100644 index 0000000..8339076 --- /dev/null +++ b/internal/db/global.go @@ -0,0 +1,5 @@ +package db + +import "github.com/uptrace/bun" + +var database *bun.DB diff --git a/internal/db/init_test.go b/internal/db/init_test.go new file mode 100644 index 0000000..c3cb3b4 --- /dev/null +++ b/internal/db/init_test.go @@ -0,0 +1,8 @@ +// myfile_test.go +package db + +import ( + "github.com/uptrace/bun" +) + +var TestingDB *bun.DB diff --git a/internal/db/initialize.go b/internal/db/initialize.go index b2e410e..af67493 100644 --- a/internal/db/initialize.go +++ b/internal/db/initialize.go @@ -1,38 +1,66 @@ package db import ( - "codeberg.org/lauralani/go-urlsh/models" "context" "database/sql" - "fmt" + + "code.lila.network/adoralaura/go-urlsh/internal/config" + "code.lila.network/adoralaura/go-urlsh/models" + "github.com/rs/zerolog" "github.com/uptrace/bun" "github.com/uptrace/bun/dialect/pgdialect" "github.com/uptrace/bun/driver/pgdriver" - "os" ) -func InitializeDB() error { - sqldb := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(os.Getenv("DATABASE_URL")))) - models.DB = bun.NewDB(sqldb, pgdialect.New()) - - _, err := models.DB.NewCreateTable().IfNotExists().Model((*models.Link)(nil)).Exec(context.Background()) - if err != nil { - return fmt.Errorf("couldn't create database: [%w]", err) - } - - _, err = models.DB.NewCreateTable().IfNotExists().Model((*models.User)(nil)).Exec(context.Background()) - if err != nil { - return fmt.Errorf("couldn't create database: [%w]", err) - } - - _, err = models.DB.NewCreateTable().IfNotExists().Model((*models.Session)(nil)).Exec(context.Background()) - if err != nil { - return fmt.Errorf("couldn't create database: [%w]", err) - } - - _, err = models.DB.NewCreateTable().IfNotExists().Model((*models.ApiKey)(nil)).Exec(context.Background()) - if err != nil { - return fmt.Errorf("couldn't create database: [%w]", err) - } - return nil +func dbError(err error, logger *zerolog.Logger) { + logger.Fatal().Str("error", err.Error()).Msg("[DB] couldn't create database") +} + +func InitializeDB(cfg *config.Config, logger *zerolog.Logger) *bun.DB { + sqldb := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(cfg.DatabaseDSN))) + db := bun.NewDB(sqldb, pgdialect.New()) + + models.DB = db + + _, err := db.NewCreateTable().IfNotExists().Model((*models.Link)(nil)).Exec(context.Background()) + if err != nil { + dbError(err, logger) + } + + _, err = db.NewCreateTable().IfNotExists().Model((*models.User)(nil)).Exec(context.Background()) + if err != nil { + dbError(err, logger) + } + + _, err = db.NewCreateTable().IfNotExists().Model((*models.Session)(nil)).Exec(context.Background()) + if err != nil { + dbError(err, logger) + } + + _, err = db.NewCreateTable().IfNotExists().Model((*models.ApiKey)(nil)).Exec(context.Background()) + if err != nil { + dbError(err, logger) + } + + _, err = db.NewCreateTable().IfNotExists().Model((*models.MFALoginTransaction)(nil)).Exec(context.Background()) + if err != nil { + dbError(err, logger) + } + + _, err = db.NewCreateTable().IfNotExists().Model((*models.MFAConfig)(nil)).Exec(context.Background()) + if err != nil { + dbError(err, logger) + } + + _, err = db.NewCreateTable().IfNotExists().Model((*models.MFAScratchCode)(nil)).Exec(context.Background()) + if err != nil { + dbError(err, logger) + } + + err = doMigrations(db, logger) + if err != nil { + dbError(err, logger) + } + + return db } diff --git a/internal/db/interactions.go b/internal/db/interactions.go new file mode 100644 index 0000000..77c67d2 --- /dev/null +++ b/internal/db/interactions.go @@ -0,0 +1,14 @@ +package db + +import ( + "context" + + "github.com/uptrace/bun" +) + +func InsertIntoDB(db *bun.DB, thing any) error { + _, err := db.NewInsert().Model(&thing).Exec(context.Background()) + if err != nil { + t.Fatalf("Couldn't insert test mfa config into DB: %q\n", err) + } +} diff --git a/internal/db/migrations.go b/internal/db/migrations.go new file mode 100644 index 0000000..a8d0901 --- /dev/null +++ b/internal/db/migrations.go @@ -0,0 +1,28 @@ +package db + +import ( + "context" + + "code.lila.network/adoralaura/go-urlsh/migrations" + "github.com/rs/zerolog" + "github.com/uptrace/bun" + "github.com/uptrace/bun/migrate" +) + +func doMigrations(db *bun.DB, logger *zerolog.Logger) error { + ctx := context.Background() + migrator := migrate.NewMigrator(db, migrations.Migrations) + + migrator.Init(ctx) + + group, err := migrator.Migrate(ctx) + if err != nil { + return err + } + if group.IsZero() { + logger.Info().Msg("No new database migrations to run") + return nil + } + logger.Info().Msgf("Database got migrated to %s", group) + return nil +} diff --git a/internal/db/multifactor.go b/internal/db/multifactor.go new file mode 100644 index 0000000..66f6450 --- /dev/null +++ b/internal/db/multifactor.go @@ -0,0 +1,114 @@ +package db + +import ( + "context" + "errors" + "fmt" + "log" + + "code.lila.network/adoralaura/go-urlsh/internal/misc" + "code.lila.network/adoralaura/go-urlsh/models" + "github.com/uptrace/bun" +) + +// UserHasMFA checks the DB if given models.User has MFA enabled. +// Returns (true, nil) if User has MFA enabled, (false, nil) if not. +// (false, error) if a DB error happened +func UserHasMFA(user models.User) (bool, error) { + numrows, err := models.DB.NewSelect().Model((*models.MFAConfig)(nil)).Where("username = ?", user.UserName).Where("active = ?", true).Count(context.Background()) + if err != nil { + return false, fmt.Errorf("[UserHasMFA] error getting MFA count from database: %q", err) + } + + if numrows >= 1 { + return true, nil + } + return false, nil +} + +// scratchCodeUnique checks the database if the generated scratch code +// is unique (not in the database yet) +func scratchCodeIsUnique(db *bun.DB, scratchcode string) bool { + var dbitem models.MFAScratchCode + numrows, err := db.NewSelect().Model(&dbitem).Where("code = ?", scratchcode).Count(context.Background()) + if err != nil { + return false + } + + if numrows != 0 { + return false + } + return true +} + +// RemoveMFAFromDB removes MFA entries for given models.User from the database. +// Returns nil on success, error otherwise. +func RemoveMFAFromDB(user models.User) error { + hasMfa, err := UserHasMFA(user) + if err != nil { + return fmt.Errorf("[RemoveMFAFromDB] Error removing MFA from DB for user %v: %w", user.UserName, err) + } + + if !hasMfa { + return nil + } + + _, err = models.DB.NewDelete().Model((*models.MFAConfig)(nil)).Where("username = ?", user.UserName).Exec(context.Background()) + if err != nil { + log.Println(err.Error()) + return fmt.Errorf("[RemoveMFAFromDB] Error removing MFA Config from DB for user %v: %w", user.UserName, err) + } + + _, err = models.DB.NewDelete().Model((*models.MFAScratchCode)(nil)).Where("username = ?", user.UserName).Exec(context.Background()) + if err != nil { + log.Println(err.Error()) + return fmt.Errorf("[RemoveMFAFromDB] Error removing MFA scratch codes from DB for user %v: %w", user.UserName, err) + } + + return nil +} + +// UserHasFailedMFAAttempt checks the DB for failed MFA Setup attempts +// e.g. inactive MFA config +func UserHasFailedMFAAttempt(user models.User) (bool, error) { + //var mfaconfig models.MFAConfig + //numrows, err := models.DB.NewSelect().Model(&mfaconfig). + // Where("username = ?", user.UserName).Where("active = ?", false). + // Count(context.Background()) + //if err != nil { + // return false, err + //} + + return true, nil +} + +// GenerateNewScratchcodes generates new unique scratch codes, inserts them into the database +// and returns the scratch codes as []models.MFAScratchCode, and nil if successful. Returns empty +// []models.MFAScratchCode and an error if something failed +func GenerateNewScratchcodes(db *bun.DB, user models.User) ([]models.MFAScratchCode, error) { + scratchcodes := []models.MFAScratchCode{} + scratchcodeFailed := 0 + + // generate four unique(!) scratch codes for the user + for len(scratchcodes) != 4 { + if scratchcodeFailed > 15 { + return []models.MFAScratchCode{}, errors.New("failed to generate new scratch codes: maximum tries exceeded") + } + + code := misc.RandomString(8) + + if scratchCodeIsUnique(db, code) { + scratchcodes = append(scratchcodes, models.MFAScratchCode{ + IsUsed: false, Code: code, UserName: user.UserName}) + } else { + scratchcodeFailed++ + } + } + + _, err := db.NewInsert().Model(&scratchcodes).Exec(context.Background()) + if err != nil { + return []models.MFAScratchCode{}, fmt.Errorf("error inserting new scratch codes to DB: %w", err) + } + + return scratchcodes, nil +} diff --git a/internal/db/multifactor_test.go b/internal/db/multifactor_test.go new file mode 100644 index 0000000..b4a15ab --- /dev/null +++ b/internal/db/multifactor_test.go @@ -0,0 +1,109 @@ +package db + +import ( + "context" + "os" + "testing" + "time" + + "code.lila.network/adoralaura/go-urlsh/internal/config" + "code.lila.network/adoralaura/go-urlsh/models" + "github.com/rs/zerolog" + "github.com/uptrace/bun" +) + +// createTestingUser creates the necessary testing users for testing MFA. +func createTestingUser(t *testing.T, db *bun.DB, user *models.User) { + mfaconfig := models.MFAConfig{ + UserName: user.UserName, + TOTPSecret: "abcd", + ExpiresAt: time.Now().Add(5 * time.Minute), + Active: false, + } + + _, err := db.NewInsert().Model(user).Exec(context.Background()) + if err != nil { + t.Fatalf("Couldn't insert test user into DB: %q\n", err) + } + + _, err = db.NewInsert().Model(&mfaconfig).Exec(context.Background()) + if err != nil { + t.Fatalf("Couldn't insert test mfa config into DB: %q\n", err) + } +} + +// removeTestingUser is used as deferred cleanup in multifactor tests. +// It removes models.User and models.MFAConfig with given username from DB. +func removeTestingUser(t *testing.T, db *bun.DB, username string) { + _, err := db.NewInsert().Model((*models.User)(nil)). + Where("username = ?", username).Exec(context.Background()) + if err != nil { + t.Fatalf("Couldn't remove test user %q from DB: %q\n", username, err) + } + + _, err = db.NewInsert().Model((*models.MFAConfig)(nil)). + Where("username = ?", username).Exec(context.Background()) + if err != nil { + t.Fatalf("Couldn't remove test mfa config for %q from DB: %q\n", username, err) + } +} + +func TestUserHasFailedMFAAttemptTrue(t *testing.T) { + cfgfile := os.Getenv("GOURLSH_TEST_CONFIGFILE") + logger := config.NewLogger(zerolog.InfoLevel) + cfg := config.NewConfig(cfgfile) + // setup test environment + testdb := InitializeDB(cfg, logger) + testUserName := "test_mfafailedtrue" + + mfauser := models.User{ + UserName: testUserName, + Created: time.Now(), + } + + createTestingUser(t, testdb, &mfauser) + + defer removeTestingUser(t, testdb, testUserName) + + answer, err := UserHasFailedMFAAttempt(mfauser) + if err != nil { + t.Fatalf("Error running UserHasFailedMFAAttempt in tests: %q\n", err) + } + + if answer == false { + t.Fatalf("db.UserHasFailedMFAAttempt() = false, want true") + } + +} + +func TestUserHasFailedMFAAttemptFalse(t *testing.T) { + cfgfile := os.Getenv("GOURLSH_TEST_CONFIGFILE") + cfg := config.NewConfig(cfgfile) + logger := config.NewLogger(zerolog.InfoLevel) + // setup test environment + testdb := InitializeDB(cfg, logger) + testUserName := "test_mfafailed" + + mfauser := models.User{ + UserName: testUserName, + Created: time.Now(), + } + + createTestingUser(t, testdb, &mfauser) + + defer removeTestingUser(t, testdb, testUserName) + + answer, err := UserHasFailedMFAAttempt(mfauser) + if err != nil { + t.Fatalf("Error running UserHasFailedMFAAttempt in tests: %q\n", err) + } + + if answer == true { + t.Fatalf("db.UserHasFailedMFAAttempt() = true, want false") + } + +} + +func TestGenerateNewScratchcodes(t *testing.T) { + +} diff --git a/internal/misc/constants.go b/internal/misc/constants.go deleted file mode 100644 index 68b5caf..0000000 --- a/internal/misc/constants.go +++ /dev/null @@ -1,3 +0,0 @@ -package misc - -var CookieName = "gourlsh_auth" diff --git a/internal/misc/cookie.go b/internal/misc/cookie.go new file mode 100644 index 0000000..e621ab3 --- /dev/null +++ b/internal/misc/cookie.go @@ -0,0 +1,69 @@ +package misc + +import ( + "context" + "log" + "time" + + "code.lila.network/adoralaura/go-urlsh/internal/constants" + "code.lila.network/adoralaura/go-urlsh/models" + "github.com/gofiber/fiber/v2" +) + +// SetLoginCookie handles setting the Login Cookie. It +// - generates a new cookie secret +// - sets its expiry +// - adds the necessary DB entry for the session and last login +// - adds the cookie to the fiber context +func SetLoginCookie(c *fiber.Ctx, user models.User, expiryTime time.Duration) error { + expires := time.Now().Add(expiryTime) + + key := NewLoginCookie(constants.LoginCookieLength) + var dblogin models.Session + + cookie := new(fiber.Cookie) + cookie.Name = constants.LoginCookieName + cookie.Value = key + cookie.Expires = expires + + dblogin.Expires = expires + dblogin.Cookie = key + dblogin.UserName = user.UserName + + _, err := models.DB.NewInsert().Model(&dblogin).Exec(context.Background()) + if err != nil { + log.Printf("DB Error inserting login cookie information for user %v: %v\n", dblogin.UserName, err.Error()) + return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") + } + + user.LastLogin = time.Now() + _, err = models.DB.NewUpdate().Model(&user).WherePK().Exec(context.Background()) + if err != nil { + log.Printf("DB Error updating last login information for user %v: %v\n", dblogin.UserName, err.Error()) + return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") + } + c.Cookie(cookie) + return nil +} + +func SetMFAFlowCookie(c *fiber.Ctx, cookievalue string) { + expires := time.Now().Add(30 * time.Minute) + + cookie := new(fiber.Cookie) + cookie.Name = constants.MFAFlowCookieName + cookie.Value = cookievalue + cookie.Expires = expires + + c.Cookie(cookie) +} + +func SetMFASetupCookie(c *fiber.Ctx, cookievalue string) { + expires := time.Now().Add(30 * time.Minute) + + cookie := new(fiber.Cookie) + cookie.Name = constants.MFASetupCookieName + cookie.Value = cookievalue + cookie.Expires = expires + + c.Cookie(cookie) +} diff --git a/internal/misc/error.go b/internal/misc/error.go new file mode 100644 index 0000000..bb2de73 --- /dev/null +++ b/internal/misc/error.go @@ -0,0 +1,43 @@ +package misc + +import ( + "encoding/json" + "errors" + + "code.lila.network/adoralaura/go-urlsh/models" + "github.com/gofiber/fiber/v2" +) + +func HandleError(c *fiber.Ctx, err error) error { + code := fiber.StatusInternalServerError + + // Retrieve the custom status code if it's a *fiber.Error + var e *fiber.Error + if errors.As(err, &e) { + code = e.Code + } + + // Set Content-Type: text/plain; charset=utf-8 + c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8) + + // Return status code with error message + return c.Status(code).SendString(err.Error()) + +} + +func New500Error() error { + return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") +} + +func New400Error() error { + return fiber.NewError(fiber.StatusBadRequest, "400 Bad Request") +} + +func New400WithMessageError(msg string) error { + body, _ := json.Marshal(models.HttpErrorBody{Message: msg}) + return fiber.NewError(fiber.StatusBadRequest, string(body[:])) +} + +func New401Error() error { + return fiber.NewError(fiber.StatusUnauthorized, "401 Unauthorized") +} diff --git a/internal/misc/misc.go b/internal/misc/misc.go index 18d5e6c..bb729df 100644 --- a/internal/misc/misc.go +++ b/internal/misc/misc.go @@ -13,3 +13,13 @@ func RandomString(n int) string { } return string(s) } + +func NewLoginCookie(n int) string { + var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") + + s := make([]rune, n) + for i := range s { + s[i] = letters[rand.Intn(len(letters))] + } + return string(s) +} diff --git a/internal/web/account.go b/internal/web/account.go index 7ec9cf6..30d5ae3 100644 --- a/internal/web/account.go +++ b/internal/web/account.go @@ -1,41 +1,38 @@ package web import ( - "codeberg.org/lauralani/go-urlsh/internal/db" - "codeberg.org/lauralani/go-urlsh/internal/misc" - "codeberg.org/lauralani/go-urlsh/models" - "context" - "database/sql" - "github.com/gofiber/fiber/v2" "log" + + "code.lila.network/adoralaura/go-urlsh/internal/constants" + "code.lila.network/adoralaura/go-urlsh/internal/db" + "code.lila.network/adoralaura/go-urlsh/models" + "github.com/gofiber/fiber/v2" ) func HandleAdminAccountGet(c *fiber.Ctx) error { - if !db.IsCookieValid(c.Cookies(misc.CookieName, "")) { + if !db.IsCookieValid(c.Cookies(constants.LoginCookieName, "")) { c.Location("/admin/") c.Status(fiber.StatusSeeOther) return nil } - cookie := c.Cookies(misc.CookieName, "") - var session models.Session - var user models.User - - err := models.DB.NewSelect().Model(&session).Where("cookie = ?", cookie).Scan(context.Background()) + cookie := c.Cookies(constants.LoginCookieName, "") + user, err := db.GetUserFromCookie(cookie) if err != nil { - if err == sql.ErrNoRows { - log.Printf("[HandleUserMe] Session %v not found\n", cookie) - } else { - log.Printf("[HandleUserMe] Error querying session %v from database: %v\n", cookie, err) - } - return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") + log.Println(err) + fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") + } + var userresponse models.UserResponse + userresponse.UserName = user.UserName + userresponse.Created = user.Created + + hasmfa, err := db.UserHasMFA(user) + if err != nil { + log.Println(err) + fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") } - err = models.DB.NewSelect().Model(&user).Where("username = ?", session.UserName).Scan(context.Background()) - if err != nil { - log.Printf("[HandleUserMe] Error querying user %v from database: %v\n", session.UserName, err) - return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") - } + userresponse.MFAEnabled = hasmfa - return c.Render("account", user) + return c.Render("account", userresponse) } diff --git a/internal/web/root.go b/internal/web/index.go similarity index 73% rename from internal/web/root.go rename to internal/web/index.go index 9738e39..df71e9a 100644 --- a/internal/web/root.go +++ b/internal/web/index.go @@ -1,24 +1,25 @@ package web import ( - "codeberg.org/lauralani/go-urlsh/internal/db" - "codeberg.org/lauralani/go-urlsh/internal/misc" - "codeberg.org/lauralani/go-urlsh/models" "context" "database/sql" - "github.com/gofiber/fiber/v2" "log" + + "code.lila.network/adoralaura/go-urlsh/internal/constants" + "code.lila.network/adoralaura/go-urlsh/internal/db" + "code.lila.network/adoralaura/go-urlsh/models" + "github.com/gofiber/fiber/v2" ) -func HandleRootGet(c *fiber.Ctx) error { +func HandleIndexGet(c *fiber.Ctx) error { if c.Params("id", "") == "" { - if db.IsCookieValid(c.Cookies(misc.CookieName, "")) { + if db.IsCookieValid(c.Cookies(constants.LoginCookieName, "")) { c.Location("/admin/") c.Status(fiber.StatusSeeOther) return nil } else { err := c.SendString("This is the index page of go-urlsh.\n " + - "See https://codeberg.org/lauralani/go-urlsh for more info.") + "See https://code.lila.network/adoralaura/go-urlsh for more info.") if err != nil { log.Println(err) return err diff --git a/internal/web/links.go b/internal/web/links.go index 4a88e81..c517769 100644 --- a/internal/web/links.go +++ b/internal/web/links.go @@ -1,18 +1,19 @@ package web import ( - "codeberg.org/lauralani/go-urlsh/internal/db" - "codeberg.org/lauralani/go-urlsh/internal/misc" - "codeberg.org/lauralani/go-urlsh/models" "context" "database/sql" "fmt" - "github.com/gofiber/fiber/v2" "log" + + "code.lila.network/adoralaura/go-urlsh/internal/constants" + "code.lila.network/adoralaura/go-urlsh/internal/db" + "code.lila.network/adoralaura/go-urlsh/models" + "github.com/gofiber/fiber/v2" ) func HandleAdminLinkNewGet(c *fiber.Ctx) error { - if !db.IsCookieValid(c.Cookies(misc.CookieName, "")) { + if !db.IsCookieValid(c.Cookies(constants.LoginCookieName, "")) { c.Location("/admin/") c.Status(fiber.StatusSeeOther) return nil @@ -22,7 +23,7 @@ func HandleAdminLinkNewGet(c *fiber.Ctx) error { } func HandleAdminLinkEditGet(c *fiber.Ctx) error { - if !db.IsCookieValid(c.Cookies(misc.CookieName, "")) { + if !db.IsCookieValid(c.Cookies(constants.LoginCookieName, "")) { c.Location("/admin/") c.Status(fiber.StatusSeeOther) return nil @@ -52,7 +53,7 @@ func HandleAdminLinkEditGet(c *fiber.Ctx) error { } func HandleAdminLinkIndexGet(c *fiber.Ctx) error { - if !db.IsCookieValid(c.Cookies(misc.CookieName, "")) { + if !db.IsCookieValid(c.Cookies(constants.LoginCookieName, "")) { c.Location("/admin/login") c.Status(fiber.StatusSeeOther) return nil diff --git a/internal/web/login.go b/internal/web/login.go index e2e4b87..daa8f30 100644 --- a/internal/web/login.go +++ b/internal/web/login.go @@ -1,16 +1,17 @@ package web import ( - "codeberg.org/lauralani/go-urlsh/internal/db" - "codeberg.org/lauralani/go-urlsh/internal/misc" - "codeberg.org/lauralani/go-urlsh/models" "context" "crypto/sha256" "encoding/hex" - "github.com/gofiber/fiber/v2" - "github.com/google/uuid" "log" "time" + + "code.lila.network/adoralaura/go-urlsh/internal/constants" + "code.lila.network/adoralaura/go-urlsh/internal/db" + "code.lila.network/adoralaura/go-urlsh/internal/misc" + "code.lila.network/adoralaura/go-urlsh/models" + "github.com/gofiber/fiber/v2" ) func HandleAdminLoginPost(c *fiber.Ctx) error { @@ -32,39 +33,41 @@ func HandleAdminLoginPost(c *fiber.Ctx) error { if passwordsum == user.PasswordHash { // Passwords match - var expires time.Time - if login.Remember == "on" { - expires = time.Now().Add(30 * 24 * time.Hour) - } else { - expires = time.Now().Add(24 * time.Hour) - } - - key := uuid.New().String() - dblogin := new(models.Session) - - cookie := new(fiber.Cookie) - cookie.Name = misc.CookieName - cookie.Value = key - cookie.Expires = expires - - dblogin.Expires = expires - dblogin.Cookie = key - dblogin.UserName = user.UserName - - _, err = models.DB.NewInsert().Model(dblogin).Exec(context.Background()) + hasmfa, err := db.UserHasMFA(user) if err != nil { - log.Printf("DB Error inserting login cookie information for user %v: %v\n", dblogin.UserName, err.Error()) + log.Printf("[HandleAdminLoginPost] Error checking MFA status for user %v: %q", user.UserName, err) return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") } - user.LastLogin = time.Now() - _, err = models.DB.NewUpdate().Model(&user).WherePK().Exec(context.Background()) + if hasmfa { + var mfatransaction models.MFALoginTransaction + sessionkey := misc.NewLoginCookie(constants.LoginCookieLength) + + mfatransaction.SessionKey = sessionkey + mfatransaction.Expires = time.Now().Add(30 * time.Minute) + mfatransaction.UserName = user.UserName + + _, err = models.DB.NewInsert().Model(&mfatransaction).Exec(context.Background()) + if err != nil { + log.Printf("[HandleAdminLoginPost] Error inserting MFA transaction to DB: %q\n", err) + return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") + } + misc.SetMFAFlowCookie(c, sessionkey) + + c.Status(fiber.StatusSeeOther) + c.Location("/admin/login/multifactor") + return nil + } + + // TODO: maybe make login cookie time configurable + // TODO: handle rememberme + err = misc.SetLoginCookie(c, user, constants.LoginCookieExpiryDuration) if err != nil { - log.Printf("DB Error updating last login information for user %v: %v\n", dblogin.UserName, err.Error()) + log.Printf("[HandleAdminLoginPost] Error setting cookie: %q\n", err) return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") } - c.Cookie(cookie) + c.Status(fiber.StatusSeeOther) c.Location("/admin/") return nil @@ -75,7 +78,7 @@ func HandleAdminLoginPost(c *fiber.Ctx) error { } func HandleAdminLoginGet(c *fiber.Ctx) error { - if db.IsCookieValid(c.Cookies(misc.CookieName, "")) { + if db.IsCookieValid(c.Cookies(constants.LoginCookieName, "")) { c.Location("/admin/") c.Status(fiber.StatusSeeOther) return nil diff --git a/internal/web/model.go b/internal/web/model.go new file mode 100644 index 0000000..8260525 --- /dev/null +++ b/internal/web/model.go @@ -0,0 +1,22 @@ +package web + +import ( + "code.lila.network/adoralaura/go-urlsh/internal/config" + "github.com/rs/zerolog" + "github.com/uptrace/bun" +) + +type WebRouteManager struct { + db *bun.DB + logger *zerolog.Logger + config *config.Config +} + +func NewWebRouteManager(db *bun.DB, logger *zerolog.Logger, config *config.Config) *WebRouteManager { + manager := new(WebRouteManager) + manager.db = db + manager.logger = logger + manager.config = config + + return manager +} diff --git a/internal/web/multifactor-login.go b/internal/web/multifactor-login.go new file mode 100644 index 0000000..cae4480 --- /dev/null +++ b/internal/web/multifactor-login.go @@ -0,0 +1,112 @@ +package web + +import ( + "context" + "fmt" + "log" + "slices" + + "code.lila.network/adoralaura/go-urlsh/internal/constants" + "code.lila.network/adoralaura/go-urlsh/internal/db" + "code.lila.network/adoralaura/go-urlsh/internal/misc" + "code.lila.network/adoralaura/go-urlsh/models" + "github.com/gofiber/fiber/v2" + "github.com/pquerna/otp/totp" +) + +// handles the POST request where the User has to input 2fa token +func HandleAdminLoginMFAPost(c *fiber.Ctx) error { + mfacookie := c.Cookies(constants.MFAFlowCookieName, "") + + if mfacookie == "" { + return misc.New400Error() + } + + token := new(models.TokenRequest) + var istotp bool + + if err := c.BodyParser(token); err != nil { + // TODO: Debug logging + return misc.New400Error() + } + if len(token.Token) == 6 { + istotp = true + } else if len(token.Token) == 8 { + istotp = false + } else { + // TODO: Debug logging + return misc.New400Error() + } + + user, err := db.GetUserFromMFACookie(mfacookie) + if err != nil { + log.Println(err) + // TODO: Debug logging + return misc.New400Error() + } + + // check token/scratch validity + var scratchcodeIsValid bool + if istotp { + scratchcodeIsValid = checkTotpIsValid(token.Token, user) + } else { + scratchcodeIsValid = checkScratchIsValid(token.Token, user) + } + + if scratchcodeIsValid { + err = misc.SetLoginCookie(c, user, constants.LoginCookieExpiryDuration) + if err != nil { + log.Printf("[HandleAdminLoginPost] Error setting cookie: %q\n", err) + return misc.New500Error() + } + + _, err = models.DB.NewUpdate(). + Model(&models.MFAScratchCode{Code: token.Token, IsUsed: true}). + OmitZero().WherePK().Exec(context.Background()) + if err != nil { + fmt.Printf("[HandleAdminLoginMFAPost] Error marking scratch code as used: %v\n", err.Error()) + return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") + } + + c.Status(fiber.StatusOK) + return nil + } + + log.Printf("[HandleAdminLoginPost] Error handling MFA code: %q\n", err) + return misc.New400Error() +} + +func checkTotpIsValid(passcode string, user models.User) bool { + var mfaconfig models.MFAConfig + + err := models.DB.NewSelect().Model(&mfaconfig).Where("username = ?", user.UserName).Scan(context.Background()) + if err != nil { + log.Printf("Error getting MFA config for %v from DB: %v\n", user.UserName, err.Error()) + // TODO: Debug logging + return false + } + + return totp.Validate(passcode, mfaconfig.TOTPSecret) +} + +func checkScratchIsValid(scratch string, user models.User) bool { + var scratchcodes []models.MFAScratchCode + + err := models.DB.NewSelect().Model(&scratchcodes).Where("username = ?", user.UserName).Where("is_used = ?", false).Scan(context.Background()) + if err != nil { + log.Printf("Error getting MFA config for %v from DB: %v\n", user.UserName, err.Error()) + // TODO: Debug logging + return false + } + + var scratchcodeSlice []string + for _, code := range scratchcodes { + scratchcodeSlice = append(scratchcodeSlice, code.Code) + } + + return slices.Contains(scratchcodeSlice, scratch) +} + +func HandleAdminLoginMFAGet(c *fiber.Ctx) error { + return c.Render("login-multifactor", nil) +} diff --git a/internal/web/multifactor-remove.go b/internal/web/multifactor-remove.go new file mode 100644 index 0000000..c8f9a12 --- /dev/null +++ b/internal/web/multifactor-remove.go @@ -0,0 +1,49 @@ +package web + +import ( + "log" + "net/http" + + "code.lila.network/adoralaura/go-urlsh/internal/constants" + "code.lila.network/adoralaura/go-urlsh/internal/db" + "code.lila.network/adoralaura/go-urlsh/internal/misc" + "github.com/gofiber/fiber/v2" +) + +// HandleAdminAccountMFARemove is a DELETE endpoint that handles the deletion +// of the logged in users MFA configuration. +// +// Returns HTTP 401 if no valid user cookie, HTTP 400 if no MFA is configured for the user, +// HTTP 500 if a DB error happened or HTTP 204 if the deletion request succeeded. +func HandleAdminAccountMFARemove(c *fiber.Ctx) error { + + if !db.IsCookieValid(c.Cookies(constants.LoginCookieName, "")) { + c.Status(http.StatusUnauthorized) + return nil + } + + user, err := db.GetUserFromCookie(c.Cookies(constants.LoginCookieName)) + if err != nil { + log.Println(err) + return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") + } + + hasMfa, err := db.UserHasMFA(user) + if err != nil { + log.Println(err) + return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") + } + + if !hasMfa { + return misc.New400Error() + } + + err = db.RemoveMFAFromDB(user) + if err != nil { + log.Println(err) + return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") + } + + c.Status(fiber.StatusNoContent) + return nil +} diff --git a/internal/web/multifactor-setup.go b/internal/web/multifactor-setup.go new file mode 100644 index 0000000..71fbc2a --- /dev/null +++ b/internal/web/multifactor-setup.go @@ -0,0 +1,159 @@ +package web + +import ( + "bytes" + "context" + "encoding/base64" + "encoding/json" + "image/png" + "log" + "strconv" + "time" + + "code.lila.network/adoralaura/go-urlsh/internal/constants" + "code.lila.network/adoralaura/go-urlsh/internal/db" + "code.lila.network/adoralaura/go-urlsh/internal/misc" + "code.lila.network/adoralaura/go-urlsh/models" + "github.com/gofiber/fiber/v2" + "github.com/pquerna/otp/totp" +) + +func HandleAdminAccountMFASetupGet(c *fiber.Ctx) error { + if !db.IsCookieValid(c.Cookies(constants.LoginCookieName, "")) { + c.Location("/admin/") + c.Status(fiber.StatusSeeOther) + return nil + } + + var mfaobject models.MFATemplateObject + var mfaconfig models.MFAConfig + mfaconfig.Active = false + mfaconfig.ExpiresAt = time.Now().Add(15 * time.Minute) + + user, err := db.GetUserFromCookie(c.Cookies(constants.LoginCookieName)) + if err != nil { + log.Println(err) + fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") + } + + mfaconfig.UserName = user.UserName + + key, err := totp.Generate(totp.GenerateOpts{ + Issuer: "go-urlsh", + AccountName: user.UserName, + }) + if err != nil { + log.Println(err) + fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") + } + + mfaconfig.TOTPSecret = key.Secret() + mfaobject.Key = key.URL() + + var buf bytes.Buffer + img, err := key.Image(200, 200) + if err != nil { + log.Println(err) + fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") + } + + png.Encode(&buf, img) + base64img := base64.StdEncoding.EncodeToString(buf.Bytes()) + + mfaobject.Image = base64img + + // todo: use function + _, err = models.DB.NewInsert().Model(&scratchcodes).Exec(context.Background()) + if err != nil { + log.Printf("[HandleAdminAccountMFASetupGet] Error inserting scratch codes to DB: %q\n", err) + fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") + } + + _, err = models.DB.NewInsert().Model(&mfaconfig).Exec(context.Background()) + if err != nil { + log.Printf("[HandleAdminAccountMFASetupGet] Error inserting mfaconfig to DB: %q\n", err) + fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") + } + + misc.SetMFASetupCookie(c, strconv.Itoa(int(mfaconfig.ID))) + return c.Render("setup-multifactor", mfaobject) +} + +func HandleAdminAccountMFASetupPost(c *fiber.Ctx) error { + if !db.IsCookieValid(c.Cookies(constants.LoginCookieName, "")) { + c.Location("/admin/") + c.Status(fiber.StatusSeeOther) + return nil + } + + var response models.MFASetupResponse + response.Error = true + + var token models.TokenRequest + var config models.MFAConfig + var scratchcodes []models.MFAScratchCode + //var user models.User + + err := json.Unmarshal(c.Body(), &token) + if err != nil { + log.Println(err.Error()) + return fiber.NewError(fiber.StatusBadRequest, "400 Bad Request") + } + + //if err := c.BodyParser(&token); err != nil { + // response.Message = "Token is invalid" + // c.Status(fiber.StatusBadRequest) + // c.JSON(response) + // return nil + //} + setupcookie := c.Cookies(constants.MFASetupCookieName, "") + + if setupcookie == "" { + return fiber.NewError(fiber.StatusBadRequest, "400 Bad Request") + } + + err = models.DB.NewSelect().Model(&config).Where("id = ?", setupcookie).Scan(context.Background()) + if err != nil { + log.Printf("[HandleAdminAccountMFASetupPost] Error getting MFAConfig from DB: %q\n", err) + return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") + } + + totpvalid := totp.Validate(token.Token, config.TOTPSecret) + if totpvalid { + response.Error = false + response.Message = "Multifactor authentication was successfully set up!" + + err = models.DB.NewSelect().Model(&scratchcodes).Where("username = ?", config.UserName).Scan(context.Background()) + if err != nil { + log.Printf("[HandleAdminAccountMFASetupPost] Error getting MFA scratch codes from DB: %q\n", err) + return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error") + } + + var scratchcodeSlice []string + for _, code := range scratchcodes { + scratchcodeSlice = append(scratchcodeSlice, code.Code) + } + + response.RecoveryTokens = scratchcodeSlice + + config.Active = true + + _, err := models.DB.NewUpdate().Model(&config).Column("active").WherePK().Exec(context.Background()) + if err != nil { + log.Printf("[HandleAdminAccountMFASetupGet] Error getting MFAConfig from DB: %q\n", err) + response.Message = "500: DB Error, see logs" + c.Status(fiber.StatusInternalServerError) + c.JSON(response) + return nil + } + c.Status(fiber.StatusOK) + c.JSON(response) + } else { + response.Error = true + response.Message = "Token is invalid, please try again." + c.Status(fiber.StatusBadRequest) + c.JSON(response) + } + + return nil +} diff --git a/main.go b/main.go index 841013c..80fa779 100644 --- a/main.go +++ b/main.go @@ -1,8 +1,9 @@ package main import ( - app "codeberg.org/lauralani/go-urlsh/cmd/go-urlsh" "log" + + app "code.lila.network/adoralaura/go-urlsh/cmd/go-urlsh" ) func main() { diff --git a/main_test.go b/main_test.go new file mode 100644 index 0000000..5047bcb --- /dev/null +++ b/main_test.go @@ -0,0 +1,17 @@ +package main + +import ( + "os" + "testing" + + "code.lila.network/adoralaura/go-urlsh/internal/db" + "github.com/uptrace/bun" +) + +var TestingDB *bun.DB + +func TestMain(m *testing.M) { + TestingDB = db.InitializeDB() + + os.Exit(m.Run()) +} diff --git a/migrations/20230618095614_sessioncookie_changed.go b/migrations/20230618095614_sessioncookie_changed.go new file mode 100644 index 0000000..cb15741 --- /dev/null +++ b/migrations/20230618095614_sessioncookie_changed.go @@ -0,0 +1,19 @@ +package migrations + +import ( + "context" + + "github.com/uptrace/bun" +) + +func init() { + Migrations.MustRegister(func(ctx context.Context, db *bun.DB) error { + db.ExecContext(context.Background(), `ALTER TABLE logins ALTER COLUMN cookie SET DATA TYPE VARCHAR`) + db.ExecContext(context.Background(), `TRUNCATE TABLE logins`) + return nil + }, func(ctx context.Context, db *bun.DB) error { + db.ExecContext(context.Background(), `ALTER TABLE logins ALTER COLUMN cookie SET DATA TYPE UUID USING (gen_random_uuid());`) + db.ExecContext(context.Background(), `ALTER TABLE logins ALTER COLUMN cookie SET DEFAULT gen_random_uuid();`) + return nil + }) +} diff --git a/migrations/20240506000001_mfa_rename_tables.go b/migrations/20240506000001_mfa_rename_tables.go new file mode 100644 index 0000000..903cabe --- /dev/null +++ b/migrations/20240506000001_mfa_rename_tables.go @@ -0,0 +1,23 @@ +package migrations + +import ( + "context" + + "github.com/uptrace/bun" +) + +func init() { + Migrations.MustRegister(func(ctx context.Context, db *bun.DB) error { + db.ExecContext(context.Background(), `ALTER TABLE multifactor RENAME COLUMN expiresat TO expires_at`) + db.ExecContext(context.Background(), `ALTER TABLE multifactor RENAME COLUMN totpurl TO totp_secret`) + db.ExecContext(context.Background(), `ALTER TABLE users RENAME COLUMN lastlogin TO last_login`) + db.ExecContext(context.Background(), `ALTER TABLE multifactor_scratchcodes RENAME COLUMN isused TO is_used`) + return nil + }, func(ctx context.Context, db *bun.DB) error { + db.ExecContext(context.Background(), `ALTER TABLE multifactor RENAME COLUMN expires_at TO expiresat`) + db.ExecContext(context.Background(), `ALTER TABLE multifactor RENAME COLUMN totp_secret TO totpurl`) + db.ExecContext(context.Background(), `ALTER TABLE users RENAME COLUMN last_login TO lastlogin`) + db.ExecContext(context.Background(), `ALTER TABLE multifactor_scratchcodes RENAME COLUMN is_used TO isused`) + return nil + }) +} diff --git a/migrations/main.go b/migrations/main.go new file mode 100644 index 0000000..f7346fb --- /dev/null +++ b/migrations/main.go @@ -0,0 +1,7 @@ +package migrations + +import ( + "github.com/uptrace/bun/migrate" +) + +var Migrations = migrate.NewMigrations() diff --git a/models/db.go b/models/db.go index e0ab6e9..9003cb7 100644 --- a/models/db.go +++ b/models/db.go @@ -4,4 +4,5 @@ import ( "github.com/uptrace/bun" ) +// Deprecated: use db.database in db Package instead var DB *bun.DB diff --git a/models/error.go b/models/error.go new file mode 100644 index 0000000..009ff00 --- /dev/null +++ b/models/error.go @@ -0,0 +1,5 @@ +package models + +type HttpErrorBody struct { + Message string `json:"message"` +} diff --git a/models/login.go b/models/login.go index 2c23d32..638ebb0 100644 --- a/models/login.go +++ b/models/login.go @@ -1,13 +1,14 @@ package models import ( - "github.com/uptrace/bun" "time" + + "github.com/uptrace/bun" ) type Session struct { bun.BaseModel `bun:"table:logins"` - Cookie string `bun:"cookie,pk,type:uuid"` + Cookie string `bun:"cookie,pk"` UserName string `bun:"username,notnull"` Expires time.Time `bun:"expires,notnull"` } diff --git a/models/multifactor.go b/models/multifactor.go new file mode 100644 index 0000000..af2f452 --- /dev/null +++ b/models/multifactor.go @@ -0,0 +1,49 @@ +package models + +import ( + "time" + + "github.com/uptrace/bun" +) + +type TokenRequest struct { + Token string `json:"token"` +} + +type MFALoginTransaction struct { + bun.BaseModel `bun:"table:logintransactions"` + SessionKey string `bun:"sessionkey,pk"` + UserName string `bun:"username,notnull"` + Expires time.Time `bun:"expires,notnull"` +} + +// TODO: Rework Scratch tokens: +// Only one Scratch token +// Possibility to regenerate scratch token +// mark Tokens as used +type MFAConfig struct { + bun.BaseModel `bun:"table:multifactor"` + ID int64 `bun:"id,pk,autoincrement"` + UserName string `bun:"username,notnull"` + TOTPSecret string `bun:"totp_secret,notnull"` + ExpiresAt time.Time `bun:"expires_at,notnull"` + Active bool `bun:"active,notnull"` +} + +type MFAScratchCode struct { + bun.BaseModel `bun:"table:multifactor_scratchcodes"` + Code string `bun:"code,pk"` + UserName string `bun:"username,notnull"` + IsUsed bool `bun:"is_used,notnull"` +} + +type MFATemplateObject struct { + Key string + Image string +} + +type MFASetupResponse struct { + Error bool `json:"error"` + Message string `json:"message,omitempty"` + RecoveryTokens []string `json:"recovery_tokens,omitempty"` +} diff --git a/models/user.go b/models/user.go index 8e5dd32..6d1cb6f 100644 --- a/models/user.go +++ b/models/user.go @@ -1,20 +1,22 @@ package models import ( - "github.com/uptrace/bun" "time" + + "github.com/uptrace/bun" ) type User struct { bun.BaseModel `bun:"table:users"` UserName string `bun:"username,pk" json:"username"` Created time.Time `bun:"created,notnull,default:now()" json:"created"` - LastLogin time.Time `bun:"lastlogin" json:"last_login"` + LastLogin time.Time `bun:"last_login" json:"last_login"` PasswordSalt string `bun:"salt" json:"password_salt"` PasswordHash string `bun:"password" json:"password_hash"` } type UserResponse struct { - UserName string `json:"username"` - Created time.Time `json:"created"` + UserName string `json:"username"` + Created time.Time `json:"created"` + MFAEnabled bool `json:"mfa_neabled"` } diff --git a/views/account.tmpl b/views/account.tmpl index 66ec3d7..836641c 100644 --- a/views/account.tmpl +++ b/views/account.tmpl @@ -7,12 +7,22 @@ Account - go-urlsh + @@ -32,7 +42,7 @@ API Keys
  • - Users (coming soon) + Users (coming soon)
  • Logout @@ -47,13 +57,23 @@

    Created at: {{ .Created }}

    Security

    -

    nothing here yet

    - -

    -

    -
    - -
    + {{if .MFAEnabled}} + disable Two-Factor Authentication + {{else}} + Setup Two-Factor Authentication + {{end}} + +

    ⚠️ Are you sure you want to disable two-factor authentication?

    +

    Two-factor authentication adds an additional layer of security to your account by requiring + more than just a password to sign in.
    If you need to change your configuration, you can delete and re-add + Two-Factor authentication again.

    Do you really want to remove your Two-Factor authentication?

    +
    + + + + +
    {{template "partials/footer" .}} diff --git a/views/add_link.tmpl b/views/add_link.tmpl index 6696115..2f5f9ea 100644 --- a/views/add_link.tmpl +++ b/views/add_link.tmpl @@ -7,6 +7,7 @@ Add new Shortlink - go-urlsh + diff --git a/views/edit_link.tmpl b/views/edit_link.tmpl index aa836cd..47bd3b7 100644 --- a/views/edit_link.tmpl +++ b/views/edit_link.tmpl @@ -7,6 +7,7 @@ Edit Shortlink - go-urlsh + diff --git a/views/links.tmpl b/views/links.tmpl index 9c0b4fe..fb11a3c 100644 --- a/views/links.tmpl +++ b/views/links.tmpl @@ -7,6 +7,7 @@ Shortlinks - go-urlsh + diff --git a/views/login-multifactor.tmpl b/views/login-multifactor.tmpl new file mode 100644 index 0000000..0b0bf35 --- /dev/null +++ b/views/login-multifactor.tmpl @@ -0,0 +1,40 @@ + + + + + + + Multi Factor Authentication - go-urlsh + + + + + + + + +
    +
    +
    +
    +

    + Multi Factor Authentication

    + +
    +
    + + + + +
    +
    +
    +
    + + + diff --git a/views/login.tmpl b/views/login.tmpl index d3e5c63..a9121dd 100644 --- a/views/login.tmpl +++ b/views/login.tmpl @@ -7,6 +7,7 @@ Login - go-urlsh + @@ -26,13 +27,6 @@ -
    - -
    - diff --git a/views/partials/footer.tmpl b/views/partials/footer.tmpl index 8cd265e..a9592ba 100644 --- a/views/partials/footer.tmpl +++ b/views/partials/footer.tmpl @@ -1,8 +1,8 @@ \ No newline at end of file + diff --git a/views/setup-multifactor.tmpl b/views/setup-multifactor.tmpl new file mode 100644 index 0000000..6bcc6f8 --- /dev/null +++ b/views/setup-multifactor.tmpl @@ -0,0 +1,109 @@ + + + + + + + Set up Two-Factor authentication - go-urlsh + + + + + + + + + + + +
    +

    Setup Two-Factor authentication

    + In order to setup Two-Factor authentication, please scan this image with your authentication application:
    + TOTP QR-Code
    + + Or enter the secret manually into your TOTP application: +
    + {{ .Key }} +

    + Afterwards please enter the passcode shown in the TOTP application here for confirmation: +
    +
    + +
    + + + +
    +
    + +

    2FA successfully set up!

    +

    These are your recovery codes, keep them somewhere safe, you'll only see them once:

    +

    +
    + +
    +
    + +

    +

    +
    + +
    +
    +
    + {{template "partials/footer" .}} + + + diff --git a/web/add_link.html b/web/add_link.html index c954e24..59ce33d 100644 --- a/web/add_link.html +++ b/web/add_link.html @@ -7,8 +7,8 @@ Add new Shortlink - go-urlsh + - diff --git a/web/custom.css b/web/custom.css index 06b24af..01ec04f 100644 --- a/web/custom.css +++ b/web/custom.css @@ -75,4 +75,8 @@ body>footer { input[readonly] { color: gray; -} \ No newline at end of file +} + +.monospace { + font-family: 'Courier New', monospace; +} diff --git a/web/link_edit.html b/web/link_edit.html index dd56808..6304bc5 100644 --- a/web/link_edit.html +++ b/web/link_edit.html @@ -7,6 +7,7 @@ Edit Shortlink - go-urlsh + diff --git a/web/links.html b/web/links.html index 6457ed3..313cde1 100644 --- a/web/links.html +++ b/web/links.html @@ -7,6 +7,7 @@ Shortlinks - go-urlsh + diff --git a/web/login.html b/web/login.html index d3e5c63..436c646 100644 --- a/web/login.html +++ b/web/login.html @@ -7,6 +7,7 @@ Login - go-urlsh + diff --git a/web/main.js b/web/main.js index 9c1b656..902a7dc 100644 --- a/web/main.js +++ b/web/main.js @@ -1,6 +1,6 @@ // Link overview -async function HandleLinkIndexDelete(id){ +async function HandleLinkIndexDelete(id) { let response = await fetch("/api/v1/links/" + id, { credentials: "include", mode: "same-origin", @@ -30,7 +30,7 @@ async function HandleLinkEditSubmit() { await LinkAction("edit") } -async function LinkAction(action){ +async function LinkAction(action) { document.getElementById("submit").active = false let slug = document.getElementById("linkname").value let url = document.getElementById("link").value @@ -38,22 +38,22 @@ async function LinkAction(action){ let method, endpoint = "" let body; - switch(action) { + switch (action) { case "add": method = "POST" endpoint = "/api/v1/links/" body = { - "id" : slug, - "url" : url, - "description" : description + "id": slug, + "url": url, + "description": description } break; case "edit": method = "PUT" endpoint = "/api/v1/links/" + slug body = { - "url" : url, - "description" : description + "url": url, + "description": description } break; default: @@ -82,8 +82,7 @@ async function LinkAction(action){ async function HandleLinkFieldChange() { console.log("HandleChange") let buttonactive = true - if (document.getElementById("link").value === "") - { + if (document.getElementById("link").value === "") { buttonactive = false } document.getElementById("submit").active = buttonactive @@ -98,7 +97,7 @@ async function HandleApiKeyNewSubmit() { button.setAttribute("aria-busy", "true") let body = { - "description" : description + "description": description } let response = await fetch("/api/v1/apikeys", { @@ -117,11 +116,111 @@ async function HandleApiKeyNewSubmit() { } } -async function HandleApiKeyModalClose() { - let modal = document.getElementById('dialog-info'); - modal.close() +async function HandleMFASetupTokenSubmit() { + let token = document.getElementById("token").value + let button = document.getElementById("button-submit") + + button.disabled = true + button.setAttribute('aria-busy', 'true') + + let body = { + "token": token + } + + let response = await fetch("/admin/account/mfa/confirm", { + credentials: "include", + body: JSON.stringify(body), + headers: { "Content-Type": "application/json", }, + mode: "same-origin", + method: "POST" + }); + + if (response.ok) { + let data = await response.json() + + document.getElementById("dialog-tokens").textContent = data["recovery_tokens"].join(" ") + document.getElementById('user-dialog').showModal() + } else if (response.status == 400) { + // document.cookie = 'gourlsh_mfa_setup=; Max-Age=-1; path=/; domain=' + location.hostname; + + document.getElementById('token').setAttribute('aria-invalid', 'true') + button.setAttribute('aria-busy', 'false') + button.disabled = false + document.getElementById('error-message').setAttribute('class', '') + } } +async function HandleMFARemovalRequest() { + document.getElementById('mfa-disable-dialog').showModal() +} + +async function HandleMFARemoval() { + let keepButton = document.getElementById('button-keep') + let deleteButton = document.getElementById('button-delete') + + keepButton.disabled = true + deleteButton.disabled = true + deleteButton.value = 'Please wait...' + deleteButton.setAttribute('aria-busy', 'true') + + endpoint = "/admin/account/mfa" + let response = await fetch(endpoint, { + credentials: "include", + mode: "same-origin", + method: "DELETE" + }); + + if (response.ok) { + document.location = "/admin/account" + } //else { + // TODO + // Handle error condition + //document.cookie = 'gourlsh_mfa_setup=; Max-Age=-1; path=/; domain=' + location.hostname; + + //document.getElementById("dialog-heading").textContent = "Error!" + //document.getElementById("dialog-text").textContent = "Something didnt work!" + //document.getElementById('dialog-error').showModal() + //} +} + +async function HandleMFALoginTokenPost() { + document.getElementById("submit").disabled = true; + document.getElementById("token").disabled = true; + let token = document.getElementById("token").value + let body = { + "token": token + } + + let response = await fetch("/admin/login/multifactor", { + credentials: "include", + headers: { "Content-Type": "application/json", }, + body: JSON.stringify(body), + mode: "same-origin", + method: "POST" + }); + + if (response.ok) { + document.location = "/admin/" + } else { + document.getElementById("submit").disabled = false; + document.getElementById("token").disabled = false; + document.getElementById('error-message').innerHTML = "Two Factor Authentication failed. Please try again." + document.getElementById('error-message').setAttribute("class", "") + document.getElementById('token').value = "" + document.getElementById('token').setAttribute("aria-invalid", "true") + + } +} + +function HandleModalClose(id, redir) { + document.getElementById(id).close(); + + if (redir) { + document.location = redir + } +} + + // General function Logout() { diff --git a/web/pico.classless.min.css b/web/pico.classless.min.css deleted file mode 100644 index 2a48b58..0000000 --- a/web/pico.classless.min.css +++ /dev/null @@ -1,5 +0,0 @@ -@charset "UTF-8";/*! - * Pico CSS v1.5.10 (https://picocss.com) - * Copyright 2019-2023 - Licensed under MIT - */:root{--font-family:system-ui,-apple-system,"Segoe UI","Roboto","Ubuntu","Cantarell","Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--line-height:1.5;--font-weight:400;--font-size:16px;--border-radius:0.25rem;--border-width:1px;--outline-width:3px;--spacing:1rem;--typography-spacing-vertical:1.5rem;--block-spacing-vertical:calc(var(--spacing) * 2);--block-spacing-horizontal:var(--spacing);--form-element-spacing-vertical:0.75rem;--form-element-spacing-horizontal:1rem;--nav-element-spacing-vertical:1rem;--nav-element-spacing-horizontal:0.5rem;--nav-link-spacing-vertical:0.5rem;--nav-link-spacing-horizontal:0.5rem;--form-label-font-weight:var(--font-weight);--transition:0.2s ease-in-out;--modal-overlay-backdrop-filter:blur(0.25rem)}@media (min-width:576px){:root{--font-size:17px}}@media (min-width:768px){:root{--font-size:18px}}@media (min-width:992px){:root{--font-size:19px}}@media (min-width:1200px){:root{--font-size:20px}}@media (min-width:576px){body>footer,body>header,body>main,section{--block-spacing-vertical:calc(var(--spacing) * 2.5)}}@media (min-width:768px){body>footer,body>header,body>main,section{--block-spacing-vertical:calc(var(--spacing) * 3)}}@media (min-width:992px){body>footer,body>header,body>main,section{--block-spacing-vertical:calc(var(--spacing) * 3.5)}}@media (min-width:1200px){body>footer,body>header,body>main,section{--block-spacing-vertical:calc(var(--spacing) * 4)}}@media (min-width:576px){article{--block-spacing-horizontal:calc(var(--spacing) * 1.25)}}@media (min-width:768px){article{--block-spacing-horizontal:calc(var(--spacing) * 1.5)}}@media (min-width:992px){article{--block-spacing-horizontal:calc(var(--spacing) * 1.75)}}@media (min-width:1200px){article{--block-spacing-horizontal:calc(var(--spacing) * 2)}}dialog>article{--block-spacing-vertical:calc(var(--spacing) * 2);--block-spacing-horizontal:var(--spacing)}@media (min-width:576px){dialog>article{--block-spacing-vertical:calc(var(--spacing) * 2.5);--block-spacing-horizontal:calc(var(--spacing) * 1.25)}}@media (min-width:768px){dialog>article{--block-spacing-vertical:calc(var(--spacing) * 3);--block-spacing-horizontal:calc(var(--spacing) * 1.5)}}a{--text-decoration:none}small{--font-size:0.875em}h1,h2,h3,h4,h5,h6{--font-weight:700}h1{--font-size:2rem;--typography-spacing-vertical:3rem}h2{--font-size:1.75rem;--typography-spacing-vertical:2.625rem}h3{--font-size:1.5rem;--typography-spacing-vertical:2.25rem}h4{--font-size:1.25rem;--typography-spacing-vertical:1.874rem}h5{--font-size:1.125rem;--typography-spacing-vertical:1.6875rem}[type=checkbox],[type=radio]{--border-width:2px}[type=checkbox][role=switch]{--border-width:3px}tfoot td,tfoot th,thead td,thead th{--border-width:3px}:not(thead,tfoot)>*>td{--font-size:0.875em}code,kbd,pre,samp{--font-family:"Menlo","Consolas","Roboto Mono","Ubuntu Monospace","Noto Mono","Oxygen Mono","Liberation Mono",monospace,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"}kbd{--font-weight:bolder}:root:not([data-theme=dark]),[data-theme=light]{--background-color:#fff;--color:hsl(205, 20%, 32%);--h1-color:hsl(205, 30%, 15%);--h2-color:#24333e;--h3-color:hsl(205, 25%, 23%);--h4-color:#374956;--h5-color:hsl(205, 20%, 32%);--h6-color:#4d606d;--muted-color:hsl(205, 10%, 50%);--muted-border-color:hsl(205, 20%, 94%);--primary:hsl(195, 85%, 41%);--primary-hover:hsl(195, 90%, 32%);--primary-focus:rgba(16, 149, 193, 0.125);--primary-inverse:#fff;--secondary:hsl(205, 15%, 41%);--secondary-hover:hsl(205, 20%, 32%);--secondary-focus:rgba(89, 107, 120, 0.125);--secondary-inverse:#fff;--contrast:hsl(205, 30%, 15%);--contrast-hover:#000;--contrast-focus:rgba(89, 107, 120, 0.125);--contrast-inverse:#fff;--mark-background-color:#fff2ca;--mark-color:#543a26;--ins-color:#388e3c;--del-color:#c62828;--blockquote-border-color:var(--muted-border-color);--blockquote-footer-color:var(--muted-color);--button-box-shadow:0 0 0 rgba(0, 0, 0, 0);--button-hover-box-shadow:0 0 0 rgba(0, 0, 0, 0);--form-element-background-color:transparent;--form-element-border-color:hsl(205, 14%, 68%);--form-element-color:var(--color);--form-element-placeholder-color:var(--muted-color);--form-element-active-background-color:transparent;--form-element-active-border-color:var(--primary);--form-element-focus-color:var(--primary-focus);--form-element-disabled-background-color:hsl(205, 18%, 86%);--form-element-disabled-border-color:hsl(205, 14%, 68%);--form-element-disabled-opacity:0.5;--form-element-invalid-border-color:#c62828;--form-element-invalid-active-border-color:#d32f2f;--form-element-invalid-focus-color:rgba(211, 47, 47, 0.125);--form-element-valid-border-color:#388e3c;--form-element-valid-active-border-color:#43a047;--form-element-valid-focus-color:rgba(67, 160, 71, 0.125);--switch-background-color:hsl(205, 16%, 77%);--switch-color:var(--primary-inverse);--switch-checked-background-color:var(--primary);--range-border-color:hsl(205, 18%, 86%);--range-active-border-color:hsl(205, 16%, 77%);--range-thumb-border-color:var(--background-color);--range-thumb-color:var(--secondary);--range-thumb-hover-color:var(--secondary-hover);--range-thumb-active-color:var(--primary);--table-border-color:var(--muted-border-color);--table-row-stripped-background-color:#f6f8f9;--code-background-color:hsl(205, 20%, 94%);--code-color:var(--muted-color);--code-kbd-background-color:var(--contrast);--code-kbd-color:var(--contrast-inverse);--code-tag-color:hsl(330, 40%, 50%);--code-property-color:hsl(185, 40%, 40%);--code-value-color:hsl(40, 20%, 50%);--code-comment-color:hsl(205, 14%, 68%);--accordion-border-color:var(--muted-border-color);--accordion-close-summary-color:var(--color);--accordion-open-summary-color:var(--muted-color);--card-background-color:var(--background-color);--card-border-color:var(--muted-border-color);--card-box-shadow:0.0145rem 0.029rem 0.174rem rgba(27, 40, 50, 0.01698),0.0335rem 0.067rem 0.402rem rgba(27, 40, 50, 0.024),0.0625rem 0.125rem 0.75rem rgba(27, 40, 50, 0.03),0.1125rem 0.225rem 1.35rem rgba(27, 40, 50, 0.036),0.2085rem 0.417rem 2.502rem rgba(27, 40, 50, 0.04302),0.5rem 1rem 6rem rgba(27, 40, 50, 0.06),0 0 0 0.0625rem rgba(27, 40, 50, 0.015);--card-sectionning-background-color:#fbfbfc;--dropdown-background-color:#fbfbfc;--dropdown-border-color:#e1e6eb;--dropdown-box-shadow:var(--card-box-shadow);--dropdown-color:var(--color);--dropdown-hover-background-color:hsl(205, 20%, 94%);--modal-overlay-background-color:rgba(213, 220, 226, 0.7);--progress-background-color:hsl(205, 18%, 86%);--progress-color:var(--primary);--loading-spinner-opacity:0.5;--tooltip-background-color:var(--contrast);--tooltip-color:var(--contrast-inverse);--icon-checkbox:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(65, 84, 98)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button-inverse:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-close:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(115, 130, 140)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E");--icon-date:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(65, 84, 98)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");--icon-invalid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(198, 40, 40)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E");--icon-minus:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E");--icon-search:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(65, 84, 98)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E");--icon-time:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(65, 84, 98)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E");--icon-valid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(56, 142, 60)' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");color-scheme:light}@media only screen and (prefers-color-scheme:dark){:root:not([data-theme]){--background-color:#11191f;--color:hsl(205, 16%, 77%);--h1-color:hsl(205, 20%, 94%);--h2-color:#e1e6eb;--h3-color:hsl(205, 18%, 86%);--h4-color:#c8d1d8;--h5-color:hsl(205, 16%, 77%);--h6-color:#afbbc4;--muted-color:hsl(205, 10%, 50%);--muted-border-color:#1f2d38;--primary:hsl(195, 85%, 41%);--primary-hover:hsl(195, 80%, 50%);--primary-focus:rgba(16, 149, 193, 0.25);--primary-inverse:#fff;--secondary:hsl(205, 15%, 41%);--secondary-hover:hsl(205, 10%, 50%);--secondary-focus:rgba(115, 130, 140, 0.25);--secondary-inverse:#fff;--contrast:hsl(205, 20%, 94%);--contrast-hover:#fff;--contrast-focus:rgba(115, 130, 140, 0.25);--contrast-inverse:#000;--mark-background-color:#d1c284;--mark-color:#11191f;--ins-color:#388e3c;--del-color:#c62828;--blockquote-border-color:var(--muted-border-color);--blockquote-footer-color:var(--muted-color);--button-box-shadow:0 0 0 rgba(0, 0, 0, 0);--button-hover-box-shadow:0 0 0 rgba(0, 0, 0, 0);--form-element-background-color:#11191f;--form-element-border-color:#374956;--form-element-color:var(--color);--form-element-placeholder-color:var(--muted-color);--form-element-active-background-color:var(--form-element-background-color);--form-element-active-border-color:var(--primary);--form-element-focus-color:var(--primary-focus);--form-element-disabled-background-color:hsl(205, 25%, 23%);--form-element-disabled-border-color:hsl(205, 20%, 32%);--form-element-disabled-opacity:0.5;--form-element-invalid-border-color:#b71c1c;--form-element-invalid-active-border-color:#c62828;--form-element-invalid-focus-color:rgba(198, 40, 40, 0.25);--form-element-valid-border-color:#2e7d32;--form-element-valid-active-border-color:#388e3c;--form-element-valid-focus-color:rgba(56, 142, 60, 0.25);--switch-background-color:#374956;--switch-color:var(--primary-inverse);--switch-checked-background-color:var(--primary);--range-border-color:#24333e;--range-active-border-color:hsl(205, 25%, 23%);--range-thumb-border-color:var(--background-color);--range-thumb-color:var(--secondary);--range-thumb-hover-color:var(--secondary-hover);--range-thumb-active-color:var(--primary);--table-border-color:var(--muted-border-color);--table-row-stripped-background-color:rgba(115, 130, 140, 0.05);--code-background-color:#18232c;--code-color:var(--muted-color);--code-kbd-background-color:var(--contrast);--code-kbd-color:var(--contrast-inverse);--code-tag-color:hsl(330, 30%, 50%);--code-property-color:hsl(185, 30%, 50%);--code-value-color:hsl(40, 10%, 50%);--code-comment-color:#4d606d;--accordion-border-color:var(--muted-border-color);--accordion-active-summary-color:var(--primary);--accordion-close-summary-color:var(--color);--accordion-open-summary-color:var(--muted-color);--card-background-color:#141e26;--card-border-color:var(--card-background-color);--card-box-shadow:0.0145rem 0.029rem 0.174rem rgba(0, 0, 0, 0.01698),0.0335rem 0.067rem 0.402rem rgba(0, 0, 0, 0.024),0.0625rem 0.125rem 0.75rem rgba(0, 0, 0, 0.03),0.1125rem 0.225rem 1.35rem rgba(0, 0, 0, 0.036),0.2085rem 0.417rem 2.502rem rgba(0, 0, 0, 0.04302),0.5rem 1rem 6rem rgba(0, 0, 0, 0.06),0 0 0 0.0625rem rgba(0, 0, 0, 0.015);--card-sectionning-background-color:#18232c;--dropdown-background-color:hsl(205, 30%, 15%);--dropdown-border-color:#24333e;--dropdown-box-shadow:var(--card-box-shadow);--dropdown-color:var(--color);--dropdown-hover-background-color:rgba(36, 51, 62, 0.75);--modal-overlay-background-color:rgba(36, 51, 62, 0.8);--progress-background-color:#24333e;--progress-color:var(--primary);--loading-spinner-opacity:0.5;--tooltip-background-color:var(--contrast);--tooltip-color:var(--contrast-inverse);--icon-checkbox:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button-inverse:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(0, 0, 0)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-close:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(115, 130, 140)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E");--icon-date:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");--icon-invalid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(183, 28, 28)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E");--icon-minus:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E");--icon-search:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E");--icon-time:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E");--icon-valid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(46, 125, 50)' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");color-scheme:dark}}[data-theme=dark]{--background-color:#11191f;--color:hsl(205, 16%, 77%);--h1-color:hsl(205, 20%, 94%);--h2-color:#e1e6eb;--h3-color:hsl(205, 18%, 86%);--h4-color:#c8d1d8;--h5-color:hsl(205, 16%, 77%);--h6-color:#afbbc4;--muted-color:hsl(205, 10%, 50%);--muted-border-color:#1f2d38;--primary:hsl(195, 85%, 41%);--primary-hover:hsl(195, 80%, 50%);--primary-focus:rgba(16, 149, 193, 0.25);--primary-inverse:#fff;--secondary:hsl(205, 15%, 41%);--secondary-hover:hsl(205, 10%, 50%);--secondary-focus:rgba(115, 130, 140, 0.25);--secondary-inverse:#fff;--contrast:hsl(205, 20%, 94%);--contrast-hover:#fff;--contrast-focus:rgba(115, 130, 140, 0.25);--contrast-inverse:#000;--mark-background-color:#d1c284;--mark-color:#11191f;--ins-color:#388e3c;--del-color:#c62828;--blockquote-border-color:var(--muted-border-color);--blockquote-footer-color:var(--muted-color);--button-box-shadow:0 0 0 rgba(0, 0, 0, 0);--button-hover-box-shadow:0 0 0 rgba(0, 0, 0, 0);--form-element-background-color:#11191f;--form-element-border-color:#374956;--form-element-color:var(--color);--form-element-placeholder-color:var(--muted-color);--form-element-active-background-color:var(--form-element-background-color);--form-element-active-border-color:var(--primary);--form-element-focus-color:var(--primary-focus);--form-element-disabled-background-color:hsl(205, 25%, 23%);--form-element-disabled-border-color:hsl(205, 20%, 32%);--form-element-disabled-opacity:0.5;--form-element-invalid-border-color:#b71c1c;--form-element-invalid-active-border-color:#c62828;--form-element-invalid-focus-color:rgba(198, 40, 40, 0.25);--form-element-valid-border-color:#2e7d32;--form-element-valid-active-border-color:#388e3c;--form-element-valid-focus-color:rgba(56, 142, 60, 0.25);--switch-background-color:#374956;--switch-color:var(--primary-inverse);--switch-checked-background-color:var(--primary);--range-border-color:#24333e;--range-active-border-color:hsl(205, 25%, 23%);--range-thumb-border-color:var(--background-color);--range-thumb-color:var(--secondary);--range-thumb-hover-color:var(--secondary-hover);--range-thumb-active-color:var(--primary);--table-border-color:var(--muted-border-color);--table-row-stripped-background-color:rgba(115, 130, 140, 0.05);--code-background-color:#18232c;--code-color:var(--muted-color);--code-kbd-background-color:var(--contrast);--code-kbd-color:var(--contrast-inverse);--code-tag-color:hsl(330, 30%, 50%);--code-property-color:hsl(185, 30%, 50%);--code-value-color:hsl(40, 10%, 50%);--code-comment-color:#4d606d;--accordion-border-color:var(--muted-border-color);--accordion-active-summary-color:var(--primary);--accordion-close-summary-color:var(--color);--accordion-open-summary-color:var(--muted-color);--card-background-color:#141e26;--card-border-color:var(--card-background-color);--card-box-shadow:0.0145rem 0.029rem 0.174rem rgba(0, 0, 0, 0.01698),0.0335rem 0.067rem 0.402rem rgba(0, 0, 0, 0.024),0.0625rem 0.125rem 0.75rem rgba(0, 0, 0, 0.03),0.1125rem 0.225rem 1.35rem rgba(0, 0, 0, 0.036),0.2085rem 0.417rem 2.502rem rgba(0, 0, 0, 0.04302),0.5rem 1rem 6rem rgba(0, 0, 0, 0.06),0 0 0 0.0625rem rgba(0, 0, 0, 0.015);--card-sectionning-background-color:#18232c;--dropdown-background-color:hsl(205, 30%, 15%);--dropdown-border-color:#24333e;--dropdown-box-shadow:var(--card-box-shadow);--dropdown-color:var(--color);--dropdown-hover-background-color:rgba(36, 51, 62, 0.75);--modal-overlay-background-color:rgba(36, 51, 62, 0.8);--progress-background-color:#24333e;--progress-color:var(--primary);--loading-spinner-opacity:0.5;--tooltip-background-color:var(--contrast);--tooltip-color:var(--contrast-inverse);--icon-checkbox:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button-inverse:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(0, 0, 0)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-close:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(115, 130, 140)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E");--icon-date:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");--icon-invalid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(183, 28, 28)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E");--icon-minus:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E");--icon-search:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E");--icon-time:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E");--icon-valid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(46, 125, 50)' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");color-scheme:dark}[type=checkbox],[type=radio],[type=range],progress{accent-color:var(--primary)}*,::after,::before{box-sizing:border-box;background-repeat:no-repeat}::after,::before{text-decoration:inherit;vertical-align:inherit}:where(:root){-webkit-tap-highlight-color:transparent;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%;background-color:var(--background-color);color:var(--color);font-weight:var(--font-weight);font-size:var(--font-size);line-height:var(--line-height);font-family:var(--font-family);text-rendering:optimizeLegibility;overflow-wrap:break-word;cursor:default;-moz-tab-size:4;-o-tab-size:4;tab-size:4}main{display:block}body{width:100%;margin:0}body>footer,body>header,body>main{width:100%;margin-right:auto;margin-left:auto;padding:var(--block-spacing-vertical) var(--block-spacing-horizontal)}@media (min-width:576px){body>footer,body>header,body>main{max-width:510px;padding-right:0;padding-left:0}}@media (min-width:768px){body>footer,body>header,body>main{max-width:700px}}@media (min-width:992px){body>footer,body>header,body>main{max-width:920px}}@media (min-width:1200px){body>footer,body>header,body>main{max-width:1130px}}section{margin-bottom:var(--block-spacing-vertical)}figure{display:block;margin:0;padding:0;overflow-x:auto}figure figcaption{padding:calc(var(--spacing) * .5) 0;color:var(--muted-color)}b,strong{font-weight:bolder}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}address,blockquote,dl,figure,form,ol,p,pre,table,ul{margin-top:0;margin-bottom:var(--typography-spacing-vertical);color:var(--color);font-style:normal;font-weight:var(--font-weight);font-size:var(--font-size)}[role=link],a{--color:var(--primary);--background-color:transparent;outline:0;background-color:var(--background-color);color:var(--color);-webkit-text-decoration:var(--text-decoration);text-decoration:var(--text-decoration);transition:background-color var(--transition),color var(--transition),box-shadow var(--transition),-webkit-text-decoration var(--transition);transition:background-color var(--transition),color var(--transition),text-decoration var(--transition),box-shadow var(--transition);transition:background-color var(--transition),color var(--transition),text-decoration var(--transition),box-shadow var(--transition),-webkit-text-decoration var(--transition)}[role=link]:is([aria-current],:hover,:active,:focus),a:is([aria-current],:hover,:active,:focus){--color:var(--primary-hover);--text-decoration:underline}[role=link]:focus,a:focus{--background-color:var(--primary-focus)}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:var(--typography-spacing-vertical);color:var(--color);font-weight:var(--font-weight);font-size:var(--font-size);font-family:var(--font-family)}h1{--color:var(--h1-color)}h2{--color:var(--h2-color)}h3{--color:var(--h3-color)}h4{--color:var(--h4-color)}h5{--color:var(--h5-color)}h6{--color:var(--h6-color)}:where(address,blockquote,dl,figure,form,ol,p,pre,table,ul)~:is(h1,h2,h3,h4,h5,h6){margin-top:var(--typography-spacing-vertical)}hgroup{margin-bottom:var(--typography-spacing-vertical)}hgroup>*{margin-bottom:0}hgroup>:last-child{--color:var(--muted-color);--font-weight:unset;font-size:1rem;font-family:unset}p{margin-bottom:var(--typography-spacing-vertical)}small{font-size:var(--font-size)}:where(dl,ol,ul){padding-right:0;padding-left:var(--spacing);-webkit-padding-start:var(--spacing);padding-inline-start:var(--spacing);-webkit-padding-end:0;padding-inline-end:0}:where(dl,ol,ul) li{margin-bottom:calc(var(--typography-spacing-vertical) * .25)}:where(dl,ol,ul) :is(dl,ol,ul){margin:0;margin-top:calc(var(--typography-spacing-vertical) * .25)}ul li{list-style:square}mark{padding:.125rem .25rem;background-color:var(--mark-background-color);color:var(--mark-color);vertical-align:baseline}blockquote{display:block;margin:var(--typography-spacing-vertical) 0;padding:var(--spacing);border-right:none;border-left:.25rem solid var(--blockquote-border-color);-webkit-border-start:0.25rem solid var(--blockquote-border-color);border-inline-start:0.25rem solid var(--blockquote-border-color);-webkit-border-end:none;border-inline-end:none}blockquote footer{margin-top:calc(var(--typography-spacing-vertical) * .5);color:var(--blockquote-footer-color)}abbr[title]{border-bottom:1px dotted;text-decoration:none;cursor:help}ins{color:var(--ins-color);text-decoration:none}del{color:var(--del-color)}::-moz-selection{background-color:var(--primary-focus)}::selection{background-color:var(--primary-focus)}:where(audio,canvas,iframe,img,svg,video){vertical-align:middle}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}:where(iframe){border-style:none}img{max-width:100%;height:auto;border-style:none}:where(svg:not([fill])){fill:currentColor}svg:not(:root){overflow:hidden}button{margin:0;overflow:visible;font-family:inherit;text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}button{display:block;width:100%;margin-bottom:var(--spacing)}[role=button]{display:inline-block;text-decoration:none}[role=button],button,input[type=button],input[type=reset],input[type=submit]{--background-color:var(--primary);--border-color:var(--primary);--color:var(--primary-inverse);--box-shadow:var(--button-box-shadow, 0 0 0 rgba(0, 0, 0, 0));padding:var(--form-element-spacing-vertical) var(--form-element-spacing-horizontal);border:var(--border-width) solid var(--border-color);border-radius:var(--border-radius);outline:0;background-color:var(--background-color);box-shadow:var(--box-shadow);color:var(--color);font-weight:var(--font-weight);font-size:1rem;line-height:var(--line-height);text-align:center;cursor:pointer;transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}[role=button]:is([aria-current],:hover,:active,:focus),button:is([aria-current],:hover,:active,:focus),input[type=button]:is([aria-current],:hover,:active,:focus),input[type=reset]:is([aria-current],:hover,:active,:focus),input[type=submit]:is([aria-current],:hover,:active,:focus){--background-color:var(--primary-hover);--border-color:var(--primary-hover);--box-shadow:var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0));--color:var(--primary-inverse)}[role=button]:focus,button:focus,input[type=button]:focus,input[type=reset]:focus,input[type=submit]:focus{--box-shadow:var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),0 0 0 var(--outline-width) var(--primary-focus)}input[type=reset]{--background-color:var(--secondary);--border-color:var(--secondary);--color:var(--secondary-inverse);cursor:pointer}input[type=reset]:is([aria-current],:hover,:active,:focus){--background-color:var(--secondary-hover);--border-color:var(--secondary-hover)}input[type=reset]:focus{--box-shadow:var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),0 0 0 var(--outline-width) var(--secondary-focus)}:where(button,[type=submit],[type=button],[type=reset],[role=button])[disabled],:where(fieldset[disabled]) :is(button,[type=submit],[type=button],[type=reset],[role=button]),a[role=button]:not([href]){opacity:.5;pointer-events:none}input,optgroup,select,textarea{margin:0;font-size:1rem;line-height:var(--line-height);font-family:inherit;letter-spacing:inherit}input{overflow:visible}select{text-transform:none}legend{max-width:100%;padding:0;color:inherit;white-space:normal}textarea{overflow:auto}[type=checkbox],[type=radio]{padding:0}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}::-moz-focus-inner{padding:0;border-style:none}:-moz-focusring{outline:0}:-moz-ui-invalid{box-shadow:none}::-ms-expand{display:none}[type=file],[type=range]{padding:0;border-width:0}input:not([type=checkbox],[type=radio],[type=range]){height:calc(1rem * var(--line-height) + var(--form-element-spacing-vertical) * 2 + var(--border-width) * 2)}fieldset{margin:0;margin-bottom:var(--spacing);padding:0;border:0}fieldset legend,label{display:block;margin-bottom:calc(var(--spacing) * .25);font-weight:var(--form-label-font-weight,var(--font-weight))}input:not([type=checkbox],[type=radio]),select,textarea{width:100%}input:not([type=checkbox],[type=radio],[type=range],[type=file]),select,textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:var(--form-element-spacing-vertical) var(--form-element-spacing-horizontal)}input,select,textarea{--background-color:var(--form-element-background-color);--border-color:var(--form-element-border-color);--color:var(--form-element-color);--box-shadow:none;border:var(--border-width) solid var(--border-color);border-radius:var(--border-radius);outline:0;background-color:var(--background-color);box-shadow:var(--box-shadow);color:var(--color);font-weight:var(--font-weight);transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}:where(select,textarea):is(:active,:focus),input:not([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[readonly]):is(:active,:focus){--background-color:var(--form-element-active-background-color)}:where(select,textarea):is(:active,:focus),input:not([type=submit],[type=button],[type=reset],[role=switch],[readonly]):is(:active,:focus){--border-color:var(--form-element-active-border-color)}input:not([type=submit],[type=button],[type=reset],[type=range],[type=file],[readonly]):focus,select:focus,textarea:focus{--box-shadow:0 0 0 var(--outline-width) var(--form-element-focus-color)}:where(fieldset[disabled]) :is(input:not([type=submit],[type=button],[type=reset]),select,textarea),input:not([type=submit],[type=button],[type=reset])[disabled],select[disabled],textarea[disabled]{--background-color:var(--form-element-disabled-background-color);--border-color:var(--form-element-disabled-border-color);opacity:var(--form-element-disabled-opacity);pointer-events:none}:where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week])[aria-invalid]{padding-right:calc(var(--form-element-spacing-horizontal) + 1.5rem)!important;padding-left:var(--form-element-spacing-horizontal);-webkit-padding-start:var(--form-element-spacing-horizontal)!important;padding-inline-start:var(--form-element-spacing-horizontal)!important;-webkit-padding-end:calc(var(--form-element-spacing-horizontal) + 1.5rem)!important;padding-inline-end:calc(var(--form-element-spacing-horizontal) + 1.5rem)!important;background-position:center right .75rem;background-size:1rem auto;background-repeat:no-repeat}:where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week])[aria-invalid=false]{background-image:var(--icon-valid)}:where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week])[aria-invalid=true]{background-image:var(--icon-invalid)}:where(input,select,textarea)[aria-invalid=false]{--border-color:var(--form-element-valid-border-color)}:where(input,select,textarea)[aria-invalid=false]:is(:active,:focus){--border-color:var(--form-element-valid-active-border-color)!important;--box-shadow:0 0 0 var(--outline-width) var(--form-element-valid-focus-color)!important}:where(input,select,textarea)[aria-invalid=true]{--border-color:var(--form-element-invalid-border-color)}:where(input,select,textarea)[aria-invalid=true]:is(:active,:focus){--border-color:var(--form-element-invalid-active-border-color)!important;--box-shadow:0 0 0 var(--outline-width) var(--form-element-invalid-focus-color)!important}[dir=rtl] :where(input,select,textarea):not([type=checkbox],[type=radio]):is([aria-invalid],[aria-invalid=true],[aria-invalid=false]){background-position:center left .75rem}input::-webkit-input-placeholder,input::placeholder,select:invalid,textarea::-webkit-input-placeholder,textarea::placeholder{color:var(--form-element-placeholder-color);opacity:1}input:not([type=checkbox],[type=radio]),select,textarea{margin-bottom:var(--spacing)}select::-ms-expand{border:0;background-color:transparent}select:not([multiple],[size]){padding-right:calc(var(--form-element-spacing-horizontal) + 1.5rem);padding-left:var(--form-element-spacing-horizontal);-webkit-padding-start:var(--form-element-spacing-horizontal);padding-inline-start:var(--form-element-spacing-horizontal);-webkit-padding-end:calc(var(--form-element-spacing-horizontal) + 1.5rem);padding-inline-end:calc(var(--form-element-spacing-horizontal) + 1.5rem);background-image:var(--icon-chevron);background-position:center right .75rem;background-size:1rem auto;background-repeat:no-repeat}[dir=rtl] select:not([multiple],[size]){background-position:center left .75rem}:where(input,select,textarea)+small{display:block;width:100%;margin-top:calc(var(--spacing) * -.75);margin-bottom:var(--spacing);color:var(--muted-color)}label>:where(input,select,textarea){margin-top:calc(var(--spacing) * .25)}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:1.25em;height:1.25em;margin-top:-.125em;margin-right:.375em;margin-left:0;-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:.375em;margin-inline-end:.375em;border-width:var(--border-width);font-size:inherit;vertical-align:middle;cursor:pointer}[type=checkbox]::-ms-check,[type=radio]::-ms-check{display:none}[type=checkbox]:checked,[type=checkbox]:checked:active,[type=checkbox]:checked:focus,[type=radio]:checked,[type=radio]:checked:active,[type=radio]:checked:focus{--background-color:var(--primary);--border-color:var(--primary);background-image:var(--icon-checkbox);background-position:center;background-size:.75em auto;background-repeat:no-repeat}[type=checkbox]~label,[type=radio]~label{display:inline-block;margin-right:.375em;margin-bottom:0;cursor:pointer}[type=checkbox]:indeterminate{--background-color:var(--primary);--border-color:var(--primary);background-image:var(--icon-minus);background-position:center;background-size:.75em auto;background-repeat:no-repeat}[type=radio]{border-radius:50%}[type=radio]:checked,[type=radio]:checked:active,[type=radio]:checked:focus{--background-color:var(--primary-inverse);border-width:.35em;background-image:none}[type=checkbox][role=switch]{--background-color:var(--switch-background-color);--border-color:var(--switch-background-color);--color:var(--switch-color);width:2.25em;height:1.25em;border:var(--border-width) solid var(--border-color);border-radius:1.25em;background-color:var(--background-color);line-height:1.25em}[type=checkbox][role=switch]:focus{--background-color:var(--switch-background-color);--border-color:var(--switch-background-color)}[type=checkbox][role=switch]:checked{--background-color:var(--switch-checked-background-color);--border-color:var(--switch-checked-background-color)}[type=checkbox][role=switch]:before{display:block;width:calc(1.25em - (var(--border-width) * 2));height:100%;border-radius:50%;background-color:var(--color);content:"";transition:margin .1s ease-in-out}[type=checkbox][role=switch]:checked{background-image:none}[type=checkbox][role=switch]:checked::before{margin-left:calc(1.125em - var(--border-width));-webkit-margin-start:calc(1.125em - var(--border-width));margin-inline-start:calc(1.125em - var(--border-width))}[type=checkbox]:checked[aria-invalid=false],[type=checkbox][aria-invalid=false],[type=checkbox][role=switch]:checked[aria-invalid=false],[type=checkbox][role=switch][aria-invalid=false],[type=radio]:checked[aria-invalid=false],[type=radio][aria-invalid=false]{--border-color:var(--form-element-valid-border-color)}[type=checkbox]:checked[aria-invalid=true],[type=checkbox][aria-invalid=true],[type=checkbox][role=switch]:checked[aria-invalid=true],[type=checkbox][role=switch][aria-invalid=true],[type=radio]:checked[aria-invalid=true],[type=radio][aria-invalid=true]{--border-color:var(--form-element-invalid-border-color)}[type=color]::-webkit-color-swatch-wrapper{padding:0}[type=color]::-moz-focus-inner{padding:0}[type=color]::-webkit-color-swatch{border:0;border-radius:calc(var(--border-radius) * .5)}[type=color]::-moz-color-swatch{border:0;border-radius:calc(var(--border-radius) * .5)}input:not([type=checkbox],[type=radio],[type=range],[type=file]):is([type=date],[type=datetime-local],[type=month],[type=time],[type=week]){--icon-position:0.75rem;--icon-width:1rem;padding-right:calc(var(--icon-width) + var(--icon-position));background-image:var(--icon-date);background-position:center right var(--icon-position);background-size:var(--icon-width) auto;background-repeat:no-repeat}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=time]{background-image:var(--icon-time)}[type=date]::-webkit-calendar-picker-indicator,[type=datetime-local]::-webkit-calendar-picker-indicator,[type=month]::-webkit-calendar-picker-indicator,[type=time]::-webkit-calendar-picker-indicator,[type=week]::-webkit-calendar-picker-indicator{width:var(--icon-width);margin-right:calc(var(--icon-width) * -1);margin-left:var(--icon-position);opacity:0}[dir=rtl] :is([type=date],[type=datetime-local],[type=month],[type=time],[type=week]){text-align:right}@-moz-document url-prefix(){[type=date],[type=datetime-local],[type=month],[type=time],[type=week]{padding-right:var(--form-element-spacing-horizontal)!important;background-image:none!important}}[type=file]{--color:var(--muted-color);padding:calc(var(--form-element-spacing-vertical) * .5) 0;border:0;border-radius:0;background:0 0}[type=file]::file-selector-button{--background-color:var(--secondary);--border-color:var(--secondary);--color:var(--secondary-inverse);margin-right:calc(var(--spacing)/ 2);margin-left:0;-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:calc(var(--spacing)/ 2);margin-inline-end:calc(var(--spacing)/ 2);padding:calc(var(--form-element-spacing-vertical) * .5) calc(var(--form-element-spacing-horizontal) * .5);border:var(--border-width) solid var(--border-color);border-radius:var(--border-radius);outline:0;background-color:var(--background-color);box-shadow:var(--box-shadow);color:var(--color);font-weight:var(--font-weight);font-size:1rem;line-height:var(--line-height);text-align:center;cursor:pointer;transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}[type=file]::file-selector-button:is(:hover,:active,:focus){--background-color:var(--secondary-hover);--border-color:var(--secondary-hover)}[type=file]::-webkit-file-upload-button{--background-color:var(--secondary);--border-color:var(--secondary);--color:var(--secondary-inverse);margin-right:calc(var(--spacing)/ 2);margin-left:0;-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:calc(var(--spacing)/ 2);margin-inline-end:calc(var(--spacing)/ 2);padding:calc(var(--form-element-spacing-vertical) * .5) calc(var(--form-element-spacing-horizontal) * .5);border:var(--border-width) solid var(--border-color);border-radius:var(--border-radius);outline:0;background-color:var(--background-color);box-shadow:var(--box-shadow);color:var(--color);font-weight:var(--font-weight);font-size:1rem;line-height:var(--line-height);text-align:center;cursor:pointer;-webkit-transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition);transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}[type=file]::-webkit-file-upload-button:is(:hover,:active,:focus){--background-color:var(--secondary-hover);--border-color:var(--secondary-hover)}[type=file]::-ms-browse{--background-color:var(--secondary);--border-color:var(--secondary);--color:var(--secondary-inverse);margin-right:calc(var(--spacing)/ 2);margin-left:0;margin-inline-start:0;margin-inline-end:calc(var(--spacing)/ 2);padding:calc(var(--form-element-spacing-vertical) * .5) calc(var(--form-element-spacing-horizontal) * .5);border:var(--border-width) solid var(--border-color);border-radius:var(--border-radius);outline:0;background-color:var(--background-color);box-shadow:var(--box-shadow);color:var(--color);font-weight:var(--font-weight);font-size:1rem;line-height:var(--line-height);text-align:center;cursor:pointer;-ms-transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition);transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}[type=file]::-ms-browse:is(:hover,:active,:focus){--background-color:var(--secondary-hover);--border-color:var(--secondary-hover)}[type=range]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;height:1.25rem;background:0 0}[type=range]::-webkit-slider-runnable-track{width:100%;height:.25rem;border-radius:var(--border-radius);background-color:var(--range-border-color);-webkit-transition:background-color var(--transition),box-shadow var(--transition);transition:background-color var(--transition),box-shadow var(--transition)}[type=range]::-moz-range-track{width:100%;height:.25rem;border-radius:var(--border-radius);background-color:var(--range-border-color);-moz-transition:background-color var(--transition),box-shadow var(--transition);transition:background-color var(--transition),box-shadow var(--transition)}[type=range]::-ms-track{width:100%;height:.25rem;border-radius:var(--border-radius);background-color:var(--range-border-color);-ms-transition:background-color var(--transition),box-shadow var(--transition);transition:background-color var(--transition),box-shadow var(--transition)}[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.5rem;border:2px solid var(--range-thumb-border-color);border-radius:50%;background-color:var(--range-thumb-color);cursor:pointer;-webkit-transition:background-color var(--transition),transform var(--transition);transition:background-color var(--transition),transform var(--transition)}[type=range]::-moz-range-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.5rem;border:2px solid var(--range-thumb-border-color);border-radius:50%;background-color:var(--range-thumb-color);cursor:pointer;-moz-transition:background-color var(--transition),transform var(--transition);transition:background-color var(--transition),transform var(--transition)}[type=range]::-ms-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.5rem;border:2px solid var(--range-thumb-border-color);border-radius:50%;background-color:var(--range-thumb-color);cursor:pointer;-ms-transition:background-color var(--transition),transform var(--transition);transition:background-color var(--transition),transform var(--transition)}[type=range]:focus,[type=range]:hover{--range-border-color:var(--range-active-border-color);--range-thumb-color:var(--range-thumb-hover-color)}[type=range]:active{--range-thumb-color:var(--range-thumb-active-color)}[type=range]:active::-webkit-slider-thumb{transform:scale(1.25)}[type=range]:active::-moz-range-thumb{transform:scale(1.25)}[type=range]:active::-ms-thumb{transform:scale(1.25)}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search]{-webkit-padding-start:calc(var(--form-element-spacing-horizontal) + 1.75rem);padding-inline-start:calc(var(--form-element-spacing-horizontal) + 1.75rem);border-radius:5rem;background-image:var(--icon-search);background-position:center left 1.125rem;background-size:1rem auto;background-repeat:no-repeat}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid]{-webkit-padding-start:calc(var(--form-element-spacing-horizontal) + 1.75rem)!important;padding-inline-start:calc(var(--form-element-spacing-horizontal) + 1.75rem)!important;background-position:center left 1.125rem,center right .75rem}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid=false]{background-image:var(--icon-search),var(--icon-valid)}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid=true]{background-image:var(--icon-search),var(--icon-invalid)}[type=search]::-webkit-search-cancel-button{-webkit-appearance:none;display:none}[dir=rtl] :where(input):not([type=checkbox],[type=radio],[type=range],[type=file])[type=search]{background-position:center right 1.125rem}[dir=rtl] :where(input):not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid]{background-position:center right 1.125rem,center left .75rem}:where(table){width:100%;border-collapse:collapse;border-spacing:0;text-indent:0}td,th{padding:calc(var(--spacing)/ 2) var(--spacing);border-bottom:var(--border-width) solid var(--table-border-color);color:var(--color);font-weight:var(--font-weight);font-size:var(--font-size);text-align:left;text-align:start}tfoot td,tfoot th{border-top:var(--border-width) solid var(--table-border-color);border-bottom:0}table[role=grid] tbody tr:nth-child(odd){background-color:var(--table-row-stripped-background-color)}code,kbd,pre,samp{font-size:.875em;font-family:var(--font-family)}pre{-ms-overflow-style:scrollbar;overflow:auto}code,kbd,pre{border-radius:var(--border-radius);background:var(--code-background-color);color:var(--code-color);font-weight:var(--font-weight);line-height:initial}code,kbd{display:inline-block;padding:.375rem .5rem}pre{display:block;margin-bottom:var(--spacing);overflow-x:auto}pre>code{display:block;padding:var(--spacing);background:0 0;font-size:14px;line-height:var(--line-height)}code b{color:var(--code-tag-color);font-weight:var(--font-weight)}code i{color:var(--code-property-color);font-style:normal}code u{color:var(--code-value-color);text-decoration:none}code em{color:var(--code-comment-color);font-style:normal}kbd{background-color:var(--code-kbd-background-color);color:var(--code-kbd-color);vertical-align:baseline}hr{height:0;border:0;border-top:1px solid var(--muted-border-color);color:inherit}[hidden],template{display:none!important}canvas{display:inline-block}details{display:block;margin-bottom:var(--spacing);padding-bottom:var(--spacing);border-bottom:var(--border-width) solid var(--accordion-border-color)}details summary{line-height:1rem;list-style-type:none;cursor:pointer;transition:color var(--transition)}details summary:not([role]){color:var(--accordion-close-summary-color)}details summary::-webkit-details-marker{display:none}details summary::marker{display:none}details summary::-moz-list-bullet{list-style-type:none}details summary::after{display:block;width:1rem;height:1rem;-webkit-margin-start:calc(var(--spacing,1rem) * 0.5);margin-inline-start:calc(var(--spacing,1rem) * .5);float:right;transform:rotate(-90deg);background-image:var(--icon-chevron);background-position:right center;background-size:1rem auto;background-repeat:no-repeat;content:"";transition:transform var(--transition)}details summary:focus{outline:0}details summary:focus:not([role=button]){color:var(--accordion-active-summary-color)}details summary[role=button]{width:100%;text-align:left}details summary[role=button]::after{height:calc(1rem * var(--line-height,1.5));background-image:var(--icon-chevron-button)}details[open]>summary{margin-bottom:calc(var(--spacing))}details[open]>summary:not([role]):not(:focus){color:var(--accordion-open-summary-color)}details[open]>summary::after{transform:rotate(0)}[dir=rtl] details summary{text-align:right}[dir=rtl] details summary::after{float:left;background-position:left center}article{margin:var(--block-spacing-vertical) 0;padding:var(--block-spacing-vertical) var(--block-spacing-horizontal);border-radius:var(--border-radius);background:var(--card-background-color);box-shadow:var(--card-box-shadow)}article>footer,article>header{margin-right:calc(var(--block-spacing-horizontal) * -1);margin-left:calc(var(--block-spacing-horizontal) * -1);padding:calc(var(--block-spacing-vertical) * .66) var(--block-spacing-horizontal);background-color:var(--card-sectionning-background-color)}article>header{margin-top:calc(var(--block-spacing-vertical) * -1);margin-bottom:var(--block-spacing-vertical);border-bottom:var(--border-width) solid var(--card-border-color);border-top-right-radius:var(--border-radius);border-top-left-radius:var(--border-radius)}article>footer{margin-top:var(--block-spacing-vertical);margin-bottom:calc(var(--block-spacing-vertical) * -1);border-top:var(--border-width) solid var(--card-border-color);border-bottom-right-radius:var(--border-radius);border-bottom-left-radius:var(--border-radius)}:root{--scrollbar-width:0px}dialog{display:flex;z-index:999;position:fixed;top:0;right:0;bottom:0;left:0;align-items:center;justify-content:center;width:inherit;min-width:100%;height:inherit;min-height:100%;padding:var(--spacing);border:0;-webkit-backdrop-filter:var(--modal-overlay-backdrop-filter);backdrop-filter:var(--modal-overlay-backdrop-filter);background-color:var(--modal-overlay-background-color);color:var(--color)}dialog article{max-height:calc(100vh - var(--spacing) * 2);overflow:auto}@media (min-width:576px){dialog article{max-width:510px}}@media (min-width:768px){dialog article{max-width:700px}}dialog article>footer,dialog article>header{padding:calc(var(--block-spacing-vertical) * .5) var(--block-spacing-horizontal)}dialog article>header .close{margin:0;margin-left:var(--spacing);float:right}dialog article>footer{text-align:right}dialog article>footer [role=button]{margin-bottom:0}dialog article>footer [role=button]:not(:first-of-type){margin-left:calc(var(--spacing) * .5)}dialog article p:last-of-type{margin:0}dialog:not([open]),dialog[open=false]{display:none}:where(nav li)::before{float:left;content:"​"}nav,nav ul{display:flex}nav{justify-content:space-between}nav ol,nav ul{align-items:center;margin-bottom:0;padding:0;list-style:none}nav ol:first-of-type,nav ul:first-of-type{margin-left:calc(var(--nav-element-spacing-horizontal) * -1)}nav ol:last-of-type,nav ul:last-of-type{margin-right:calc(var(--nav-element-spacing-horizontal) * -1)}nav li{display:inline-block;margin:0;padding:var(--nav-element-spacing-vertical) var(--nav-element-spacing-horizontal)}nav li>*{--spacing:0}nav :where(a,[role=link]){display:inline-block;margin:calc(var(--nav-link-spacing-vertical) * -1) calc(var(--nav-link-spacing-horizontal) * -1);padding:var(--nav-link-spacing-vertical) var(--nav-link-spacing-horizontal);border-radius:var(--border-radius);text-decoration:none}nav :where(a,[role=link]):is([aria-current],:hover,:active,:focus){text-decoration:none}nav[aria-label=breadcrumb]{align-items:center;justify-content:start}nav[aria-label=breadcrumb] ul li:not(:first-child){-webkit-margin-start:var(--nav-link-spacing-horizontal);margin-inline-start:var(--nav-link-spacing-horizontal)}nav[aria-label=breadcrumb] ul li:not(:last-child) ::after{position:absolute;width:calc(var(--nav-link-spacing-horizontal) * 2);-webkit-margin-start:calc(var(--nav-link-spacing-horizontal)/ 2);margin-inline-start:calc(var(--nav-link-spacing-horizontal)/ 2);content:"/";color:var(--muted-color);text-align:center}nav[aria-label=breadcrumb] a[aria-current]{background-color:transparent;color:inherit;text-decoration:none;pointer-events:none}nav [role=button]{margin-right:inherit;margin-left:inherit;padding:var(--nav-link-spacing-vertical) var(--nav-link-spacing-horizontal)}aside li,aside nav,aside ol,aside ul{display:block}aside li{padding:calc(var(--nav-element-spacing-vertical) * .5) var(--nav-element-spacing-horizontal)}aside li a{display:block}aside li [role=button]{margin:inherit}[dir=rtl] nav[aria-label=breadcrumb] ul li:not(:last-child) ::after{content:"\\"}progress{display:inline-block;vertical-align:baseline}progress{-webkit-appearance:none;-moz-appearance:none;display:inline-block;appearance:none;width:100%;height:.5rem;margin-bottom:calc(var(--spacing) * .5);overflow:hidden;border:0;border-radius:var(--border-radius);background-color:var(--progress-background-color);color:var(--progress-color)}progress::-webkit-progress-bar{border-radius:var(--border-radius);background:0 0}progress[value]::-webkit-progress-value{background-color:var(--progress-color)}progress::-moz-progress-bar{background-color:var(--progress-color)}@media (prefers-reduced-motion:no-preference){progress:indeterminate{background:var(--progress-background-color) linear-gradient(to right,var(--progress-color) 30%,var(--progress-background-color) 30%) top left/150% 150% no-repeat;animation:progress-indeterminate 1s linear infinite}progress:indeterminate[value]::-webkit-progress-value{background-color:transparent}progress:indeterminate::-moz-progress-bar{background-color:transparent}}@media (prefers-reduced-motion:no-preference){[dir=rtl] progress:indeterminate{animation-direction:reverse}}@keyframes progress-indeterminate{0%{background-position:200% 0}100%{background-position:-200% 0}}details[role=list],li[role=list]{position:relative}details[role=list] summary+ul,li[role=list]>ul{display:flex;z-index:99;position:absolute;top:auto;right:0;left:0;flex-direction:column;margin:0;padding:0;border:var(--border-width) solid var(--dropdown-border-color);border-radius:var(--border-radius);border-top-right-radius:0;border-top-left-radius:0;background-color:var(--dropdown-background-color);box-shadow:var(--card-box-shadow);color:var(--dropdown-color);white-space:nowrap}details[role=list] summary+ul li,li[role=list]>ul li{width:100%;margin-bottom:0;padding:calc(var(--form-element-spacing-vertical) * .5) var(--form-element-spacing-horizontal);list-style:none}details[role=list] summary+ul li:first-of-type,li[role=list]>ul li:first-of-type{margin-top:calc(var(--form-element-spacing-vertical) * .5)}details[role=list] summary+ul li:last-of-type,li[role=list]>ul li:last-of-type{margin-bottom:calc(var(--form-element-spacing-vertical) * .5)}details[role=list] summary+ul li a,li[role=list]>ul li a{display:block;margin:calc(var(--form-element-spacing-vertical) * -.5) calc(var(--form-element-spacing-horizontal) * -1);padding:calc(var(--form-element-spacing-vertical) * .5) var(--form-element-spacing-horizontal);overflow:hidden;color:var(--dropdown-color);text-decoration:none;text-overflow:ellipsis}details[role=list] summary+ul li a:hover,li[role=list]>ul li a:hover{background-color:var(--dropdown-hover-background-color)}details[role=list] summary::after,li[role=list]>a::after{display:block;width:1rem;height:calc(1rem * var(--line-height,1.5));-webkit-margin-start:0.5rem;margin-inline-start:.5rem;float:right;transform:rotate(0);background-position:right center;background-size:1rem auto;background-repeat:no-repeat;content:""}details[role=list]{padding:0;border-bottom:none}details[role=list] summary{margin-bottom:0}details[role=list] summary:not([role]){height:calc(1rem * var(--line-height) + var(--form-element-spacing-vertical) * 2 + var(--border-width) * 2);padding:var(--form-element-spacing-vertical) var(--form-element-spacing-horizontal);border:var(--border-width) solid var(--form-element-border-color);border-radius:var(--border-radius);background-color:var(--form-element-background-color);color:var(--form-element-placeholder-color);line-height:inherit;cursor:pointer;transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}details[role=list] summary:not([role]):active,details[role=list] summary:not([role]):focus{border-color:var(--form-element-active-border-color);background-color:var(--form-element-active-background-color)}details[role=list] summary:not([role]):focus{box-shadow:0 0 0 var(--outline-width) var(--form-element-focus-color)}details[role=list][open] summary{border-bottom-right-radius:0;border-bottom-left-radius:0}details[role=list][open] summary::before{display:block;z-index:1;position:fixed;top:0;right:0;bottom:0;left:0;background:0 0;content:"";cursor:default}nav details[role=list] summary,nav li[role=list] a{display:flex;direction:ltr}nav details[role=list] summary+ul,nav li[role=list]>ul{min-width:-moz-fit-content;min-width:fit-content;border-radius:var(--border-radius)}nav details[role=list] summary+ul li a,nav li[role=list]>ul li a{border-radius:0}nav details[role=list] summary,nav details[role=list] summary:not([role]){height:auto;padding:var(--nav-link-spacing-vertical) var(--nav-link-spacing-horizontal)}nav details[role=list][open] summary{border-radius:var(--border-radius)}nav details[role=list] summary+ul{margin-top:var(--outline-width);-webkit-margin-start:0;margin-inline-start:0}nav details[role=list] summary[role=link]{margin-bottom:calc(var(--nav-link-spacing-vertical) * -1);line-height:var(--line-height)}nav details[role=list] summary[role=link]+ul{margin-top:calc(var(--nav-link-spacing-vertical) + var(--outline-width));-webkit-margin-start:calc(var(--nav-link-spacing-horizontal) * -1);margin-inline-start:calc(var(--nav-link-spacing-horizontal) * -1)}li[role=list] a:active~ul,li[role=list] a:focus~ul,li[role=list]:hover>ul{display:flex}li[role=list]>ul{display:none;margin-top:calc(var(--nav-link-spacing-vertical) + var(--outline-width));-webkit-margin-start:calc(var(--nav-element-spacing-horizontal) - var(--nav-link-spacing-horizontal));margin-inline-start:calc(var(--nav-element-spacing-horizontal) - var(--nav-link-spacing-horizontal))}li[role=list]>a::after{background-image:var(--icon-chevron)}label>details[role=list]{margin-top:calc(var(--spacing) * .25);margin-bottom:var(--spacing)}[aria-busy=true]{cursor:progress}[aria-busy=true]:not(input,select,textarea,html)::before{display:inline-block;width:1em;height:1em;border:.1875em solid currentColor;border-radius:1em;border-right-color:transparent;content:"";vertical-align:text-bottom;vertical-align:-.125em;animation:spinner .75s linear infinite;opacity:var(--loading-spinner-opacity)}[aria-busy=true]:not(input,select,textarea,html):not(:empty)::before{margin-right:calc(var(--spacing) * .5);margin-left:0;-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:calc(var(--spacing) * .5);margin-inline-end:calc(var(--spacing) * .5)}[aria-busy=true]:not(input,select,textarea,html):empty{text-align:center}a[aria-busy=true],button[aria-busy=true],input[type=button][aria-busy=true],input[type=reset][aria-busy=true],input[type=submit][aria-busy=true]{pointer-events:none}@keyframes spinner{to{transform:rotate(360deg)}}[data-tooltip]{position:relative}[data-tooltip]:not(a,button,input){border-bottom:1px dotted;text-decoration:none;cursor:help}[data-tooltip]::after,[data-tooltip]::before,[data-tooltip][data-placement=top]::after,[data-tooltip][data-placement=top]::before{display:block;z-index:99;position:absolute;bottom:100%;left:50%;padding:.25rem .5rem;overflow:hidden;transform:translate(-50%,-.25rem);border-radius:var(--border-radius);background:var(--tooltip-background-color);content:attr(data-tooltip);color:var(--tooltip-color);font-style:normal;font-weight:var(--font-weight);font-size:.875rem;text-decoration:none;text-overflow:ellipsis;white-space:nowrap;opacity:0;pointer-events:none}[data-tooltip]::after,[data-tooltip][data-placement=top]::after{padding:0;transform:translate(-50%,0);border-top:.3rem solid;border-right:.3rem solid transparent;border-left:.3rem solid transparent;border-radius:0;background-color:transparent;content:"";color:var(--tooltip-background-color)}[data-tooltip][data-placement=bottom]::after,[data-tooltip][data-placement=bottom]::before{top:100%;bottom:auto;transform:translate(-50%,.25rem)}[data-tooltip][data-placement=bottom]:after{transform:translate(-50%,-.3rem);border:.3rem solid transparent;border-bottom:.3rem solid}[data-tooltip][data-placement=left]::after,[data-tooltip][data-placement=left]::before{top:50%;right:100%;bottom:auto;left:auto;transform:translate(-.25rem,-50%)}[data-tooltip][data-placement=left]:after{transform:translate(.3rem,-50%);border:.3rem solid transparent;border-left:.3rem solid}[data-tooltip][data-placement=right]::after,[data-tooltip][data-placement=right]::before{top:50%;right:auto;bottom:auto;left:100%;transform:translate(.25rem,-50%)}[data-tooltip][data-placement=right]:after{transform:translate(-.3rem,-50%);border:.3rem solid transparent;border-right:.3rem solid}[data-tooltip]:focus::after,[data-tooltip]:focus::before,[data-tooltip]:hover::after,[data-tooltip]:hover::before{opacity:1}@media (hover:hover) and (pointer:fine){[data-tooltip]:hover::after,[data-tooltip]:hover::before,[data-tooltip][data-placement=bottom]:focus::after,[data-tooltip][data-placement=bottom]:focus::before,[data-tooltip][data-placement=bottom]:hover [data-tooltip]:focus::after,[data-tooltip][data-placement=bottom]:hover [data-tooltip]:focus::before{animation-duration:.2s;animation-name:tooltip-slide-top}[data-tooltip]:hover::after,[data-tooltip][data-placement=bottom]:focus::after,[data-tooltip][data-placement=bottom]:hover [data-tooltip]:focus::after{animation-name:tooltip-caret-slide-top}[data-tooltip][data-placement=bottom]:focus::after,[data-tooltip][data-placement=bottom]:focus::before,[data-tooltip][data-placement=bottom]:hover::after,[data-tooltip][data-placement=bottom]:hover::before{animation-duration:.2s;animation-name:tooltip-slide-bottom}[data-tooltip][data-placement=bottom]:focus::after,[data-tooltip][data-placement=bottom]:hover::after{animation-name:tooltip-caret-slide-bottom}[data-tooltip][data-placement=left]:focus::after,[data-tooltip][data-placement=left]:focus::before,[data-tooltip][data-placement=left]:hover::after,[data-tooltip][data-placement=left]:hover::before{animation-duration:.2s;animation-name:tooltip-slide-left}[data-tooltip][data-placement=left]:focus::after,[data-tooltip][data-placement=left]:hover::after{animation-name:tooltip-caret-slide-left}[data-tooltip][data-placement=right]:focus::after,[data-tooltip][data-placement=right]:focus::before,[data-tooltip][data-placement=right]:hover::after,[data-tooltip][data-placement=right]:hover::before{animation-duration:.2s;animation-name:tooltip-slide-right}[data-tooltip][data-placement=right]:focus::after,[data-tooltip][data-placement=right]:hover::after{animation-name:tooltip-caret-slide-right}}@keyframes tooltip-slide-top{from{transform:translate(-50%,.75rem);opacity:0}to{transform:translate(-50%,-.25rem);opacity:1}}@keyframes tooltip-caret-slide-top{from{opacity:0}50%{transform:translate(-50%,-.25rem);opacity:0}to{transform:translate(-50%,0);opacity:1}}@keyframes tooltip-slide-bottom{from{transform:translate(-50%,-.75rem);opacity:0}to{transform:translate(-50%,.25rem);opacity:1}}@keyframes tooltip-caret-slide-bottom{from{opacity:0}50%{transform:translate(-50%,-.5rem);opacity:0}to{transform:translate(-50%,-.3rem);opacity:1}}@keyframes tooltip-slide-left{from{transform:translate(.75rem,-50%);opacity:0}to{transform:translate(-.25rem,-50%);opacity:1}}@keyframes tooltip-caret-slide-left{from{opacity:0}50%{transform:translate(.05rem,-50%);opacity:0}to{transform:translate(.3rem,-50%);opacity:1}}@keyframes tooltip-slide-right{from{transform:translate(-.75rem,-50%);opacity:0}to{transform:translate(.25rem,-50%);opacity:1}}@keyframes tooltip-caret-slide-right{from{opacity:0}50%{transform:translate(-.05rem,-50%);opacity:0}to{transform:translate(-.3rem,-50%);opacity:1}}[aria-controls]{cursor:pointer}[aria-disabled=true],[disabled]{cursor:not-allowed}[aria-hidden=false][hidden]{display:initial}[aria-hidden=false][hidden]:not(:focus){clip:rect(0,0,0,0);position:absolute}[tabindex],a,area,button,input,label,select,summary,textarea{-ms-touch-action:manipulation}[dir=rtl]{direction:rtl}@media (prefers-reduced-motion:reduce){:not([aria-busy=true]),:not([aria-busy=true])::after,:not([aria-busy=true])::before{background-attachment:initial!important;animation-duration:1ms!important;animation-delay:-1ms!important;animation-iteration-count:1!important;scroll-behavior:auto!important;transition-delay:0s!important;transition-duration:0s!important}} -/*# sourceMappingURL=pico.classless.min.css.map */ \ No newline at end of file diff --git a/web/pico.classless.min.css.gz b/web/pico.classless.min.css.gz deleted file mode 100644 index 7caf6c7..0000000 Binary files a/web/pico.classless.min.css.gz and /dev/null differ diff --git a/web/pico.classless.min.css.map b/web/pico.classless.min.css.map deleted file mode 100644 index beda428..0000000 --- a/web/pico.classless.min.css.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["scss/pico.scss","scss/themes/default/_styles.scss","css/pico.classless.css","scss/themes/default/_light.scss","scss/themes/default.scss","scss/themes/default/_dark.scss","scss/layout/_document.scss","scss/layout/_sectioning.scss","scss/layout/_section.scss","scss/layout/_scroller.scss","scss/content/_typography.scss","scss/content/_embedded.scss","scss/content/_button.scss","scss/content/_form.scss","scss/content/_form-checkbox-radio.scss","scss/content/_form-alt-input-types.scss","scss/content/_table.scss","scss/content/_code.scss","scss/content/_miscs.scss","scss/components/_accordion.scss","scss/components/_card.scss","scss/components/_modal.scss","scss/components/_nav.scss","scss/components/_progress.scss","scss/components/_dropdown.scss","scss/utilities/_loading.scss","scss/utilities/_tooltip.scss","scss/utilities/_accessibility.scss","scss/utilities/_reduce-motion.scss"],"names":[],"mappings":"iBAAA;;;ACCA,MAEE,cAAA,SAAA,CAAA,aAAA,CAAA,UAAA,CAAA,QAAA,CAAA,QAAA,CCOE,WAAW,CAAE,WAAW,CAAE,UAAU,CAAE,mBAAmB,CAAE,gBAAgB,CAC3E,iBAAiB,CAAE,mBDLrB,cAAA,IACA,cAAA,IACA,YAAA,KA8BA,gBAAA,QACA,eAAA,IACA,gBAAA,IAGA,UAAA,KAGA,8BAAA,OAGA,yBAAA,yBACA,2BAAA,eAQA,gCAAA,QACA,kCAAA,KAGA,+BAAA,KACA,iCAAA,OACA,4BAAA,OACA,8BAAA,OAGA,yBAAA,mBAGA,aAAA,KAAA,YAGA,gCAAA,cA7DI,yBAZN,MAaQ,YAAA,MAKF,yBAlBN,MAmBQ,YAAA,MAKF,yBAxBN,MAyBQ,YAAA,MAKF,0BA9BN,MA+BQ,YAAA,MAqDF,yBC7BJ,YDwBA,YCzBA,UAEA,QD6BM,yBAAA,4BAKF,yBC3BJ,YDgBA,YCjBA,UAEA,QD2BM,yBAAA,0BAKF,yBCzBJ,YDQA,YCTA,UAEA,QDyBM,yBAAA,4BAKF,0BCvBJ,YDAA,YCDA,UAEA,QDuBM,yBAAA,0BAQF,yBAFJ,QAGM,2BAAA,6BAKF,yBARJ,QASM,2BAAA,4BAKF,yBAdJ,QAeM,2BAAA,6BAKF,0BApBJ,QAqBM,2BAAA,0BAMN,eAEE,yBAAA,yBACA,2BAAA,eAGE,yBANJ,eAOM,yBAAA,2BACA,2BAAA,6BAKF,yBAbJ,eAcM,yBAAA,yBACA,2BAAA,4BAOR,EACE,kBAAA,KAYF,MACE,YAAA,QAIF,GC5CA,GACA,GACA,GACA,GACA,GD8CE,cAAA,IAGF,GACE,YAAA,KACA,8BAAA,KAGF,GACE,YAAA,QACA,8BAAA,SAGF,GACE,YAAA,OACA,8BAAA,QAGF,GACE,YAAA,QACA,8BAAA,SAGF,GACE,YAAA,SACA,8BAAA,UAIF,gBC7CA,aD+CE,eAAA,IAGF,6BACE,eAAA,ICxCF,SADA,SADA,SDgDE,SAEE,eAAA,IAIJ,uBACE,YAAA,QC5CF,KACA,ID+CA,IC9CA,KDkDE,cAAA,OAAA,CAAA,UAAA,CAAA,aAAA,CAAA,kBAAA,CChDE,WAAW,CAAE,aAAa,CAAE,iBAAiB,CAAE,SAAS,CACxD,mBAAmB,CAAE,gBAAgB,CAAE,iBAAiB,CAAE,mBDoD9D,IACE,cAAA,OC7CF,6BCrMA,mBAEE,mBAAA,KAGA,QAAA,mBACA,WAAA,mBACA,WAAA,QACA,WAAA,mBACA,WAAA,QACA,WAAA,mBACA,WAAA,QAGA,cAAA,mBACA,qBAAA,mBAGA,UAAA,mBACA,gBAAA,mBACA,gBAAA,0BACA,kBAAA,KAGA,YAAA,mBACA,kBAAA,mBACA,kBAAA,0BACA,oBAAA,KAGA,WAAA,mBACA,iBAAA,KACA,iBAAA,0BACA,mBAAA,KAGA,wBAAA,QACA,aAAA,QAGA,YAAA,QACA,YAAA,QAGA,0BAAA,0BACA,0BAAA,mBAKA,oBAAA,EAAA,EAAA,EAAA,iBACA,0BAAA,EAAA,EAAA,EAAA,iBAGA,gCAAA,YACA,4BAAA,mBACA,qBAAA,aACA,iCAAA,mBACA,uCAAA,YACA,mCAAA,eACA,2BAAA,qBACA,yCAAA,mBACA,qCAAA,mBACA,gCAAA,IACA,oCAAA,QACA,2CAAA,QACA,mCAAA,yBACA,kCAAA,QACA,yCAAA,QACA,iCAAA,yBAGA,0BAAA,mBACA,eAAA,uBACA,kCAAA,eAGA,qBAAA,mBACA,4BAAA,mBACA,2BAAA,wBACA,oBAAA,iBACA,0BAAA,uBACA,2BAAA,eAGA,qBAAA,0BACA,sCAAA,QAGA,wBAAA,mBACA,aAAA,mBACA,4BAAA,gBACA,iBAAA,wBACA,iBAAA,mBACA,sBAAA,mBACA,mBAAA,kBACA,qBAAA,mBAGA,yBAAA,0BACA,gCAAA,aACA,+BAAA,mBAMA,wBAAA,wBACA,oBAAA,0BACA,kBDgKE,UAAU,SAAS,SAAS,yBAAyB,CACrD,UAAU,SAAS,SAAS,uBAAuB,CACnD,UAAU,SAAS,QAAQ,sBAAsB,CACjD,UAAU,SAAS,QAAQ,uBAAuB,CAClD,UAAU,SAAS,SAAS,yBAAyB,CACrD,OAAO,KAAK,KAAK,sBAAsB,CACvC,EAAE,EAAE,EAAE,UAAU,wBC9JlB,oCAAA,QAGA,4BAAA,QACA,wBAAA,QACA,sBAAA,uBACA,iBAAA,aACA,kCAAA,mBAGA,iCAAA,yBAGA,4BAAA,mBACA,iBAAA,eAGA,0BAAA,IAGA,2BAAA,gBACA,gBAAA,wBAGA,gBAAA,yRACA,eAAA,sRACA,sBAAA,yRACA,8BAAA,yRACA,aAAA,0UACA,YAAA,+bACA,eAAA,8XACA,aAAA,wRACA,cAAA,2UACA,YAAA,wUACA,aAAA,uRAGA,aAAA,MC3IF,mDACE,wBCfA,mBAAA,QAGA,QAAA,mBACA,WAAA,mBACA,WAAA,QACA,WAAA,mBACA,WAAA,QACA,WAAA,mBACA,WAAA,QAGA,cAAA,mBACA,qBAAA,QAGA,UAAA,mBACA,gBAAA,mBACA,gBAAA,yBACA,kBAAA,KAGA,YAAA,mBACA,kBAAA,mBACA,kBAAA,0BACA,oBAAA,KAGA,WAAA,mBACA,iBAAA,KACA,iBAAA,0BACA,mBAAA,KAGA,wBAAA,QACA,aAAA,QAGA,YAAA,QACA,YAAA,QAGA,0BAAA,0BACA,0BAAA,mBAKA,oBAAA,EAAA,EAAA,EAAA,iBACA,0BAAA,EAAA,EAAA,EAAA,iBAGA,gCAAA,QACA,4BAAA,QACA,qBAAA,aACA,iCAAA,mBACA,uCAAA,qCACA,mCAAA,eACA,2BAAA,qBACA,yCAAA,mBACA,qCAAA,mBACA,gCAAA,IACA,oCAAA,QACA,2CAAA,QACA,mCAAA,wBACA,kCAAA,QACA,yCAAA,QACA,iCAAA,wBAGA,0BAAA,QACA,eAAA,uBACA,kCAAA,eAGA,qBAAA,QACA,4BAAA,mBACA,2BAAA,wBACA,oBAAA,iBACA,0BAAA,uBACA,2BAAA,eAGA,qBAAA,0BACA,sCAAA,0BAGA,wBAAA,QACA,aAAA,mBACA,4BAAA,gBACA,iBAAA,wBACA,iBAAA,mBACA,sBAAA,mBACA,mBAAA,kBACA,qBAAA,QAGA,yBAAA,0BACA,iCAAA,eACA,gCAAA,aACA,+BAAA,mBAMA,wBAAA,QACA,oBAAA,6BACA,kBH2QI,UAAU,SAAS,SAAS,sBAAsB,CAClD,UAAU,SAAS,SAAS,oBAAoB,CAChD,UAAU,SAAS,QAAQ,mBAAmB,CAC9C,UAAU,SAAS,QAAQ,oBAAoB,CAC/C,UAAU,SAAS,SAAS,sBAAsB,CAClD,OAAO,KAAK,KAAK,mBAAmB,CACpC,EAAE,EAAE,EAAE,UAAU,qBGzQpB,oCAAA,QAGA,4BAAA,mBACA,wBAAA,QACA,sBAAA,uBACA,iBAAA,aACA,kCAAA,uBAGA,iCAAA,sBAGA,4BAAA,QACA,iBAAA,eAGA,0BAAA,IAGA,2BAAA,gBACA,gBAAA,wBAGA,gBAAA,yRACA,eAAA,yRACA,sBAAA,yRACA,8BAAA,mRACA,aAAA,0UACA,YAAA,kcACA,eAAA,8XACA,aAAA,wRACA,cAAA,8UACA,YAAA,2UACA,aAAA,uRAGA,aAAA,MDnIF,kBCtBE,mBAAA,QAGA,QAAA,mBACA,WAAA,mBACA,WAAA,QACA,WAAA,mBACA,WAAA,QACA,WAAA,mBACA,WAAA,QAGA,cAAA,mBACA,qBAAA,QAGA,UAAA,mBACA,gBAAA,mBACA,gBAAA,yBACA,kBAAA,KAGA,YAAA,mBACA,kBAAA,mBACA,kBAAA,0BACA,oBAAA,KAGA,WAAA,mBACA,iBAAA,KACA,iBAAA,0BACA,mBAAA,KAGA,wBAAA,QACA,aAAA,QAGA,YAAA,QACA,YAAA,QAGA,0BAAA,0BACA,0BAAA,mBAKA,oBAAA,EAAA,EAAA,EAAA,iBACA,0BAAA,EAAA,EAAA,EAAA,iBAGA,gCAAA,QACA,4BAAA,QACA,qBAAA,aACA,iCAAA,mBACA,uCAAA,qCACA,mCAAA,eACA,2BAAA,qBACA,yCAAA,mBACA,qCAAA,mBACA,gCAAA,IACA,oCAAA,QACA,2CAAA,QACA,mCAAA,wBACA,kCAAA,QACA,yCAAA,QACA,iCAAA,wBAGA,0BAAA,QACA,eAAA,uBACA,kCAAA,eAGA,qBAAA,QACA,4BAAA,mBACA,2BAAA,wBACA,oBAAA,iBACA,0BAAA,uBACA,2BAAA,eAGA,qBAAA,0BACA,sCAAA,0BAGA,wBAAA,QACA,aAAA,mBACA,4BAAA,gBACA,iBAAA,wBACA,iBAAA,mBACA,sBAAA,mBACA,mBAAA,kBACA,qBAAA,QAGA,yBAAA,0BACA,iCAAA,eACA,gCAAA,aACA,+BAAA,mBAMA,wBAAA,QACA,oBAAA,6BACA,kBHqXE,UAAU,SAAS,SAAS,sBAAsB,CAClD,UAAU,SAAS,SAAS,oBAAoB,CAChD,UAAU,SAAS,QAAQ,mBAAmB,CAC9C,UAAU,SAAS,QAAQ,oBAAoB,CAC/C,UAAU,SAAS,SAAS,sBAAsB,CAClD,OAAO,KAAK,KAAK,mBAAmB,CACpC,EAAE,EAAE,EAAE,UAAU,qBGnXlB,oCAAA,QAGA,4BAAA,mBACA,wBAAA,QACA,sBAAA,uBACA,iBAAA,aACA,kCAAA,uBAGA,iCAAA,sBAGA,4BAAA,QACA,iBAAA,eAGA,0BAAA,IAGA,2BAAA,gBACA,gBAAA,wBAGA,gBAAA,yRACA,eAAA,yRACA,sBAAA,yRACA,8BAAA,mRACA,aAAA,0UACA,YAAA,kcACA,eAAA,8XACA,aAAA,wRACA,cAAA,8UACA,YAAA,2UACA,aAAA,uRAGA,aAAA,KH0WF,gBACA,aACA,aE1eA,SAIE,aAAA,eEvBF,EJugBA,QADA,SIngBE,WAAA,WACA,kBAAA,UJygBF,QIpgBA,SAEE,gBAAA,QACA,eAAA,QASF,cACE,4BAAA,YACA,yBAAA,KACA,sBAAA,KAAA,iBAAA,KACA,iBAAA,wBACA,MAAA,aACA,YAAA,mBACA,UAAA,iBACA,YAAA,mBACA,YAAA,mBACA,eAAA,mBACA,cAAA,WACA,OAAA,QACA,cAAA,EAAA,YAAA,EAAA,SAAA,ECnCF,KACE,QAAA,MAOF,KACE,MAAA,KACA,OAAA,EL0iBF,YKxiBE,YLuiBF,UKpiBI,MAAA,KACA,aAAA,KACA,YAAA,KAIE,QAAA,8BAAA,gCAKI,yBLmiBR,YKjjBA,YLgjBA,UKjiBU,UAAA,MACA,cAAA,EACA,aAAA,GAKF,yBLoiBR,YK1jBA,YLyjBA,UKliBU,UAAA,OAKF,yBLqiBR,YKjkBA,YLgkBA,UKniBU,UAAA,OAKF,0BLsiBR,YKxkBA,YLukBA,UKpiBU,UAAA,QCrDZ,QACE,cAAA,8BCDF,OACE,QAAA,MACA,OAAA,EACA,QAAA,EACA,WAAA,KAEA,kBACE,QAAA,0BAAA,EACA,MAAA,mBCHJ,ERonBA,OQlnBE,YAAA,OAIF,IRmnBA,IQjnBE,SAAA,SACA,UAAA,MACA,YAAA,EACA,eAAA,SAEF,IACE,OAAA,OAEF,IACE,IAAA,MAMF,QRknBA,WACA,GACA,OACA,KACA,GACA,EACA,IACA,MACA,GQhnBE,WAAA,EACA,cAAA,mCACA,MAAA,aACA,WAAA,OACA,YAAA,mBACA,UAAA,iBRqnBF,YQhnBA,EAEE,QAAA,eACA,mBAAA,YACA,QAAA,EACA,iBAAA,wBACA,MAAA,aACA,wBAAA,uBAAA,gBAAA,uBAGE,WAAA,iBAAA,iBAAA,CAAA,MAAA,iBAAA,CAAA,WAAA,iBAAA,CAAA,wBAAA,kBAAA,WAAA,iBAAA,iBAAA,CAAA,MAAA,iBAAA,CAAA,gBAAA,iBAAA,CAAA,WAAA,kBAAA,WAAA,iBAAA,iBAAA,CAAA,MAAA,iBAAA,CAAA,gBAAA,iBAAA,CAAA,WAAA,iBAAA,CAAA,wBAAA,kBRmnBJ,qDQ/mBE,2CACE,QAAA,qBACA,kBAAA,URknBJ,kBQ/mBE,QACE,mBAAA,qBAiCJ,GRklBA,GACA,GACA,GACA,GACA,GQhlBE,WAAA,EACA,cAAA,mCACA,MAAA,aACA,YAAA,mBACA,UAAA,iBACA,YAAA,mBAGF,GACE,QAAA,gBAEF,GACE,QAAA,gBAEF,GACE,QAAA,gBAEF,GACE,QAAA,gBAEF,GACE,QAAA,gBAEF,GACE,QAAA,gBAKA,mFACE,WAAA,mCAMF,OACE,cAAA,mCAEA,SACE,cAAA,EAGF,mBACE,QAAA,mBACA,cAAA,MACA,UAAA,KACA,YAAA,MAwBN,EACE,cAAA,mCAIF,MACE,UAAA,iBAIF,iBACE,cAAA,EACA,aAAA,eACA,sBAAA,eAAA,qBAAA,eACA,oBAAA,EAAA,mBAAA,EAEA,oBACE,cAAA,+CAOF,+BACE,OAAA,EACA,WAAA,+CAIJ,MACE,WAAA,OAIF,KACE,QAAA,QAAA,OACA,iBAAA,6BACA,MAAA,kBACA,eAAA,SAIF,WACE,QAAA,MACA,OAAA,mCAAA,EACA,QAAA,eACA,aAAA,KACA,YAAA,OAAA,MAAA,+BACA,qBAAA,QAAA,MAAA,+BAAA,oBAAA,QAAA,MAAA,+BACA,mBAAA,KAAA,kBAAA,KAEA,kBACE,WAAA,8CACA,MAAA,+BAMJ,YACE,cAAA,IAAA,OACA,gBAAA,KACA,OAAA,KAIF,IACE,MAAA,iBACA,gBAAA,KAIF,IACE,MAAA,iBAIF,iBACE,iBAAA,qBADF,YACE,iBAAA,qBC5PF,0CACE,eAAA,OAIF,MTszBA,MSpzBE,QAAA,aAIF,sBACE,QAAA,KACA,OAAA,EAIF,eACE,aAAA,KAKF,IACE,UAAA,KACA,OAAA,KACA,aAAA,KAIF,wBACE,KAAA,aAIF,eACE,SAAA,OClCF,OACE,OAAA,EACA,SAAA,QACA,YAAA,QACA,eAAA,KV21BF,cACA,aACA,cUz1BA,OAIE,mBAAA,OAMF,OACE,QAAA,MACA,MAAA,KACA,cAAA,eAGF,cACE,QAAA,aACA,gBAAA,KV01BF,cUv1BA,OVq1BA,mBACA,kBAFA,mBU/0BE,mBAAA,eACA,eAAA,eACA,QAAA,uBACA,aAAA,iDACA,QAAA,qCAAA,uCAEA,OAAA,oBAAA,MAAA,oBACA,cAAA,qBACA,QAAA,EACA,iBAAA,wBACA,WAAA,kBACA,MAAA,aACA,YAAA,mBACA,UAAA,KACA,YAAA,mBACA,WAAA,OACA,OAAA,QAGE,WAAA,iBAAA,iBAAA,CAAA,aAAA,iBAAA,CAAA,MAAA,iBAAA,CAAA,WAAA,kBVs1BJ,uDUj1BE,gDV+0BF,4DACA,2DAFA,4DU70BI,mBAAA,qBACA,eAAA,qBACA,aAAA,uDACA,QAAA,uBVu1BJ,oBUp1BE,aVk1BF,yBACA,wBAFA,yBUh1BI,aAAA,sDAAA,CVq1BA,EAAE,EAAE,EAAE,qBAAqB,qBUtwB7B,kBACE,mBAAA,iBACA,eAAA,iBACA,QAAA,yBACA,OAAA,QAEA,2DACE,mBAAA,uBACA,eAAA,uBAGF,wBACE,aAAA,sDAAA,CVywBF,EAAE,EAAE,EAAE,qBAAqB,uBUjwB/B,gFVqwBA,8FACA,2BUnwBE,QAAA,GACA,eAAA,KC1KF,MXq7BA,SACA,OACA,SWn7BE,OAAA,EACA,UAAA,KACA,YAAA,mBACA,YAAA,QACA,eAAA,QAIF,MACE,SAAA,QAIF,OACE,eAAA,KAOF,OACE,UAAA,KACA,QAAA,EACA,MAAA,QACA,YAAA,OAIF,SACE,SAAA,KAIF,gBX66BA,aW36BE,QAAA,EAIF,4BX46BA,4BW16BE,OAAA,KAKF,cACE,mBAAA,UACA,eAAA,KAIF,yCACE,mBAAA,KAKF,6BACE,mBAAA,OACA,KAAA,QAIF,mBACE,QAAA,EACA,aAAA,KAIF,gBACE,QAAA,EAIF,iBACE,WAAA,KAIF,aACE,QAAA,KAIF,YXk6BA,aWh6BE,QAAA,EACA,aAAA,EAOF,qDACE,OAAA,qGAOF,SACE,OAAA,EACA,cAAA,eACA,QAAA,EACA,OAAA,EX65BF,gBWz5BA,MAEE,QAAA,MACA,cAAA,2BACA,YAAA,iDAIF,wCXw5BA,OACA,SWt5BE,MAAA,KAIF,iEXu5BA,OACA,SWr5BE,mBAAA,KAAA,gBAAA,KAAA,WAAA,KACA,QAAA,qCAAA,uCAKF,MXu5BA,OACA,SWr5BE,mBAAA,qCACA,eAAA,iCACA,QAAA,0BACA,aAAA,KACA,OAAA,oBAAA,MAAA,oBACA,cAAA,qBACA,QAAA,EACA,iBAAA,wBACA,WAAA,kBACA,MAAA,aACA,YAAA,mBAGE,WAAA,iBAAA,iBAAA,CAAA,aAAA,iBAAA,CAAA,MAAA,iBAAA,CAAA,WAAA,kBXw5BJ,2CW/4BE,+GACE,mBAAA,4CXm5BJ,2CW54BE,gGACE,eAAA,wCAQF,8FXw4BF,aACA,eWx4BI,aAAA,EAAA,EAAA,EAAA,qBAAA,gCX+4BJ,oGW14BA,8DXw4BA,iBACA,mBWr4BE,mBAAA,8CACA,eAAA,0CACA,QAAA,qCACA,eAAA,KAME,qJAEI,cAAA,gEAGA,aAAA,uCACA,sBAAA,iDAAA,qBAAA,iDACA,oBAAA,gEAAA,mBAAA,gEAUF,oBAAA,OAAA,MAAA,OACA,gBAAA,KAAA,KACA,kBAAA,UAGF,2JACE,iBAAA,kBAGF,0JACE,iBAAA,oBAIJ,kDACE,eAAA,uCAEA,qEAEI,eAAA,wDACA,aAAA,EAAA,EAAA,EAAA,qBAAA,gDASN,iDACE,eAAA,yCAEA,oEAEI,eAAA,0DACA,aAAA,EAAA,EAAA,EAAA,qBAAA,kDAaF,sIACE,oBAAA,OAAA,KAAA,OXu2BR,iCWh2BA,mBXm2BA,eADA,oCADA,sBW51BE,MAAA,sCACA,QAAA,EAIF,wCX+1BA,OACA,SW71BE,cAAA,eAMA,mBACE,OAAA,EACA,iBAAA,YAGF,8BACE,cAAA,sDACA,aAAA,uCACA,sBAAA,uCAAA,qBAAA,uCACA,oBAAA,sDAAA,mBAAA,sDACA,iBAAA,oBACA,oBAAA,OAAA,MAAA,OACA,gBAAA,KAAA,KACA,kBAAA,UAMA,wCACE,oBAAA,OAAA,KAAA,OAaJ,oCACE,QAAA,MACA,MAAA,KACA,WAAA,4BACA,cAAA,eACA,MAAA,mBAMF,oCACE,WAAA,2BCxVJ,gBZ4qCA,aY1qCE,mBAAA,KACA,gBAAA,KACA,WAAA,KACA,MAAA,OACA,OAAA,OACA,WAAA,QACA,aAAA,OACA,YAAA,EACA,qBAAA,EAAA,oBAAA,EACA,mBAAA,OAAA,kBAAA,OACA,aAAA,oBACA,UAAA,QACA,eAAA,OACA,OAAA,QAEA,2BZ8qCF,wBY7qCI,QAAA,KAGF,wBAAA,+BAAA,8BZ8qCF,qBACA,4BACA,2BY7qCI,mBAAA,eACA,eAAA,eACA,iBAAA,qBACA,oBAAA,OACA,gBAAA,MAAA,KACA,kBAAA,UAGF,sBZ8qCF,mBY7qCI,QAAA,aACA,aAAA,OACA,cAAA,EACA,OAAA,QAMF,8BACE,mBAAA,eACA,eAAA,eACA,iBAAA,kBACA,oBAAA,OACA,gBAAA,MAAA,KACA,kBAAA,UAKJ,aACE,cAAA,IAEA,qBAAA,4BAAA,2BAGE,mBAAA,uBACA,aAAA,MACA,iBAAA,KAKJ,6BACE,mBAAA,+BACA,eAAA,+BACA,QAAA,oBAQA,MAAA,OACA,OAAA,OACA,OAAA,oBAAA,MAAA,oBACA,cAAA,OACA,iBAAA,wBACA,YAAA,OAEA,mCACE,mBAAA,+BACA,eAAA,+BAGF,qCACE,mBAAA,uCACA,eAAA,uCAGF,oCACE,QAAA,MACA,MAAA,yCACA,OAAA,KACA,cAAA,IACA,iBAAA,aACA,QAAA,GAGE,WAAA,OAAA,IAAA,YAIJ,qCACE,iBAAA,KAEA,6CACE,YAAA,oCACA,qBAAA,oCAAA,oBAAA,oCZ6pCN,4CYhpCE,oCZopCF,yDADA,iDADA,yCADA,iCYhpCI,eAAA,uCZupCJ,2CYppCE,mCZwpCF,wDADA,gDADA,wCADA,gCYppCI,eAAA,yCC3HF,2CAHE,QAAA,EAOF,+BAPE,QAAA,EAiBF,mCAJE,OAAA,EACA,cAAA,gCAOF,gCARE,OAAA,EACA,cAAA,gCAeF,4IACE,gBAAA,QACA,aAAA,KACA,cAAA,+CACA,iBAAA,iBACA,oBAAA,OAAA,MAAA,qBACA,gBAAA,kBAAA,KACA,kBAAA,UAIF,4EACE,iBAAA,iBAUF,+CbuwCF,yDACA,gDACA,+CACA,+CazwCI,MAAA,kBACA,aAAA,6BACA,YAAA,qBACA,QAAA,EAIJ,sFAEE,WAAA,MAKA,4BACE,YbuwCF,sBACA,aACA,YACA,YarwCI,cAAA,iDACA,iBAAA,gBAMN,YACE,QAAA,mBACA,QAAA,gDAAA,EACA,OAAA,EACA,cAAA,EACA,WAAA,IAoCA,kCAjCE,mBAAA,iBACA,eAAA,iBACA,QAAA,yBACA,aAAA,wBACA,YAAA,EACA,qBAAA,EAAA,oBAAA,EACA,mBAAA,wBAAA,kBAAA,wBACA,QAAA,gDAAA,kDAEA,OAAA,oBAAA,MAAA,oBACA,cAAA,qBACA,QAAA,EACA,iBAAA,wBACA,WAAA,kBACA,MAAA,aACA,YAAA,mBACA,UAAA,KACA,YAAA,mBACA,WAAA,OACA,OAAA,QAGE,WAAA,iBAAA,iBAAA,CAAA,aAAA,iBAAA,CAAA,MAAA,iBAAA,CAAA,WAAA,kBAKF,4DACE,mBAAA,uBACA,eAAA,uBAQJ,wCArCE,mBAAA,iBACA,eAAA,iBACA,QAAA,yBACA,aAAA,wBACA,YAAA,EACA,qBAAA,EAAA,oBAAA,EACA,mBAAA,wBAAA,kBAAA,wBACA,QAAA,gDAAA,kDAEA,OAAA,oBAAA,MAAA,oBACA,cAAA,qBACA,QAAA,EACA,iBAAA,wBACA,WAAA,kBACA,MAAA,aACA,YAAA,mBACA,UAAA,KACA,YAAA,mBACA,WAAA,OACA,OAAA,QAGE,mBAAA,iBAAA,iBAAA,CAAA,aAAA,iBAAA,CAAA,MAAA,iBAAA,CAAA,WAAA,kBAAA,WAAA,iBAAA,iBAAA,CAAA,aAAA,iBAAA,CAAA,MAAA,iBAAA,CAAA,WAAA,kBAKF,kEACE,mBAAA,uBACA,eAAA,uBAYJ,wBAzCE,mBAAA,iBACA,eAAA,iBACA,QAAA,yBACA,aAAA,wBACA,YAAA,EACA,oBAAA,EACA,kBAAA,wBACA,QAAA,gDAAA,kDAEA,OAAA,oBAAA,MAAA,oBACA,cAAA,qBACA,QAAA,EACA,iBAAA,wBACA,WAAA,kBACA,MAAA,aACA,YAAA,mBACA,UAAA,KACA,YAAA,mBACA,WAAA,OACA,OAAA,QAGE,eAAA,iBAAA,iBAAA,CAAA,aAAA,iBAAA,CAAA,MAAA,iBAAA,CAAA,WAAA,kBAAA,WAAA,iBAAA,iBAAA,CAAA,aAAA,iBAAA,CAAA,MAAA,iBAAA,CAAA,WAAA,kBAKF,kDACE,mBAAA,uBACA,eAAA,uBAkBN,aAOE,mBAAA,KACA,gBAAA,KACA,WAAA,KACA,MAAA,KACA,OAAA,QACA,WAAA,IAeA,4CAXE,MAAA,KACA,OAAA,OACA,cAAA,qBACA,iBAAA,0BAGE,mBAAA,iBAAA,iBAAA,CAAA,WAAA,kBAAA,WAAA,iBAAA,iBAAA,CAAA,WAAA,kBASJ,+BAfE,MAAA,KACA,OAAA,OACA,cAAA,qBACA,iBAAA,0BAGE,gBAAA,iBAAA,iBAAA,CAAA,WAAA,kBAAA,WAAA,iBAAA,iBAAA,CAAA,WAAA,kBAaJ,wBAnBE,MAAA,KACA,OAAA,OACA,cAAA,qBACA,iBAAA,0BAGE,eAAA,iBAAA,iBAAA,CAAA,WAAA,kBAAA,WAAA,iBAAA,iBAAA,CAAA,WAAA,kBAiCJ,mCAdE,mBAAA,KACA,MAAA,QACA,OAAA,QACA,WAAA,OACA,OAAA,IAAA,MAAA,gCACA,cAAA,IACA,iBAAA,yBACA,OAAA,QAGE,mBAAA,iBAAA,iBAAA,CAAA,UAAA,kBAAA,WAAA,iBAAA,iBAAA,CAAA,UAAA,kBAQJ,+BAlBE,mBAAA,KACA,MAAA,QACA,OAAA,QACA,WAAA,OACA,OAAA,IAAA,MAAA,gCACA,cAAA,IACA,iBAAA,yBACA,OAAA,QAGE,gBAAA,iBAAA,iBAAA,CAAA,UAAA,kBAAA,WAAA,iBAAA,iBAAA,CAAA,UAAA,kBAYJ,wBAtBE,mBAAA,KACA,MAAA,QACA,OAAA,QACA,WAAA,OACA,OAAA,IAAA,MAAA,gCACA,cAAA,IACA,iBAAA,yBACA,OAAA,QAGE,eAAA,iBAAA,iBAAA,CAAA,UAAA,kBAAA,WAAA,iBAAA,iBAAA,CAAA,UAAA,kBAgBJ,mBAAA,mBAEE,qBAAA,iCACA,oBAAA,+BAGF,oBACE,oBAAA,gCAGA,0CACE,UAAA,YAGF,sCACE,UAAA,YAGF,+BACE,UAAA,YAQJ,8EACE,sBAAA,uDAAA,qBAAA,uDACA,cAAA,KACA,iBAAA,mBACA,oBAAA,OAAA,KAAA,SACA,gBAAA,KAAA,KACA,kBAAA,UAEA,4FAEI,sBAAA,iEAAA,qBAAA,iEAKF,oBAAA,OAAA,KAAA,QAAA,CAAA,OAAA,MAAA,OAGF,kGACE,iBAAA,kBAAA,CAAA,kBAGF,iGACE,iBAAA,kBAAA,CAAA,oBAOJ,4CACE,mBAAA,KACA,QAAA,KAOE,gGACE,oBAAA,OAAA,MAAA,SAEA,8GACE,oBAAA,OAAA,MAAA,QAAA,CAAA,OAAA,KAAA,OC7QV,cACE,MAAA,KACA,gBAAA,SACA,eAAA,EACA,YAAA,EdyiDF,GcliDA,GAEE,QAAA,wBAAA,eACA,cAAA,oBAAA,MAAA,0BACA,MAAA,aACA,YAAA,mBACA,UAAA,iBACA,WAAA,KACA,WAAA,MdqiDF,SchiDE,SAEE,WAAA,oBAAA,MAAA,0BACA,cAAA,EAOA,yCACE,iBAAA,2CdkiDN,KACA,IetkDA,IfukDA,KenkDE,UAAA,OACA,YAAA,mBAIF,IACE,mBAAA,UACA,SAAA,KfukDF,KACA,IelkDA,IAGE,cAAA,qBACA,WAAA,6BACA,MAAA,kBACA,YAAA,mBACA,YAAA,QAGF,KfikDA,Ie/jDE,QAAA,aACA,QAAA,QAAA,MAGF,IACE,QAAA,MACA,cAAA,eACA,WAAA,KAEA,SACE,QAAA,MACA,QAAA,eACA,WAAA,IACA,UAAA,KACA,YAAA,mBAOF,OACE,MAAA,sBACA,YAAA,mBAIF,OACE,MAAA,2BACA,WAAA,OAIF,OACE,MAAA,wBACA,gBAAA,KAIF,QACE,MAAA,0BACA,WAAA,OAKJ,IACE,iBAAA,iCACA,MAAA,sBACA,eAAA,SC9EF,GACE,OAAA,EACA,OAAA,EACA,WAAA,IAAA,MAAA,0BACA,MAAA,QAIF,ShBwoDA,SgBroDI,QAAA,eAQJ,OACE,QAAA,aC3BF,QACE,QAAA,MACA,cAAA,eACA,eAAA,eACA,cAAA,oBAAA,MAAA,8BAEA,gBACE,YAAA,KACA,gBAAA,KACA,OAAA,QAOE,WAAA,MAAA,kBALF,4BACE,MAAA,qCAQF,wCACE,QAAA,KAGF,wBACE,QAAA,KAGF,kCACE,gBAAA,KAIF,uBACE,QAAA,MACA,MAAA,KACA,OAAA,KACA,qBAAA,gCAAA,oBAAA,+BACA,MAAA,MACA,UAAA,eACA,iBAAA,oBACA,oBAAA,MAAA,OACA,gBAAA,KAAA,KACA,kBAAA,UACA,QAAA,GAGE,WAAA,UAAA,kBAIJ,sBACE,QAAA,EAEA,yCACE,MAAA,sCAKJ,6BACE,MAAA,KACA,WAAA,KAGA,oCACE,OAAA,oCACA,iBAAA,2BAiBJ,sBACE,cAAA,qBAGE,8CACE,MAAA,oCAIJ,6BACE,UAAA,UAQJ,0BACE,WAAA,MAEA,iCACE,MAAA,KACA,oBAAA,KAAA,OC3GR,QACE,OAAA,8BAAA,EACA,QAAA,8BAAA,gCACA,cAAA,qBACA,WAAA,6BACA,WAAA,uBlB+uDF,ekB7uDE,eAEE,aAAA,2CACA,YAAA,2CACA,QAAA,0CAAA,gCAEA,iBAAA,yCAGF,eACE,WAAA,yCACA,cAAA,8BACA,cAAA,oBAAA,MAAA,yBACA,wBAAA,qBACA,uBAAA,qBAGF,eACE,WAAA,8BACA,cAAA,yCACA,WAAA,oBAAA,MAAA,yBACA,2BAAA,qBACA,0BAAA,qBC7BJ,MACE,kBAAA,IAGF,OACE,QAAA,KACA,QAAA,IACA,SAAA,MACA,IAAA,EACA,MAAA,EACA,OAAA,EACA,KAAA,EACA,YAAA,OACA,gBAAA,OACA,MAAA,QACA,UAAA,KACA,OAAA,QACA,WAAA,KACA,QAAA,eACA,OAAA,EACA,wBAAA,qCAAA,gBAAA,qCACA,iBAAA,sCACA,MAAA,aAGA,eACE,WAAA,iCACA,SAAA,KAGE,yBALJ,eAMM,UAAA,OAKF,yBAXJ,eAYM,UAAA,OnB+wDR,sBmB3wDI,sBAEE,QAAA,yCAAA,gCAKA,6BACE,OAAA,EACA,YAAA,eACA,MAAA,MAIJ,sBACE,WAAA,MAEA,oCACE,cAAA,EAEA,wDACE,YAAA,0BAMJ,8BACE,OAAA,EA+BN,mBAAA,mBAEE,QAAA,KClGJ,uBACE,MAAA,KACA,QAAA,IAOF,IpBw0DA,OoBt0DE,QAAA,KAGF,IACE,gBAAA,cAEA,OpBw0DF,OoBt0DI,YAAA,OACA,cAAA,EACA,QAAA,EACA,WAAA,KAEA,qBpBw0DJ,qBoBv0DM,YAAA,iDAEF,oBpBy0DJ,oBoBx0DM,aAAA,iDAIJ,OACE,QAAA,aACA,OAAA,EACA,QAAA,oCAAA,sCAIA,SACE,UAAA,EAIJ,0BACE,QAAA,aACA,OAAA,4CAAA,8CAEA,QAAA,iCAAA,mCACA,cAAA,qBACA,gBAAA,KAEA,mEACE,gBAAA,KAKJ,2BACE,YAAA,OACA,gBAAA,MAGE,mDACE,qBAAA,mCAAA,oBAAA,mCAIA,0DACE,SAAA,SACA,MAAA,6CACA,qBAAA,4CAAA,oBAAA,4CACA,QAAA,IACA,MAAA,mBACA,WAAA,OAKN,2CACE,iBAAA,YACA,MAAA,QACA,gBAAA,KACA,eAAA,KAKJ,kBACE,aAAA,QACA,YAAA,QACA,QAAA,iCAAA,mCpB8zDJ,SoBxzDE,UpBszDF,SACA,SoBnzDI,QAAA,MAGF,SACE,QAAA,+CAAA,sCAGA,WACE,QAAA,MAIF,uBACE,OAAA,QAWI,oEACE,QAAA,KC3HZ,SACE,QAAA,aACA,eAAA,SAMF,SAEE,mBAAA,KACA,gBAAA,KAGA,QAAA,aACA,WAAA,KACA,MAAA,KACA,OAAA,MACA,cAAA,0BACA,SAAA,OAGA,OAAA,EACA,cAAA,qBACA,iBAAA,iCAGA,MAAA,sBAEA,+BACE,cAAA,qBACA,WAAA,IAEF,wCACE,iBAAA,sBAEF,4BACE,iBAAA,sBAIF,8CACE,uBACE,WAAA,iCAAA,yFAAA,IAAA,IAAA,CAAA,KAAA,KAAA,UAOA,UAAA,uBAAA,GAAA,OAAA,SAEA,sDACE,iBAAA,YAEF,0CACE,iBAAA,aAON,8CACE,iCACE,oBAAA,SAKN,kCACE,GACE,oBAAA,KAAA,EAEF,KACE,oBAAA,MAAA,GCjFJ,mBtB4+DA,csB1+DE,SAAA,SAGF,8BtB4+DA,iBsB1+DE,QAAA,KACA,QAAA,GACA,SAAA,SACA,IAAA,KACA,MAAA,EACA,KAAA,EACA,eAAA,OACA,OAAA,EACA,QAAA,EACA,OAAA,oBAAA,MAAA,6BACA,cAAA,qBACA,wBAAA,EACA,uBAAA,EACA,iBAAA,iCACA,WAAA,uBACA,MAAA,sBACA,YAAA,OAEA,iCtB4+DF,oBsB3+DI,MAAA,KACA,cAAA,EACA,QAAA,gDAAA,uCAEA,WAAA,KAEA,+CtB4+DJ,kCsB3+DM,WAAA,gDAGF,8CtB4+DJ,iCsB3+DM,cAAA,gDAGF,mCtB4+DJ,sBsB3+DM,QAAA,MACA,OAAA,iDAAA,kDAEA,QAAA,gDAAA,uCAEA,SAAA,OACA,MAAA,sBACA,gBAAA,KACA,cAAA,SAEA,yCtB2+DN,4BsB1+DQ,iBAAA,uCASN,kCtBs+DF,uBsBr+DI,QAAA,MACA,MAAA,KACA,OAAA,oCACA,qBAAA,OAAA,oBAAA,MACA,MAAA,MACA,UAAA,UACA,oBAAA,MAAA,OACA,gBAAA,KAAA,KACA,kBAAA,UACA,QAAA,GAKJ,mBACE,QAAA,EACA,cAAA,KAGA,2BACE,cAAA,EAEA,uCACE,OAAA,qGAIA,QAAA,qCAAA,uCAEA,OAAA,oBAAA,MAAA,iCACA,cAAA,qBACA,iBAAA,qCACA,MAAA,sCACA,YAAA,QACA,OAAA,QAGE,WAAA,iBAAA,iBAAA,CAAA,aAAA,iBAAA,CAAA,MAAA,iBAAA,CAAA,WAAA,kBAKF,8CAAA,6CAEE,aAAA,wCACA,iBAAA,4CAGF,6CACE,WAAA,EAAA,EAAA,EAAA,qBAAA,gCAMN,iCACE,2BAAA,EACA,0BAAA,EAEA,yCACE,QAAA,MACA,QAAA,EACA,SAAA,MACA,IAAA,EACA,MAAA,EACA,OAAA,EACA,KAAA,EACA,WAAA,IACA,QAAA,GACA,OAAA,QAMN,+BtBm9DA,oBsBj9DE,QAAA,KACA,UAAA,IAGF,kCtBm9DA,qBsBj9DE,UAAA,iBAAA,UAAA,YACA,cAAA,qBAEA,uCtBo9DF,0BsBn9DI,cAAA,EAMF,+BtBk9DF,2CsBh9DI,OAAA,KACA,QAAA,iCAAA,mCAGF,qCACE,cAAA,qBAGF,kCACE,WAAA,qBACA,qBAAA,EAAA,oBAAA,EAGF,0CACE,cAAA,4CACA,YAAA,mBAEA,6CACE,WAAA,8DACA,qBAAA,8CAAA,oBAAA,8CtBo9DN,0BACA,yBsB58DE,uBAGE,QAAA,KAGF,iBACE,QAAA,KACA,WAAA,8DACA,qBAAA,iFAAA,oBAAA,iFAKF,uBACE,iBAAA,oBAIJ,yBACE,WAAA,2BACA,cAAA,eC7MF,iBACE,OAAA,SAMA,yDACE,QAAA,aACA,MAAA,IACA,OAAA,IACA,OAAA,QAAA,MAAA,aACA,cAAA,IACA,mBAAA,YACA,QAAA,GACA,eAAA,YACA,eAAA,QACA,UAAA,QAAA,KAAA,OAAA,SACA,QAAA,+BAIA,qEACE,aAAA,0BACA,YAAA,EACA,qBAAA,EAAA,oBAAA,EACA,mBAAA,0BAAA,kBAAA,0BAIJ,uDACE,WAAA,OvB2pEJ,kBuBjpEE,uBvB+oEF,mCACA,kCAFA,mCuB7oEI,eAAA,KAKJ,mBACE,GACE,UAAA,gBCnDJ,eACE,SAAA,SAEA,mCACE,cAAA,IAAA,OACA,gBAAA,KACA,OAAA,KAGF,sBAAA,uBAAA,0CAAA,2CAIE,QAAA,MACA,QAAA,GACA,SAAA,SACA,OAAA,KACA,KAAA,IACA,QAAA,OAAA,MACA,SAAA,OACA,UAAA,wBACA,cAAA,qBACA,WAAA,gCACA,QAAA,mBACA,MAAA,qBACA,WAAA,OACA,YAAA,mBACA,UAAA,QACA,gBAAA,KACA,cAAA,SACA,YAAA,OACA,QAAA,EACA,eAAA,KAIF,sBAAA,0CAEE,QAAA,EACA,UAAA,kBACA,WAAA,MAAA,MACA,aAAA,MAAA,MAAA,YACA,YAAA,MAAA,MAAA,YACA,cAAA,EACA,iBAAA,YACA,QAAA,GACA,MAAA,gCAIA,6CAAA,8CAEE,IAAA,KACA,OAAA,KACA,UAAA,uBAGF,4CACE,UAAA,uBACA,OAAA,MAAA,MAAA,YACA,cAAA,MAAA,MAKF,2CAAA,4CAEE,IAAA,IACA,MAAA,KACA,OAAA,KACA,KAAA,KACA,UAAA,wBAGF,0CACE,UAAA,sBACA,OAAA,MAAA,MAAA,YACA,YAAA,MAAA,MAKF,4CAAA,6CAEE,IAAA,IACA,MAAA,KACA,OAAA,KACA,KAAA,KACA,UAAA,uBAGF,2CACE,UAAA,uBACA,OAAA,MAAA,MAAA,YACA,aAAA,MAAA,MAOF,4BAAA,6BAAA,4BAAA,6BAEE,QAAA,EAQF,wCAKI,4BAAA,6BAAA,mDAAA,oDAAA,wEAAA,yEAEE,mBAAA,IACA,eAAA,kBAGF,4BAAA,mDAAA,wEACE,eAAA,wBAOA,mDAAA,oDAAA,mDAAA,oDAEE,mBAAA,IACA,eAAA,qBAGF,mDAAA,mDACE,eAAA,2BAQF,iDAAA,kDAAA,iDAAA,kDAEE,mBAAA,IACA,eAAA,mBAGF,iDAAA,iDACE,eAAA,yBAQF,kDAAA,mDAAA,kDAAA,mDAEE,mBAAA,IACA,eAAA,oBAGF,kDAAA,kDACE,eAAA,2BAMR,6BACE,KACE,UAAA,uBACA,QAAA,EAEF,GACE,UAAA,wBACA,QAAA,GAIJ,mCACE,KACE,QAAA,EAEF,IACE,UAAA,wBACA,QAAA,EAEF,GACE,UAAA,kBACA,QAAA,GAIJ,gCACE,KACE,UAAA,wBACA,QAAA,EAEF,GACE,UAAA,uBACA,QAAA,GAIJ,sCACE,KACE,QAAA,EAEF,IACE,UAAA,uBACA,QAAA,EAEF,GACE,UAAA,uBACA,QAAA,GAIJ,8BACE,KACE,UAAA,uBACA,QAAA,EAEF,GACE,UAAA,wBACA,QAAA,GAIJ,oCACE,KACE,QAAA,EAEF,IACE,UAAA,uBACA,QAAA,EAEF,GACE,UAAA,sBACA,QAAA,GAIJ,+BACE,KACE,UAAA,wBACA,QAAA,EAEF,GACE,UAAA,uBACA,QAAA,GAIJ,qCACE,KACE,QAAA,EAEF,IACE,UAAA,wBACA,QAAA,EAEF,GACE,UAAA,uBACA,QAAA,GCrQR,gBACE,OAAA,QAIF,qBzB44EA,WyB14EE,OAAA,YAIF,4BACE,QAAA,QAGF,wCACE,KAAA,cACA,SAAA,SzBq5EF,WyBh5EA,EzBy4EA,KACA,OACA,MACA,MACA,OACA,QACA,SyBt4EE,iBAAA,aAMF,UACE,UAAA,ICrCA,uCACE,uB1Bk7EF,8BADA,+B0B96EI,sBAAA,kBACA,mBAAA,cACA,gBAAA,eACA,0BAAA,YACA,gBAAA,eACA,iBAAA,aACA,oBAAA","sourcesContent":["/*!\n * Pico CSS v1.5.10 (https://picocss.com)\n * Copyright 2019-2023 - Licensed under MIT\n */\n\n// Config\n@import \"variables\";\n\n// Theming\n@import \"themes/default\";\n\n// Layout\n@import \"layout/document\"; // html\n@import \"layout/sectioning\"; // body, header, main, footer\n@import \"layout/container\"; // .container, .container-fluid\n@import \"layout/section\"; // section\n@import \"layout/grid\"; // .grid\n@import \"layout/scroller\"; // figure\n\n// Content\n@import \"content/typography\"; // a, headings, p, ul, blockquote, ...\n@import \"content/embedded\"; // audio, canvas, iframe, img, svg, video\n@import \"content/button\"; // button, a[role=button], type=button, type=submit ...\n@import \"content/form\"; // input, select, textarea, label, fieldset, legend\n@import \"content/form-checkbox-radio\"; // type=checkbox, type=radio, role=switch\n@import \"content/form-alt-input-types\"; // type=color, type=date, type=file, type=search, ...\n@import \"content/table\"; // table, tr, td, ...\n@import \"content/code\"; // pre, code, ...\n@import \"content/miscs\"; // hr, template, [hidden], dialog, canvas\n\n// Components\n@import \"components/accordion\"; // details, summary\n@import \"components/card\"; // article\n@import \"components/modal\"; // dialog\n@import \"components/nav\"; // nav\n@import \"components/progress\"; // progress\n@import \"components/dropdown\"; // dropdown\n\n// Utilities\n@import \"utilities/loading\"; // aria-busy=true\n@import \"utilities/tooltip\"; // data-tooltip\n@import \"utilities/accessibility\"; // -ms-touch-action, aria-*\n@import \"utilities/reduce-motion\"; // prefers-reduced-motion\n","// Commons Styles\n:root {\n // Typography\n --font-family: system-ui, -apple-system, \"Segoe UI\", \"Roboto\", \"Ubuntu\",\n \"Cantarell\", \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\",\n \"Segoe UI Symbol\", \"Noto Color Emoji\";\n --line-height: 1.5;\n --font-weight: 400;\n --font-size: 16px;\n\n // Responsive typography\n @if $enable-responsive-typography {\n @if map-get($breakpoints, \"sm\") {\n @media (min-width: map-get($breakpoints, \"sm\")) {\n --font-size: 17px;\n }\n }\n\n @if map-get($breakpoints, \"md\") {\n @media (min-width: map-get($breakpoints, \"md\")) {\n --font-size: 18px;\n }\n }\n\n @if map-get($breakpoints, \"lg\") {\n @media (min-width: map-get($breakpoints, \"lg\")) {\n --font-size: 19px;\n }\n }\n\n @if map-get($breakpoints, \"xl\") {\n @media (min-width: map-get($breakpoints, \"xl\")) {\n --font-size: 20px;\n }\n }\n }\n\n // Borders\n --border-radius: 0.25rem;\n --border-width: 1px;\n --outline-width: 3px;\n\n // Spacings\n --spacing: 1rem;\n\n // Spacings for typography elements\n --typography-spacing-vertical: 1.5rem;\n\n // Spacings for body > header, body > main, body > footer, section, article\n --block-spacing-vertical: calc(var(--spacing) * 2);\n --block-spacing-horizontal: var(--spacing);\n\n @if ($enable-classes and $enable-grid) {\n --grid-spacing-vertical: 0;\n --grid-spacing-horizontal: var(--spacing);\n }\n\n // Spacings for form elements and button\n --form-element-spacing-vertical: 0.75rem;\n --form-element-spacing-horizontal: 1rem;\n\n // Spacings for nav component\n --nav-element-spacing-vertical: 1rem;\n --nav-element-spacing-horizontal: 0.5rem;\n --nav-link-spacing-vertical: 0.5rem;\n --nav-link-spacing-horizontal: 0.5rem;\n\n // Font weight for form labels & fieldsets legend\n --form-label-font-weight: var(--font-weight);\n\n // Transitions\n --transition: 0.2s ease-in-out;\n\n // Modal ()\n --modal-overlay-backdrop-filter: blur(0.25rem);\n}\n\n// Responsives spacings\n@if $enable-responsive-spacings {\n // Sectioning\n #{$semantic-root-element} > header,\n #{$semantic-root-element} > main,\n #{$semantic-root-element} > footer,\n section {\n @if map-get($breakpoints, \"sm\") {\n @media (min-width: map-get($breakpoints, \"sm\")) {\n --block-spacing-vertical: calc(var(--spacing) * 2.5);\n }\n }\n\n @if map-get($breakpoints, \"md\") {\n @media (min-width: map-get($breakpoints, \"md\")) {\n --block-spacing-vertical: calc(var(--spacing) * 3);\n }\n }\n\n @if map-get($breakpoints, \"lg\") {\n @media (min-width: map-get($breakpoints, \"lg\")) {\n --block-spacing-vertical: calc(var(--spacing) * 3.5);\n }\n }\n\n @if map-get($breakpoints, \"xl\") {\n @media (min-width: map-get($breakpoints, \"xl\")) {\n --block-spacing-vertical: calc(var(--spacing) * 4);\n }\n }\n }\n\n // Card (
    )\n article {\n @if map-get($breakpoints, \"sm\") {\n @media (min-width: map-get($breakpoints, \"sm\")) {\n --block-spacing-horizontal: calc(var(--spacing) * 1.25);\n }\n }\n\n @if map-get($breakpoints, \"md\") {\n @media (min-width: map-get($breakpoints, \"md\")) {\n --block-spacing-horizontal: calc(var(--spacing) * 1.5);\n }\n }\n\n @if map-get($breakpoints, \"lg\") {\n @media (min-width: map-get($breakpoints, \"lg\")) {\n --block-spacing-horizontal: calc(var(--spacing) * 1.75);\n }\n }\n\n @if map-get($breakpoints, \"xl\") {\n @media (min-width: map-get($breakpoints, \"xl\")) {\n --block-spacing-horizontal: calc(var(--spacing) * 2);\n }\n }\n }\n\n // Modal\n dialog > article {\n\n --block-spacing-vertical: calc(var(--spacing) * 2);\n --block-spacing-horizontal: var(--spacing);\n\n @if map-get($breakpoints, \"sm\") {\n @media (min-width: map-get($breakpoints, \"sm\")) {\n --block-spacing-vertical: calc(var(--spacing) * 2.5);\n --block-spacing-horizontal: calc(var(--spacing) * 1.25);\n }\n }\n\n @if map-get($breakpoints, \"md\") {\n @media (min-width: map-get($breakpoints, \"md\")) {\n --block-spacing-vertical: calc(var(--spacing) * 3);\n --block-spacing-horizontal: calc(var(--spacing) * 1.5);\n }\n }\n }\n}\n\n// Link\na {\n --text-decoration: none;\n\n // Secondary & Contrast\n @if $enable-classes {\n &.secondary,\n &.contrast {\n --text-decoration: underline;\n }\n }\n}\n\n// Small\nsmall {\n --font-size: 0.875em;\n}\n\n// Headings\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n --font-weight: 700;\n}\n\nh1 {\n --font-size: 2rem;\n --typography-spacing-vertical: 3rem;\n}\n\nh2 {\n --font-size: 1.75rem;\n --typography-spacing-vertical: 2.625rem;\n}\n\nh3 {\n --font-size: 1.5rem;\n --typography-spacing-vertical: 2.25rem;\n}\n\nh4 {\n --font-size: 1.25rem;\n --typography-spacing-vertical: 1.874rem;\n}\n\nh5 {\n --font-size: 1.125rem;\n --typography-spacing-vertical: 1.6875rem;\n}\n\n// Forms elements\n[type=\"checkbox\"],\n[type=\"radio\"] {\n --border-width: 2px;\n}\n\n[type=\"checkbox\"][role=\"switch\"] {\n --border-width: 3px;\n}\n\n// Table\nthead,\ntfoot {\n th,\n td {\n --border-width: 3px;\n }\n}\n\n:not(thead, tfoot) > * > td {\n --font-size: 0.875em;\n}\n\n// Code\npre,\ncode,\nkbd,\nsamp {\n --font-family: \"Menlo\", \"Consolas\", \"Roboto Mono\", \"Ubuntu Monospace\",\n \"Noto Mono\", \"Oxygen Mono\", \"Liberation Mono\", monospace,\n \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n}\n\nkbd {\n --font-weight: bolder;\n}\n","@charset \"UTF-8\";\n/*!\n * Pico CSS v1.5.10 (https://picocss.com)\n * Copyright 2019-2023 - Licensed under MIT\n */\n/**\n * Theme: default\n */\n:root {\n --font-family: system-ui, -apple-system, \"Segoe UI\", \"Roboto\", \"Ubuntu\",\n \"Cantarell\", \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\",\n \"Segoe UI Symbol\", \"Noto Color Emoji\";\n --line-height: 1.5;\n --font-weight: 400;\n --font-size: 16px;\n --border-radius: 0.25rem;\n --border-width: 1px;\n --outline-width: 3px;\n --spacing: 1rem;\n --typography-spacing-vertical: 1.5rem;\n --block-spacing-vertical: calc(var(--spacing) * 2);\n --block-spacing-horizontal: var(--spacing);\n --form-element-spacing-vertical: 0.75rem;\n --form-element-spacing-horizontal: 1rem;\n --nav-element-spacing-vertical: 1rem;\n --nav-element-spacing-horizontal: 0.5rem;\n --nav-link-spacing-vertical: 0.5rem;\n --nav-link-spacing-horizontal: 0.5rem;\n --form-label-font-weight: var(--font-weight);\n --transition: 0.2s ease-in-out;\n --modal-overlay-backdrop-filter: blur(0.25rem);\n}\n@media (min-width: 576px) {\n :root {\n --font-size: 17px;\n }\n}\n@media (min-width: 768px) {\n :root {\n --font-size: 18px;\n }\n}\n@media (min-width: 992px) {\n :root {\n --font-size: 19px;\n }\n}\n@media (min-width: 1200px) {\n :root {\n --font-size: 20px;\n }\n}\n\n@media (min-width: 576px) {\n body > header,\n body > main,\n body > footer,\n section {\n --block-spacing-vertical: calc(var(--spacing) * 2.5);\n }\n}\n@media (min-width: 768px) {\n body > header,\n body > main,\n body > footer,\n section {\n --block-spacing-vertical: calc(var(--spacing) * 3);\n }\n}\n@media (min-width: 992px) {\n body > header,\n body > main,\n body > footer,\n section {\n --block-spacing-vertical: calc(var(--spacing) * 3.5);\n }\n}\n@media (min-width: 1200px) {\n body > header,\n body > main,\n body > footer,\n section {\n --block-spacing-vertical: calc(var(--spacing) * 4);\n }\n}\n\n@media (min-width: 576px) {\n article {\n --block-spacing-horizontal: calc(var(--spacing) * 1.25);\n }\n}\n@media (min-width: 768px) {\n article {\n --block-spacing-horizontal: calc(var(--spacing) * 1.5);\n }\n}\n@media (min-width: 992px) {\n article {\n --block-spacing-horizontal: calc(var(--spacing) * 1.75);\n }\n}\n@media (min-width: 1200px) {\n article {\n --block-spacing-horizontal: calc(var(--spacing) * 2);\n }\n}\n\ndialog > article {\n --block-spacing-vertical: calc(var(--spacing) * 2);\n --block-spacing-horizontal: var(--spacing);\n}\n@media (min-width: 576px) {\n dialog > article {\n --block-spacing-vertical: calc(var(--spacing) * 2.5);\n --block-spacing-horizontal: calc(var(--spacing) * 1.25);\n }\n}\n@media (min-width: 768px) {\n dialog > article {\n --block-spacing-vertical: calc(var(--spacing) * 3);\n --block-spacing-horizontal: calc(var(--spacing) * 1.5);\n }\n}\n\na {\n --text-decoration: none;\n}\n\nsmall {\n --font-size: 0.875em;\n}\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n --font-weight: 700;\n}\n\nh1 {\n --font-size: 2rem;\n --typography-spacing-vertical: 3rem;\n}\n\nh2 {\n --font-size: 1.75rem;\n --typography-spacing-vertical: 2.625rem;\n}\n\nh3 {\n --font-size: 1.5rem;\n --typography-spacing-vertical: 2.25rem;\n}\n\nh4 {\n --font-size: 1.25rem;\n --typography-spacing-vertical: 1.874rem;\n}\n\nh5 {\n --font-size: 1.125rem;\n --typography-spacing-vertical: 1.6875rem;\n}\n\n[type=checkbox],\n[type=radio] {\n --border-width: 2px;\n}\n\n[type=checkbox][role=switch] {\n --border-width: 3px;\n}\n\nthead th,\nthead td,\ntfoot th,\ntfoot td {\n --border-width: 3px;\n}\n\n:not(thead, tfoot) > * > td {\n --font-size: 0.875em;\n}\n\npre,\ncode,\nkbd,\nsamp {\n --font-family: \"Menlo\", \"Consolas\", \"Roboto Mono\", \"Ubuntu Monospace\",\n \"Noto Mono\", \"Oxygen Mono\", \"Liberation Mono\", monospace,\n \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n}\n\nkbd {\n --font-weight: bolder;\n}\n\n[data-theme=light],\n:root:not([data-theme=dark]) {\n --background-color: #fff;\n --color: hsl(205, 20%, 32%);\n --h1-color: hsl(205, 30%, 15%);\n --h2-color: #24333e;\n --h3-color: hsl(205, 25%, 23%);\n --h4-color: #374956;\n --h5-color: hsl(205, 20%, 32%);\n --h6-color: #4d606d;\n --muted-color: hsl(205, 10%, 50%);\n --muted-border-color: hsl(205, 20%, 94%);\n --primary: hsl(195, 85%, 41%);\n --primary-hover: hsl(195, 90%, 32%);\n --primary-focus: rgba(16, 149, 193, 0.125);\n --primary-inverse: #fff;\n --secondary: hsl(205, 15%, 41%);\n --secondary-hover: hsl(205, 20%, 32%);\n --secondary-focus: rgba(89, 107, 120, 0.125);\n --secondary-inverse: #fff;\n --contrast: hsl(205, 30%, 15%);\n --contrast-hover: #000;\n --contrast-focus: rgba(89, 107, 120, 0.125);\n --contrast-inverse: #fff;\n --mark-background-color: #fff2ca;\n --mark-color: #543a26;\n --ins-color: #388e3c;\n --del-color: #c62828;\n --blockquote-border-color: var(--muted-border-color);\n --blockquote-footer-color: var(--muted-color);\n --button-box-shadow: 0 0 0 rgba(0, 0, 0, 0);\n --button-hover-box-shadow: 0 0 0 rgba(0, 0, 0, 0);\n --form-element-background-color: transparent;\n --form-element-border-color: hsl(205, 14%, 68%);\n --form-element-color: var(--color);\n --form-element-placeholder-color: var(--muted-color);\n --form-element-active-background-color: transparent;\n --form-element-active-border-color: var(--primary);\n --form-element-focus-color: var(--primary-focus);\n --form-element-disabled-background-color: hsl(205, 18%, 86%);\n --form-element-disabled-border-color: hsl(205, 14%, 68%);\n --form-element-disabled-opacity: 0.5;\n --form-element-invalid-border-color: #c62828;\n --form-element-invalid-active-border-color: #d32f2f;\n --form-element-invalid-focus-color: rgba(211, 47, 47, 0.125);\n --form-element-valid-border-color: #388e3c;\n --form-element-valid-active-border-color: #43a047;\n --form-element-valid-focus-color: rgba(67, 160, 71, 0.125);\n --switch-background-color: hsl(205, 16%, 77%);\n --switch-color: var(--primary-inverse);\n --switch-checked-background-color: var(--primary);\n --range-border-color: hsl(205, 18%, 86%);\n --range-active-border-color: hsl(205, 16%, 77%);\n --range-thumb-border-color: var(--background-color);\n --range-thumb-color: var(--secondary);\n --range-thumb-hover-color: var(--secondary-hover);\n --range-thumb-active-color: var(--primary);\n --table-border-color: var(--muted-border-color);\n --table-row-stripped-background-color: #f6f8f9;\n --code-background-color: hsl(205, 20%, 94%);\n --code-color: var(--muted-color);\n --code-kbd-background-color: var(--contrast);\n --code-kbd-color: var(--contrast-inverse);\n --code-tag-color: hsl(330, 40%, 50%);\n --code-property-color: hsl(185, 40%, 40%);\n --code-value-color: hsl(40, 20%, 50%);\n --code-comment-color: hsl(205, 14%, 68%);\n --accordion-border-color: var(--muted-border-color);\n --accordion-close-summary-color: var(--color);\n --accordion-open-summary-color: var(--muted-color);\n --card-background-color: var(--background-color);\n --card-border-color: var(--muted-border-color);\n --card-box-shadow:\n 0.0145rem 0.029rem 0.174rem rgba(27, 40, 50, 0.01698),\n 0.0335rem 0.067rem 0.402rem rgba(27, 40, 50, 0.024),\n 0.0625rem 0.125rem 0.75rem rgba(27, 40, 50, 0.03),\n 0.1125rem 0.225rem 1.35rem rgba(27, 40, 50, 0.036),\n 0.2085rem 0.417rem 2.502rem rgba(27, 40, 50, 0.04302),\n 0.5rem 1rem 6rem rgba(27, 40, 50, 0.06),\n 0 0 0 0.0625rem rgba(27, 40, 50, 0.015);\n --card-sectionning-background-color: #fbfbfc;\n --dropdown-background-color: #fbfbfc;\n --dropdown-border-color: #e1e6eb;\n --dropdown-box-shadow: var(--card-box-shadow);\n --dropdown-color: var(--color);\n --dropdown-hover-background-color: hsl(205, 20%, 94%);\n --modal-overlay-background-color: rgba(213, 220, 226, 0.7);\n --progress-background-color: hsl(205, 18%, 86%);\n --progress-color: var(--primary);\n --loading-spinner-opacity: 0.5;\n --tooltip-background-color: var(--contrast);\n --tooltip-color: var(--contrast-inverse);\n --icon-checkbox: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-chevron: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(65, 84, 98)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-chevron-button: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-chevron-button-inverse: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-close: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(115, 130, 140)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E\");\n --icon-date: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(65, 84, 98)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E\");\n --icon-invalid: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(198, 40, 40)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E\");\n --icon-minus: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E\");\n --icon-search: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(65, 84, 98)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E\");\n --icon-time: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(65, 84, 98)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-valid: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(56, 142, 60)' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E\");\n color-scheme: light;\n}\n\n@media only screen and (prefers-color-scheme: dark) {\n :root:not([data-theme]) {\n --background-color: #11191f;\n --color: hsl(205, 16%, 77%);\n --h1-color: hsl(205, 20%, 94%);\n --h2-color: #e1e6eb;\n --h3-color: hsl(205, 18%, 86%);\n --h4-color: #c8d1d8;\n --h5-color: hsl(205, 16%, 77%);\n --h6-color: #afbbc4;\n --muted-color: hsl(205, 10%, 50%);\n --muted-border-color: #1f2d38;\n --primary: hsl(195, 85%, 41%);\n --primary-hover: hsl(195, 80%, 50%);\n --primary-focus: rgba(16, 149, 193, 0.25);\n --primary-inverse: #fff;\n --secondary: hsl(205, 15%, 41%);\n --secondary-hover: hsl(205, 10%, 50%);\n --secondary-focus: rgba(115, 130, 140, 0.25);\n --secondary-inverse: #fff;\n --contrast: hsl(205, 20%, 94%);\n --contrast-hover: #fff;\n --contrast-focus: rgba(115, 130, 140, 0.25);\n --contrast-inverse: #000;\n --mark-background-color: #d1c284;\n --mark-color: #11191f;\n --ins-color: #388e3c;\n --del-color: #c62828;\n --blockquote-border-color: var(--muted-border-color);\n --blockquote-footer-color: var(--muted-color);\n --button-box-shadow: 0 0 0 rgba(0, 0, 0, 0);\n --button-hover-box-shadow: 0 0 0 rgba(0, 0, 0, 0);\n --form-element-background-color: #11191f;\n --form-element-border-color: #374956;\n --form-element-color: var(--color);\n --form-element-placeholder-color: var(--muted-color);\n --form-element-active-background-color: var(--form-element-background-color);\n --form-element-active-border-color: var(--primary);\n --form-element-focus-color: var(--primary-focus);\n --form-element-disabled-background-color: hsl(205, 25%, 23%);\n --form-element-disabled-border-color: hsl(205, 20%, 32%);\n --form-element-disabled-opacity: 0.5;\n --form-element-invalid-border-color: #b71c1c;\n --form-element-invalid-active-border-color: #c62828;\n --form-element-invalid-focus-color: rgba(198, 40, 40, 0.25);\n --form-element-valid-border-color: #2e7d32;\n --form-element-valid-active-border-color: #388e3c;\n --form-element-valid-focus-color: rgba(56, 142, 60, 0.25);\n --switch-background-color: #374956;\n --switch-color: var(--primary-inverse);\n --switch-checked-background-color: var(--primary);\n --range-border-color: #24333e;\n --range-active-border-color: hsl(205, 25%, 23%);\n --range-thumb-border-color: var(--background-color);\n --range-thumb-color: var(--secondary);\n --range-thumb-hover-color: var(--secondary-hover);\n --range-thumb-active-color: var(--primary);\n --table-border-color: var(--muted-border-color);\n --table-row-stripped-background-color: rgba(115, 130, 140, 0.05);\n --code-background-color: #18232c;\n --code-color: var(--muted-color);\n --code-kbd-background-color: var(--contrast);\n --code-kbd-color: var(--contrast-inverse);\n --code-tag-color: hsl(330, 30%, 50%);\n --code-property-color: hsl(185, 30%, 50%);\n --code-value-color: hsl(40, 10%, 50%);\n --code-comment-color: #4d606d;\n --accordion-border-color: var(--muted-border-color);\n --accordion-active-summary-color: var(--primary);\n --accordion-close-summary-color: var(--color);\n --accordion-open-summary-color: var(--muted-color);\n --card-background-color: #141e26;\n --card-border-color: var(--card-background-color);\n --card-box-shadow:\n 0.0145rem 0.029rem 0.174rem rgba(0, 0, 0, 0.01698),\n 0.0335rem 0.067rem 0.402rem rgba(0, 0, 0, 0.024),\n 0.0625rem 0.125rem 0.75rem rgba(0, 0, 0, 0.03),\n 0.1125rem 0.225rem 1.35rem rgba(0, 0, 0, 0.036),\n 0.2085rem 0.417rem 2.502rem rgba(0, 0, 0, 0.04302),\n 0.5rem 1rem 6rem rgba(0, 0, 0, 0.06),\n 0 0 0 0.0625rem rgba(0, 0, 0, 0.015);\n --card-sectionning-background-color: #18232c;\n --dropdown-background-color: hsl(205, 30%, 15%);\n --dropdown-border-color: #24333e;\n --dropdown-box-shadow: var(--card-box-shadow);\n --dropdown-color: var(--color);\n --dropdown-hover-background-color: rgba(36, 51, 62, 0.75);\n --modal-overlay-background-color: rgba(36, 51, 62, 0.8);\n --progress-background-color: #24333e;\n --progress-color: var(--primary);\n --loading-spinner-opacity: 0.5;\n --tooltip-background-color: var(--contrast);\n --tooltip-color: var(--contrast-inverse);\n --icon-checkbox: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-chevron: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-chevron-button: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-chevron-button-inverse: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(0, 0, 0)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-close: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(115, 130, 140)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E\");\n --icon-date: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E\");\n --icon-invalid: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(183, 28, 28)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E\");\n --icon-minus: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E\");\n --icon-search: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E\");\n --icon-time: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-valid: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(46, 125, 50)' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E\");\n color-scheme: dark;\n }\n}\n[data-theme=dark] {\n --background-color: #11191f;\n --color: hsl(205, 16%, 77%);\n --h1-color: hsl(205, 20%, 94%);\n --h2-color: #e1e6eb;\n --h3-color: hsl(205, 18%, 86%);\n --h4-color: #c8d1d8;\n --h5-color: hsl(205, 16%, 77%);\n --h6-color: #afbbc4;\n --muted-color: hsl(205, 10%, 50%);\n --muted-border-color: #1f2d38;\n --primary: hsl(195, 85%, 41%);\n --primary-hover: hsl(195, 80%, 50%);\n --primary-focus: rgba(16, 149, 193, 0.25);\n --primary-inverse: #fff;\n --secondary: hsl(205, 15%, 41%);\n --secondary-hover: hsl(205, 10%, 50%);\n --secondary-focus: rgba(115, 130, 140, 0.25);\n --secondary-inverse: #fff;\n --contrast: hsl(205, 20%, 94%);\n --contrast-hover: #fff;\n --contrast-focus: rgba(115, 130, 140, 0.25);\n --contrast-inverse: #000;\n --mark-background-color: #d1c284;\n --mark-color: #11191f;\n --ins-color: #388e3c;\n --del-color: #c62828;\n --blockquote-border-color: var(--muted-border-color);\n --blockquote-footer-color: var(--muted-color);\n --button-box-shadow: 0 0 0 rgba(0, 0, 0, 0);\n --button-hover-box-shadow: 0 0 0 rgba(0, 0, 0, 0);\n --form-element-background-color: #11191f;\n --form-element-border-color: #374956;\n --form-element-color: var(--color);\n --form-element-placeholder-color: var(--muted-color);\n --form-element-active-background-color: var(--form-element-background-color);\n --form-element-active-border-color: var(--primary);\n --form-element-focus-color: var(--primary-focus);\n --form-element-disabled-background-color: hsl(205, 25%, 23%);\n --form-element-disabled-border-color: hsl(205, 20%, 32%);\n --form-element-disabled-opacity: 0.5;\n --form-element-invalid-border-color: #b71c1c;\n --form-element-invalid-active-border-color: #c62828;\n --form-element-invalid-focus-color: rgba(198, 40, 40, 0.25);\n --form-element-valid-border-color: #2e7d32;\n --form-element-valid-active-border-color: #388e3c;\n --form-element-valid-focus-color: rgba(56, 142, 60, 0.25);\n --switch-background-color: #374956;\n --switch-color: var(--primary-inverse);\n --switch-checked-background-color: var(--primary);\n --range-border-color: #24333e;\n --range-active-border-color: hsl(205, 25%, 23%);\n --range-thumb-border-color: var(--background-color);\n --range-thumb-color: var(--secondary);\n --range-thumb-hover-color: var(--secondary-hover);\n --range-thumb-active-color: var(--primary);\n --table-border-color: var(--muted-border-color);\n --table-row-stripped-background-color: rgba(115, 130, 140, 0.05);\n --code-background-color: #18232c;\n --code-color: var(--muted-color);\n --code-kbd-background-color: var(--contrast);\n --code-kbd-color: var(--contrast-inverse);\n --code-tag-color: hsl(330, 30%, 50%);\n --code-property-color: hsl(185, 30%, 50%);\n --code-value-color: hsl(40, 10%, 50%);\n --code-comment-color: #4d606d;\n --accordion-border-color: var(--muted-border-color);\n --accordion-active-summary-color: var(--primary);\n --accordion-close-summary-color: var(--color);\n --accordion-open-summary-color: var(--muted-color);\n --card-background-color: #141e26;\n --card-border-color: var(--card-background-color);\n --card-box-shadow:\n 0.0145rem 0.029rem 0.174rem rgba(0, 0, 0, 0.01698),\n 0.0335rem 0.067rem 0.402rem rgba(0, 0, 0, 0.024),\n 0.0625rem 0.125rem 0.75rem rgba(0, 0, 0, 0.03),\n 0.1125rem 0.225rem 1.35rem rgba(0, 0, 0, 0.036),\n 0.2085rem 0.417rem 2.502rem rgba(0, 0, 0, 0.04302),\n 0.5rem 1rem 6rem rgba(0, 0, 0, 0.06),\n 0 0 0 0.0625rem rgba(0, 0, 0, 0.015);\n --card-sectionning-background-color: #18232c;\n --dropdown-background-color: hsl(205, 30%, 15%);\n --dropdown-border-color: #24333e;\n --dropdown-box-shadow: var(--card-box-shadow);\n --dropdown-color: var(--color);\n --dropdown-hover-background-color: rgba(36, 51, 62, 0.75);\n --modal-overlay-background-color: rgba(36, 51, 62, 0.8);\n --progress-background-color: #24333e;\n --progress-color: var(--primary);\n --loading-spinner-opacity: 0.5;\n --tooltip-background-color: var(--contrast);\n --tooltip-color: var(--contrast-inverse);\n --icon-checkbox: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-chevron: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-chevron-button: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-chevron-button-inverse: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(0, 0, 0)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-close: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(115, 130, 140)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E\");\n --icon-date: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E\");\n --icon-invalid: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(183, 28, 28)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E\");\n --icon-minus: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E\");\n --icon-search: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E\");\n --icon-time: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(162, 175, 185)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-valid: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(46, 125, 50)' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E\");\n color-scheme: dark;\n}\n\nprogress,\n[type=checkbox],\n[type=radio],\n[type=range] {\n accent-color: var(--primary);\n}\n\n/**\n * Document\n * Content-box & Responsive typography\n */\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n background-repeat: no-repeat;\n}\n\n::before,\n::after {\n text-decoration: inherit;\n vertical-align: inherit;\n}\n\n:where(:root) {\n -webkit-tap-highlight-color: transparent;\n -webkit-text-size-adjust: 100%;\n text-size-adjust: 100%;\n background-color: var(--background-color);\n color: var(--color);\n font-weight: var(--font-weight);\n font-size: var(--font-size);\n line-height: var(--line-height);\n font-family: var(--font-family);\n text-rendering: optimizeLegibility;\n overflow-wrap: break-word;\n cursor: default;\n tab-size: 4;\n}\n\n/**\n * Sectioning\n * Container and responsive spacings for header, main, footer\n */\nmain {\n display: block;\n}\n\nbody {\n width: 100%;\n margin: 0;\n}\nbody > header,\nbody > main,\nbody > footer {\n width: 100%;\n margin-right: auto;\n margin-left: auto;\n padding: var(--block-spacing-vertical) var(--block-spacing-horizontal);\n}\n@media (min-width: 576px) {\n body > header,\n body > main,\n body > footer {\n max-width: 510px;\n padding-right: 0;\n padding-left: 0;\n }\n}\n@media (min-width: 768px) {\n body > header,\n body > main,\n body > footer {\n max-width: 700px;\n }\n}\n@media (min-width: 992px) {\n body > header,\n body > main,\n body > footer {\n max-width: 920px;\n }\n}\n@media (min-width: 1200px) {\n body > header,\n body > main,\n body > footer {\n max-width: 1130px;\n }\n}\n\n/**\n * Section\n * Responsive spacings for section\n */\nsection {\n margin-bottom: var(--block-spacing-vertical);\n}\n\n/**\n * Horizontal scroller (
    )\n */\nfigure {\n display: block;\n margin: 0;\n padding: 0;\n overflow-x: auto;\n}\nfigure figcaption {\n padding: calc(var(--spacing) * 0.5) 0;\n color: var(--muted-color);\n}\n\n/**\n * Typography\n */\nb,\nstrong {\n font-weight: bolder;\n}\n\nsub,\nsup {\n position: relative;\n font-size: 0.75em;\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -0.25em;\n}\n\nsup {\n top: -0.5em;\n}\n\naddress,\nblockquote,\ndl,\nfigure,\nform,\nol,\np,\npre,\ntable,\nul {\n margin-top: 0;\n margin-bottom: var(--typography-spacing-vertical);\n color: var(--color);\n font-style: normal;\n font-weight: var(--font-weight);\n font-size: var(--font-size);\n}\n\na,\n[role=link] {\n --color: var(--primary);\n --background-color: transparent;\n outline: none;\n background-color: var(--background-color);\n color: var(--color);\n text-decoration: var(--text-decoration);\n transition: background-color var(--transition), color var(--transition), text-decoration var(--transition), box-shadow var(--transition);\n}\na:is([aria-current], :hover, :active, :focus),\n[role=link]:is([aria-current], :hover, :active, :focus) {\n --color: var(--primary-hover);\n --text-decoration: underline;\n}\na:focus,\n[role=link]:focus {\n --background-color: var(--primary-focus);\n}\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n margin-top: 0;\n margin-bottom: var(--typography-spacing-vertical);\n color: var(--color);\n font-weight: var(--font-weight);\n font-size: var(--font-size);\n font-family: var(--font-family);\n}\n\nh1 {\n --color: var(--h1-color);\n}\n\nh2 {\n --color: var(--h2-color);\n}\n\nh3 {\n --color: var(--h3-color);\n}\n\nh4 {\n --color: var(--h4-color);\n}\n\nh5 {\n --color: var(--h5-color);\n}\n\nh6 {\n --color: var(--h6-color);\n}\n\n:where(address, blockquote, dl, figure, form, ol, p, pre, table, ul) ~ :is(h1, h2, h3, h4, h5, h6) {\n margin-top: var(--typography-spacing-vertical);\n}\n\nhgroup {\n margin-bottom: var(--typography-spacing-vertical);\n}\nhgroup > * {\n margin-bottom: 0;\n}\nhgroup > *:last-child {\n --color: var(--muted-color);\n --font-weight: unset;\n font-size: 1rem;\n font-family: unset;\n}\n\np {\n margin-bottom: var(--typography-spacing-vertical);\n}\n\nsmall {\n font-size: var(--font-size);\n}\n\n:where(dl, ol, ul) {\n padding-right: 0;\n padding-left: var(--spacing);\n padding-inline-start: var(--spacing);\n padding-inline-end: 0;\n}\n:where(dl, ol, ul) li {\n margin-bottom: calc(var(--typography-spacing-vertical) * 0.25);\n}\n\n:where(dl, ol, ul) :is(dl, ol, ul) {\n margin: 0;\n margin-top: calc(var(--typography-spacing-vertical) * 0.25);\n}\n\nul li {\n list-style: square;\n}\n\nmark {\n padding: 0.125rem 0.25rem;\n background-color: var(--mark-background-color);\n color: var(--mark-color);\n vertical-align: baseline;\n}\n\nblockquote {\n display: block;\n margin: var(--typography-spacing-vertical) 0;\n padding: var(--spacing);\n border-right: none;\n border-left: 0.25rem solid var(--blockquote-border-color);\n border-inline-start: 0.25rem solid var(--blockquote-border-color);\n border-inline-end: none;\n}\nblockquote footer {\n margin-top: calc(var(--typography-spacing-vertical) * 0.5);\n color: var(--blockquote-footer-color);\n}\n\nabbr[title] {\n border-bottom: 1px dotted;\n text-decoration: none;\n cursor: help;\n}\n\nins {\n color: var(--ins-color);\n text-decoration: none;\n}\n\ndel {\n color: var(--del-color);\n}\n\n::selection {\n background-color: var(--primary-focus);\n}\n\n/**\n * Embedded content\n */\n:where(audio, canvas, iframe, img, svg, video) {\n vertical-align: middle;\n}\n\naudio,\nvideo {\n display: inline-block;\n}\n\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n\n:where(iframe) {\n border-style: none;\n}\n\nimg {\n max-width: 100%;\n height: auto;\n border-style: none;\n}\n\n:where(svg:not([fill])) {\n fill: currentColor;\n}\n\nsvg:not(:root) {\n overflow: hidden;\n}\n\n/**\n * Button\n */\nbutton {\n margin: 0;\n overflow: visible;\n font-family: inherit;\n text-transform: none;\n}\n\nbutton,\n[type=button],\n[type=reset],\n[type=submit] {\n -webkit-appearance: button;\n}\n\nbutton {\n display: block;\n width: 100%;\n margin-bottom: var(--spacing);\n}\n\n[role=button] {\n display: inline-block;\n text-decoration: none;\n}\n\nbutton,\ninput[type=submit],\ninput[type=button],\ninput[type=reset],\n[role=button] {\n --background-color: var(--primary);\n --border-color: var(--primary);\n --color: var(--primary-inverse);\n --box-shadow: var(--button-box-shadow, 0 0 0 rgba(0, 0, 0, 0));\n padding: var(--form-element-spacing-vertical) var(--form-element-spacing-horizontal);\n border: var(--border-width) solid var(--border-color);\n border-radius: var(--border-radius);\n outline: none;\n background-color: var(--background-color);\n box-shadow: var(--box-shadow);\n color: var(--color);\n font-weight: var(--font-weight);\n font-size: 1rem;\n line-height: var(--line-height);\n text-align: center;\n cursor: pointer;\n transition: background-color var(--transition), border-color var(--transition), color var(--transition), box-shadow var(--transition);\n}\nbutton:is([aria-current], :hover, :active, :focus),\ninput[type=submit]:is([aria-current], :hover, :active, :focus),\ninput[type=button]:is([aria-current], :hover, :active, :focus),\ninput[type=reset]:is([aria-current], :hover, :active, :focus),\n[role=button]:is([aria-current], :hover, :active, :focus) {\n --background-color: var(--primary-hover);\n --border-color: var(--primary-hover);\n --box-shadow: var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0));\n --color: var(--primary-inverse);\n}\nbutton:focus,\ninput[type=submit]:focus,\ninput[type=button]:focus,\ninput[type=reset]:focus,\n[role=button]:focus {\n --box-shadow: var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),\n 0 0 0 var(--outline-width) var(--primary-focus);\n}\n\ninput[type=reset] {\n --background-color: var(--secondary);\n --border-color: var(--secondary);\n --color: var(--secondary-inverse);\n cursor: pointer;\n}\ninput[type=reset]:is([aria-current], :hover, :active, :focus) {\n --background-color: var(--secondary-hover);\n --border-color: var(--secondary-hover);\n}\ninput[type=reset]:focus {\n --box-shadow: var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),\n 0 0 0 var(--outline-width) var(--secondary-focus);\n}\n\n:where(button, [type=submit], [type=button], [type=reset], [role=button])[disabled],\n:where(fieldset[disabled]) :is(button, [type=submit], [type=button], [type=reset], [role=button]),\na[role=button]:not([href]) {\n opacity: 0.5;\n pointer-events: none;\n}\n\n/**\n * Form elements\n */\ninput,\noptgroup,\nselect,\ntextarea {\n margin: 0;\n font-size: 1rem;\n line-height: var(--line-height);\n font-family: inherit;\n letter-spacing: inherit;\n}\n\ninput {\n overflow: visible;\n}\n\nselect {\n text-transform: none;\n}\n\nlegend {\n max-width: 100%;\n padding: 0;\n color: inherit;\n white-space: normal;\n}\n\ntextarea {\n overflow: auto;\n}\n\n[type=checkbox],\n[type=radio] {\n padding: 0;\n}\n\n::-webkit-inner-spin-button,\n::-webkit-outer-spin-button {\n height: auto;\n}\n\n[type=search] {\n -webkit-appearance: textfield;\n outline-offset: -2px;\n}\n\n[type=search]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n::-webkit-file-upload-button {\n -webkit-appearance: button;\n font: inherit;\n}\n\n::-moz-focus-inner {\n padding: 0;\n border-style: none;\n}\n\n:-moz-focusring {\n outline: none;\n}\n\n:-moz-ui-invalid {\n box-shadow: none;\n}\n\n::-ms-expand {\n display: none;\n}\n\n[type=file],\n[type=range] {\n padding: 0;\n border-width: 0;\n}\n\ninput:not([type=checkbox], [type=radio], [type=range]) {\n height: calc(1rem * var(--line-height) + var(--form-element-spacing-vertical) * 2 + var(--border-width) * 2);\n}\n\nfieldset {\n margin: 0;\n margin-bottom: var(--spacing);\n padding: 0;\n border: 0;\n}\n\nlabel,\nfieldset legend {\n display: block;\n margin-bottom: calc(var(--spacing) * 0.25);\n font-weight: var(--form-label-font-weight, var(--font-weight));\n}\n\ninput:not([type=checkbox], [type=radio]),\nselect,\ntextarea {\n width: 100%;\n}\n\ninput:not([type=checkbox], [type=radio], [type=range], [type=file]),\nselect,\ntextarea {\n appearance: none;\n padding: var(--form-element-spacing-vertical) var(--form-element-spacing-horizontal);\n}\n\ninput,\nselect,\ntextarea {\n --background-color: var(--form-element-background-color);\n --border-color: var(--form-element-border-color);\n --color: var(--form-element-color);\n --box-shadow: none;\n border: var(--border-width) solid var(--border-color);\n border-radius: var(--border-radius);\n outline: none;\n background-color: var(--background-color);\n box-shadow: var(--box-shadow);\n color: var(--color);\n font-weight: var(--font-weight);\n transition: background-color var(--transition), border-color var(--transition), color var(--transition), box-shadow var(--transition);\n}\n\ninput:not([type=submit], [type=button], [type=reset], [type=checkbox], [type=radio], [readonly]):is(:active, :focus),\n:where(select, textarea):is(:active, :focus) {\n --background-color: var(--form-element-active-background-color);\n}\n\ninput:not([type=submit], [type=button], [type=reset], [role=switch], [readonly]):is(:active, :focus),\n:where(select, textarea):is(:active, :focus) {\n --border-color: var(--form-element-active-border-color);\n}\n\ninput:not([type=submit], [type=button], [type=reset], [type=range], [type=file], [readonly]):focus,\nselect:focus,\ntextarea:focus {\n --box-shadow: 0 0 0 var(--outline-width) var(--form-element-focus-color);\n}\n\ninput:not([type=submit], [type=button], [type=reset])[disabled],\nselect[disabled],\ntextarea[disabled],\n:where(fieldset[disabled]) :is(input:not([type=submit], [type=button], [type=reset]), select, textarea) {\n --background-color: var(--form-element-disabled-background-color);\n --border-color: var(--form-element-disabled-border-color);\n opacity: var(--form-element-disabled-opacity);\n pointer-events: none;\n}\n\n:where(input, select, textarea):not([type=checkbox], [type=radio], [type=date], [type=datetime-local], [type=month], [type=time], [type=week])[aria-invalid] {\n padding-right: calc(var(--form-element-spacing-horizontal) + 1.5rem) !important;\n padding-left: var(--form-element-spacing-horizontal);\n padding-inline-start: var(--form-element-spacing-horizontal) !important;\n padding-inline-end: calc(var(--form-element-spacing-horizontal) + 1.5rem) !important;\n background-position: center right 0.75rem;\n background-size: 1rem auto;\n background-repeat: no-repeat;\n}\n:where(input, select, textarea):not([type=checkbox], [type=radio], [type=date], [type=datetime-local], [type=month], [type=time], [type=week])[aria-invalid=false] {\n background-image: var(--icon-valid);\n}\n:where(input, select, textarea):not([type=checkbox], [type=radio], [type=date], [type=datetime-local], [type=month], [type=time], [type=week])[aria-invalid=true] {\n background-image: var(--icon-invalid);\n}\n:where(input, select, textarea)[aria-invalid=false] {\n --border-color: var(--form-element-valid-border-color);\n}\n:where(input, select, textarea)[aria-invalid=false]:is(:active, :focus) {\n --border-color: var(--form-element-valid-active-border-color) !important;\n --box-shadow: 0 0 0 var(--outline-width) var(--form-element-valid-focus-color) !important;\n}\n:where(input, select, textarea)[aria-invalid=true] {\n --border-color: var(--form-element-invalid-border-color);\n}\n:where(input, select, textarea)[aria-invalid=true]:is(:active, :focus) {\n --border-color: var(--form-element-invalid-active-border-color) !important;\n --box-shadow: 0 0 0 var(--outline-width) var(--form-element-invalid-focus-color) !important;\n}\n\n[dir=rtl] :where(input, select, textarea):not([type=checkbox], [type=radio]):is([aria-invalid], [aria-invalid=true], [aria-invalid=false]) {\n background-position: center left 0.75rem;\n}\n\ninput::placeholder,\ninput::-webkit-input-placeholder,\ntextarea::placeholder,\ntextarea::-webkit-input-placeholder,\nselect:invalid {\n color: var(--form-element-placeholder-color);\n opacity: 1;\n}\n\ninput:not([type=checkbox], [type=radio]),\nselect,\ntextarea {\n margin-bottom: var(--spacing);\n}\n\nselect::-ms-expand {\n border: 0;\n background-color: transparent;\n}\nselect:not([multiple], [size]) {\n padding-right: calc(var(--form-element-spacing-horizontal) + 1.5rem);\n padding-left: var(--form-element-spacing-horizontal);\n padding-inline-start: var(--form-element-spacing-horizontal);\n padding-inline-end: calc(var(--form-element-spacing-horizontal) + 1.5rem);\n background-image: var(--icon-chevron);\n background-position: center right 0.75rem;\n background-size: 1rem auto;\n background-repeat: no-repeat;\n}\n\n[dir=rtl] select:not([multiple], [size]) {\n background-position: center left 0.75rem;\n}\n\n:where(input, select, textarea) + small {\n display: block;\n width: 100%;\n margin-top: calc(var(--spacing) * -0.75);\n margin-bottom: var(--spacing);\n color: var(--muted-color);\n}\n\nlabel > :where(input, select, textarea) {\n margin-top: calc(var(--spacing) * 0.25);\n}\n\n/**\n * Form elements\n * Checkboxes & Radios\n */\n[type=checkbox],\n[type=radio] {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n width: 1.25em;\n height: 1.25em;\n margin-top: -0.125em;\n margin-right: 0.375em;\n margin-left: 0;\n margin-inline-start: 0;\n margin-inline-end: 0.375em;\n border-width: var(--border-width);\n font-size: inherit;\n vertical-align: middle;\n cursor: pointer;\n}\n[type=checkbox]::-ms-check,\n[type=radio]::-ms-check {\n display: none;\n}\n[type=checkbox]:checked, [type=checkbox]:checked:active, [type=checkbox]:checked:focus,\n[type=radio]:checked,\n[type=radio]:checked:active,\n[type=radio]:checked:focus {\n --background-color: var(--primary);\n --border-color: var(--primary);\n background-image: var(--icon-checkbox);\n background-position: center;\n background-size: 0.75em auto;\n background-repeat: no-repeat;\n}\n[type=checkbox] ~ label,\n[type=radio] ~ label {\n display: inline-block;\n margin-right: 0.375em;\n margin-bottom: 0;\n cursor: pointer;\n}\n\n[type=checkbox]:indeterminate {\n --background-color: var(--primary);\n --border-color: var(--primary);\n background-image: var(--icon-minus);\n background-position: center;\n background-size: 0.75em auto;\n background-repeat: no-repeat;\n}\n\n[type=radio] {\n border-radius: 50%;\n}\n[type=radio]:checked, [type=radio]:checked:active, [type=radio]:checked:focus {\n --background-color: var(--primary-inverse);\n border-width: 0.35em;\n background-image: none;\n}\n\n[type=checkbox][role=switch] {\n --background-color: var(--switch-background-color);\n --border-color: var(--switch-background-color);\n --color: var(--switch-color);\n width: 2.25em;\n height: 1.25em;\n border: var(--border-width) solid var(--border-color);\n border-radius: 1.25em;\n background-color: var(--background-color);\n line-height: 1.25em;\n}\n[type=checkbox][role=switch]:focus {\n --background-color: var(--switch-background-color);\n --border-color: var(--switch-background-color);\n}\n[type=checkbox][role=switch]:checked {\n --background-color: var(--switch-checked-background-color);\n --border-color: var(--switch-checked-background-color);\n}\n[type=checkbox][role=switch]:before {\n display: block;\n width: calc(1.25em - (var(--border-width) * 2));\n height: 100%;\n border-radius: 50%;\n background-color: var(--color);\n content: \"\";\n transition: margin 0.1s ease-in-out;\n}\n[type=checkbox][role=switch]:checked {\n background-image: none;\n}\n[type=checkbox][role=switch]:checked::before {\n margin-left: calc(1.125em - var(--border-width));\n margin-inline-start: calc(1.125em - var(--border-width));\n}\n\n[type=checkbox][aria-invalid=false],\n[type=checkbox]:checked[aria-invalid=false],\n[type=radio][aria-invalid=false],\n[type=radio]:checked[aria-invalid=false],\n[type=checkbox][role=switch][aria-invalid=false],\n[type=checkbox][role=switch]:checked[aria-invalid=false] {\n --border-color: var(--form-element-valid-border-color);\n}\n[type=checkbox][aria-invalid=true],\n[type=checkbox]:checked[aria-invalid=true],\n[type=radio][aria-invalid=true],\n[type=radio]:checked[aria-invalid=true],\n[type=checkbox][role=switch][aria-invalid=true],\n[type=checkbox][role=switch]:checked[aria-invalid=true] {\n --border-color: var(--form-element-invalid-border-color);\n}\n\n/**\n * Form elements\n * Alternatives input types (Not Checkboxes & Radios)\n */\n[type=color]::-webkit-color-swatch-wrapper {\n padding: 0;\n}\n[type=color]::-moz-focus-inner {\n padding: 0;\n}\n[type=color]::-webkit-color-swatch {\n border: 0;\n border-radius: calc(var(--border-radius) * 0.5);\n}\n[type=color]::-moz-color-swatch {\n border: 0;\n border-radius: calc(var(--border-radius) * 0.5);\n}\n\ninput:not([type=checkbox], [type=radio], [type=range], [type=file]):is([type=date], [type=datetime-local], [type=month], [type=time], [type=week]) {\n --icon-position: 0.75rem;\n --icon-width: 1rem;\n padding-right: calc(var(--icon-width) + var(--icon-position));\n background-image: var(--icon-date);\n background-position: center right var(--icon-position);\n background-size: var(--icon-width) auto;\n background-repeat: no-repeat;\n}\ninput:not([type=checkbox], [type=radio], [type=range], [type=file])[type=time] {\n background-image: var(--icon-time);\n}\n\n[type=date]::-webkit-calendar-picker-indicator,\n[type=datetime-local]::-webkit-calendar-picker-indicator,\n[type=month]::-webkit-calendar-picker-indicator,\n[type=time]::-webkit-calendar-picker-indicator,\n[type=week]::-webkit-calendar-picker-indicator {\n width: var(--icon-width);\n margin-right: calc(var(--icon-width) * -1);\n margin-left: var(--icon-position);\n opacity: 0;\n}\n\n[dir=rtl] :is([type=date], [type=datetime-local], [type=month], [type=time], [type=week]) {\n text-align: right;\n}\n\n@-moz-document url-prefix() {\n [type=date],\n [type=datetime-local],\n [type=month],\n [type=time],\n [type=week] {\n padding-right: var(--form-element-spacing-horizontal) !important;\n background-image: none !important;\n }\n}\n[type=file] {\n --color: var(--muted-color);\n padding: calc(var(--form-element-spacing-vertical) * 0.5) 0;\n border: 0;\n border-radius: 0;\n background: none;\n}\n[type=file]::file-selector-button {\n --background-color: var(--secondary);\n --border-color: var(--secondary);\n --color: var(--secondary-inverse);\n margin-right: calc(var(--spacing) / 2);\n margin-left: 0;\n margin-inline-start: 0;\n margin-inline-end: calc(var(--spacing) / 2);\n padding: calc(var(--form-element-spacing-vertical) * 0.5) calc(var(--form-element-spacing-horizontal) * 0.5);\n border: var(--border-width) solid var(--border-color);\n border-radius: var(--border-radius);\n outline: none;\n background-color: var(--background-color);\n box-shadow: var(--box-shadow);\n color: var(--color);\n font-weight: var(--font-weight);\n font-size: 1rem;\n line-height: var(--line-height);\n text-align: center;\n cursor: pointer;\n transition: background-color var(--transition), border-color var(--transition), color var(--transition), box-shadow var(--transition);\n}\n[type=file]::file-selector-button:is(:hover, :active, :focus) {\n --background-color: var(--secondary-hover);\n --border-color: var(--secondary-hover);\n}\n[type=file]::-webkit-file-upload-button {\n --background-color: var(--secondary);\n --border-color: var(--secondary);\n --color: var(--secondary-inverse);\n margin-right: calc(var(--spacing) / 2);\n margin-left: 0;\n margin-inline-start: 0;\n margin-inline-end: calc(var(--spacing) / 2);\n padding: calc(var(--form-element-spacing-vertical) * 0.5) calc(var(--form-element-spacing-horizontal) * 0.5);\n border: var(--border-width) solid var(--border-color);\n border-radius: var(--border-radius);\n outline: none;\n background-color: var(--background-color);\n box-shadow: var(--box-shadow);\n color: var(--color);\n font-weight: var(--font-weight);\n font-size: 1rem;\n line-height: var(--line-height);\n text-align: center;\n cursor: pointer;\n transition: background-color var(--transition), border-color var(--transition), color var(--transition), box-shadow var(--transition);\n}\n[type=file]::-webkit-file-upload-button:is(:hover, :active, :focus) {\n --background-color: var(--secondary-hover);\n --border-color: var(--secondary-hover);\n}\n[type=file]::-ms-browse {\n --background-color: var(--secondary);\n --border-color: var(--secondary);\n --color: var(--secondary-inverse);\n margin-right: calc(var(--spacing) / 2);\n margin-left: 0;\n margin-inline-start: 0;\n margin-inline-end: calc(var(--spacing) / 2);\n padding: calc(var(--form-element-spacing-vertical) * 0.5) calc(var(--form-element-spacing-horizontal) * 0.5);\n border: var(--border-width) solid var(--border-color);\n border-radius: var(--border-radius);\n outline: none;\n background-color: var(--background-color);\n box-shadow: var(--box-shadow);\n color: var(--color);\n font-weight: var(--font-weight);\n font-size: 1rem;\n line-height: var(--line-height);\n text-align: center;\n cursor: pointer;\n transition: background-color var(--transition), border-color var(--transition), color var(--transition), box-shadow var(--transition);\n}\n[type=file]::-ms-browse:is(:hover, :active, :focus) {\n --background-color: var(--secondary-hover);\n --border-color: var(--secondary-hover);\n}\n\n[type=range] {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n width: 100%;\n height: 1.25rem;\n background: none;\n}\n[type=range]::-webkit-slider-runnable-track {\n width: 100%;\n height: 0.25rem;\n border-radius: var(--border-radius);\n background-color: var(--range-border-color);\n transition: background-color var(--transition), box-shadow var(--transition);\n}\n[type=range]::-moz-range-track {\n width: 100%;\n height: 0.25rem;\n border-radius: var(--border-radius);\n background-color: var(--range-border-color);\n transition: background-color var(--transition), box-shadow var(--transition);\n}\n[type=range]::-ms-track {\n width: 100%;\n height: 0.25rem;\n border-radius: var(--border-radius);\n background-color: var(--range-border-color);\n transition: background-color var(--transition), box-shadow var(--transition);\n}\n[type=range]::-webkit-slider-thumb {\n -webkit-appearance: none;\n width: 1.25rem;\n height: 1.25rem;\n margin-top: -0.5rem;\n border: 2px solid var(--range-thumb-border-color);\n border-radius: 50%;\n background-color: var(--range-thumb-color);\n cursor: pointer;\n transition: background-color var(--transition), transform var(--transition);\n}\n[type=range]::-moz-range-thumb {\n -webkit-appearance: none;\n width: 1.25rem;\n height: 1.25rem;\n margin-top: -0.5rem;\n border: 2px solid var(--range-thumb-border-color);\n border-radius: 50%;\n background-color: var(--range-thumb-color);\n cursor: pointer;\n transition: background-color var(--transition), transform var(--transition);\n}\n[type=range]::-ms-thumb {\n -webkit-appearance: none;\n width: 1.25rem;\n height: 1.25rem;\n margin-top: -0.5rem;\n border: 2px solid var(--range-thumb-border-color);\n border-radius: 50%;\n background-color: var(--range-thumb-color);\n cursor: pointer;\n transition: background-color var(--transition), transform var(--transition);\n}\n[type=range]:hover, [type=range]:focus {\n --range-border-color: var(--range-active-border-color);\n --range-thumb-color: var(--range-thumb-hover-color);\n}\n[type=range]:active {\n --range-thumb-color: var(--range-thumb-active-color);\n}\n[type=range]:active::-webkit-slider-thumb {\n transform: scale(1.25);\n}\n[type=range]:active::-moz-range-thumb {\n transform: scale(1.25);\n}\n[type=range]:active::-ms-thumb {\n transform: scale(1.25);\n}\n\ninput:not([type=checkbox], [type=radio], [type=range], [type=file])[type=search] {\n padding-inline-start: calc(var(--form-element-spacing-horizontal) + 1.75rem);\n border-radius: 5rem;\n background-image: var(--icon-search);\n background-position: center left 1.125rem;\n background-size: 1rem auto;\n background-repeat: no-repeat;\n}\ninput:not([type=checkbox], [type=radio], [type=range], [type=file])[type=search][aria-invalid] {\n padding-inline-start: calc(var(--form-element-spacing-horizontal) + 1.75rem) !important;\n background-position: center left 1.125rem, center right 0.75rem;\n}\ninput:not([type=checkbox], [type=radio], [type=range], [type=file])[type=search][aria-invalid=false] {\n background-image: var(--icon-search), var(--icon-valid);\n}\ninput:not([type=checkbox], [type=radio], [type=range], [type=file])[type=search][aria-invalid=true] {\n background-image: var(--icon-search), var(--icon-invalid);\n}\n\n[type=search]::-webkit-search-cancel-button {\n -webkit-appearance: none;\n display: none;\n}\n\n[dir=rtl] :where(input):not([type=checkbox], [type=radio], [type=range], [type=file])[type=search] {\n background-position: center right 1.125rem;\n}\n[dir=rtl] :where(input):not([type=checkbox], [type=radio], [type=range], [type=file])[type=search][aria-invalid] {\n background-position: center right 1.125rem, center left 0.75rem;\n}\n\n/**\n * Table\n */\n:where(table) {\n width: 100%;\n border-collapse: collapse;\n border-spacing: 0;\n text-indent: 0;\n}\n\nth,\ntd {\n padding: calc(var(--spacing) / 2) var(--spacing);\n border-bottom: var(--border-width) solid var(--table-border-color);\n color: var(--color);\n font-weight: var(--font-weight);\n font-size: var(--font-size);\n text-align: left;\n text-align: start;\n}\n\ntfoot th,\ntfoot td {\n border-top: var(--border-width) solid var(--table-border-color);\n border-bottom: 0;\n}\n\ntable[role=grid] tbody tr:nth-child(odd) {\n background-color: var(--table-row-stripped-background-color);\n}\n\n/**\n * Code\n */\npre,\ncode,\nkbd,\nsamp {\n font-size: 0.875em;\n font-family: var(--font-family);\n}\n\npre {\n -ms-overflow-style: scrollbar;\n overflow: auto;\n}\n\npre,\ncode,\nkbd {\n border-radius: var(--border-radius);\n background: var(--code-background-color);\n color: var(--code-color);\n font-weight: var(--font-weight);\n line-height: initial;\n}\n\ncode,\nkbd {\n display: inline-block;\n padding: 0.375rem 0.5rem;\n}\n\npre {\n display: block;\n margin-bottom: var(--spacing);\n overflow-x: auto;\n}\npre > code {\n display: block;\n padding: var(--spacing);\n background: none;\n font-size: 14px;\n line-height: var(--line-height);\n}\n\ncode b {\n color: var(--code-tag-color);\n font-weight: var(--font-weight);\n}\ncode i {\n color: var(--code-property-color);\n font-style: normal;\n}\ncode u {\n color: var(--code-value-color);\n text-decoration: none;\n}\ncode em {\n color: var(--code-comment-color);\n font-style: normal;\n}\n\nkbd {\n background-color: var(--code-kbd-background-color);\n color: var(--code-kbd-color);\n vertical-align: baseline;\n}\n\n/**\n * Miscs\n */\nhr {\n height: 0;\n border: 0;\n border-top: 1px solid var(--muted-border-color);\n color: inherit;\n}\n\n[hidden],\ntemplate {\n display: none !important;\n}\n\ncanvas {\n display: inline-block;\n}\n\n/**\n * Accordion (
    )\n */\ndetails {\n display: block;\n margin-bottom: var(--spacing);\n padding-bottom: var(--spacing);\n border-bottom: var(--border-width) solid var(--accordion-border-color);\n}\ndetails summary {\n line-height: 1rem;\n list-style-type: none;\n cursor: pointer;\n transition: color var(--transition);\n}\ndetails summary:not([role]) {\n color: var(--accordion-close-summary-color);\n}\ndetails summary::-webkit-details-marker {\n display: none;\n}\ndetails summary::marker {\n display: none;\n}\ndetails summary::-moz-list-bullet {\n list-style-type: none;\n}\ndetails summary::after {\n display: block;\n width: 1rem;\n height: 1rem;\n margin-inline-start: calc(var(--spacing, 1rem) * 0.5);\n float: right;\n transform: rotate(-90deg);\n background-image: var(--icon-chevron);\n background-position: right center;\n background-size: 1rem auto;\n background-repeat: no-repeat;\n content: \"\";\n transition: transform var(--transition);\n}\ndetails summary:focus {\n outline: none;\n}\ndetails summary:focus:not([role=button]) {\n color: var(--accordion-active-summary-color);\n}\ndetails summary[role=button] {\n width: 100%;\n text-align: left;\n}\ndetails summary[role=button]::after {\n height: calc(1rem * var(--line-height, 1.5));\n background-image: var(--icon-chevron-button);\n}\ndetails[open] > summary {\n margin-bottom: calc(var(--spacing));\n}\ndetails[open] > summary:not([role]):not(:focus) {\n color: var(--accordion-open-summary-color);\n}\ndetails[open] > summary::after {\n transform: rotate(0);\n}\n\n[dir=rtl] details summary {\n text-align: right;\n}\n[dir=rtl] details summary::after {\n float: left;\n background-position: left center;\n}\n\n/**\n * Card (
    )\n */\narticle {\n margin: var(--block-spacing-vertical) 0;\n padding: var(--block-spacing-vertical) var(--block-spacing-horizontal);\n border-radius: var(--border-radius);\n background: var(--card-background-color);\n box-shadow: var(--card-box-shadow);\n}\narticle > header,\narticle > footer {\n margin-right: calc(var(--block-spacing-horizontal) * -1);\n margin-left: calc(var(--block-spacing-horizontal) * -1);\n padding: calc(var(--block-spacing-vertical) * 0.66) var(--block-spacing-horizontal);\n background-color: var(--card-sectionning-background-color);\n}\narticle > header {\n margin-top: calc(var(--block-spacing-vertical) * -1);\n margin-bottom: var(--block-spacing-vertical);\n border-bottom: var(--border-width) solid var(--card-border-color);\n border-top-right-radius: var(--border-radius);\n border-top-left-radius: var(--border-radius);\n}\narticle > footer {\n margin-top: var(--block-spacing-vertical);\n margin-bottom: calc(var(--block-spacing-vertical) * -1);\n border-top: var(--border-width) solid var(--card-border-color);\n border-bottom-right-radius: var(--border-radius);\n border-bottom-left-radius: var(--border-radius);\n}\n\n/**\n * Modal ()\n */\n:root {\n --scrollbar-width: 0px;\n}\n\ndialog {\n display: flex;\n z-index: 999;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n align-items: center;\n justify-content: center;\n width: inherit;\n min-width: 100%;\n height: inherit;\n min-height: 100%;\n padding: var(--spacing);\n border: 0;\n backdrop-filter: var(--modal-overlay-backdrop-filter);\n background-color: var(--modal-overlay-background-color);\n color: var(--color);\n}\ndialog article {\n max-height: calc(100vh - var(--spacing) * 2);\n overflow: auto;\n}\n@media (min-width: 576px) {\n dialog article {\n max-width: 510px;\n }\n}\n@media (min-width: 768px) {\n dialog article {\n max-width: 700px;\n }\n}\ndialog article > header,\ndialog article > footer {\n padding: calc(var(--block-spacing-vertical) * 0.5) var(--block-spacing-horizontal);\n}\ndialog article > header .close {\n margin: 0;\n margin-left: var(--spacing);\n float: right;\n}\ndialog article > footer {\n text-align: right;\n}\ndialog article > footer [role=button] {\n margin-bottom: 0;\n}\ndialog article > footer [role=button]:not(:first-of-type) {\n margin-left: calc(var(--spacing) * 0.5);\n}\ndialog article p:last-of-type {\n margin: 0;\n}\ndialog:not([open]), dialog[open=false] {\n display: none;\n}\n\n/**\n * Nav\n */\n:where(nav li)::before {\n float: left;\n content: \"​\";\n}\n\nnav,\nnav ul {\n display: flex;\n}\n\nnav {\n justify-content: space-between;\n}\nnav ol,\nnav ul {\n align-items: center;\n margin-bottom: 0;\n padding: 0;\n list-style: none;\n}\nnav ol:first-of-type,\nnav ul:first-of-type {\n margin-left: calc(var(--nav-element-spacing-horizontal) * -1);\n}\nnav ol:last-of-type,\nnav ul:last-of-type {\n margin-right: calc(var(--nav-element-spacing-horizontal) * -1);\n}\nnav li {\n display: inline-block;\n margin: 0;\n padding: var(--nav-element-spacing-vertical) var(--nav-element-spacing-horizontal);\n}\nnav li > * {\n --spacing: 0;\n}\nnav :where(a, [role=link]) {\n display: inline-block;\n margin: calc(var(--nav-link-spacing-vertical) * -1) calc(var(--nav-link-spacing-horizontal) * -1);\n padding: var(--nav-link-spacing-vertical) var(--nav-link-spacing-horizontal);\n border-radius: var(--border-radius);\n text-decoration: none;\n}\nnav :where(a, [role=link]):is([aria-current], :hover, :active, :focus) {\n text-decoration: none;\n}\nnav[aria-label=breadcrumb] {\n align-items: center;\n justify-content: start;\n}\nnav[aria-label=breadcrumb] ul li:not(:first-child) {\n margin-inline-start: var(--nav-link-spacing-horizontal);\n}\nnav[aria-label=breadcrumb] ul li:not(:last-child) ::after {\n position: absolute;\n width: calc(var(--nav-link-spacing-horizontal) * 2);\n margin-inline-start: calc(var(--nav-link-spacing-horizontal) / 2);\n content: \"/\";\n color: var(--muted-color);\n text-align: center;\n}\nnav[aria-label=breadcrumb] a[aria-current] {\n background-color: transparent;\n color: inherit;\n text-decoration: none;\n pointer-events: none;\n}\nnav [role=button] {\n margin-right: inherit;\n margin-left: inherit;\n padding: var(--nav-link-spacing-vertical) var(--nav-link-spacing-horizontal);\n}\n\naside nav,\naside ol,\naside ul,\naside li {\n display: block;\n}\naside li {\n padding: calc(var(--nav-element-spacing-vertical) * 0.5) var(--nav-element-spacing-horizontal);\n}\naside li a {\n display: block;\n}\naside li [role=button] {\n margin: inherit;\n}\n\n[dir=rtl] nav[aria-label=breadcrumb] ul li:not(:last-child) ::after {\n content: \"\\\\\";\n}\n\n/**\n * Progress\n */\nprogress {\n display: inline-block;\n vertical-align: baseline;\n}\n\nprogress {\n -webkit-appearance: none;\n -moz-appearance: none;\n display: inline-block;\n appearance: none;\n width: 100%;\n height: 0.5rem;\n margin-bottom: calc(var(--spacing) * 0.5);\n overflow: hidden;\n border: 0;\n border-radius: var(--border-radius);\n background-color: var(--progress-background-color);\n color: var(--progress-color);\n}\nprogress::-webkit-progress-bar {\n border-radius: var(--border-radius);\n background: none;\n}\nprogress[value]::-webkit-progress-value {\n background-color: var(--progress-color);\n}\nprogress::-moz-progress-bar {\n background-color: var(--progress-color);\n}\n@media (prefers-reduced-motion: no-preference) {\n progress:indeterminate {\n background: var(--progress-background-color) linear-gradient(to right, var(--progress-color) 30%, var(--progress-background-color) 30%) top left/150% 150% no-repeat;\n animation: progress-indeterminate 1s linear infinite;\n }\n progress:indeterminate[value]::-webkit-progress-value {\n background-color: transparent;\n }\n progress:indeterminate::-moz-progress-bar {\n background-color: transparent;\n }\n}\n\n@media (prefers-reduced-motion: no-preference) {\n [dir=rtl] progress:indeterminate {\n animation-direction: reverse;\n }\n}\n\n@keyframes progress-indeterminate {\n 0% {\n background-position: 200% 0;\n }\n 100% {\n background-position: -200% 0;\n }\n}\n/**\n * Dropdown ([role=\"list\"])\n */\ndetails[role=list],\nli[role=list] {\n position: relative;\n}\n\ndetails[role=list] summary + ul,\nli[role=list] > ul {\n display: flex;\n z-index: 99;\n position: absolute;\n top: auto;\n right: 0;\n left: 0;\n flex-direction: column;\n margin: 0;\n padding: 0;\n border: var(--border-width) solid var(--dropdown-border-color);\n border-radius: var(--border-radius);\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n background-color: var(--dropdown-background-color);\n box-shadow: var(--card-box-shadow);\n color: var(--dropdown-color);\n white-space: nowrap;\n}\ndetails[role=list] summary + ul li,\nli[role=list] > ul li {\n width: 100%;\n margin-bottom: 0;\n padding: calc(var(--form-element-spacing-vertical) * 0.5) var(--form-element-spacing-horizontal);\n list-style: none;\n}\ndetails[role=list] summary + ul li:first-of-type,\nli[role=list] > ul li:first-of-type {\n margin-top: calc(var(--form-element-spacing-vertical) * 0.5);\n}\ndetails[role=list] summary + ul li:last-of-type,\nli[role=list] > ul li:last-of-type {\n margin-bottom: calc(var(--form-element-spacing-vertical) * 0.5);\n}\ndetails[role=list] summary + ul li a,\nli[role=list] > ul li a {\n display: block;\n margin: calc(var(--form-element-spacing-vertical) * -0.5) calc(var(--form-element-spacing-horizontal) * -1);\n padding: calc(var(--form-element-spacing-vertical) * 0.5) var(--form-element-spacing-horizontal);\n overflow: hidden;\n color: var(--dropdown-color);\n text-decoration: none;\n text-overflow: ellipsis;\n}\ndetails[role=list] summary + ul li a:hover,\nli[role=list] > ul li a:hover {\n background-color: var(--dropdown-hover-background-color);\n}\n\ndetails[role=list] summary::after,\nli[role=list] > a::after {\n display: block;\n width: 1rem;\n height: calc(1rem * var(--line-height, 1.5));\n margin-inline-start: 0.5rem;\n float: right;\n transform: rotate(0deg);\n background-position: right center;\n background-size: 1rem auto;\n background-repeat: no-repeat;\n content: \"\";\n}\n\ndetails[role=list] {\n padding: 0;\n border-bottom: none;\n}\ndetails[role=list] summary {\n margin-bottom: 0;\n}\ndetails[role=list] summary:not([role]) {\n height: calc(1rem * var(--line-height) + var(--form-element-spacing-vertical) * 2 + var(--border-width) * 2);\n padding: var(--form-element-spacing-vertical) var(--form-element-spacing-horizontal);\n border: var(--border-width) solid var(--form-element-border-color);\n border-radius: var(--border-radius);\n background-color: var(--form-element-background-color);\n color: var(--form-element-placeholder-color);\n line-height: inherit;\n cursor: pointer;\n transition: background-color var(--transition), border-color var(--transition), color var(--transition), box-shadow var(--transition);\n}\ndetails[role=list] summary:not([role]):active, details[role=list] summary:not([role]):focus {\n border-color: var(--form-element-active-border-color);\n background-color: var(--form-element-active-background-color);\n}\ndetails[role=list] summary:not([role]):focus {\n box-shadow: 0 0 0 var(--outline-width) var(--form-element-focus-color);\n}\ndetails[role=list][open] summary {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\ndetails[role=list][open] summary::before {\n display: block;\n z-index: 1;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n background: none;\n content: \"\";\n cursor: default;\n}\n\nnav details[role=list] summary,\nnav li[role=list] a {\n display: flex;\n direction: ltr;\n}\n\nnav details[role=list] summary + ul,\nnav li[role=list] > ul {\n min-width: fit-content;\n border-radius: var(--border-radius);\n}\nnav details[role=list] summary + ul li a,\nnav li[role=list] > ul li a {\n border-radius: 0;\n}\n\nnav details[role=list] summary,\nnav details[role=list] summary:not([role]) {\n height: auto;\n padding: var(--nav-link-spacing-vertical) var(--nav-link-spacing-horizontal);\n}\nnav details[role=list][open] summary {\n border-radius: var(--border-radius);\n}\nnav details[role=list] summary + ul {\n margin-top: var(--outline-width);\n margin-inline-start: 0;\n}\nnav details[role=list] summary[role=link] {\n margin-bottom: calc(var(--nav-link-spacing-vertical) * -1);\n line-height: var(--line-height);\n}\nnav details[role=list] summary[role=link] + ul {\n margin-top: calc(var(--nav-link-spacing-vertical) + var(--outline-width));\n margin-inline-start: calc(var(--nav-link-spacing-horizontal) * -1);\n}\n\nli[role=list]:hover > ul,\nli[role=list] a:active ~ ul,\nli[role=list] a:focus ~ ul {\n display: flex;\n}\nli[role=list] > ul {\n display: none;\n margin-top: calc(var(--nav-link-spacing-vertical) + var(--outline-width));\n margin-inline-start: calc(var(--nav-element-spacing-horizontal) - var(--nav-link-spacing-horizontal));\n}\nli[role=list] > a::after {\n background-image: var(--icon-chevron);\n}\n\nlabel > details[role=list] {\n margin-top: calc(var(--spacing) * 0.25);\n margin-bottom: var(--spacing);\n}\n\n/**\n * Loading ([aria-busy=true])\n */\n[aria-busy=true] {\n cursor: progress;\n}\n\n[aria-busy=true]:not(input, select, textarea, html)::before {\n display: inline-block;\n width: 1em;\n height: 1em;\n border: 0.1875em solid currentColor;\n border-radius: 1em;\n border-right-color: transparent;\n content: \"\";\n vertical-align: text-bottom;\n vertical-align: -0.125em;\n animation: spinner 0.75s linear infinite;\n opacity: var(--loading-spinner-opacity);\n}\n[aria-busy=true]:not(input, select, textarea, html):not(:empty)::before {\n margin-right: calc(var(--spacing) * 0.5);\n margin-left: 0;\n margin-inline-start: 0;\n margin-inline-end: calc(var(--spacing) * 0.5);\n}\n[aria-busy=true]:not(input, select, textarea, html):empty {\n text-align: center;\n}\n\nbutton[aria-busy=true],\ninput[type=submit][aria-busy=true],\ninput[type=button][aria-busy=true],\ninput[type=reset][aria-busy=true],\na[aria-busy=true] {\n pointer-events: none;\n}\n\n@keyframes spinner {\n to {\n transform: rotate(360deg);\n }\n}\n/**\n * Tooltip ([data-tooltip])\n */\n[data-tooltip] {\n position: relative;\n}\n[data-tooltip]:not(a, button, input) {\n border-bottom: 1px dotted;\n text-decoration: none;\n cursor: help;\n}\n[data-tooltip][data-placement=top]::before, [data-tooltip][data-placement=top]::after, [data-tooltip]::before, [data-tooltip]::after {\n display: block;\n z-index: 99;\n position: absolute;\n bottom: 100%;\n left: 50%;\n padding: 0.25rem 0.5rem;\n overflow: hidden;\n transform: translate(-50%, -0.25rem);\n border-radius: var(--border-radius);\n background: var(--tooltip-background-color);\n content: attr(data-tooltip);\n color: var(--tooltip-color);\n font-style: normal;\n font-weight: var(--font-weight);\n font-size: 0.875rem;\n text-decoration: none;\n text-overflow: ellipsis;\n white-space: nowrap;\n opacity: 0;\n pointer-events: none;\n}\n[data-tooltip][data-placement=top]::after, [data-tooltip]::after {\n padding: 0;\n transform: translate(-50%, 0rem);\n border-top: 0.3rem solid;\n border-right: 0.3rem solid transparent;\n border-left: 0.3rem solid transparent;\n border-radius: 0;\n background-color: transparent;\n content: \"\";\n color: var(--tooltip-background-color);\n}\n[data-tooltip][data-placement=bottom]::before, [data-tooltip][data-placement=bottom]::after {\n top: 100%;\n bottom: auto;\n transform: translate(-50%, 0.25rem);\n}\n[data-tooltip][data-placement=bottom]:after {\n transform: translate(-50%, -0.3rem);\n border: 0.3rem solid transparent;\n border-bottom: 0.3rem solid;\n}\n[data-tooltip][data-placement=left]::before, [data-tooltip][data-placement=left]::after {\n top: 50%;\n right: 100%;\n bottom: auto;\n left: auto;\n transform: translate(-0.25rem, -50%);\n}\n[data-tooltip][data-placement=left]:after {\n transform: translate(0.3rem, -50%);\n border: 0.3rem solid transparent;\n border-left: 0.3rem solid;\n}\n[data-tooltip][data-placement=right]::before, [data-tooltip][data-placement=right]::after {\n top: 50%;\n right: auto;\n bottom: auto;\n left: 100%;\n transform: translate(0.25rem, -50%);\n}\n[data-tooltip][data-placement=right]:after {\n transform: translate(-0.3rem, -50%);\n border: 0.3rem solid transparent;\n border-right: 0.3rem solid;\n}\n[data-tooltip]:focus::before, [data-tooltip]:focus::after, [data-tooltip]:hover::before, [data-tooltip]:hover::after {\n opacity: 1;\n}\n@media (hover: hover) and (pointer: fine) {\n [data-tooltip][data-placement=bottom]:focus::before, [data-tooltip][data-placement=bottom]:focus::after, [data-tooltip][data-placement=bottom]:hover [data-tooltip]:focus::before, [data-tooltip][data-placement=bottom]:hover [data-tooltip]:focus::after, [data-tooltip]:hover::before, [data-tooltip]:hover::after {\n animation-duration: 0.2s;\n animation-name: tooltip-slide-top;\n }\n [data-tooltip][data-placement=bottom]:focus::after, [data-tooltip][data-placement=bottom]:hover [data-tooltip]:focus::after, [data-tooltip]:hover::after {\n animation-name: tooltip-caret-slide-top;\n }\n [data-tooltip][data-placement=bottom]:focus::before, [data-tooltip][data-placement=bottom]:focus::after, [data-tooltip][data-placement=bottom]:hover::before, [data-tooltip][data-placement=bottom]:hover::after {\n animation-duration: 0.2s;\n animation-name: tooltip-slide-bottom;\n }\n [data-tooltip][data-placement=bottom]:focus::after, [data-tooltip][data-placement=bottom]:hover::after {\n animation-name: tooltip-caret-slide-bottom;\n }\n [data-tooltip][data-placement=left]:focus::before, [data-tooltip][data-placement=left]:focus::after, [data-tooltip][data-placement=left]:hover::before, [data-tooltip][data-placement=left]:hover::after {\n animation-duration: 0.2s;\n animation-name: tooltip-slide-left;\n }\n [data-tooltip][data-placement=left]:focus::after, [data-tooltip][data-placement=left]:hover::after {\n animation-name: tooltip-caret-slide-left;\n }\n [data-tooltip][data-placement=right]:focus::before, [data-tooltip][data-placement=right]:focus::after, [data-tooltip][data-placement=right]:hover::before, [data-tooltip][data-placement=right]:hover::after {\n animation-duration: 0.2s;\n animation-name: tooltip-slide-right;\n }\n [data-tooltip][data-placement=right]:focus::after, [data-tooltip][data-placement=right]:hover::after {\n animation-name: tooltip-caret-slide-right;\n }\n}\n@keyframes tooltip-slide-top {\n from {\n transform: translate(-50%, 0.75rem);\n opacity: 0;\n }\n to {\n transform: translate(-50%, -0.25rem);\n opacity: 1;\n }\n}\n@keyframes tooltip-caret-slide-top {\n from {\n opacity: 0;\n }\n 50% {\n transform: translate(-50%, -0.25rem);\n opacity: 0;\n }\n to {\n transform: translate(-50%, 0rem);\n opacity: 1;\n }\n}\n@keyframes tooltip-slide-bottom {\n from {\n transform: translate(-50%, -0.75rem);\n opacity: 0;\n }\n to {\n transform: translate(-50%, 0.25rem);\n opacity: 1;\n }\n}\n@keyframes tooltip-caret-slide-bottom {\n from {\n opacity: 0;\n }\n 50% {\n transform: translate(-50%, -0.5rem);\n opacity: 0;\n }\n to {\n transform: translate(-50%, -0.3rem);\n opacity: 1;\n }\n}\n@keyframes tooltip-slide-left {\n from {\n transform: translate(0.75rem, -50%);\n opacity: 0;\n }\n to {\n transform: translate(-0.25rem, -50%);\n opacity: 1;\n }\n}\n@keyframes tooltip-caret-slide-left {\n from {\n opacity: 0;\n }\n 50% {\n transform: translate(0.05rem, -50%);\n opacity: 0;\n }\n to {\n transform: translate(0.3rem, -50%);\n opacity: 1;\n }\n}\n@keyframes tooltip-slide-right {\n from {\n transform: translate(-0.75rem, -50%);\n opacity: 0;\n }\n to {\n transform: translate(0.25rem, -50%);\n opacity: 1;\n }\n}\n@keyframes tooltip-caret-slide-right {\n from {\n opacity: 0;\n }\n 50% {\n transform: translate(-0.05rem, -50%);\n opacity: 0;\n }\n to {\n transform: translate(-0.3rem, -50%);\n opacity: 1;\n }\n}\n\n/**\n * Accessibility & User interaction\n */\n[aria-controls] {\n cursor: pointer;\n}\n\n[aria-disabled=true],\n[disabled] {\n cursor: not-allowed;\n}\n\n[aria-hidden=false][hidden] {\n display: initial;\n}\n\n[aria-hidden=false][hidden]:not(:focus) {\n clip: rect(0, 0, 0, 0);\n position: absolute;\n}\n\na,\narea,\nbutton,\ninput,\nlabel,\nselect,\nsummary,\ntextarea,\n[tabindex] {\n -ms-touch-action: manipulation;\n}\n\n[dir=rtl] {\n direction: rtl;\n}\n\n/**\n* Reduce Motion Features\n*/\n@media (prefers-reduced-motion: reduce) {\n *:not([aria-busy=true]),\n :not([aria-busy=true])::before,\n :not([aria-busy=true])::after {\n background-attachment: initial !important;\n animation-duration: 1ms !important;\n animation-delay: -1ms !important;\n animation-iteration-count: 1 !important;\n scroll-behavior: auto !important;\n transition-delay: 0s !important;\n transition-duration: 0s !important;\n }\n}\n\n/*# sourceMappingURL=pico.classless.css.map */\n","@import \"../../functions\";\n\n// Default: Light theme\n[data-theme=\"light\"],\n:root:not([data-theme=\"dark\"]) {\n --background-color: #{$white};\n\n // Texts colors\n --color: #{$grey-700};\n --h1-color: #{$grey-900};\n --h2-color: #{mix($grey-900, $grey-800)};\n --h3-color: #{$grey-800};\n --h4-color: #{mix($grey-800, $grey-700)};\n --h5-color: #{$grey-700};\n --h6-color: #{mix($grey-700, $grey-600)};\n\n // Muted colors\n --muted-color: #{$grey-500};\n --muted-border-color: #{$grey-50};\n\n // Primary colors\n --primary: #{$primary-600};\n --primary-hover: #{$primary-700};\n --primary-focus: #{rgba($primary-600, 0.125)};\n --primary-inverse: #{$white};\n\n // Secondary colors\n --secondary: #{$grey-600};\n --secondary-hover: #{$grey-700};\n --secondary-focus: #{rgba($grey-600, 0.125)};\n --secondary-inverse: #{$white};\n\n // Contrast colors\n --contrast: #{$grey-900};\n --contrast-hover: #{$black};\n --contrast-focus: #{rgba($grey-600, 0.125)};\n --contrast-inverse: #{$white};\n\n // Highlighted text ()\n --mark-background-color: #{mix($amber-100, $amber-50)};\n --mark-color: #{mix($grey-900, $amber-900, 75%)};\n\n // Inserted () & Deleted ()\n --ins-color: #{$green-700};\n --del-color: #{$red-800};\n\n // Blockquote\n --blockquote-border-color: var(--muted-border-color);\n --blockquote-footer-color: var(--muted-color);\n\n // Button\n // To disable box-shadow, remove the var or set to '0 0 0 rgba(0, 0, 0, 0)'\n // Don't use, 'none, 'false, 'null', '0', etc.\n --button-box-shadow: 0 0 0 rgba(0, 0, 0, 0);\n --button-hover-box-shadow: 0 0 0 rgba(0, 0, 0, 0);\n\n // Form elements\n --form-element-background-color: transparent;\n --form-element-border-color: #{$grey-300};\n --form-element-color: var(--color);\n --form-element-placeholder-color: var(--muted-color);\n --form-element-active-background-color: transparent;\n --form-element-active-border-color: var(--primary);\n --form-element-focus-color: var(--primary-focus);\n --form-element-disabled-background-color: #{$grey-100};\n --form-element-disabled-border-color: #{$grey-300};\n --form-element-disabled-opacity: 0.5;\n --form-element-invalid-border-color: #{$red-800};\n --form-element-invalid-active-border-color: #{$red-700};\n --form-element-invalid-focus-color: #{rgba($red-700, 0.125)};\n --form-element-valid-border-color: #{$green-700};\n --form-element-valid-active-border-color: #{$green-600};\n --form-element-valid-focus-color: #{rgba($green-600, 0.125)};\n\n // Switch (input[type=\"checkbox\"][role=\"switch\"])\n --switch-background-color: #{$grey-200};\n --switch-color: var(--primary-inverse);\n --switch-checked-background-color: var(--primary);\n\n // Range (input[type=\"range\"])\n --range-border-color: #{$grey-100};\n --range-active-border-color: #{$grey-200};\n --range-thumb-border-color: var(--background-color);\n --range-thumb-color: var(--secondary);\n --range-thumb-hover-color: var(--secondary-hover);\n --range-thumb-active-color: var(--primary);\n\n // Table\n --table-border-color: var(--muted-border-color);\n --table-row-stripped-background-color: #{mix($grey-50, $white)};\n\n // Code\n --code-background-color: #{$grey-50};\n --code-color: var(--muted-color);\n --code-kbd-background-color: var(--contrast);\n --code-kbd-color: var(--contrast-inverse);\n --code-tag-color: #{hsl(330, 40%, 50%)};\n --code-property-color: #{hsl(185, 40%, 40%)};\n --code-value-color: #{hsl(40, 20%, 50%)};\n --code-comment-color: #{$grey-300};\n\n // Accordion (
    )\n --accordion-border-color: var(--muted-border-color);\n --accordion-close-summary-color: var(--color);\n --accordion-open-summary-color: var(--muted-color);\n\n // Card (
    )\n $box-shadow-elevation: 1rem;\n $box-shadow-blur-strengh: 6rem;\n $box-shadow-opacity: 0.06;\n --card-background-color: var(--background-color);\n --card-border-color: var(--muted-border-color);\n --card-box-shadow:\n #{($box-shadow-elevation * 0.5 * 0.029)} #{($box-shadow-elevation * 0.029)} #{($box-shadow-blur-strengh * 0.029)} #{rgba($grey-900, ($box-shadow-opacity * 0.283))},\n #{($box-shadow-elevation * 0.5 * 0.067)} #{($box-shadow-elevation * 0.067)} #{($box-shadow-blur-strengh * 0.067)} #{rgba($grey-900, ($box-shadow-opacity * 0.4))},\n #{($box-shadow-elevation * 0.5 * 0.125)} #{($box-shadow-elevation * 0.125)} #{($box-shadow-blur-strengh * 0.125)} #{rgba($grey-900, ($box-shadow-opacity * 0.5))},\n #{($box-shadow-elevation * 0.5 * 0.225)} #{($box-shadow-elevation * 0.225)} #{($box-shadow-blur-strengh * 0.225)} #{rgba($grey-900, ($box-shadow-opacity * 0.6))},\n #{($box-shadow-elevation * 0.5 * 0.417)} #{($box-shadow-elevation * 0.417)} #{($box-shadow-blur-strengh * 0.417)} #{rgba($grey-900, ($box-shadow-opacity * 0.717))},\n #{($box-shadow-elevation * 0.5)} #{$box-shadow-elevation} #{$box-shadow-blur-strengh} #{rgba($grey-900, $box-shadow-opacity)},\n 0 0 0 0.0625rem #{rgba($grey-900, ($box-shadow-opacity * 0.25) )};\n --card-sectionning-background-color: #{mix($grey-50, $white, 25%)};\n\n // Dropdown (
    )\n --dropdown-background-color: #{mix($grey-50, $white, 25%)};\n --dropdown-border-color: #{mix($grey-100, $grey-50)};\n --dropdown-box-shadow: var(--card-box-shadow);\n --dropdown-color: var(--color);\n --dropdown-hover-background-color: #{$grey-50};\n\n // Modal ()\n --modal-overlay-background-color: #{rgba($grey-100, 0.7)};\n\n // Progress\n --progress-background-color: #{$grey-100};\n --progress-color: var(--primary);\n\n // Loading ([aria-busy=true])\n --loading-spinner-opacity: 0.5;\n\n // Tooltip ([data-tooltip])\n --tooltip-background-color: var(--contrast);\n --tooltip-color: var(--contrast-inverse);\n\n // Icons\n --icon-checkbox: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($white)}' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-chevron: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($grey-700)}' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-chevron-button: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($white)}' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-chevron-button-inverse: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($white)}' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-close: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($grey-500)}' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E\");\n --icon-date: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($grey-700)}' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E\");\n --icon-invalid: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($red-800)}' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E\");\n --icon-minus: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($white)}' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E\");\n --icon-search: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($grey-700)}' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E\");\n --icon-time: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($grey-700)}' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E\"); \n --icon-valid: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($green-700)}' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E\");\n \n // Document\n color-scheme: light;\n}\n","/**\n * Theme: default\n */\n\n// Variables\n@import \"../variables\";\n@import \"default/colors\";\n\n// Commons styles\n@import \"default/styles\";\n\n// Light theme (Default)\n// Can be forced with data-theme=\"light\"\n@import \"default/light\";\n\n// Dark theme (Auto)\n// Automatically enabled if user has Dark mode enabled\n@import \"default/dark\";\n@media only screen and (prefers-color-scheme: dark) {\n :root:not([data-theme]) {\n @include dark;\n }\n}\n\n// Dark theme (Forced)\n// Enabled if forced with data-theme=\"dark\"\n[data-theme=\"dark\"] {\n @include dark;\n}\n\n// Accent-color\nprogress,\n[type=\"checkbox\"],\n[type=\"radio\"],\n[type=\"range\"] {\n accent-color: var(--primary);\n}\n","@import \"../../functions\";\n\n// Default: Dark theme\n@mixin dark {\n --background-color: #{mix($black, $grey-900, 37.5%)};\n\n // Texts colors\n --color: #{$grey-200};\n --h1-color: #{$grey-50};\n --h2-color: #{mix($grey-100, $grey-50)};\n --h3-color: #{$grey-100};\n --h4-color: #{mix($grey-200, $grey-100)};\n --h5-color: #{$grey-200};\n --h6-color: #{mix($grey-300, $grey-200)};\n\n // Muted colors\n --muted-color: #{$grey-500};\n --muted-border-color: #{mix($grey-900, $grey-800, 75%)};\n\n // Primary colors\n --primary: #{$primary-600};\n --primary-hover: #{$primary-500};\n --primary-focus: #{rgba($primary-600, 0.25)};\n --primary-inverse: #{$white};\n\n // Secondary colors\n --secondary: #{$grey-600};\n --secondary-hover: #{$grey-500};\n --secondary-focus: #{rgba($grey-500, 0.25)};\n --secondary-inverse: #{$white};\n\n // Contrast colors\n --contrast: #{$grey-50};\n --contrast-hover: #{$white};\n --contrast-focus: #{rgba($grey-500, 0.25)};\n --contrast-inverse: #{$black};\n\n // Highlighted text ()\n --mark-background-color: #{mix($grey-300, $amber-300)};\n --mark-color: #{mix($black, $grey-900, 37.5%)};\n\n // Inserted () & Deleted ()\n --ins-color: #{$green-700};\n --del-color: #{$red-800};\n\n // Blockquote\n --blockquote-border-color: var(--muted-border-color);\n --blockquote-footer-color: var(--muted-color);\n\n // Button\n // To disable box-shadow, remove the var or set to '0 0 0 rgba(0, 0, 0, 0)'\n // Don't use, 'none, 'false, 'null', '0', etc.\n --button-box-shadow: 0 0 0 rgba(0, 0, 0, 0);\n --button-hover-box-shadow: 0 0 0 rgba(0, 0, 0, 0);\n\n // Form elements\n --form-element-background-color: #{mix($black, $grey-900, 37.5%)};\n --form-element-border-color: #{mix($grey-800, $grey-700)};\n --form-element-color: var(--color);\n --form-element-placeholder-color: var(--muted-color);\n --form-element-active-background-color: var(--form-element-background-color);\n --form-element-active-border-color: var(--primary);\n --form-element-focus-color: var(--primary-focus);\n --form-element-disabled-background-color: #{$grey-800};\n --form-element-disabled-border-color: #{$grey-700};\n --form-element-disabled-opacity: 0.5;\n --form-element-invalid-border-color: #{$red-900};\n --form-element-invalid-active-border-color: #{$red-800};\n --form-element-invalid-focus-color: #{rgba($red-800, 0.25)};\n --form-element-valid-border-color: #{$green-800};\n --form-element-valid-active-border-color: #{$green-700};\n --form-element-valid-focus-color: #{rgba($green-700, 0.25)};\n\n // Switch (input[type=\"checkbox\"][role=\"switch\"])\n --switch-background-color: #{mix($grey-800, $grey-700)};\n --switch-color: var(--primary-inverse);\n --switch-checked-background-color: var(--primary);\n\n // Range (input[type=\"range\"])\n --range-border-color: #{mix($grey-900, $grey-800)};\n --range-active-border-color: #{$grey-800};\n --range-thumb-border-color: var(--background-color);\n --range-thumb-color: var(--secondary);\n --range-thumb-hover-color: var(--secondary-hover);\n --range-thumb-active-color: var(--primary);\n\n // Table\n --table-border-color: var(--muted-border-color);\n --table-row-stripped-background-color: #{rgba($grey-500, 0.05)};\n\n // Code\n --code-background-color: #{mix($black, $grey-900, 12.5%)};\n --code-color: var(--muted-color);\n --code-kbd-background-color: var(--contrast);\n --code-kbd-color: var(--contrast-inverse);\n --code-tag-color: #{hsl(330, 30%, 50%)};\n --code-property-color: #{hsl(185, 30%, 50%)};\n --code-value-color: #{hsl(40, 10%, 50%)};\n --code-comment-color: #{mix($grey-700, $grey-600)};\n\n // Accordion (
    )\n --accordion-border-color: var(--muted-border-color);\n --accordion-active-summary-color: var(--primary);\n --accordion-close-summary-color: var(--color);\n --accordion-open-summary-color: var(--muted-color);\n\n // Card (
    )\n $box-shadow-elevation: 1rem;\n $box-shadow-blur-strengh: 6rem;\n $box-shadow-opacity: 0.06;\n --card-background-color: #{mix($black, $grey-900, 25%)};\n --card-border-color: var(--card-background-color);\n --card-box-shadow:\n #{($box-shadow-elevation * 0.5 * 0.029)} #{($box-shadow-elevation * 0.029)} #{($box-shadow-blur-strengh * 0.029)} #{rgba($black, ($box-shadow-opacity * 0.283))},\n #{($box-shadow-elevation * 0.5 * 0.067)} #{($box-shadow-elevation * 0.067)} #{($box-shadow-blur-strengh * 0.067)} #{rgba($black, ($box-shadow-opacity * 0.4))},\n #{($box-shadow-elevation * 0.5 * 0.125)} #{($box-shadow-elevation * 0.125)} #{($box-shadow-blur-strengh * 0.125)} #{rgba($black, ($box-shadow-opacity * 0.5))},\n #{($box-shadow-elevation * 0.5 * 0.225)} #{($box-shadow-elevation * 0.225)} #{($box-shadow-blur-strengh * 0.225)} #{rgba($black, ($box-shadow-opacity * 0.6))},\n #{($box-shadow-elevation * 0.5 * 0.417)} #{($box-shadow-elevation * 0.417)} #{($box-shadow-blur-strengh * 0.417)} #{rgba($black, ($box-shadow-opacity * 0.717))},\n #{($box-shadow-elevation * 0.5)} #{$box-shadow-elevation} #{$box-shadow-blur-strengh} #{rgba($black, $box-shadow-opacity)},\n 0 0 0 0.0625rem #{rgba($black, ($box-shadow-opacity * 0.25) )};\n --card-sectionning-background-color: #{mix($black, $grey-900, 12.5%)};\n\n // Dropdown (
    )\n --dropdown-background-color: #{$grey-900};\n --dropdown-border-color: #{mix($grey-900, $grey-800)};\n --dropdown-box-shadow: var(--card-box-shadow);\n --dropdown-color: var(--color);\n --dropdown-hover-background-color: #{rgba(mix($grey-900, $grey-800), 0.75)};\n\n // Modal ()\n --modal-overlay-background-color: #{rgba(mix($grey-900, $grey-800), 0.8)};\n\n // Progress\n --progress-background-color: #{mix($grey-900, $grey-800)};\n --progress-color: var(--primary);\n\n // Loading ([aria-busy=true])\n --loading-spinner-opacity: 0.5;\n\n // Tooltip ([data-tooltip])\n --tooltip-background-color: var(--contrast);\n --tooltip-color: var(--contrast-inverse);\n\n // Icons\n --icon-checkbox: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($white)}' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-chevron: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($grey-300)}' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-chevron-button: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($white)}' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-chevron-button-inverse: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($black)}' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-close: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($grey-500)}' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E\");\n --icon-date: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($grey-300)}' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E\");\n --icon-invalid: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($red-900)}' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E\");\n --icon-minus: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($white)}' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E\");\n --icon-search: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($grey-300)}' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E\");\n --icon-time: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($grey-300)}' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E\");\n --icon-valid: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($green-800)}' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E\");\n \n // Document\n color-scheme: dark;\n}\n","/**\n * Document\n * Content-box & Responsive typography\n */\n\n// Reboot based on :\n// - normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css\n// - sanitize.css v13.0.0 | CC0 1.0 Universal | github.com/csstools/sanitize.css\n// ––––––––––––––––––––\n\n// 1. Add border box sizing in all browsers (opinionated)\n// 2. Backgrounds do not repeat by default (opinionated)\n*,\n*::before,\n*::after {\n box-sizing: border-box; // 1\n background-repeat: no-repeat; // 2\n}\n\n// 1. Add text decoration inheritance in all browsers (opinionated)\n// 2. Add vertical alignment inheritance in all browsers (opinionated)\n::before,\n::after {\n text-decoration: inherit; // 1\n vertical-align: inherit; // 2\n}\n\n// 1. Use the default cursor in all browsers (opinionated)\n// 2. Change the line height in all browsers (opinionated)\n// 3. Breaks words to prevent overflow in all browsers (opinionated)\n// 4. Use a 4-space tab width in all browsers (opinionated)\n// 5. Remove the grey highlight on links in iOS (opinionated)\n// 6. Prevent adjustments of font size after orientation changes in iOS\n:where(:root) {\n -webkit-tap-highlight-color: transparent; // 5\n -webkit-text-size-adjust: 100%; // 6\n text-size-adjust: 100%; // 6\n background-color: var(--background-color);\n color: var(--color);\n font-weight: var(--font-weight);\n font-size: var(--font-size);\n line-height: var(--line-height); // 2\n font-family: var(--font-family);\n text-rendering: optimizeLegibility;\n overflow-wrap: break-word; // 3\n cursor: default; // 1\n tab-size: 4; // 4\n}\n","/**\n * Sectioning\n * Container and responsive spacings for header, main, footer\n */\n\n// Reboot based on :\n// - normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css\n// - sanitize.css v13.0.0 | CC0 1.0 Universal | github.com/csstools/sanitize.css\n// ––––––––––––––––––––\n\n// Render the `main` element consistently in IE\nmain {\n display: block;\n}\n\n// Pico\n// ––––––––––––––––––––\n\n// 1. Remove the margin in all browsers (opinionated)\n#{$semantic-root-element} {\n width: 100%;\n margin: 0; // 1\n\n > header,\n > main,\n > footer {\n width: 100%;\n margin-right: auto;\n margin-left: auto;\n\n // Semantic container\n @if $enable-semantic-container {\n padding: var(--block-spacing-vertical) var(--block-spacing-horizontal);\n\n // Centered viewport\n @if $enable-viewport {\n @if map-get($breakpoints, \"sm\") and $enable-viewport {\n @media (min-width: map-get($breakpoints, \"sm\")) {\n max-width: map-get($viewports, \"sm\");\n padding-right: 0;\n padding-left: 0;\n }\n }\n\n @if map-get($breakpoints, \"md\") and $enable-viewport {\n @media (min-width: map-get($breakpoints, \"md\")) {\n max-width: map-get($viewports, \"md\");\n }\n }\n\n @if map-get($breakpoints, \"lg\") and $enable-viewport {\n @media (min-width: map-get($breakpoints, \"lg\")) {\n max-width: map-get($viewports, \"lg\");\n }\n }\n\n @if map-get($breakpoints, \"xl\") and $enable-viewport {\n @media (min-width: map-get($breakpoints, \"xl\")) {\n max-width: map-get($viewports, \"xl\");\n }\n }\n }\n }\n\n // Semantic container\n @else {\n padding: var(--block-spacing-vertical) 0;\n }\n }\n}\n","/**\n * Section\n * Responsive spacings for section\n */\n\nsection {\n margin-bottom: var(--block-spacing-vertical);\n}\n","/**\n * Horizontal scroller (
    )\n */\n\n// Wrapper to make any content responsive across all viewports\nfigure {\n display: block;\n margin: 0;\n padding: 0;\n overflow-x: auto;\n\n figcaption {\n padding: calc(var(--spacing) * 0.5) 0;\n color: var(--muted-color);\n }\n}\n","/**\n * Typography\n */\n\n// Reboot based on :\n// - normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css\n// - sanitize.css v13.0.0 | CC0 1.0 Universal | github.com/csstools/sanitize.css\n// ––––––––––––––––––––\n\n// Add the correct font weight in Chrome, Edge, and Safari\nb,\nstrong {\n font-weight: bolder;\n}\n\n// Prevent `sub` and `sup` elements from affecting the line height in all browsers\nsub,\nsup {\n position: relative;\n font-size: 0.75em;\n line-height: 0;\n vertical-align: baseline;\n}\nsub {\n bottom: -0.25em;\n}\nsup {\n top: -0.5em;\n}\n\n// Pico\n// ––––––––––––––––––––\n\naddress,\nblockquote,\ndl,\nfigure,\nform,\nol,\np,\npre,\ntable,\nul {\n margin-top: 0;\n margin-bottom: var(--typography-spacing-vertical);\n color: var(--color);\n font-style: normal;\n font-weight: var(--font-weight);\n font-size: var(--font-size);\n}\n\n// Links\n// 1. Remove the gray background on active links in IE 10\na,\n[role=\"link\"] {\n --color: var(--primary);\n --background-color: transparent;\n outline: none;\n background-color: var(--background-color); // 1\n color: var(--color);\n text-decoration: var(--text-decoration);\n\n @if $enable-transitions {\n transition: background-color var(--transition), color var(--transition),\n text-decoration var(--transition), box-shadow var(--transition);\n }\n\n &:is([aria-current], :hover, :active, :focus) {\n --color: var(--primary-hover);\n --text-decoration: underline;\n }\n\n &:focus {\n --background-color: var(--primary-focus);\n }\n\n @if $enable-classes {\n // Secondary\n &.secondary {\n --color: var(--secondary);\n\n &:is([aria-current], :hover, :active, :focus) {\n --color: var(--secondary-hover);\n }\n\n &:focus {\n --background-color: var(--secondary-focus);\n }\n }\n\n // Contrast\n &.contrast {\n --color: var(--contrast);\n\n &:is([aria-current], :hover, :active, :focus) {\n --color: var(--contrast-hover);\n }\n\n &:focus {\n --background-color: var(--contrast-focus);\n }\n }\n }\n}\n\n// Headings\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n margin-top: 0;\n margin-bottom: var(--typography-spacing-vertical);\n color: var(--color);\n font-weight: var(--font-weight);\n font-size: var(--font-size);\n font-family: var(--font-family);\n}\n\nh1 {\n --color: var(--h1-color);\n}\nh2 {\n --color: var(--h2-color);\n}\nh3 {\n --color: var(--h3-color);\n}\nh4 {\n --color: var(--h4-color);\n}\nh5 {\n --color: var(--h5-color);\n}\nh6 {\n --color: var(--h6-color);\n}\n\n// Margin-top for headings after a typography block\n:where(address, blockquote, dl, figure, form, ol, p, pre, table, ul) {\n ~ :is(h1, h2, h3, h4, h5, h6) {\n margin-top: var(--typography-spacing-vertical);\n }\n}\n\n// Heading group\n@if $enable-classes == false {\n hgroup {\n margin-bottom: var(--typography-spacing-vertical);\n\n > * {\n margin-bottom: 0;\n }\n\n > *:last-child {\n --color: var(--muted-color);\n --font-weight: unset;\n font-size: 1rem;\n font-family: unset;\n }\n }\n}\n\n@if $enable-classes {\n hgroup,\n .headings {\n margin-bottom: var(--typography-spacing-vertical);\n\n > * {\n margin-bottom: 0;\n }\n\n > *:last-child {\n --color: var(--muted-color);\n --font-weight: unset;\n font-size: 1rem;\n font-family: unset;\n }\n }\n}\n\n// Paragraphs\np {\n margin-bottom: var(--typography-spacing-vertical);\n}\n\n// Small\nsmall {\n font-size: var(--font-size);\n}\n\n// Lists\n:where(dl, ol, ul) {\n padding-right: 0;\n padding-left: var(--spacing);\n padding-inline-start: var(--spacing);\n padding-inline-end: 0;\n\n li {\n margin-bottom: calc(var(--typography-spacing-vertical) * 0.25);\n }\n}\n\n// Margin-top for nested lists\n// 1. Remove the margin on nested lists in Chrome, Edge, IE, and Safari\n:where(dl, ol, ul) {\n :is(dl, ol, ul) {\n margin: 0; // 1\n margin-top: calc(var(--typography-spacing-vertical) * 0.25);\n }\n}\n\nul li {\n list-style: square;\n}\n\n// Highlighted text\nmark {\n padding: 0.125rem 0.25rem;\n background-color: var(--mark-background-color);\n color: var(--mark-color);\n vertical-align: baseline;\n}\n\n// Blockquote\nblockquote {\n display: block;\n margin: var(--typography-spacing-vertical) 0;\n padding: var(--spacing);\n border-right: none;\n border-left: 0.25rem solid var(--blockquote-border-color);\n border-inline-start: 0.25rem solid var(--blockquote-border-color);\n border-inline-end: none;\n\n footer {\n margin-top: calc(var(--typography-spacing-vertical) * 0.5);\n color: var(--blockquote-footer-color);\n }\n}\n\n// Abbreviations\n// 1. Remove underline decoration in Chrome, Edge, IE, Opera, and Safari\nabbr[title] {\n border-bottom: 1px dotted;\n text-decoration: none; // 1\n cursor: help;\n}\n\n// Ins\nins {\n color: var(--ins-color);\n text-decoration: none;\n}\n\n// del\ndel {\n color: var(--del-color);\n}\n\n// selection\n::selection {\n background-color: var(--primary-focus);\n}\n","/**\n * Embedded content\n */\n\n// Reboot based on :\n// - normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css\n// - sanitize.css v13.0.0 | CC0 1.0 Universal | github.com/csstools/sanitize.css\n// ––––––––––––––––––––\n\n// Change the alignment on media elements in all browsers (opinionated)\n:where(audio, canvas, iframe, img, svg, video) {\n vertical-align: middle;\n}\n\n// Add the correct display in IE 9-\naudio,\nvideo {\n display: inline-block;\n}\n\n// Add the correct display in iOS 4-7\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n\n// Remove the border on iframes in all browsers (opinionated)\n:where(iframe) {\n border-style: none;\n}\n\n// 1. Remove the border on images inside links in IE 10.\n// 2. Responsive by default\nimg {\n max-width: 100%; // 2\n height: auto; // 2\n border-style: none; // 1\n}\n\n// Change the fill color to match the text color in all browsers (opinionated)\n:where(svg:not([fill])) {\n fill: currentColor;\n}\n\n// Hide the overflow in IE\nsvg:not(:root) {\n overflow: hidden;\n}\n","/**\n * Button\n */\n\n// Reboot based on :\n// - normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css\n// - sanitize.css v13.0.0 | CC0 1.0 Universal | github.com/csstools/sanitize.css\n// ––––––––––––––––––––\n\n// 1. Change the font styles in all browsers\n// 2. Remove the margin on controls in Safari\n// 3. Show the overflow in Edge\nbutton {\n margin: 0; // 2\n overflow: visible; // 3\n font-family: inherit; // 1\n text-transform: none; // 1\n}\n\n// Correct the inability to style buttons in iOS and Safari\nbutton,\n[type=\"button\"],\n[type=\"reset\"],\n[type=\"submit\"] {\n -webkit-appearance: button;\n}\n\n// Pico\n// ––––––––––––––––––––\n\nbutton {\n display: block;\n width: 100%;\n margin-bottom: var(--spacing);\n}\n\n[role=\"button\"] {\n display: inline-block;\n text-decoration: none;\n}\n\nbutton,\ninput[type=\"submit\"],\ninput[type=\"button\"],\ninput[type=\"reset\"],\n[role=\"button\"] {\n --background-color: var(--primary);\n --border-color: var(--primary);\n --color: var(--primary-inverse);\n --box-shadow: var(--button-box-shadow, 0 0 0 rgba(0, 0, 0, 0));\n padding: var(--form-element-spacing-vertical)\n var(--form-element-spacing-horizontal);\n border: var(--border-width) solid var(--border-color);\n border-radius: var(--border-radius);\n outline: none;\n background-color: var(--background-color);\n box-shadow: var(--box-shadow);\n color: var(--color);\n font-weight: var(--font-weight);\n font-size: 1rem;\n line-height: var(--line-height);\n text-align: center;\n cursor: pointer;\n\n @if $enable-transitions {\n transition: background-color var(--transition),\n border-color var(--transition), color var(--transition),\n box-shadow var(--transition);\n }\n\n &:is([aria-current], :hover, :active, :focus) {\n --background-color: var(--primary-hover);\n --border-color: var(--primary-hover);\n --box-shadow: var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0));\n --color: var(--primary-inverse);\n }\n\n &:focus {\n --box-shadow: var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),\n 0 0 0 var(--outline-width) var(--primary-focus);\n }\n}\n\n// .secondary, .contrast & .outline\n@if $enable-classes {\n\n // Secondary\n :is(button, input[type=\"submit\"], input[type=\"button\"], [role=\"button\"]).secondary,\n input[type=\"reset\"] {\n --background-color: var(--secondary);\n --border-color: var(--secondary);\n --color: var(--secondary-inverse);\n cursor: pointer;\n\n &:is([aria-current], :hover, :active, :focus) {\n --background-color: var(--secondary-hover);\n --border-color: var(--secondary-hover);\n --color: var(--secondary-inverse);\n }\n\n &:focus {\n --box-shadow: var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),\n 0 0 0 var(--outline-width) var(--secondary-focus);\n }\n }\n\n // Contrast\n :is(button, input[type=\"submit\"], input[type=\"button\"], [role=\"button\"]).contrast {\n --background-color: var(--contrast);\n --border-color: var(--contrast);\n --color: var(--contrast-inverse);\n\n &:is([aria-current], :hover, :active, :focus) {\n --background-color: var(--contrast-hover);\n --border-color: var(--contrast-hover);\n --color: var(--contrast-inverse);\n }\n\n &:focus {\n --box-shadow: var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),\n 0 0 0 var(--outline-width) var(--contrast-focus);\n }\n }\n\n // Outline (primary)\n :is(button, input[type=\"submit\"], input[type=\"button\"], [role=\"button\"]).outline,\n input[type=\"reset\"].outline {\n --background-color: transparent;\n --color: var(--primary);\n\n &:is([aria-current], :hover, :active, :focus) {\n --background-color: transparent;\n --color: var(--primary-hover);\n }\n }\n\n // Outline (secondary)\n :is(button, input[type=\"submit\"], input[type=\"button\"], [role=\"button\"]).outline.secondary,\n input[type=\"reset\"].outline {\n --color: var(--secondary);\n\n &:is([aria-current], :hover, :active, :focus) {\n --color: var(--secondary-hover);\n }\n }\n\n // Outline (contrast)\n :is(button, input[type=\"submit\"], input[type=\"button\"], [role=\"button\"]).outline.contrast {\n --color: var(--contrast);\n\n &:is([aria-current], :hover, :active, :focus) {\n --color: var(--contrast-hover);\n }\n }\n} \n@else {\n // Secondary button without .class\n input[type=\"reset\"] {\n --background-color: var(--secondary);\n --border-color: var(--secondary);\n --color: var(--secondary-inverse);\n cursor: pointer;\n\n &:is([aria-current], :hover, :active, :focus) {\n --background-color: var(--secondary-hover);\n --border-color: var(--secondary-hover);\n }\n\n &:focus {\n --box-shadow: var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),\n 0 0 0 var(--outline-width) var(--secondary-focus);\n }\n }\n}\n\n// Button [disabled]\n// Links without href are disabled by default\n:where(button, [type=\"submit\"], [type=\"button\"], [type=\"reset\"], [role=\"button\"])[disabled],\n:where(fieldset[disabled]) :is(button, [type=\"submit\"], [type=\"button\"], [type=\"reset\"], [role=\"button\"]),\na[role=\"button\"]:not([href]) {\n opacity: 0.5;\n pointer-events: none;\n}\n","/**\n * Form elements\n */\n\n// Reboot based on :\n// - normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css\n// - sanitize.css v13.0.0 | CC0 1.0 Universal | github.com/csstools/sanitize.css\n// ––––––––––––––––––––\n\n// 1. Change the font styles in all browsers\n// 2. Remove the margin in Firefox and Safari\ninput,\noptgroup,\nselect,\ntextarea {\n margin: 0; // 2\n font-size: 1rem; // 1\n line-height: var(--line-height); // 1\n font-family: inherit; // 1\n letter-spacing: inherit; // 2\n}\n\n// Show the overflow in IE.\ninput {\n overflow: visible;\n}\n\n// Remove the inheritance of text transform in Edge, Firefox, and IE\nselect {\n text-transform: none;\n}\n\n// 1. Correct the text wrapping in Edge and IE\n// 2. Correct the color inheritance from `fieldset` elements in IE\n// 3. Remove the padding so developers are not caught out when they zero out\n// `fieldset` elements in all browsers\nlegend {\n max-width: 100%; // 1\n padding: 0; // 3\n color: inherit; // 2\n white-space: normal; // 1\n}\n\n// 1. Remove the default vertical scrollbar in IE\ntextarea {\n overflow: auto; // 1\n}\n\n// Remove the padding in IE 10\n[type=\"checkbox\"],\n[type=\"radio\"] {\n padding: 0;\n}\n\n// Correct the cursor style of increment and decrement buttons in Safari\n::-webkit-inner-spin-button,\n::-webkit-outer-spin-button {\n height: auto;\n}\n\n// 1. Correct the odd appearance in Chrome and Safari\n// 2. Correct the outline style in Safari\n[type=\"search\"] {\n -webkit-appearance: textfield; // 1\n outline-offset: -2px; // 2\n}\n\n// Remove the inner padding in Chrome and Safari on macOS\n[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n// 1. Correct the inability to style clickable types in iOS and Safari\n// 2. Change font properties to `inherit` in Safari\n::-webkit-file-upload-button {\n -webkit-appearance: button; // 1\n font: inherit; // 2\n}\n\n// Remove the inner border and padding of focus outlines in Firefox\n::-moz-focus-inner {\n padding: 0;\n border-style: none;\n}\n\n// Remove the focus outline in Firefox\n:-moz-focusring {\n outline: none;\n}\n\n// Remove the additional :invalid styles in Firefox\n:-moz-ui-invalid {\n box-shadow: none;\n}\n\n// Change the inconsistent appearance in IE (opinionated)\n::-ms-expand {\n display: none;\n}\n\n// Remove the border and padding in all browsers (opinionated)\n[type=\"file\"],\n[type=\"range\"] {\n padding: 0;\n border-width: 0;\n}\n\n// Pico\n// ––––––––––––––––––––\n\n// Force height for alternatives input types\ninput:not([type=\"checkbox\"], [type=\"radio\"], [type=\"range\"]) {\n height: calc(\n (1rem * var(--line-height)) + (var(--form-element-spacing-vertical) * 2) +\n (var(--border-width) * 2)\n );\n}\n\n// Fieldset\nfieldset {\n margin: 0;\n margin-bottom: var(--spacing);\n padding: 0;\n border: 0;\n}\n\n// Label & legend\nlabel,\nfieldset legend {\n display: block;\n margin-bottom: calc(var(--spacing) * 0.25);\n font-weight: var(--form-label-font-weight, var(--font-weight));\n}\n\n// Blocks, 100%\ninput:not([type=\"checkbox\"], [type=\"radio\"]),\nselect,\ntextarea {\n width: 100%;\n}\n\n// Reset appearance (Not Checkboxes, Radios, Range and File)\ninput:not([type=\"checkbox\"], [type=\"radio\"], [type=\"range\"], [type=\"file\"]),\nselect,\ntextarea {\n appearance: none;\n padding: var(--form-element-spacing-vertical)\n var(--form-element-spacing-horizontal);\n}\n\n// Commons styles\ninput,\nselect,\ntextarea {\n --background-color: var(--form-element-background-color);\n --border-color: var(--form-element-border-color);\n --color: var(--form-element-color);\n --box-shadow: none;\n border: var(--border-width) solid var(--border-color);\n border-radius: var(--border-radius);\n outline: none;\n background-color: var(--background-color);\n box-shadow: var(--box-shadow);\n color: var(--color);\n font-weight: var(--font-weight);\n\n @if $enable-transitions {\n transition: background-color var(--transition),\n border-color var(--transition), color var(--transition),\n box-shadow var(--transition);\n }\n}\n\n// Active & Focus\ninput:not([type=\"submit\"], [type=\"button\"], [type=\"reset\"], [type=\"checkbox\"], [type=\"radio\"], [readonly]),\n:where(select, textarea) {\n &:is(:active, :focus) {\n --background-color: var(--form-element-active-background-color);\n }\n}\n\n// Active & Focus\ninput:not([type=\"submit\"], [type=\"button\"], [type=\"reset\"], [role=\"switch\"], [readonly]),\n:where(select, textarea) {\n &:is(:active, :focus) {\n --border-color: var(--form-element-active-border-color);\n }\n}\n\n// Focus\ninput:not([type=\"submit\"], [type=\"button\"], [type=\"reset\"], [type=\"range\"], [type=\"file\"], [readonly]),\nselect,\ntextarea {\n &:focus {\n --box-shadow: 0 0 0 var(--outline-width) var(--form-element-focus-color);\n }\n}\n\n// Disabled\ninput:not([type=\"submit\"], [type=\"button\"], [type=\"reset\"])[disabled],\nselect[disabled],\ntextarea[disabled],\n:where(fieldset[disabled]) :is(input:not([type=\"submit\"], [type=\"button\"], [type=\"reset\"]), select, textarea) {\n --background-color: var(--form-element-disabled-background-color);\n --border-color: var(--form-element-disabled-border-color);\n opacity: var(--form-element-disabled-opacity);\n pointer-events: none;\n}\n\n// Aria-invalid\n:where(input, select, textarea) {\n &:not([type=\"checkbox\"], [type=\"radio\"], [type=\"date\"], [type=\"datetime-local\"], [type=\"month\"], [type=\"time\"], [type=\"week\"]) {\n &[aria-invalid] {\n @if $enable-important {\n padding-right: calc(\n var(--form-element-spacing-horizontal) + 1.5rem\n ) !important;\n padding-left: var(--form-element-spacing-horizontal);\n padding-inline-start: var(--form-element-spacing-horizontal) !important;\n padding-inline-end: calc(\n var(--form-element-spacing-horizontal) + 1.5rem\n ) !important;\n }\n @else {\n padding-right: calc(var(--form-element-spacing-horizontal) + 1.5rem);\n padding-left: var(--form-element-spacing-horizontal);\n padding-inline-start: var(--form-element-spacing-horizontal);\n padding-inline-end: calc(var(--form-element-spacing-horizontal) + 1.5rem);\n }\n background-position: center right 0.75rem;\n background-size: 1rem auto;\n background-repeat: no-repeat;\n }\n\n &[aria-invalid=\"false\"] {\n background-image: var(--icon-valid);\n }\n\n &[aria-invalid=\"true\"] {\n background-image: var(--icon-invalid);\n }\n }\n\n &[aria-invalid=\"false\"] {\n --border-color: var(--form-element-valid-border-color);\n\n &:is(:active, :focus) {\n @if $enable-important {\n --border-color: var(--form-element-valid-active-border-color) !important;\n --box-shadow: 0 0 0 var(--outline-width) var(--form-element-valid-focus-color) !important;\n }\n @else {\n --border-color: var(--form-element-valid-active-border-color);\n --box-shadow: 0 0 0 var(--outline-width) var(--form-element-valid-focus-color);\n }\n }\n }\n\n &[aria-invalid=\"true\"] {\n --border-color: var(--form-element-invalid-border-color);\n\n &:is(:active, :focus) {\n @if $enable-important {\n --border-color: var(--form-element-invalid-active-border-color) !important;\n --box-shadow: 0 0 0 var(--outline-width) var(--form-element-invalid-focus-color) !important;\n }\n @else {\n --border-color: var(--form-element-invalid-active-border-color);\n --box-shadow: 0 0 0 var(--outline-width) var(--form-element-invalid-focus-color);\n }\n }\n }\n}\n\n[dir=\"rtl\"] {\n :where(input, select, textarea) {\n &:not([type=\"checkbox\"], [type=\"radio\"]) {\n &:is([aria-invalid], [aria-invalid=\"true\"], [aria-invalid=\"false\"] ){\n background-position: center left 0.75rem;\n }\n }\n }\n}\n\n// Placeholder\ninput::placeholder,\ninput::-webkit-input-placeholder,\ntextarea::placeholder,\ntextarea::-webkit-input-placeholder,\nselect:invalid {\n color: var(--form-element-placeholder-color);\n opacity: 1;\n}\n\n// Margin bottom (Not Checkboxes and Radios)\ninput:not([type=\"checkbox\"], [type=\"radio\"]),\nselect,\ntextarea {\n margin-bottom: var(--spacing);\n}\n\n// Select\nselect {\n // Unstyle the caret on `\n summary {\n margin-bottom: 0;\n\n &:not([role]) {\n height: calc(\n 1rem * var(--line-height) + var(--form-element-spacing-vertical) * 2 +\n var(--border-width) * 2\n );\n padding: var(--form-element-spacing-vertical)\n var(--form-element-spacing-horizontal);\n border: var(--border-width) solid var(--form-element-border-color);\n border-radius: var(--border-radius);\n background-color: var(--form-element-background-color);\n color: var(--form-element-placeholder-color);\n line-height: inherit;\n cursor: pointer;\n\n @if $enable-transitions {\n transition: background-color var(--transition),\n border-color var(--transition), color var(--transition),\n box-shadow var(--transition);\n }\n\n &:active,\n &:focus {\n border-color: var(--form-element-active-border-color);\n background-color: var(--form-element-active-background-color);\n }\n\n &:focus {\n box-shadow: 0 0 0 var(--outline-width) var(--form-element-focus-color);\n }\n }\n }\n\n // Close for details[role=\"list\"]\n &[open] summary {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n\n &::before {\n display: block;\n z-index: 1;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n background: none;\n content: \"\";\n cursor: default;\n }\n }\n}\n\n// All Dropdowns inside