Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
556 changes: 556 additions & 0 deletions AGENTS.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ test:

fmt:
go fmt ./... && \
goimports -w -local github.com/MontFerret ./pkg/browser ./cmd ./pkg/config ./ferret ./pkg/logger ./pkg/repl ./pkg/runtime
goimports -w -local github.com/MontFerret ./pkg/browser ./cmd ./pkg/debugger ./pkg/config ./ferret ./pkg/logger ./pkg/repl ./pkg/runtime

lint:
staticcheck ./... && \
revive -config revive.toml -formatter stylish -exclude ./pkg/parser/fql/... -exclude ./vendor/... ./...
revive -config revive.toml -formatter stylish -exclude ./vendor/... ./...


vet:
Expand Down
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ ferret run example.fql

> **Note:** `exec` is an alias for `run` — both work interchangeably.

Debug a local source script interactively:

```bash
ferret debug example.fql
```

### Browser Automation

For JavaScript-heavy sites, use browser automation:
Expand Down Expand Up @@ -203,6 +209,7 @@ Available Commands:
build Compile FQL scripts into bytecode artifacts
check Check FQL scripts for syntax and semantic errors
config Manage Ferret configs
debug Debug a FQL script interactively
fmt Format FQL scripts
inspect Compile and disassemble a FQL script
repl Launch interactive FQL shell
Expand Down Expand Up @@ -242,6 +249,44 @@ ferret exec [script] # alias

Compiled artifacts are auto-detected by content for file inputs and piped stdin, so artifacts produced by `ferret build` work even when they do not use a `.fqlc` filename. Artifact execution currently requires the builtin runtime.

### debug

Launch the local source-level debugger for one FQL script:

```bash
ferret debug example.fql
ferret debug example.fql --param limit=10
```

The debugger accepts the same runtime, browser, and repeatable `--param name=value` flags as `run`, but currently requires the builtin runtime and a source file.

```
Commands:
break <location> Set at next executable location in file
break --exact <location> Set only at the exact executable location
break --next <location> Set at next executable location in file
break --in-function <location> Set at next executable location in function
breakpoints List breakpoints
delete <id> Delete breakpoint
continue Resume execution
step Step into next source location
next Step over current source location
out Step out of current frame
pause Pause at the next source location
where Show stack trace
locals Show local variables
print <expr> Evaluate a safe debug expression
quit Stop debugging and exit
```

Breakpoint locations may be written as `12`, `12:4`, `file.fql:12`, or `file.fql:12:4`. The default and `--next` modes bind to the next executable location in the file; `--exact` requires an exact executable location, and `--in-function` stays within the current function context.

`print` uses the conservative debugger evaluator. It supports locals, parameters, literals, member access, scalar arithmetic and comparisons, boolean logic, and conditionals. It does not execute function calls, queries, mutation, asynchronous behavior, or full collection expressions.

Aliases: `b` = `break`, `c` = `continue`, `s` = `step`, `n` = `next`, `bt` = `where`, `p` = `print`, and `q` = `quit`.

Phase 1 does not support compiled artifacts, stdin, inline evaluation, remote debugging, DAP, VS Code integration, conditional or hit-count breakpoints, logpoints, variable mutation, tracing, record/replay, or module-specific inspectors.

### repl

Launch the interactive FQL shell. Supports command history, multiline input (toggle with `%`), and all runtime flags.
Expand Down
87 changes: 87 additions & 0 deletions cmd/debug.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package cmd

import (
"fmt"

"github.com/spf13/cobra"

"github.com/MontFerret/cli/v2/pkg/browser"
"github.com/MontFerret/cli/v2/pkg/config"
"github.com/MontFerret/cli/v2/pkg/debugger"
clirun "github.com/MontFerret/cli/v2/pkg/run"
cliruntime "github.com/MontFerret/cli/v2/pkg/runtime"
)

func DebugCommand(store *config.Store) *cobra.Command {
cmd := &cobra.Command{
Use: "debug <script.fql>",
Short: "Debug a FQL script interactively",
Long: `Debug a local FQL source script using the interactive Ferret debugger.

Prompt commands: help, break, delete, breakpoints, continue, step, next, out,
pause, where, locals, print, and quit.

Debugging currently requires the builtin runtime and does not support compiled
artifacts, stdin, inline evaluation, remote runtimes, or conditional breakpoints.`,
Args: cobra.ExactArgs(1),
PreRun: func(cmd *cobra.Command, _ []string) {
store.BindFlags(cmd)
},
RunE: func(cmd *cobra.Command, args []string) error {
paramFlags, err := cmd.Flags().GetStringArray(paramFlag)
if err != nil {
return err
}

params, err := parseParams(paramFlags)
if err != nil {
return err
}

store := config.From(cmd.Context())
return executeDebug(cmd, store.GetRuntimeOptions(), store.GetBrowserOptions(), params, args)
},
}

addParamFlags(cmd)
addRuntimeFlags(cmd)

return cmd
}

