Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/y9s4 #113

Merged
merged 7 commits into from
Dec 4, 2024
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
4 changes: 2 additions & 2 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ jobs:
run: |
c=$(git rev-parse --short HEAD); b=$(git name-rev --name-only "$c"); echo "version=$c ($b branch)" >> $GITHUB_ENV
echo "ext=$( if [ '${{ matrix.goos }}' = 'windows' ]; then echo 'dll'; elif [ '${{ matrix.goos }}' = 'darwin' ]; then echo 'dylib'; elif [ '${{ matrix.goos }}' = 'linux' ]; then echo 'so'; fi )" >> $GITHUB_ENV
- uses: wangyoucao577/go-release-action@v1.38
- uses: wangyoucao577/go-release-action@v1.52
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
goos: ${{ matrix.goos }}
goarch: ${{ matrix.goarch }}
goversion: "1.23.0"
goversion: "1.23.3"
pre_command: "go build -o libr6dissect.${{ env.ext }} -buildmode=c-shared exports/exports.go"
extra_files: "LICENSE README.md libr6dissect.h libr6dissect.${{ env.ext }}"
ldflags: "-X 'main.Version=${{ env.version }}'"
27 changes: 22 additions & 5 deletions dissect/header.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ type Header struct {
}

type Team struct {
Name string `json:"name"`
Score int `json:"score"`
Won bool `json:"won"`
WinCondition WinCondition `json:"winCondition,omitempty"`
Role TeamRole `json:"role,omitempty"`
Name string `json:"name"`
StartingScore int `json:"startingScore"`
Score int `json:"score"`
Won bool `json:"won"`
WinCondition WinCondition `json:"winCondition,omitempty"`
Role TeamRole `json:"role,omitempty"`
}

type Player struct {
Expand All @@ -53,6 +54,7 @@ type Player struct {
RolePortrait int `json:"rolePortrait,omitempty"`
Spawn string `json:"spawn,omitempty"`
DissectID []byte `json:"-" deep:"-"` // dissect player id at end of packet (4 bytes)
uiID uint64 `json:"-" deep:"-"`
}

type stringerIntMarshal struct {
Expand Down Expand Up @@ -404,6 +406,8 @@ func (r *Reader) readHeader() (Header, error) {
return Header{}, err
}
currentPlayer.RolePortrait = n
default:
props[k] = v
}
}
_, lastProp = props["teamscore1"]
Expand Down Expand Up @@ -502,6 +506,19 @@ func (r *Reader) readHeader() (Header, error) {
return h, err
}
h.Teams[1].Score = n
// Parse starting team scores
if h.CodeVersion >= Y9S4 {
n, err = strconv.Atoi(props["startingteamscore0"])
if err != nil {
return h, err
}
h.Teams[0].StartingScore = n
n, err = strconv.Atoi(props["startingteamscore1"])
if err != nil {
return h, err
}
h.Teams[1].StartingScore = n
}

