把代码赚到了exam模块里,专门用来测试的

This commit is contained in:
zhangkun9038@dingtalk.com 2025-03-01 23:18:49 +08:00
parent 9e90da5bdb
commit 0a7f5c8fa2
8 changed files with 253 additions and 151 deletions

View File

@ -2,157 +2,8 @@ package main
import ( import (
"fmt" "fmt"
// "gitea.zjmud.xyz/phyer/blingo/cache"
// "gitea.zjmud.xyz/phyer/blingo/collector"
// "gitea.zjmud.xyz/phyer/blingo/config"
// "gitea.zjmud.xyz/phyer/blingo/feature_processor"
// "gitea.zjmud.xyz/phyer/blingo/scheduler"
// "gitea.zjmud.xyz/phyer/blingo/storage"
// "log"
// "error"
ccxt "gitea.zjmud.xyz/ext/ccxt-go"
"os"
"os/exec"
// "net/http"
"time"
) )
func main() { func main() {
fmt.Println("this is main")
// 1. 创建 OKX 交易所实例
okx := ccxt.NewOkx(map[string]interface{}{
"apiKey": "fe468418-5e40-433f-8d04-04951286d417",
"secret": "D6D74DF9DD60A25BE2B27CA71D8F814D",
"password": "M4pw71Id",
"hostname": "aws.okx.com",
})
// 3. 可选:自定义 HTTP 客户端配置
// okx.HttpClient.Timeout = 15 * time.Second
okx.EnableRateLimit = true // 启用内置速率限制
// 4. 加载市场数据(关键步骤!)
marketsChan := okx.LoadMarkets()
select {
case marketsResult := <-marketsChan:
switch v := marketsResult.(type) {
case error:
panic(fmt.Errorf("加载市场数据失败: %v", v))
case string:
panic(fmt.Errorf("加载市场数据失败: %v", v))
case map[string]interface{}:
okx.Markets = v
default:
panic(fmt.Errorf("加载市场数据失败: 未知类型的结果"))
}
case <-time.After(30 * time.Second):
panic(fmt.Errorf("加载市场数据超时"))
}
fmt.Println("OKX 初始化完成,已加载", len(okx.Markets), "个交易对")
// 获取ticker数据
symbol := "BTC/USDT"
// ticker, err := okx.FetchTicker(symbol)
// if err != nil {
// fmt.Println("获取ticker数据错误:", err)
// return
// }
// fmt.Println("ticker数据:", ticker)
// 获取BTC/USDT的1分钟K线数据
// 创建一个 FetchOHLCVOptionsStruct 实例
//
// // 使用 WithFetchOHLCVTimeframe 设置时间框架
// ccxt.WithFetchOHLCVTimeframe("1h")(opts)
//
// // 使用 WithFetchOHLCVSince 设置开始时间
// ccxt.WithFetchOHLCVSince(1672531200)(opts) // 示例时间戳
//
// // 使用 WithFetchOHLCVLimit 设置最大数量
// ccxt.WithFetchOHLCVLimit(100)(opts)
// 使用 WithFetchOHLCVParams 设置其他参数
// params := map[string]interface{}{
// "adjustForTimezone": true,
// "includeHighLow": false,
// }
// ccxt.WithFetchOHLCVParams(params)(opts)
// 打印设置后的 opts
// fmt.Printf("%+v\n", opts)
tf := "1h"
sc := int64(1672502400000)
lm := int64(1000)
pm := map[string]interface{}{
"rateLimit": true, // Hypothetical parameter to enable rate limiting
}
ohlcv, err := okx.FetchOHLCV(symbol,
ccxt.WithFetchOHLCVSince(sc),
ccxt.WithFetchOHLCVTimeframe(tf),
ccxt.WithFetchOHLCVLimit(lm),
ccxt.WithFetchOHLCVParams(pm))
if err != nil {
fmt.Println("Error fetching OHLCV:", err)
return
}
fmt.Println("ohlcv: ", ohlcv)
// 检查并删除旧文件
fileName := "ohlcv-btc.csv"
destName := "/tmp/blingo/python/" + fileName
if _, err := os.Stat(destName); err == nil {
// 文件存在,删除它
if err := os.Remove(destName); err != nil {
fmt.Println("删除旧文件失败:", err)
return
}
}
// 创建临时文件
tmpFile, err := os.CreateTemp("", fileName)
if err != nil {
fmt.Println("创建临时文件失败:", err)
return
}
defer os.Remove(tmpFile.Name()) // 程序结束后删除临时文件
// 写入CSV数据
for _, candle := range ohlcv {
line := fmt.Sprintf("%d,%.2f,%.2f,%.2f,%.2f,%.2f\n",
candle.Timestamp, // 时间戳
candle.Open, // 开盘价
candle.High, // 最高价
candle.Low, // 最低价
candle.Close, // 收盘价
candle.Volume) // 成交量
if _, err := tmpFile.WriteString(line); err != nil {
fmt.Println("写入文件失败:", err)
return
}
}
// 确保目标目录存在
destDir := "/tmp/blingo/python/"
if err := os.MkdirAll(destDir, 0755); err != nil {
fmt.Println("创建目录失败:", err)
return
}
// 重命名文件
destName = destDir + fileName
if err := os.Rename(tmpFile.Name(), destName); err != nil {
fmt.Println("重命名文件失败:", err)
return
}
tmpFile.Close()
// 调用Python脚本
cmd := exec.Command("python3", "plot_ohlcv.py", destName)
cmd.Dir = "../python" // 设置工作目录
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
fmt.Println("执行Python脚本失败:", err)
return
}
} }