func executeDebug(cmd *cobra.Command, rtOpts cliruntime.Options, brOpts browser.Options, params map[string]any, args []string) error {
input, err := clirun.ResolveInput("", args)
if err != nil {
return err
}

if input != nil && len(input.Artifact) > 0 {
return fmt.Errorf("debugging compiled artifacts is not supported yet; run debug with the original .fql source file")
}

if input == nil || input.Source == nil {
return fmt.Errorf("debug requires a source script file")
}

if err := cliruntime.ValidateOptions(rtOpts); err != nil {
return err
}

if !cliruntime.IsBuiltinType(rtOpts.Type) {
return cliruntime.ErrDebugRequiresBuiltinRuntime
}

cleanup, err := browser.EnsureBrowser(cmd.Context(), rtOpts, brOpts)
if err != nil {
return err
}
defer cleanup()

session, err := cliruntime.NewDebugSession(cmd.Context(), rtOpts, params, input.Source)
if err != nil {
printError(err)
return err
}

return debugger.Start(cmd.Context(), session, input.Source)
}
90 changes: 90 additions & 0 deletions cmd/debug_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package cmd

import (
"context"
"errors"
"path/filepath"
"testing"

"github.com/MontFerret/ferret/v2/pkg/compiler"
"github.com/MontFerret/ferret/v2/pkg/source"

"github.com/MontFerret/cli/v2/pkg/browser"
"github.com/MontFerret/cli/v2/pkg/build"
"github.com/MontFerret/cli/v2/pkg/config"
cliruntime "github.com/MontFerret/cli/v2/pkg/runtime"
)

func TestDebugCommandRequiresExactlyOneScript(t *testing.T) {
command := DebugCommand(new(config.Store))

if err := command.Args(command, nil); err == nil {
t.Fatal("expected missing argument error")
}
if err := command.Args(command, []string{"one.fql", "two.fql"}); err == nil {
t.Fatal("expected too many arguments error")
}
if err := command.Args(command, []string{"one.fql"}); err != nil {
t.Fatalf("unexpected argument error: %v", err)
}
}

func TestExecuteDebugRejectsRemoteRuntimeBeforeStarting(t *testing.T) {
path := filepath.Join(t.TempDir(), "query.fql")
writeQuery(t, path, "RETURN 1")

err := executeDebug(
newTestCommand(),
cliruntime.Options{Type: "https://worker.example"},
browser.Options{},
nil,
[]string{path},
)
if !errors.Is(err, cliruntime.ErrDebugRequiresBuiltinRuntime) {
t.Fatalf("expected builtin runtime error, got %v", err)
}
if got := err.Error(); got != "debug currently supports only the builtin runtime" {
t.Fatalf("unexpected builtin runtime error: %q", got)
}
}

func TestExecuteDebugRejectsArtifact(t *testing.T) {
dir := t.TempDir()
sourcePath := filepath.Join(dir, "query.fql")
artifactPath := filepath.Join(dir, "query.fqlc")
writeQuery(t, sourcePath, "RETURN 1")
if err := build.WriteArtifact(compiler.New(), source.New(sourcePath, "RETURN 1"), artifactPath); err != nil {
t.Fatal(err)
}

err := executeDebug(
newTestCommand(),
cliruntime.NewDefaultOptions(),
browser.Options{},
nil,
[]string{artifactPath},
)
if err == nil || err.Error() != "debugging compiled artifacts is not supported yet; run debug with the original .fql source file" {
t.Fatalf("unexpected error: %v", err)
}
}