return h, nil
}
Expand Down
77 changes: 61 additions & 16 deletions dissect/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,20 @@ func readPlayer(r *Reader) error {
if r.playersRead > 5 {
teamIndex = 1
}
// ui id (y9s3+?)
// there seems to be more to this, but its a quick fix for atk op swaps for now
var uiID uint64
if r.Header.CodeVersion >= Y9S3 {
if err = r.Seek([]byte{0x38, 0xDF, 0xEE, 0x88}); err != nil {
return err
}
if err = r.Skip(13); err != nil {
return err
}
if uiID, err = r.Uint64(); err != nil {
return err
}
}
// Older versions of siege did not include profile ids
profileID := ""
var unknownId uint64
Expand Down Expand Up @@ -121,6 +135,7 @@ func readPlayer(r *Reader) error {
Operator: Operator(op),
Spawn: spawn,
DissectID: id,
uiID: uiID,
}
if p.Operator != Recruit && p.Operator.Role() == Defense {
p.Spawn = r.Header.Site // We cannot detect the spawn here on defense
Expand All @@ -131,6 +146,7 @@ func readPlayer(r *Reader) error {
Str("profileID", profileID).
Hex("DissectID", id).
Uint64("ID", p.ID).
Uint64("uiID", p.uiID).
Str("spawn", spawn).Send()
found := false
for i, existing := range r.Header.Players {
Expand All @@ -143,6 +159,7 @@ func readPlayer(r *Reader) error {
r.Header.Players[i].Operator = p.Operator
r.Header.Players[i].Spawn = p.Spawn
r.Header.Players[i].DissectID = p.DissectID
r.Header.Players[i].uiID = p.uiID
found = true
break
}
Expand All @@ -158,27 +175,55 @@ func readAtkOpSwap(r *Reader) error {
if err != nil {
return err
}
if err = r.Skip(5); err != nil {
o := Operator(op)
// before Y9S3 caster view overhaul
if r.Header.CodeVersion < Y9S3 {
if err = r.Skip(5); err != nil {
return err
}
id, err := r.Bytes(4)
if err != nil {
return err
}
i := r.PlayerIndexByID(id)
log.Debug().Hex("id", id).Interface("op", op).Msg("atk_op_swap")
if i > -1 {
r.Header.Players[i].Operator = o
u := MatchUpdate{
Type: OperatorSwap,
Username: r.Header.Players[i].Username,
Time: r.timeRaw,
TimeInSeconds: r.time,
Operator: o,
}
r.MatchFeedback = append(r.MatchFeedback, u)
log.Debug().Interface("match_update", u).Send()
}
return nil
}
// after Y9S3 caster view overhaul
if err = r.Skip(402); err != nil {
return err
}
id, err := r.Bytes(4)
// id shows up in player data and in op swaps afaik
id, err := r.Uint64()
if err != nil {
return err
}
i := r.PlayerIndexByID(id)
o := Operator(op)
log.Debug().Hex("id", id).Interface("op", op).Msg("atk_op_swap")
if i > -1 {
r.Header.Players[i].Operator = o
u := MatchUpdate{
Type: OperatorSwap,
Username: r.Header.Players[i].Username,
Time: r.timeRaw,
TimeInSeconds: r.time,
Operator: o,
}
r.MatchFeedback = append(r.MatchFeedback, u)
log.Debug().Interface("match_update", u).Send()
for i, p := range r.Header.Players {
if p.uiID == id {
r.Header.Players[i].Operator = o
u := MatchUpdate{
Type: OperatorSwap,
Username: p.Username,
Time: r.timeRaw,
TimeInSeconds: r.time,
Operator: o,
}
r.MatchFeedback = append(r.MatchFeedback, u)
log.Debug().Interface("match_update", u).Send()
break
}
}
return nil
}
19 changes: 19 additions & 0 deletions dissect/time.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,23 @@ func readY7Time(r *Reader) error {

func (r *Reader) roundEnd() {
log.Debug().Msg("round_end")

planter := -1
deaths := make(map[int]int)
sizes := make(map[int]int)
roles := make(map[int]TeamRole)

for _, p := range r.Header.Players {
sizes[p.TeamIndex] += 1
roles[p.TeamIndex] = r.Header.Teams[p.TeamIndex].Role
}

if r.Header.CodeVersion >= Y9S4 {
team0Won := r.Header.Teams[0].StartingScore < r.Header.Teams[0].Score
r.Header.Teams[0].Won = team0Won
r.Header.Teams[1].Won = !team0Won
}

for _, u := range r.MatchFeedback {
switch u.Type {
case Kill:
Expand All @@ -77,11 +86,19 @@ func (r *Reader) roundEnd() {
return
}
}

if planter > -1 {
r.Header.Teams[r.Header.Players[planter].TeamIndex].Won = true
r.Header.Teams[r.Header.Players[planter].TeamIndex].WinCondition = DefusedBomb
return
}

// skip for now until we have a more reliable way of determining the win condition
// Y9S4 at least tells us who won now in the header with StartingScore
if r.Header.CodeVersion >= Y9S4 {
return
}

if deaths[0] == sizes[0] {
if planter > -1 && roles[0] == Attack { // ignore attackers killed post-plant
return
Expand All @@ -98,10 +115,12 @@ func (r *Reader) roundEnd() {
r.Header.Teams[0].WinCondition = KilledOpponents
return
}

i := 0
if roles[1] == Defense {
i = 1
}

r.Header.Teams[i].Won = true
r.Header.Teams[i].WinCondition = Time
}
2 changes: 2 additions & 0 deletions dissect/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ const (
Y9S1 int = 8111697
Y9S1Update3 int = 8211379
Y9S2 int = 8303162
Y9S3 int = 8506016
Y9S4 int = 8673114
)
24 changes: 12 additions & 12 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ go 1.23

require (
github.com/go-test/deep v1.1.0
github.com/klauspost/compress v1.17.9
github.com/klauspost/compress v1.17.11
github.com/rs/zerolog v1.33.0
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.19.0
github.com/xuri/excelize/v2 v2.8.1
golang.org/x/net v0.28.0
golang.org/x/tools v0.24.0
github.com/xuri/excelize/v2 v2.9.0
golang.org/x/net v0.32.0
golang.org/x/tools v0.27.0
)

require (
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
Expand All @@ -23,7 +23,7 @@ require (
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/richardlehane/mscfb v1.0.4 // indirect
github.com/richardlehane/msoleps v1.0.3 // indirect
github.com/richardlehane/msoleps v1.0.4 // indirect
github.com/sagikazarmark/locafero v0.6.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
Expand All @@ -33,12 +33,12 @@ require (
github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d // indirect
github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect
golang.org/x/mod v0.20.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/crypto v0.30.0 // indirect
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
35 changes: 35 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
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/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
Expand All @@ -15,6 +17,8 @@ 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/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
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=
Expand All @@ -41,6 +45,8 @@ github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7
github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
github.com/richardlehane/msoleps v1.0.3 h1:aznSZzrwYRl3rLKRT3gUk9am7T/mLNSnJINvN0AQoVM=
github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
github.com/richardlehane/msoleps v1.0.4 h1:WuESlvhX3gH2IHcd8UqyCuFY5yiq/GR/yqaSM/9/g00=
github.com/richardlehane/msoleps v1.0.4/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
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/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
Expand Down Expand Up @@ -68,31 +74,60 @@ github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d h1:llb0neMWDQe87IzJLS4Ci7
github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
github.com/xuri/excelize/v2 v2.8.1 h1:pZLMEwK8ep+CLIUWpWmvW8IWE/yxqG0I1xcN6cVMGuQ=
github.com/xuri/excelize/v2 v2.8.1/go.mod h1:oli1E4C3Pa5RXg1TBXn4ENCXDV5JUMlBluUhG7c+CEE=
github.com/xuri/excelize/v2 v2.9.0 h1:1tgOaEq92IOEumR1/JfYS/eR0KHOCsRv/rYXXh6YJQE=
github.com/xuri/excelize/v2 v2.9.0/go.mod h1:uqey4QBZ9gdMeWApPLdhm9x+9o2lq4iVmjiLfBS5hdE=
github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 h1:hPVCafDV85blFTabnqKgNhDCkJX25eik94Si9cTER4A=
github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY=
golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA=
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ=
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
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/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
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=
Expand Down
Loading