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

Add Excel format support #156

Merged
merged 6 commits into from
Feb 11, 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
18 changes: 11 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,20 @@ HTML:
Graphviz:
![nmap-example-graphviz](docs/images/example-dot.png)

A tool that allows you to convert NMAP XML output to html/csv/json/markdown/dot/sqlite.
A tool that allows you to convert NMAP XML output to excel/html/csv/json/markdown/dot/sqlite.

## Installation

It's possible to install it using `go install` command

```
go install github.com/vdjagilev/nmap-formatter/v2@latest
git clone https://github.com/gorkavp/nmap-formatter.git
cd nmap-formatter
go build
```

All other options can be found on [Installation Wiki page](https://github.com/vdjagilev/nmap-formatter/wiki/Installation).

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 I think people should be able to visit the wiki installation just by clicking, not sure why we are removing this.

## Usage

```bash
nmap-formatter [html|csv|md|json|dot|sqlite] [path-to-nmap.xml] [flags]
nmap-formatter [html|csv|md|json|dot|sqlite|excel] [path-to-nmap.xml] [flags]
```

Or alternatively you can read file from `stdin` and parse it
Expand All @@ -49,6 +47,12 @@ or Markdown
nmap-formatter md [path-to-nmap.xml] > some-markdown.md
```

or Excel

```bash
nmap-formatter excel [path-to-nmap.xml]
```

or JSON

```bash
Expand Down
5 changes: 3 additions & 2 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ var config = formatter.Config{
JSONOptions: formatter.JSONOutputOptions{},
CSVOptions: formatter.CSVOutputOptions{},
SqliteOutputOptions: formatter.SqliteOutputOptions{},
ExcelOptions: formatter.ExcelOutputOptions{},
},
ShowVersion: false,
CurrentVersion: VERSION,
Expand All @@ -51,9 +52,9 @@ var workflow formatter.Workflow

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "nmap-formatter [html|csv|md|json|dot|sqlite] [path-to-nmap.xml]",
Use: "nmap-formatter [html|csv|md|json|dot|sqlite|excel] [path-to-nmap.xml]",
Short: "Utility that can help you to convert NMAP XML application output to various other formats",
Long: `This utility allows you to convert NMAP XML output to various other formats like (html, csv, markdown (md), json, dot)`,
Long: `This utility allows you to convert NMAP XML output to various other formats like (html, csv, markdown (md), json, dot, excel, sqlite)`,
Args: arguments,
RunE: run,
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
// validate is checking input from the command line
func validate(config formatter.Config) error {
if !config.OutputFormat.IsValid() {
return fmt.Errorf("not valid format: %s, please choose html/json/md/csv/sqlite", config.OutputFormat)
return fmt.Errorf("not valid format: %s, please choose html/json/md/csv/excel/sqlite", config.OutputFormat)
}

err := validateIOFiles(config)
Expand Down
4 changes: 3 additions & 1 deletion formatter/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ const (
DotOutput OutputFormat = "dot"
// SqliteOutput constant defines OutputFormat for sqlite file, which can be used to generate sqlite embedded databases
SqliteOutput OutputFormat = "sqlite"
// ExcelOutput constant defines OutputFormat for Excel file, which can be used to generate Excel files
ExcelOutput OutputFormat = "excel"
)

// IsValid checks whether requested output format is valid
func (of OutputFormat) IsValid() bool {
// markdown & md is essentially the same thing
switch of {
case "markdown", "md", "html", "csv", "json", "dot", "sqlite":
case "markdown", "md", "html", "csv", "json", "dot", "sqlite", "excel":
return true
}
return false
Expand Down
4 changes: 4 additions & 0 deletions formatter/formatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
return &CSVFormatter{
config,
}
case ExcelOutput:
return &ExcelFormatter{
config,

Check warning on line 30 in formatter/formatter.go

View check run for this annotation

Codecov / codecov/patch

formatter/formatter.go#L28-L30

Added lines #L28 - L30 were not covered by tests
}
case DotOutput:
return &DotFormatter{
config,
Expand Down
71 changes: 71 additions & 0 deletions formatter/formatter_excel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package formatter

import (
"fmt"

"github.com/xuri/excelize/v2"
)

// ExcelFormatter is struct defined for Excel Output use-case
type ExcelFormatter struct {
config *Config
}

// Format the data to Excel and output it to an Excel file
func (f *ExcelFormatter) Format(td *TemplateData, templateContent string) (err error) {
file := excelize.NewFile()
sheetName := "Sheet1"

Check warning on line 17 in formatter/formatter_excel.go

View check run for this annotation

Codecov / codecov/patch

formatter/formatter_excel.go#L15-L17

Added lines #L15 - L17 were not covered by tests

// Create a style for center alignment
style, err := file.NewStyle(&excelize.Style{

Check failure on line 20 in formatter/formatter_excel.go

View workflow job for this annotation

GitHub Actions / lint (1.21.x)

ineffectual assignment to err (ineffassign)
Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center"},
})

Check warning on line 22 in formatter/formatter_excel.go

View check run for this annotation

Codecov / codecov/patch

formatter/formatter_excel.go#L20-L22

Added lines #L20 - L22 were not covered by tests

// Set the column headers
file.SetCellValue(sheetName, "A1", "IP/Host")

Check failure on line 25 in formatter/formatter_excel.go

View workflow job for this annotation

GitHub Actions / lint (1.21.x)

Error return value of `file.SetCellValue` is not checked (errcheck)
file.SetCellValue(sheetName, "B1", "Servicios")

Check failure on line 26 in formatter/formatter_excel.go

View workflow job for this annotation

GitHub Actions / lint (1.21.x)

Error return value of `file.SetCellValue` is not checked (errcheck)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Services?

file.SetCellStyle(sheetName, "A1", "A1", style)

Check failure on line 27 in formatter/formatter_excel.go

View workflow job for this annotation

GitHub Actions / lint (1.21.x)

Error return value of `file.SetCellStyle` is not checked (errcheck)
file.SetCellStyle(sheetName, "B1", "B1", style)

Check failure on line 28 in formatter/formatter_excel.go

View workflow job for this annotation

GitHub Actions / lint (1.21.x)

Error return value of `file.SetCellStyle` is not checked (errcheck)

Check warning on line 28 in formatter/formatter_excel.go

View check run for this annotation

Codecov / codecov/patch

formatter/formatter_excel.go#L25-L28

Added lines #L25 - L28 were not covered by tests

row := 2 // Start from row 2 for data

Check warning on line 30 in formatter/formatter_excel.go

View check run for this annotation

Codecov / codecov/patch

formatter/formatter_excel.go#L30

Added line #L30 was not covered by tests

for i := range td.NMAPRun.Host {
var host *Host = &td.NMAPRun.Host[i]

Check warning on line 33 in formatter/formatter_excel.go

View check run for this annotation

Codecov / codecov/patch

formatter/formatter_excel.go#L32-L33

Added lines #L32 - L33 were not covered by tests
// Skipping hosts that are down
if td.OutputOptions.ExcelOptions.SkipDownHosts && host.Status.State != "up" {
continue

Check warning on line 36 in formatter/formatter_excel.go

View check run for this annotation

Codecov / codecov/patch

formatter/formatter_excel.go#L35-L36

Added lines #L35 - L36 were not covered by tests
}
address := fmt.Sprintf("%s (%s)", host.JoinedAddresses("/"), host.JoinedHostNames("/"))

Check warning on line 38 in formatter/formatter_excel.go

View check run for this annotation

Codecov / codecov/patch

formatter/formatter_excel.go#L38

Added line #L38 was not covered by tests

// Set the IP/Host value
cell := fmt.Sprintf("A%d", row)
file.SetCellValue(sheetName, cell, address)

Check failure on line 42 in formatter/formatter_excel.go

View workflow job for this annotation

GitHub Actions / lint (1.21.x)

Error return value of `file.SetCellValue` is not checked (errcheck)
file.SetCellStyle(sheetName, cell, cell, style)

Check failure on line 43 in formatter/formatter_excel.go

View workflow job for this annotation

GitHub Actions / lint (1.21.x)

Error return value of `file.SetCellStyle` is not checked (errcheck)

Check warning on line 43 in formatter/formatter_excel.go

View check run for this annotation

Codecov / codecov/patch

formatter/formatter_excel.go#L41-L43

Added lines #L41 - L43 were not covered by tests

startRow := row // Remember the start row for this host

Check warning on line 45 in formatter/formatter_excel.go

View check run for this annotation

Codecov / codecov/patch

formatter/formatter_excel.go#L45

Added line #L45 was not covered by tests

for j := range host.Port {
var port *Port = &host.Port[j]
col := 'B' // Start from column B for Services

Check warning on line 49 in formatter/formatter_excel.go

View check run for this annotation

Codecov / codecov/patch

formatter/formatter_excel.go#L47-L49

Added lines #L47 - L49 were not covered by tests

// Set the Service value
cell = fmt.Sprintf("%c%d", col, row)
file.SetCellValue(sheetName, cell, fmt.Sprintf("%d/%s %s", port.PortID, port.Protocol, port.Service.Name))
file.SetCellStyle(sheetName, cell, cell, style)
row++ // Increment row for next service

Check warning on line 55 in formatter/formatter_excel.go

View check run for this annotation

Codecov / codecov/patch

formatter/formatter_excel.go#L52-L55

Added lines #L52 - L55 were not covered by tests
}

// Merge cells in the IP/Host column for this host
if row > startRow+1 { // Only merge if there's more than one service
file.MergeCell(sheetName, fmt.Sprintf("A%d", startRow), fmt.Sprintf("A%d", row-1))

Check failure on line 60 in formatter/formatter_excel.go

View workflow job for this annotation

GitHub Actions / lint (1.21.x)

Error return value of `file.MergeCell` is not checked (errcheck)

Check warning on line 60 in formatter/formatter_excel.go

View check run for this annotation

Codecov / codecov/patch

formatter/formatter_excel.go#L59-L60

Added lines #L59 - L60 were not covered by tests
}
}

// Save the Excel file
err = file.SaveAs("nmap-output.xlsx")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a Writer that we use for output (by default it's stdout), I think we can use this https://xuri.me/excelize/en/utils.html#FileWriter

file.Write(f.config.Writer, /* some opts */)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about the options though

return err

Check warning on line 66 in formatter/formatter_excel.go

View check run for this annotation

Codecov / codecov/patch

formatter/formatter_excel.go#L65-L66

Added lines #L65 - L66 were not covered by tests
}

func (f *ExcelFormatter) defaultTemplateContent() string {
return HTMLSimpleTemplate

Check warning on line 70 in formatter/formatter_excel.go

View check run for this annotation

Codecov / codecov/patch

formatter/formatter_excel.go#L69-L70

Added lines #L69 - L70 were not covered by tests
}
7 changes: 7 additions & 0 deletions formatter/output_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ type OutputOptions struct {
JSONOptions JSONOutputOptions
CSVOptions CSVOutputOptions
SqliteOutputOptions SqliteOutputOptions
ExcelOptions ExcelOutputOptions
}

// HTMLOutputOptions stores options related only to HTML conversion/formatting
Expand Down Expand Up @@ -61,3 +62,9 @@ type SqliteOutputOptions struct {
// ScanIdentifier is a unique string passed by the user to identify unique scans. If it's empty, it's generated automatically
ScanIdentifier string
}

// ExcelOutputOptions store options related to Excel file formatting
type ExcelOutputOptions struct {
// The hosts that are down won't be displayed
SkipDownHosts bool
}
11 changes: 11 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,18 @@ require (
golang.org/x/net v0.19.0
)

require (
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/richardlehane/mscfb v1.0.4 // indirect
github.com/richardlehane/msoleps v1.0.3 // indirect
github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca // indirect
github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a // indirect
golang.org/x/crypto v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect
)

require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/xuri/excelize/v2 v2.8.0
)
65 changes: 65 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,16 +1,81 @@
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/mattn/go-sqlite3 v1.14.18 h1:JL0eqdCOq6DJVNPSvArO/bIV9/P7fbGrV00LZHc+5aI=
github.com/mattn/go-sqlite3 v1.14.18/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM=
github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
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/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
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/xuri/efp v0.0.0-20230802181842-ad255f2331ca h1:uvPMDVyP7PXMMioYdyPH+0O+Ta/UO1WFfNYMO3Wz0eg=
github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
github.com/xuri/excelize/v2 v2.8.0 h1:Vd4Qy809fupgp1v7X+nCS/MioeQmYVVzi495UCTqB7U=
github.com/xuri/excelize/v2 v2.8.0/go.mod h1:6iA2edBTKxKbZAa7X5bDhcCg51xdOn1Ar5sfoXRGrQg=
github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a h1:Mw2VNrNNNjDtw68VsEj2+st+oCSn4Uz7vZw6TbhcV1o=
github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
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/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
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=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Loading