func TestDebugCommandUsesSharedParamFlags(t *testing.T) {
command := DebugCommand(new(config.Store))
command.SetContext(config.With(context.Background(), new(config.Store)))

if err := command.Flags().Set(paramFlag, "limit=2"); err != nil {
t.Fatal(err)
}
values, err := command.Flags().GetStringArray(paramFlag)
if err != nil {
t.Fatal(err)
}
params, err := parseParams(values)
if err != nil {
t.Fatal(err)
}
if params["limit"] != float64(2) {
t.Fatalf("unexpected params: %#v", params)
}
}
1 change: 1 addition & 0 deletions ferret/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ func main() {
cmd.VersionCommand(store),
cmd.ConfigCommand(store),
cmd.RunCommand(store),
cmd.DebugCommand(store),
cmd.ReplCommand(store),
cmd.FormatCommand(store),
cmd.CheckCommand(store),
Expand Down
9 changes: 6 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ require (
github.com/MontFerret/contrib/modules/web/sitemap v1.0.0-rc.3
github.com/MontFerret/contrib/modules/xml v1.0.0-rc.3
github.com/MontFerret/contrib/modules/yaml v1.0.0-rc.3
github.com/MontFerret/ferret/v2 v2.0.0-alpha.22
github.com/MontFerret/ferret/v2 v2.0.0-alpha.23
github.com/chzyer/readline v1.5.1
github.com/go-waitfor/waitfor v1.1.0
github.com/go-waitfor/waitfor-http v1.1.0
Expand Down Expand Up @@ -43,7 +43,7 @@ require (
github.com/gobwas/glob v0.2.3 // indirect
github.com/goccy/go-json v0.10.6 // indirect
github.com/goccy/go-yaml v1.19.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/gorilla/css v1.0.1 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
Expand All @@ -52,6 +52,7 @@ require (
github.com/mattn/go-isatty v0.0.22 // indirect
github.com/microcosm-cc/bluemonday v1.0.27 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/sagikazarmark/locafero v0.11.0 // indirect
github.com/sethgrid/pester v1.2.0 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
Expand All @@ -62,10 +63,12 @@ require (
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/wI2L/jettison v0.7.4 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect
golang.org/x/net v0.55.0 // indirect
golang.org/x/sync v0.20.0 // indirect
golang.org/x/sys v0.45.0 // indirect
golang.org/x/text v0.37.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
26 changes: 15 additions & 11 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ github.com/MontFerret/contrib/modules/yaml v1.0.0-rc.3 h1:sDHD9uddxr7ZboF7qKgHRg
github.com/MontFerret/contrib/modules/yaml v1.0.0-rc.3/go.mod h1:oxsS3gWk2tYqIGi+PCxuqTPVZRAxHwpdnrX7XJOcjbw=
github.com/MontFerret/cssx v0.2.0 h1:De0C6Irbg+qgFPXgWmPpVnwD4RRYUBQSbIYFTUVCNWU=
github.com/MontFerret/cssx v0.2.0/go.mod h1:fmGtRUNVaeJYpiPSDlNIbbYzb3+K8NxmNmJOYqlHATU=
github.com/MontFerret/ferret/v2 v2.0.0-alpha.22 h1:3N68LO1Fw5IEpyc479ibaF6AVlDcc+a5IeookVHQNxA=
github.com/MontFerret/ferret/v2 v2.0.0-alpha.22/go.mod h1:xnhO/65Sa17LSRC8GLIO51JZ4Wm08JjEtmowGVut4z0=
github.com/MontFerret/ferret/v2 v2.0.0-alpha.23 h1:K4b1sfWkFsNlz4+cLy9VV4FZdDZKplTIF8jIbmN+gAU=
github.com/MontFerret/ferret/v2 v2.0.0-alpha.23/go.mod h1:g3crJNLHr8i1g+GO9YX8ohYqbey3atUZmtpyJM7wcgA=
github.com/PuerkitoBio/goquery v1.12.0 h1:pAcL4g3WRXekcB9AU/y1mbKez2dbY2AajVhtkO8RIBo=
github.com/PuerkitoBio/goquery v1.12.0/go.mod h1:802ej+gV2y7bbIhOIoPY5sT183ZW0YFofScC4q/hIpQ=
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
Expand Down Expand Up @@ -70,8 +70,9 @@ github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU=
github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
Expand All @@ -89,8 +90,11 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mafredri/cdp v0.35.0 h1:fKQ6LbcH3WsxVrWbi/DSgLunJTqmF5o/7w8iFDDj71c=
Expand All @@ -116,8 +120,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/rs/zerolog v1.35.1 h1:m7xQeoiLIiV0BCEY4Hs+j2NG4Gp2o2KPKmhnnLiazKI=
github.com/rs/zerolog v1.35.1/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
Expand Down Expand Up @@ -173,8 +177,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM=
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
Expand Down Expand Up @@ -244,11 +248,11 @@ golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Loading
Loading