13
exam/README.md Normal file
View File

@ -0,0 +1,13 @@
## 测试 FetchOHLCV
```
go test -v ./exam/fetchOHLCV*
```
## 测试 FetchTicker
```
go test -v ./exam/fetchTicker*
```

130
exam/fetchOHLCV.go Normal file
View File

@ -0,0 +1,130 @@
package exam
import (
"fmt"
// "gitea.zjmud.xyz/phyer/blingo/cache"
// "gitea.zjmud.xyz/phyer/blingo/collector"
// "gitea.zjmud.xyz/phyer/blingo/config"
// "gitea.zjmud.xyz/phyer/blingo/feature_processor"
// "gitea.zjmud.xyz/phyer/blingo/scheduler"
// "gitea.zjmud.xyz/phyer/blingo/storage"
// "log"
// "error"
ccxt "gitea.zjmud.xyz/ext/ccxt-go"
"os"
"os/exec"
// "net/http"
"time"
)
func FetchOHLCV() {
// 1. 创建 OKX 交易所实例
okx := ccxt.NewOkx(map[string]interface{}{
"apiKey": "fe468418-5e40-433f-8d04-04951286d417",
"secret": "D6D74DF9DD60A25BE2B27CA71D8F814D",
"password": "M4pw71Id",
"hostname": "aws.okx.com",
})
// 3. 可选:自定义 HTTP 客户端配置
// okx.HttpClient.Timeout = 15 * time.Second
okx.EnableRateLimit = true // 启用内置速率限制
// 4. 加载市场数据(关键步骤!)
marketsChan := okx.LoadMarkets()
select {
case marketsResult := <-marketsChan:
switch v := marketsResult.(type) {
case error:
panic(fmt.Errorf("加载市场数据失败: %v", v))
case string:
panic(fmt.Errorf("加载市场数据失败: %v", v))
case map[string]interface{}:
okx.Markets = v
default:
panic(fmt.Errorf("加载市场数据失败: 未知类型的结果"))
}
case <-time.After(30 * time.Second):
panic(fmt.Errorf("加载市场数据超时"))
}
fmt.Println("OKX 初始化完成,已加载", len(okx.Markets), "个交易对")
// 获取ticker数据
symbol := "BTC/USDT"
tf := "1h"
sc := int64(1672502400000)
lm := int64(1000)
pm := map[string]interface{}{
"rateLimit": true, // Hypothetical parameter to enable rate limiting
}
ohlcv, err := okx.FetchOHLCV(symbol,
ccxt.WithFetchOHLCVSince(sc),
ccxt.WithFetchOHLCVTimeframe(tf),
ccxt.WithFetchOHLCVLimit(lm),
ccxt.WithFetchOHLCVParams(pm))
if err != nil {
fmt.Println("Error fetching OHLCV:", err)
return
}
fmt.Println("ohlcv: ", ohlcv)
// 检查并删除旧文件
fileName := "ohlcv-btc.csv"
destName := "/tmp/blingo/python/" + fileName
if _, err := os.Stat(destName); err == nil {
// 文件存在,删除它
if err := os.Remove(destName); err != nil {
fmt.Println("删除旧文件失败:", err)
return
}
}
// 创建临时文件
tmpFile, err := os.CreateTemp("", fileName)
if err != nil {
fmt.Println("创建临时文件失败:", err)
return
}
defer os.Remove(tmpFile.Name()) // 程序结束后删除临时文件
// 写入CSV数据
for _, candle := range ohlcv {
line := fmt.Sprintf("%d,%.2f,%.2f,%.2f,%.2f,%.2f\n",
candle.Timestamp, // 时间戳
candle.Open, // 开盘价
candle.High, // 最高价
candle.Low, // 最低价
candle.Close, // 收盘价
candle.Volume) // 成交量
if _, err := tmpFile.WriteString(line); err != nil {
fmt.Println("写入文件失败:", err)
return
}
}
// 确保目标目录存在
destDir := "/tmp/blingo/python/"
if err := os.MkdirAll(destDir, 0755); err != nil {
fmt.Println("创建目录失败:", err)
return
}
// 重命名文件
destName = destDir + fileName
if err := os.Rename(tmpFile.Name(), destName); err != nil {
fmt.Println("重命名文件失败:", err)
return
}
tmpFile.Close()
// 调用Python脚本
cmd := exec.Command("python3", "plot_ohlcv.py", destName)
cmd.Dir = "../python" // 设置工作目录
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
fmt.Println("执行Python脚本失败:", err)
return
}
}

9
exam/fetchOHLCV_test.go Normal file
View File

@ -0,0 +1,9 @@
package exam
import (
"testing"
)
func TestFetchOHLCV(t *testing.T) {
FetchOHLCV()
}

72
exam/fetchTicker.go Normal file
View File

@ -0,0 +1,72 @@
package exam
import (
"fmt"
// "gitea.zjmud.xyz/phyer/blingo/cache"
// "gitea.zjmud.xyz/phyer/blingo/collector"
// "gitea.zjmud.xyz/phyer/blingo/config"
// "gitea.zjmud.xyz/phyer/blingo/feature_processor"
// "gitea.zjmud.xyz/phyer/blingo/scheduler"
// "gitea.zjmud.xyz/phyer/blingo/storage"
// "log"
// "error"
ccxt "gitea.zjmud.xyz/ext/ccxt-go"
// "os"
// "os/exec"
// "net/http"
"time"
)
func FetchTicker() {
// 1. 创建 OKX 交易所实例
okx := ccxt.NewOkx(map[string]interface{}{
"apiKey": "fe468418-5e40-433f-8d04-04951286d417",
"secret": "D6D74DF9DD60A25BE2B27CA71D8F814D",
"password": "M4pw71Id",
"hostname": "aws.okx.com",
})
// 3. 可选:自定义 HTTP 客户端配置
// okx.HttpClient.Timeout = 15 * time.Second
okx.EnableRateLimit = true // 启用内置速率限制
// 4. 加载市场数据(关键步骤!)
marketsChan := okx.LoadMarkets()
select {
case marketsResult := <-marketsChan:
switch v := marketsResult.(type) {
case error:
panic(fmt.Errorf("加载市场数据失败: %v", v))
case string:
panic(fmt.Errorf("加载市场数据失败: %v", v))
case map[string]interface{}:
okx.Markets = v
default:
panic(fmt.Errorf("加载市场数据失败: 未知类型的结果"))
}
case <-time.After(30 * time.Second):
panic(fmt.Errorf("加载市场数据超时"))
}
fmt.Println("OKX 初始化完成,已加载", len(okx.Markets), "个交易对")
// 获取ticker数据
symbol := "BTC/USDT"
// tf := "1h"
// sc := int64(1672502400000)
// lm := int64(1000)
// pm := map[string]interface{}{
// "rateLimit": true, // Hypothetical parameter to enable rate limiting
// }
ticker, err := okx.FetchTicker(symbol)
// ticker, err := okx.FetchTicker(symbol,
// ccxt.WithFetchTickerParams(map[string]interface{}{}))
if err != nil {
fmt.Println("获取ticker数据错误:", err)
return
}
fmt.Println("ticker数据:", ticker)
}

9
exam/fetchTicker_test.go Normal file
View File

@ -0,0 +1,9 @@
package exam
import (
"testing"
)
func TestFetchTicker(t *testing.T) {
FetchTicker()
}

9
go.mod
View File

@ -2,7 +2,10 @@ module gitea.zjmud.xyz/phyer/blingo
go 1.24.0 go 1.24.0
require gitea.zjmud.xyz/ext/ccxt-go v0.0.0-20250228023320-1a2ce7046aca require (
gitea.zjmud.xyz/ext/ccxt-go v0.0.0-20250228023320-1a2ce7046aca
github.com/stretchr/testify v1.9.0
)
require ( require (
github.com/bits-and-blooms/bitset v1.13.0 // indirect github.com/bits-and-blooms/bitset v1.13.0 // indirect
@ -10,6 +13,7 @@ require (
github.com/consensys/gnark-crypto v0.12.1 // indirect github.com/consensys/gnark-crypto v0.12.1 // indirect
github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c // indirect github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c // indirect
github.com/crate-crypto/go-kzg-4844 v1.0.0 // indirect github.com/crate-crypto/go-kzg-4844 v1.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/ethereum/c-kzg-4844 v1.0.0 // indirect github.com/ethereum/c-kzg-4844 v1.0.0 // indirect
github.com/ethereum/go-ethereum v1.14.13 // indirect github.com/ethereum/go-ethereum v1.14.13 // indirect
@ -18,11 +22,14 @@ require (
github.com/holiman/uint256 v1.3.1 // indirect github.com/holiman/uint256 v1.3.1 // indirect
github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/supranational/blst v0.3.13 // indirect github.com/supranational/blst v0.3.13 // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
golang.org/x/crypto v0.31.0 // indirect golang.org/x/crypto v0.31.0 // indirect
golang.org/x/sync v0.7.0 // indirect golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.28.0 // indirect golang.org/x/sys v0.28.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
rsc.io/tmplfunc v0.0.3 // indirect rsc.io/tmplfunc v0.0.3 // indirect
) )

11
go.sum
View File

@ -39,6 +39,10 @@ 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/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/holiman/uint256 v1.3.1 h1:JfTzmih28bittyHM8z360dCjIA9dbPIBlcTI6lmctQs= github.com/holiman/uint256 v1.3.1 h1:JfTzmih28bittyHM8z360dCjIA9dbPIBlcTI6lmctQs=
github.com/holiman/uint256 v1.3.1/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/holiman/uint256 v1.3.1/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
@ -56,8 +60,12 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
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/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU=
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/supranational/blst v0.3.13 h1:AYeSxdOMacwu7FBmpfloBz5pbFXDmJL33RuwnKtmTjk= github.com/supranational/blst v0.3.13 h1:AYeSxdOMacwu7FBmpfloBz5pbFXDmJL33RuwnKtmTjk=
@ -78,6 +86,9 @@ golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 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.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 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=