major refactor

Major refactor to use kong instead of cobra. All functionality
that worked before should still be working now.

Added `reorder` command
This commit is contained in:
Zellyn Hunter 2021-07-31 22:10:44 -04:00
parent bbf7d696db
commit 09ee1c6262
27 changed files with 611 additions and 1155 deletions

View File

@ -28,9 +28,32 @@ diskii's major disadvantage is that it mostly doesn't exist yet.
It rhymes with “whiskey”. It rhymes with “whiskey”.
Discussion/support is in Discussion/support is on the
[#apple2 on the retrocomputing Slack](https://retrocomputing.slack.com/messages/apple2/) [apple2infinitum Slack](https://apple2infinitum.slack.com/)
(invites [here](https://retrocomputing.herokuapp.com)). (invites [here](http://apple2.gs:3000/)).
# Examples
Get a listing of files on a DOS 3.3 disk image:
```
diskii ls dos33master.dsk
```
… or a ProDOS disk image:
```
diskii ls ProDOS_2_4_2.po
```
… or a Super-Mon disk image:
```
diskii ls Super-Mon-2.0.dsk
```
Reorder the sectors in a disk image:
```
diskii reorder ProDOS_2_4_2.dsk ProDOS_2_4_2.po
```
# Goals # Goals
@ -74,14 +97,15 @@ My rough TODO list (apart from anything marked (✗) in the disk
operations matrix is listed below. Anything that an actual user needs operations matrix is listed below. Anything that an actual user needs
will be likely to get priority. will be likely to get priority.
- [ ] Make `put` accept load address for appropriate filetypes.
- [ ] Implement `GetFile` for prodos
- [x] Build per-platform binaries for Linux, MacOS, Windows. - [x] Build per-platform binaries for Linux, MacOS, Windows.
- [x] Implement `GetFile` for DOS 3.3 - [x] Implement `GetFile` for DOS 3.3
- [ ] Add and implement the `-l` flag for `ls` - [ ] Add and implement the `-l` flag for `ls`
- [x] Add `Delete` to the `disk.Operator` interface - [x] Add `Delete` to the `disk.Operator` interface
- [ ] Implement it for Super-Mon - [ ] Implement it for Super-Mon
- [ ] Implement it for DOS 3.3 - [ ] Implement it for DOS 3.3
- [x] Add basic ProDOS structures - [ ] Add ProDOS support for all commands
- [ ] Add ProDOS support
- [x] Make `filetypes` command use a tabwriter to write as a table - [x] Make `filetypes` command use a tabwriter to write as a table
# Related tools # Related tools

View File

@ -3,87 +3,41 @@
package cmd package cmd
import ( import (
"fmt"
"os" "os"
"github.com/spf13/cobra"
"github.com/zellyn/diskii/basic" "github.com/zellyn/diskii/basic"
"github.com/zellyn/diskii/basic/applesoft" "github.com/zellyn/diskii/basic/applesoft"
"github.com/zellyn/diskii/helpers" "github.com/zellyn/diskii/helpers"
"github.com/zellyn/diskii/types"
) )
// applesoftCmd represents the applesoft command type ApplesoftCmd struct {
var applesoftCmd = &cobra.Command{ Decode DecodeCmd `kong:"cmd,help='Convert a binary Applesoft program to a text LISTing.'"`
Use: "applesoft",
Short: "work with applesoft programs",
Long: `diskii applesoft contains the subcommands useful for working
with Applesoft programs.`,
} }
func init() { type DecodeCmd struct {
RootCmd.AddCommand(applesoftCmd) Filename string `kong:"arg,default='-',type='existingfile',help='Binary Applesoft file to read, or “-” for stdin.'"`
// Here you will define your flags and configuration settings. Location uint16 `kong:"type='anybaseuint16',default='0x801',help='Starting program location in memory.'"`
Raw bool `kong:"short='r',help='Print raw control codes (no escaping)'"`
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// applesoftCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// applesoftCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
} }
// ----- applesoft decode command ------------------------------------------- func (d DecodeCmd) Help() string {
return `Examples:
var location uint16 // flag for starting location in memory # Dump the contents of HELLO and then decode it.
var rawControlCodes bool // flag for whether to skip escaping control codes diskii dump dos33master.dsk HELLO | diskii applesoft decode -`
// decodeCmd represents the decode command
var decodeCmd = &cobra.Command{
Use: "decode filename",
Short: "convert a binary applesoft program to a LISTing",
Long: `
decode converts a binary Applesoft program to a text LISTing.
Examples:
decode filename # read filename
decode - # read stdin`,
Run: func(cmd *cobra.Command, args []string) {
if err := runDecode(args); err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(-1)
}
},
} }
func init() { func (d *DecodeCmd) Run(globals *types.Globals) error {
applesoftCmd.AddCommand(decodeCmd) contents, err := helpers.FileContentsOrStdIn(d.Filename)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// decodeCmd.PersistentFlags().String("foo", "", "A help for foo")
decodeCmd.Flags().Uint16VarP(&location, "location", "l", 0x801, "Starting program location in memory")
decodeCmd.Flags().BoolVarP(&rawControlCodes, "raw", "r", false, "Print raw control codes (no escaping)")
}
// runDecode performs the actual decode logic.
func runDecode(args []string) error {
if len(args) != 1 {
return fmt.Errorf("decode expects one argument: the filename (or - for stdin)")
}
contents, err := helpers.FileContentsOrStdIn(args[0])
if err != nil { if err != nil {
return err return err
} }
listing, err := applesoft.Decode(contents, location) listing, err := applesoft.Decode(contents, d.Location)
if err != nil { if err != nil {
return err return err
} }
if rawControlCodes { if d.Raw {
os.Stdout.WriteString(listing.String()) os.Stdout.WriteString(listing.String())
} else { } else {
os.Stdout.WriteString(basic.ChevronControlCodes(listing.String())) os.Stdout.WriteString(basic.ChevronControlCodes(listing.String()))

View File

@ -11,8 +11,8 @@ import (
) )
type LsCmd struct { type LsCmd struct {
Order string `kong:"default='auto',enum='auto,do,po',help='Logical-to-physical sector order.'"` Order types.DiskOrder `kong:"default='auto',enum='auto,do,po',help='Logical-to-physical sector order.'"`
System string `kong:"default='auto',enum='auto,dos3',help='DOS system used for image.'"` System string `kong:"default='auto',enum='auto,dos3',help='DOS system used for image.'"`
ShortNames bool `kong:"short='s',help='Whether to print short filenames (only makes a difference on Super-Mon disks).'"` ShortNames bool `kong:"short='s',help='Whether to print short filenames (only makes a difference on Super-Mon disks).'"`
Image *os.File `kong:"arg,required,help='Disk/device image to read.'"` Image *os.File `kong:"arg,required,help='Disk/device image to read.'"`
@ -20,7 +20,7 @@ type LsCmd struct {
} }
func (l *LsCmd) Run(globals *types.Globals) error { func (l *LsCmd) Run(globals *types.Globals) error {
op, order, err := disk.OpenImage(l.Image, l.Order, l.System, globals) op, order, err := disk.OpenFile(l.Image, l.Order, l.System, globals.DiskOperatorFactories, globals.Debug)
if err != nil { if err != nil {
return fmt.Errorf("%w: %s", err, l.Image.Name()) return fmt.Errorf("%w: %s", err, l.Image.Name())
} }

View File

@ -2,57 +2,40 @@
package cmd package cmd
/* import (
var missingok bool // flag for whether to consider deleting a nonexistent file okay "fmt"
// deleteCmd represents the delete command, used to delete a file. "github.com/zellyn/diskii/disk"
var deleteCmd = &cobra.Command{ "github.com/zellyn/diskii/types"
Use: "delete", )
Short: "delete a file",
Long: `Delete a file.
delete disk-image.dsk HELLO type DeleteCmd struct {
`, Order types.DiskOrder `kong:"default='auto',enum='auto,do,po',help='Logical-to-physical sector order.'"`
Run: func(cmd *cobra.Command, args []string) { System string `kong:"default='auto',enum='auto,dos3',help='DOS system used for image.'"`
if err := runDelete(args); err != nil { MissingOk bool `kong:"short='f',help='Overwrite existing file?'"`
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(-1) DiskImage string `kong:"arg,required,type='existingfile',help='Disk image to modify.'"`
} Filename string `kong:"arg,required,help='Filename to use on disk.'"`
},
} }
func init() { func (d DeleteCmd) Help() string {
RootCmd.AddCommand(deleteCmd) return `Examples:
deleteCmd.Flags().BoolVarP(&missingok, "missingok", "f", false, "if true, don't consider deleting a nonexistent file an error") # Delete file GREMLINS on disk image games.dsk.
diskii rm games.dsk GREMLINS`
} }
// runDelete performs the actual delete logic. func (d *DeleteCmd) Run(globals *types.Globals) error {
func runDelete(args []string) error { op, order, err := disk.OpenFilename(d.DiskImage, d.Order, d.System, globals.DiskOperatorFactories, globals.Debug)
if len(args) != 2 {
return fmt.Errorf("delete expects a disk image filename, and a filename")
}
op, err := disk.Open(args[0])
if err != nil { if err != nil {
return err return err
} }
deleted, err := op.Delete(args[1])
deleted, err := op.Delete(d.Filename)
if err != nil { if err != nil {
return err return err
} }
if !deleted && !missingok { if !deleted && !d.MissingOk {
return fmt.Errorf("file %q not found", args[1]) return fmt.Errorf("file %q not found (use -f to prevent this being an error)", d.Filename)
} }
f, err := os.Create(args[0]) return disk.WriteBack(d.DiskImage, op, order, true)
if err != nil {
return err
}
_, err = op.Write(f)
if err != nil {
return err
}
if err = f.Close(); err != nil {
return err
}
return nil
} }
*/

View File

@ -2,43 +2,40 @@
package cmd package cmd
/* import (
// dumpCmd represents the dump command, used to dump the raw contents "os"
// of a file.
var dumpCmd = &cobra.Command{
Use: "dump",
Short: "dump the raw contents of a file",
Long: `Dump the raw contents of a file.
dump disk-image.dsk HELLO "github.com/zellyn/diskii/disk"
`, "github.com/zellyn/diskii/types"
Run: func(cmd *cobra.Command, args []string) { )
if err := runDump(args); err != nil {
fmt.Fprintln(os.Stderr, err.Error()) type DumpCmd struct {
os.Exit(-1) Order types.DiskOrder `kong:"default='auto',enum='auto,do,po',help='Logical-to-physical sector order.'"`
} System string `kong:"default='auto',enum='auto,dos3',help='DOS system used for image.'"`
},
DiskImage string `kong:"arg,required,type='existingfile',help='Disk image to modify.'"`
Filename string `kong:"arg,required,help='Filename to use on disk.'"`
} }
func init() { func (d DumpCmd) Help() string {
RootCmd.AddCommand(dumpCmd) return `Examples:
# Dump file GREMLINS on disk image games.dsk.
diskii dump games.dsk GREMLINS`
} }
// runDump performs the actual dump logic. func (d *DumpCmd) Run(globals *types.Globals) error {
func runDump(args []string) error { op, _, err := disk.OpenFilename(d.DiskImage, d.Order, d.System, globals.DiskOperatorFactories, globals.Debug)
if len(args) != 2 {
return fmt.Errorf("dump expects a disk image filename, and a filename")
}
op, err := disk.Open(args[0])
if err != nil { if err != nil {
return err return err
} }
file, err := op.GetFile(args[1])
file, err := op.GetFile(d.Filename)
if err != nil {
return err
}
_, err = os.Stdout.Write(file.Data)
if err != nil { if err != nil {
return err return err
} }
// TODO(zellyn): allow writing to files
os.Stdout.Write(file.Data)
return nil return nil
} }
*/

View File

@ -2,81 +2,78 @@
package cmd package cmd
/* import (
// nakedosCmd represents the nakedos command "fmt"
var nakedosCmd = &cobra.Command{
Use: "nakedos",
Short: "work with NakedOS disks",
Long: `diskii nakedos contains the subcommands useful for working
with NakedOS (and Super-Mon) disks`,
Aliases: []string{"supermon"},
}
func init() { "github.com/zellyn/diskii/disk"
RootCmd.AddCommand(nakedosCmd) "github.com/zellyn/diskii/supermon"
} "github.com/zellyn/diskii/types"
)
// ----- mkhello command ----------------------------------------------------
var address uint16 // flag for address to load at
var start uint16 // flag for address to start execution at
const helloName = "FHELLO" // filename to use (if Super-Mon) const helloName = "FHELLO" // filename to use (if Super-Mon)
// mkhelloCmd represents the mkhello command type NakedOSCmd struct {
var mkhelloCmd = &cobra.Command{ Mkhello MkHelloCmd `kong:"cmd,help='Create an FHELLO program that loads and runs another file.'"`
Use: "mkhello <disk-image> filename", }
Short: "create an FHELLO program that loads and runs another file",
Long: `
mkhello creates file DF01:FHELLO that loads and runs another program at a specific address.
// Help shows extended help on NakedOS/Super-Mon.
func (n NakedOSCmd) Help() string {
return `NakedOS and Super-Mon were created by the amazing Martin Haye. For more information see:
Source/docs: https://bitbucket.org/martin.haye/super-mon/
Presentation: https://www.kansasfest.org/2012/08/2010-haye-nakedos/`
}
type MkHelloCmd struct {
Order types.DiskOrder `kong:"default='auto',enum='auto,do,po',help='Logical-to-physical sector order.'"`
DiskImage string `kong:"arg,required,type='existingfile',help='Disk image to modify.'"`
Filename string `kong:"arg,required,help='Name of NakedOS file to load.'"`
Address uint16 `kong:"type='anybaseuint16',default='0x6000',help='Address to load the code at.'"`
Start uint16 `kong:"type='anybaseuint16',default='0xFFFF',help='Address to jump to. Defaults to 0xFFFF, which means “same as address flag”'"`
}
func (m MkHelloCmd) Help() string {
return `This command creates a very short DF01:FHELLO program that simply loads another program of your choice.
Examples: Examples:
mkhello test.dsk FDEMO # load and run FDEMO at the default address, then jump to the start of the loaded code. # Load and run FDEMO at the default address, then jump to the start of the loaded code.
mkhello test.dsk --address 0x2000 --start 0x2100 DF06 # load and run file DF06 at address 0x2000, and jump to 0x2100.`, mkhello test.dsk FDEMO
Run: func(cmd *cobra.Command, args []string) {
if err := runMkhello(args); err != nil { # Load and run file DF06 at address 0x2000, and jump to 0x2100.
fmt.Fprintln(os.Stderr, err.Error()) mkhello test.dsk --address 0x2000 --start 0x2100 DF06`
os.Exit(-1)
}
},
} }
func init() { func (m *MkHelloCmd) Run(globals *types.Globals) error {
nakedosCmd.AddCommand(mkhelloCmd) if m.Start == 0xFFFF {
m.Start = m.Address
// Here you will define your flags and configuration settings.
mkhelloCmd.Flags().Uint16VarP(&address, "address", "a", 0x6000, "memory location to load code at")
mkhelloCmd.Flags().Uint16VarP(&start, "start", "s", 0x6000, "memory location to jump to")
}
// runMkhello performs the actual mkhello logic.
func runMkhello(args []string) error {
if len(args) != 2 {
return fmt.Errorf("usage: diskii mkhello <disk image> <file-to-load>")
} }
if address%256 != 0 {
return fmt.Errorf("address %d (%04X) not on a page boundary", address, address) if m.Address%256 != 0 {
return fmt.Errorf("address %d (%04X) not on a page boundary", m.Address, m.Address)
} }
if start < address { if m.Start < m.Address {
return fmt.Errorf("start address %d (%04X) < load address %d (%04X)", start, start, address, address) return fmt.Errorf("start address %d (%04X) < load address %d (%04X)", m.Start, m.Start, m.Address, m.Address)
} }
op, err := disk.Open(args[0])
op, order, err := disk.OpenFilename(m.DiskImage, m.Order, "auto", globals.DiskOperatorFactories, globals.Debug)
if err != nil { if err != nil {
return err return err
} }
if op.Name() != "nakedos" { if op.Name() != "nakedos" {
return fmt.Errorf("mkhello only works on disks of type %q; got %q", "nakedos", op.Name()) return fmt.Errorf("mkhello only works on disks of type %q; got %q", "nakedos", op.Name())
} }
nakOp, ok := op.(supermon.Operator) nakOp, ok := op.(supermon.Operator)
if !ok { if !ok {
return fmt.Errorf("internal error: cannot cast to expected supermon.Operator type") return fmt.Errorf("internal error: cannot cast to expected supermon.Operator type (got %T)", op)
} }
addr, symbolAddr, _, err := nakOp.ST.FilesForCompoundName(args[1]) addr, symbolAddr, _, err := nakOp.ST.FilesForCompoundName(m.Filename)
if err != nil { if err != nil {
return err return err
} }
if addr == 0 && symbolAddr == 0 { if addr == 0 && symbolAddr == 0 {
return fmt.Errorf("cannot parse %q as valid filename", args[1]) return fmt.Errorf("cannot parse %q as valid filename", m.Filename)
} }
toLoad := addr toLoad := addr
if addr == 0 { if addr == 0 {
@ -86,33 +83,24 @@ func runMkhello(args []string) error {
0x20, 0x40, 0x03, // JSR NAKEDOS 0x20, 0x40, 0x03, // JSR NAKEDOS
0x6D, 0x01, 0xDC, // ADC NKRDFILE 0x6D, 0x01, 0xDC, // ADC NKRDFILE
0x2C, toLoad, 0xDF, // BIT ${file number to load} 0x2C, toLoad, 0xDF, // BIT ${file number to load}
0x2C, 0x00, byte(address >> 8), // BIT ${target page} 0x2C, 0x00, byte(m.Address >> 8), // BIT ${target page}
0xD8, // CLD 0xD8, // CLD
0x4C, byte(start), byte(start >> 8), // JMP ${target page} 0x4C, byte(m.Start), byte(m.Start >> 8), // JMP ${target page}
} }
fileInfo := disk.FileInfo{ fileInfo := types.FileInfo{
Descriptor: disk.Descriptor{ Descriptor: types.Descriptor{
Name: fmt.Sprintf("DF01:%s", helloName), Name: fmt.Sprintf("DF01:%s", helloName),
Length: len(contents), Length: len(contents),
Type: disk.FiletypeBinary, Type: types.FiletypeBinary,
}, },
Data: contents, Data: contents,
} }
_ = fileInfo
_, err = op.PutFile(fileInfo, true) _, err = op.PutFile(fileInfo, true)
if err != nil { if err != nil {
return err return err
} }
f, err := os.Create(args[0])
if err != nil { return disk.WriteBack(m.DiskImage, op, order, true)
return err
}
_, err = op.Write(f)
if err != nil {
return err
}
if err = f.Close(); err != nil {
return err
}
return nil
} }
*/

View File

@ -2,75 +2,63 @@
package cmd package cmd
/* import (
var filetypeName string // flag for file type "fmt"
var overwrite bool // flag for whether to overwrite
// putCmd represents the put command, used to put the raw contents "github.com/zellyn/diskii/disk"
// of a file. "github.com/zellyn/diskii/helpers"
var putCmd = &cobra.Command{ "github.com/zellyn/diskii/types"
Use: "put", )
Short: "put the raw contents of a file",
Long: `Put the raw contents of a file.
put disk-image.dsk HELLO <name of file with contents> type PutCmd struct {
`, Order types.DiskOrder `kong:"default='auto',enum='auto,do,po',help='Logical-to-physical sector order.'"`
Run: func(cmd *cobra.Command, args []string) { System string `kong:"default='auto',enum='auto,dos3',help='DOS system used for image.'"`
if err := runPut(args); err != nil { FiletypeName string `kong:"default='B',help='Type of file (“diskii filetypes” to list).'"`
fmt.Fprintln(os.Stderr, err.Error()) Overwrite bool `kong:"short='f',help='Overwrite existing file?'"`
os.Exit(-1)
DiskImage string `kong:"arg,required,type='existingfile',help='Disk image to modify.'"`
TargetFilename string `kong:"arg,required,help='Filename to use on disk.'"`
SourceFilename string `kong:"arg,required,type='existingfile',help='Name of file containing data to put.'"`
}
func (p PutCmd) Help() string {
return `Examples:
# Put file gremlins.o onto disk image games.dsk, using the filename GREMLINS.
diskii put games.dsk GREMLINS gremlins.o`
}
func (p *PutCmd) Run(globals *types.Globals) error {
if p.DiskImage == "-" {
if p.SourceFilename == "-" {
return fmt.Errorf("cannot get both disk image and file contents from stdin")
} }
},
}
func init() {
RootCmd.AddCommand(putCmd)
putCmd.Flags().StringVarP(&filetypeName, "type", "t", "B", "Type of file (`diskii filetypes` to list)")
putCmd.Flags().BoolVarP(&overwrite, "overwrite", "f", false, "whether to overwrite existing files")
}
// runPut performs the actual put logic.
func runPut(args []string) error {
if len(args) != 3 {
return fmt.Errorf("usage: put <disk image> <target filename> <source filename>")
} }
op, err := disk.Open(args[0]) op, order, err := disk.OpenFilename(p.DiskImage, p.Order, p.System, globals.DiskOperatorFactories, globals.Debug)
if err != nil {
return err
}
contents, err := helpers.FileContentsOrStdIn(args[2])
if err != nil { if err != nil {
return err return err
} }
filetype, err := disk.FiletypeForName(filetypeName) contents, err := helpers.FileContentsOrStdIn(p.SourceFilename)
if err != nil { if err != nil {
return err return err
} }
fileInfo := disk.FileInfo{ filetype, err := types.FiletypeForName(p.FiletypeName)
Descriptor: disk.Descriptor{ if err != nil {
Name: args[1], return err
}
fileInfo := types.FileInfo{
Descriptor: types.Descriptor{
Name: p.TargetFilename,
Length: len(contents), Length: len(contents),
Type: filetype, Type: filetype,
}, },
Data: contents, Data: contents,
} }
_, err = op.PutFile(fileInfo, overwrite) _, err = op.PutFile(fileInfo, p.Overwrite)
if err != nil { if err != nil {
return err return err
} }
f, err := os.Create(args[0])
if err != nil { return disk.WriteBack(p.DiskImage, op, order, true)
return err
}
_, err = op.Write(f)
if err != nil {
return err
}
if err = f.Close(); err != nil {
return err
}
return nil
} }
*/

View File

@ -2,8 +2,6 @@ package cmd
import ( import (
"fmt" "fmt"
"path"
"strings"
"github.com/zellyn/diskii/disk" "github.com/zellyn/diskii/disk"
"github.com/zellyn/diskii/helpers" "github.com/zellyn/diskii/helpers"
@ -11,9 +9,9 @@ import (
) )
type ReorderCmd struct { type ReorderCmd struct {
Order string `kong:"default='auto',enum='auto,do,po',help='Logical-to-physical sector order.'"` Order types.DiskOrder `kong:"default='auto',enum='auto,do,po',help='Logical-to-physical sector order.'"`
NewOrder string `kong:"default='auto',enum='auto,do,po',help='New Logical-to-physical sector order.'"` NewOrder types.DiskOrder `kong:"default='auto',enum='auto,do,po',help='New Logical-to-physical sector order.'"`
Force bool `kong:"short='s',help='Overwrite existing file?'"` Overwrite bool `kong:"short='f',help='Overwrite existing file?'"`
DiskImage string `kong:"arg,required,type='existingfile',help='Disk image to read.'"` DiskImage string `kong:"arg,required,type='existingfile',help='Disk image to read.'"`
NewDiskImage string `kong:"arg,optional,type='path',help='Disk image to write, if different.'"` NewDiskImage string `kong:"arg,optional,type='path',help='Disk image to write, if different.'"`
@ -44,11 +42,18 @@ func (r *ReorderCmd) Run(globals *types.Globals) error {
if err != nil { if err != nil {
return err return err
} }
return helpers.WriteOutput(r.NewDiskImage, tobytes, r.DiskImage, r.Force)
overwrite := r.Overwrite
filename := r.NewDiskImage
if filename == "" {
filename = r.DiskImage
overwrite = true
}
return helpers.WriteOutput(filename, tobytes, overwrite)
} }
// getOrders returns the input order, and the output order. // getOrders returns the input order, and the output order.
func getOrders(inFilename string, inOrder string, outFilename string, outOrder string) (string, string, error) { func getOrders(inFilename string, inOrder types.DiskOrder, outFilename string, outOrder types.DiskOrder) (types.DiskOrder, types.DiskOrder, error) {
if inOrder == "auto" && outOrder != "auto" { if inOrder == "auto" && outOrder != "auto" {
return oppositeOrder(outOrder), outOrder, nil return oppositeOrder(outOrder), outOrder, nil
} }
@ -62,40 +67,27 @@ func getOrders(inFilename string, inOrder string, outFilename string, outOrder s
return "", "", fmt.Errorf("identical order and new-order") return "", "", fmt.Errorf("identical order and new-order")
} }
inGuess, outGuess := orderFromFilename(inFilename), orderFromFilename(outFilename) inGuess, outGuess := disk.OrderFromFilename(inFilename, types.DiskOrderUnknown), disk.OrderFromFilename(outFilename, types.DiskOrderUnknown)
if inGuess == outGuess { if inGuess == outGuess {
if inGuess == "" { if inGuess == types.DiskOrderUnknown {
return "", "", fmt.Errorf("cannot determine input or output order from file extensions") return "", "", fmt.Errorf("cannot determine input or output order from file extensions")
} }
return "", "", fmt.Errorf("guessed order (%s) from file %q is the same as guessed order (%s) from file %q", inGuess, inFilename, outGuess, outFilename) return "", "", fmt.Errorf("guessed order (%s) from file %q is the same as guessed order (%s) from file %q", inGuess, inFilename, outGuess, outFilename)
} }
if inGuess == "" { if inGuess == types.DiskOrderUnknown {
return oppositeOrder(outGuess), outGuess, nil return oppositeOrder(outGuess), outGuess, nil
} }
if outGuess == "" { if outGuess == types.DiskOrderUnknown {
return inGuess, oppositeOrder(inGuess), nil return inGuess, oppositeOrder(inGuess), nil
} }
return inGuess, outGuess, nil return inGuess, outGuess, nil
} }
// oppositeOrder returns the opposite order from the input. // oppositeOrder returns the opposite order from the input.
func oppositeOrder(order string) string { func oppositeOrder(order types.DiskOrder) types.DiskOrder {
if order == "do" { if order == types.DiskOrderDO {
return "po" return types.DiskOrderPO
}
return "do"
}
// orderFromFilename tries to guess the disk order from the filename, using the extension.
func orderFromFilename(filename string) string {
ext := strings.ToLower(path.Ext(filename))
switch ext {
case ".dsk", ".do":
return "do"
case ".po":
return "po"
default:
return ""
} }
return types.DiskOrderDO
} }

View File

@ -1,31 +0,0 @@
// Copyright © 2016 Zellyn Hunter <zellyn@gmail.com>
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
var cfgFile string
// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
Use: "diskii",
Short: "Operate on Apple II disk images and their contents",
Long: `diskii is a commandline tool for working with Apple II disk
images.
Eventually, it aims to be a comprehensive disk image manipulation tool.`,
}
// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
if err := RootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(-1)
}
}

View File

@ -4,68 +4,62 @@ package cmd
import ( import (
"fmt" "fmt"
"io"
"os" "os"
"github.com/spf13/cobra"
"github.com/zellyn/diskii/disk" "github.com/zellyn/diskii/disk"
"github.com/zellyn/diskii/helpers" "github.com/zellyn/diskii/helpers"
"github.com/zellyn/diskii/types"
) )
var sdAddress uint16 // flag for address to load at type SDCmd struct {
var sdStart uint16 // flag for address to start execution at Order types.DiskOrder `kong:"default='auto',enum='auto,do,po',help='Logical-to-physical sector order.'"`
// mksdCmd represents the mksd command DiskImage string `kong:"arg,required,type='path',help='Disk image to write.'"`
var mksdCmd = &cobra.Command{ Binary *os.File `kong:"arg,required,help='Binary file to write to the disk.'"`
Use: "mksd",
Short: "create a Standard-Delivery disk image", Address uint16 `kong:"type='anybaseuint16',default='0x6000',help='Address to load the code at.'"`
Long: `diskii mksd creates a "Standard Delivery" disk image containing a binary. Start uint16 `kong:"type='anybaseuint16',default='0xFFFF',help='Address to jump to. Defaults to 0xFFFF, which means “same as address flag”'"`
}
func (s SDCmd) Help() string {
return `
See https://github.com/peterferrie/standard-delivery for details. See https://github.com/peterferrie/standard-delivery for details.
Examples: Examples:
mksd test.dsk foo.o # load and run foo.o at the default address, then jump to the start of the loaded code. # Load and run foo.o at the default address, then jump to the start of the loaded code.
mksd test.dsk foo.o --address 0x2000 --start 0x2100 # load foo.o at address 0x2000, then jump to 0x2100.`, diskii mksd test.dsk foo.o
Run: func(cmd *cobra.Command, args []string) {
if err := runMkSd(args); err != nil { # Load foo.o at address 0x2000, then jump to 0x2100.
fmt.Fprintln(os.Stderr, err.Error()) diskii mksd test.dsk foo.o --address 0x2000 --start 0x2100`
os.Exit(-1)
}
},
} }
func init() { func (s *SDCmd) Run(globals *types.Globals) error {
RootCmd.AddCommand(mksdCmd) if s.Start == 0xFFFF {
mksdCmd.Flags().Uint16VarP(&sdAddress, "address", "a", 0x6000, "memory location to load code at") s.Start = s.Address
mksdCmd.Flags().Uint16VarP(&sdStart, "start", "s", 0x6000, "memory location to jump to")
}
// ----- mksd command -------------------------------------------------------
// runMkSd performs the actual mksd logic.
func runMkSd(args []string) error {
if len(args) != 2 {
return fmt.Errorf("usage: diskii mksd <disk image> <file-to-load>")
} }
contents, err := helpers.FileContentsOrStdIn(args[1])
contents, err := io.ReadAll(s.Binary)
if err != nil { if err != nil {
return err return err
} }
if sdAddress%256 != 0 { if s.Address%256 != 0 {
return fmt.Errorf("address %d (%04X) not on a page boundary", sdAddress, sdAddress) return fmt.Errorf("address %d (%04X) not on a page boundary", s.Address, s.Address)
} }
if sdStart < sdAddress { if s.Start < s.Address {
return fmt.Errorf("start address %d (%04X) < load address %d (%04X)", sdStart, sdStart, sdAddress, sdAddress) return fmt.Errorf("start address %d (%04X) < load address %d (%04X)", s.Start, s.Start, s.Address, s.Address)
} }
if int(sdStart) >= int(sdAddress)+len(contents) { if int(s.Start) >= int(s.Address)+len(contents) {
end := int(sdAddress) + len(contents) end := int(s.Address) + len(contents)
return fmt.Errorf("start address %d (%04X) is beyond load address %d (%04X) + file length = %d (%04X)", return fmt.Errorf("start address %d (%04X) is beyond load address %d (%04X) + file length = %d (%04X)",
sdStart, sdStart, sdAddress, sdAddress, end, end) s.Start, s.Start, s.Address, s.Address, end, end)
} }
if int(sdStart)+len(contents) > 0xC000 { if int(s.Start)+len(contents) > 0xC000 {
end := int(sdStart) + len(contents) end := int(s.Start) + len(contents)
return fmt.Errorf("start address %d (%04X) + file length %d (%04X) = %d (%04X), but we can't load past page 0xBF00", return fmt.Errorf("start address %d (%04X) + file length %d (%04X) = %d (%04X), but we can't load past page 0xBF00",
sdStart, sdStart, len(contents), len(contents), end, end) s.Start, s.Start, len(contents), len(contents), end, end)
} }
sectors := (len(contents) + 255) / 256 sectors := (len(contents) + 255) / 256
@ -76,11 +70,11 @@ func runMkSd(args []string) error {
0xc8, 0xa5, 0x27, 0xf0, 0xdf, 0x8a, 0x4a, 0x4a, 0x4a, 0x4a, 0x09, 0xc0, 0x48, 0xa9, 0x5b, 0xc8, 0xa5, 0x27, 0xf0, 0xdf, 0x8a, 0x4a, 0x4a, 0x4a, 0x4a, 0x09, 0xc0, 0x48, 0xa9, 0x5b,
0x48, 0x60, 0xe6, 0x41, 0x06, 0x40, 0x20, 0x37, 0x08, 0x18, 0x20, 0x3c, 0x08, 0xe6, 0x40, 0x48, 0x60, 0xe6, 0x41, 0x06, 0x40, 0x20, 0x37, 0x08, 0x18, 0x20, 0x3c, 0x08, 0xe6, 0x40,
0xa5, 0x40, 0x29, 0x03, 0x2a, 0x05, 0x2b, 0xa8, 0xb9, 0x80, 0xc0, 0xa9, 0x30, 0x4c, 0xa8, 0xa5, 0x40, 0x29, 0x03, 0x2a, 0x05, 0x2b, 0xa8, 0xb9, 0x80, 0xc0, 0xa9, 0x30, 0x4c, 0xa8,
0xfc, 0x4c, byte(sdStart), byte(sdStart >> 8), 0xfc, 0x4c, byte(s.Start), byte(s.Start >> 8),
} }
if len(loader)+sectors+1 > 256 { if len(loader)+sectors+1 > 256 {
return fmt.Errorf("file %q is %d bytes long, max is %d", args[1], len(contents), (255-len(loader))*256) return fmt.Errorf("file %q is %d bytes long, max is %d", s.Binary.Name(), len(contents), (255-len(loader))*256)
} }
for len(contents)%256 != 0 { for len(contents)%256 != 0 {
@ -102,7 +96,7 @@ func runMkSd(args []string) error {
} }
} }
address := int(sdAddress) + i address := int(s.Address) + i
loader = append(loader, byte(address>>8)) loader = append(loader, byte(address>>8))
if err := disk.WriteSector(diskbytes, track, sector, contents[i:i+256]); err != nil { if err := disk.WriteSector(diskbytes, track, sector, contents[i:i+256]); err != nil {
return err return err
@ -118,17 +112,13 @@ func runMkSd(args []string) error {
return err return err
} }
f, err := os.Create(args[0]) order := s.Order
if order == types.DiskOrderAuto {
order = disk.OrderFromFilename(s.DiskImage, types.DiskOrderDO)
}
rawBytes, err := disk.Swizzle(diskbytes, disk.PhysicalToLogicalByName[order])
if err != nil { if err != nil {
return err return err
} }
return fmt.Errorf("write not implemented") return helpers.WriteOutput(s.DiskImage, rawBytes, true)
//_, err = sd.Write(f)
if err != nil {
return err
}
if err = f.Close(); err != nil {
return err
}
return nil
} }

Binary file not shown.

View File

@ -4,13 +4,16 @@
// file formats. // file formats.
package disk package disk
import "github.com/zellyn/diskii/types"
// Various DOS33 disk characteristics. // Various DOS33 disk characteristics.
const ( const (
FloppyTracks = 35 FloppyTracks = 35
FloppySectors = 16 // Sectors per track FloppySectors = 16 // Sectors per track
// FloppyDiskBytes is the number of bytes on a DOS 3.3 disk. // FloppyDiskBytes is the number of bytes on a DOS 3.3 disk.
FloppyDiskBytes = 143360 // 35 tracks * 16 sectors * 256 bytes FloppyDiskBytes = 143360 // 35 tracks * 16 sectors * 256 bytes
FloppyTrackBytes = 256 * FloppySectors // Bytes per track FloppyTrackBytes = 256 * FloppySectors // Bytes per track
FloppyDiskBytes13Sector = 35 * 13 * 256
) )
// Dos33LogicalToPhysicalSectorMap maps logical sector numbers to physical ones. // Dos33LogicalToPhysicalSectorMap maps logical sector numbers to physical ones.
@ -43,16 +46,18 @@ var ProDosPhysicalToLogicalSectorMap = []int{
// LogicalToPhysicalByName maps from "do" and "po" to the corresponding // LogicalToPhysicalByName maps from "do" and "po" to the corresponding
// logical-to-physical ordering. // logical-to-physical ordering.
var LogicalToPhysicalByName map[string][]int = map[string][]int{ var LogicalToPhysicalByName map[types.DiskOrder][]int = map[types.DiskOrder][]int{
"do": Dos33LogicalToPhysicalSectorMap, types.DiskOrderDO: Dos33LogicalToPhysicalSectorMap,
"po": ProDOSLogicalToPhysicalSectorMap, types.DiskOrderPO: ProDOSLogicalToPhysicalSectorMap,
types.DiskOrderRaw: {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
} }
// PhysicalToLogicalByName maps from "do" and "po" to the corresponding // PhysicalToLogicalByName maps from "do" and "po" to the corresponding
// physical-to-logical ordering. // physical-to-logical ordering.
var PhysicalToLogicalByName map[string][]int = map[string][]int{ var PhysicalToLogicalByName map[types.DiskOrder][]int = map[types.DiskOrder][]int{
"do": Dos33PhysicalToLogicalSectorMap, types.DiskOrderDO: Dos33PhysicalToLogicalSectorMap,
"po": ProDosPhysicalToLogicalSectorMap, types.DiskOrderPO: ProDosPhysicalToLogicalSectorMap,
types.DiskOrderRaw: {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
} }
// TrackSector is a pair of track/sector bytes. // TrackSector is a pair of track/sector bytes.

View File

@ -7,24 +7,81 @@ import (
"path" "path"
"strings" "strings"
"github.com/zellyn/diskii/helpers"
"github.com/zellyn/diskii/types" "github.com/zellyn/diskii/types"
) )
// OpenImage attempts to open an image on disk, using the provided ordering and system type. // OpenFilename attempts to open a disk or device image, using the provided ordering and system type.
func OpenImage(file *os.File, order string, system string, globals *types.Globals) (types.Operator, string, error) { func OpenFilename(filename string, order types.DiskOrder, system string, operatorFactories []types.OperatorFactory, debug bool) (types.Operator, types.DiskOrder, error) {
if filename == "-" {
return OpenFile(os.Stdin, order, system, operatorFactories, debug)
}
file, err := os.Open(filename)
if err != nil {
return nil, "", err
}
return OpenFile(file, order, system, operatorFactories, debug)
}
// OpenImage attempts to open a disk or device image, using the provided ordering and system type.
// OpenImage will close the file.
func OpenFile(file *os.File, order types.DiskOrder, system string, operatorFactories []types.OperatorFactory, debug bool) (types.Operator, types.DiskOrder, error) {
bb, err := io.ReadAll(file) bb, err := io.ReadAll(file)
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
if len(bb) == FloppyDiskBytes { if err := file.Close(); err != nil {
return openDoOrPo(bb, order, system, globals, strings.ToLower(path.Ext(file.Name()))) return nil, "", err
} }
return nil, "", fmt.Errorf("OpenImage not implemented yet for non-disk-sized images") return OpenImage(bb, file.Name(), order, system, operatorFactories, debug)
} }
func openDoOrPo(diskbytes []byte, order string, system string, globals *types.Globals, ext string) (types.Operator, string, error) { // OpenImage attempts to open a disk or device image, using the provided ordering and system type.
func OpenImage(filebytes []byte, filename string, order types.DiskOrder, system string, operatorFactories []types.OperatorFactory, debug bool) (types.Operator, types.DiskOrder, error) {
ext := strings.ToLower(path.Ext(filename))
size := len(filebytes)
if size == FloppyDiskBytes {
return openDoOrPo(filebytes, order, system, ext, operatorFactories, debug)
}
if size == FloppyDiskBytes13Sector {
return nil, "", fmt.Errorf("cannot open 13-sector disk images (yet)")
}
if ext == ".hdv" {
return openHDV(filebytes, order, system, operatorFactories, debug)
}
return nil, "", fmt.Errorf("can only open disk-sized images and .hdv files")
}
func openHDV(rawbytes []byte, order types.DiskOrder, system string, operatorFactories []types.OperatorFactory, debug bool) (types.Operator, types.DiskOrder, error) {
size := len(rawbytes)
if size%512 > 0 {
return nil, "", fmt.Errorf("can only open .hdv files that are a multiple of 512 bytes: %d %% 512 == %d", size, size%512)
}
if size/512 > 65536 {
return nil, "", fmt.Errorf("can only open .hdv up to size 32MiB (%d); got %d", 65536*512, size)
}
if order != "auto" && order != types.DiskOrderPO {
return nil, "", fmt.Errorf("cannot open .hdv file in %q order", order)
}
if system != "auto" && system != "prodos" {
return nil, "", fmt.Errorf("cannot open .hdv file with %q system", system)
}
for _, factory := range operatorFactories {
if factory.Name() == "prodos" {
op, err := factory.Operator(rawbytes, debug)
if err != nil {
return nil, "", err
}
return op, types.DiskOrderPO, nil
}
}
return nil, "", fmt.Errorf("unable to find prodos module to open .hdv file") // Should not happen.
}
func openDoOrPo(rawbytes []byte, order types.DiskOrder, system string, ext string, operatorFactories []types.OperatorFactory, debug bool) (types.Operator, types.DiskOrder, error) {
var factories []types.OperatorFactory var factories []types.OperatorFactory
for _, factory := range globals.DiskOperatorFactories { for _, factory := range operatorFactories {
if system == "auto" || system == factory.Name() { if system == "auto" || system == factory.Name() {
factories = append(factories, factory) factories = append(factories, factory)
} }
@ -32,18 +89,18 @@ func openDoOrPo(diskbytes []byte, order string, system string, globals *types.Gl
if len(factories) == 0 { if len(factories) == 0 {
return nil, "", fmt.Errorf("cannot find disk system with name %q", system) return nil, "", fmt.Errorf("cannot find disk system with name %q", system)
} }
orders := []string{order} orders := []types.DiskOrder{order}
switch order { switch order {
case "do", "po": case types.DiskOrderDO, types.DiskOrderPO:
// nothing more // nothing more
case "auto": case types.DiskOrderAuto:
switch ext { switch ext {
case ".po": case ".po":
orders = []string{"po"} orders = []types.DiskOrder{types.DiskOrderPO}
case ".do": case ".do":
orders = []string{"do"} orders = []types.DiskOrder{types.DiskOrderDO}
case ".dsk", "": case ".dsk", "":
orders = []string{"do", "po"} orders = []types.DiskOrder{types.DiskOrderDO, types.DiskOrderPO}
default: default:
return nil, "", fmt.Errorf("unknown disk image extension: %q", ext) return nil, "", fmt.Errorf("unknown disk image extension: %q", ext)
} }
@ -52,31 +109,36 @@ func openDoOrPo(diskbytes []byte, order string, system string, globals *types.Gl
} }
for _, order := range orders { for _, order := range orders {
swizzled, err := Swizzle(diskbytes, LogicalToPhysicalByName[order]) swizzled, err := Swizzle(rawbytes, LogicalToPhysicalByName[order])
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
for _, factory := range factories { for _, factory := range factories {
diskbytes, err := Swizzle(swizzled, PhysicalToLogicalByName[factory.DiskOrder()])
if err != nil {
return nil, "", err
}
if len(orders) == 1 && system != "auto" { if len(orders) == 1 && system != "auto" {
if globals.Debug { if debug {
fmt.Fprintf(os.Stderr, "Attempting to open with order=%s, system=%s.\n", order, factory.Name()) fmt.Fprintf(os.Stderr, "Attempting to open with order=%s, system=%s.\n", order, factory.Name())
} }
op, err := factory.Operator(swizzled, globals.Debug) op, err := factory.Operator(diskbytes, debug)
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
return op, order, nil return op, order, nil
} }
if globals.Debug { if debug {
fmt.Fprintf(os.Stderr, "Testing whether order=%s, system=%s seems to match.\n", order, factory.Name()) fmt.Fprintf(os.Stderr, "Testing whether order=%s, system=%s seems to match.\n", order, factory.Name())
} }
if factory.SeemsToMatch(swizzled, globals.Debug) { if factory.SeemsToMatch(diskbytes, debug) {
op, err := factory.Operator(swizzled, globals.Debug) op, err := factory.Operator(diskbytes, debug)
if err == nil { if err == nil {
return op, order, nil return op, order, nil
} }
if globals.Debug { if debug {
fmt.Fprintf(os.Stderr, "Got error opening with order=%s, system=%s: %v\n", order, factory.Name(), err) fmt.Fprintf(os.Stderr, "Got error opening with order=%s, system=%s: %v\n", order, factory.Name(), err)
} }
} }
@ -140,3 +202,39 @@ func validateOrder(order []int) error {
} }
return nil return nil
} }
// OrderFromFilename tries to guess the disk order from the filename, using the extension.
func OrderFromFilename(filename string, defaultOrder types.DiskOrder) types.DiskOrder {
ext := strings.ToLower(path.Ext(filename))
switch ext {
case ".dsk", ".do":
return types.DiskOrderDO
case ".po":
return types.DiskOrderPO
default:
return defaultOrder
}
}
// WriteBack writes a disk image back out.
func WriteBack(filename string, op types.Operator, diskFileOrder types.DiskOrder, overwrite bool) error {
logicalBytes := op.GetBytes()
// If it's not floppy-sized, we don't swizzle at all.
if len(logicalBytes) != FloppyDiskBytes {
return helpers.WriteOutput(filename, logicalBytes, overwrite)
}
// Go from logical sectors for the operator back to physical sectors.
physicalBytes, err := Swizzle(logicalBytes, LogicalToPhysicalByName[op.DiskOrder()])
if err != nil {
return err
}
// Go from physical sectors to the disk order (DO or PO)
diskBytes, err := Swizzle(physicalBytes, PhysicalToLogicalByName[diskFileOrder])
if err != nil {
return err
}
return helpers.WriteOutput(filename, diskBytes, overwrite)
}

View File

@ -671,6 +671,16 @@ func (o operator) PutFile(fileInfo types.FileInfo, overwrite bool) (existed bool
return false, fmt.Errorf("%s does not implement PutFile yet", operatorName) return false, fmt.Errorf("%s does not implement PutFile yet", operatorName)
} }
// DiskOrder returns the Physical-to-Logical mapping order.
func (o operator) DiskOrder() types.DiskOrder {
return types.DiskOrderDO
}
// GetBytes returns the disk image bytes, in logical order.
func (o operator) GetBytes() []byte {
return o.data
}
// OperatorFactory is a types.OperatorFactory for DOS 3.3 disks. // OperatorFactory is a types.OperatorFactory for DOS 3.3 disks.
type OperatorFactory struct { type OperatorFactory struct {
} }
@ -682,13 +692,9 @@ func (of OperatorFactory) Name() string {
// SeemsToMatch returns true if the []byte disk image seems to match the // SeemsToMatch returns true if the []byte disk image seems to match the
// system of this operator. // system of this operator.
func (of OperatorFactory) SeemsToMatch(rawbytes []byte, debug bool) bool { func (of OperatorFactory) SeemsToMatch(diskbytes []byte, debug bool) bool {
// For now, just return true if we can run Catalog successfully. // For now, just return true if we can run Catalog successfully.
swizzled, err := of.swizzle(rawbytes) _, _, err := ReadCatalog(diskbytes, debug)
if err != nil {
return false
}
_, _, err = ReadCatalog(swizzled, debug)
if err != nil { if err != nil {
return false return false
} }
@ -696,14 +702,11 @@ func (of OperatorFactory) SeemsToMatch(rawbytes []byte, debug bool) bool {
} }
// Operator returns an Operator for the []byte disk image. // Operator returns an Operator for the []byte disk image.
func (of OperatorFactory) Operator(rawbytes []byte, debug bool) (types.Operator, error) { func (of OperatorFactory) Operator(diskbytes []byte, debug bool) (types.Operator, error) {
swizzled, err := of.swizzle(rawbytes) return operator{data: diskbytes, debug: debug}, nil
if err != nil {
return nil, err
}
return operator{data: swizzled, debug: debug}, nil
} }
func (of OperatorFactory) swizzle(rawbytes []byte) ([]byte, error) { // DiskOrder returns the Physical-to-Logical mapping order.
return disk.Swizzle(rawbytes, disk.Dos33PhysicalToLogicalSectorMap) func (of OperatorFactory) DiskOrder() types.DiskOrder {
return operator{}.DiskOrder()
} }

View File

@ -1,8 +0,0 @@
// This file contains the list of commands to run to re-generate
// generated files.
// Use go-bindata to embed static assets that we need.
//go:generate go-bindata -pkg data -prefix "data/" -o data/data.go data/disks data/boot
//go:generate goimports -w data/data.go
package main

5
go.mod
View File

@ -3,8 +3,7 @@ module github.com/zellyn/diskii
go 1.16 go 1.16
require ( require (
github.com/alecthomas/kong v0.2.17 // indirect github.com/alecthomas/kong v0.2.17
github.com/kr/pretty v0.2.1 github.com/kr/pretty v0.2.1
github.com/spf13/cobra v1.1.3 github.com/rogpeppe/go-internal v1.8.0
github.com/spf13/viper v1.8.1
) )

653
go.sum
View File

@ -1,673 +1,30 @@
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/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.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
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/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/alecthomas/kong v0.2.17 h1:URDISCI96MIgcIlQyoCAlhOmrSw6pZScBNkctg8r0W0= github.com/alecthomas/kong v0.2.17 h1:URDISCI96MIgcIlQyoCAlhOmrSw6pZScBNkctg8r0W0=
github.com/alecthomas/kong v0.2.17/go.mod h1:ka3VZ8GZNPXv9Ov+j4YNLkI8mTuhXyr/0ktSlqIydQQ= github.com/alecthomas/kong v0.2.17/go.mod h1:ka3VZ8GZNPXv9Ov+j4YNLkI8mTuhXyr/0ktSlqIydQQ=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
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-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
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/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
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/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/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
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/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
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-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/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/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
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-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
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/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/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/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/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/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/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/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-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
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/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
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/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.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
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 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
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/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/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
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/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.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A=
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
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-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
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/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
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/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
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.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
github.com/mitchellh/mapstructure v1.4.1/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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
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/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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/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/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
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/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
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.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M=
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
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.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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/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 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
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=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
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.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
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=
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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
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/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/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-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/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-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-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-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/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-20210402161424-2e8d93401602/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/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-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/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-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-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-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/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-20200122134326-e047566fdf82/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-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-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
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 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
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-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
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-20190328211700-ab21143f2384/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-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-20191112195655-aa38f8e97acc/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-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.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
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.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
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-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
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.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
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=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
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.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.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
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=
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=

View File

@ -1,7 +1,7 @@
// Copyright © 2016 Zellyn Hunter <zellyn@gmail.com> // Copyright © 2016 Zellyn Hunter <zellyn@gmail.com>
// Package helpers contains various routines used to help cobra // Package helpers contains helper routines for reading and writing files,
// commands stay succinct. // allowing `-` to mean stdin/stdout.
package helpers package helpers
import ( import (
@ -21,18 +21,15 @@ func FileContentsOrStdIn(s string) ([]byte, error) {
return os.ReadFile(s) return os.ReadFile(s)
} }
func WriteOutput(outfilename string, contents []byte, infilename string, force bool) error { func WriteOutput(filename string, contents []byte, force bool) error {
if outfilename == "" { if filename == "-" {
outfilename = infilename
}
if outfilename == "-" {
_, err := os.Stdout.Write(contents) _, err := os.Stdout.Write(contents)
return err return err
} }
if !force { if !force {
if _, err := os.Stat(outfilename); !errors.Is(err, fs.ErrNotExist) { if _, err := os.Stat(filename); !errors.Is(err, fs.ErrNotExist) {
return fmt.Errorf("cannot overwrite file %q without --force (-f)", outfilename) return fmt.Errorf("cannot overwrite file %q without --force (-f)", filename)
} }
} }
return os.WriteFile(outfilename, contents, 0666) return os.WriteFile(filename, contents, 0666)
} }

44
main.go
View File

@ -3,6 +3,9 @@
package main package main
import ( import (
"reflect"
"strconv"
"github.com/zellyn/diskii/cmd" "github.com/zellyn/diskii/cmd"
"github.com/zellyn/diskii/dos3" "github.com/zellyn/diskii/dos3"
"github.com/zellyn/diskii/prodos" "github.com/zellyn/diskii/prodos"
@ -18,21 +21,27 @@ import (
var cli struct { var cli struct {
Debug bool `kong:"short='v',help='Enable debug mode.'"` Debug bool `kong:"short='v',help='Enable debug mode.'"`
Ls cmd.LsCmd `cmd:"" aliases:"cat,catalog" help:"List paths."` Ls cmd.LsCmd `cmd:"" aliases:"list,cat,catalog" help:"List files/directories on a disk."`
Reorder cmd.ReorderCmd `cmd:"" help:"Reorder disk images."` Reorder cmd.ReorderCmd `cmd:"" help:"Convert between DOS-order and ProDOS-order disk images."`
Filetypes cmd.FiletypesCmd `cmd:"" help:"Print a list of filetypes understood by diskii."` Filetypes cmd.FiletypesCmd `cmd:"" help:"Print a list of filetypes understood by diskii."`
Put cmd.PutCmd `cmd:"" help:"Put the raw contents of a file onto a disk."`
Rm cmd.DeleteCmd `cmd:"" aliases:"delete" help:"Delete a file."`
Dump cmd.DumpCmd `cmd:"" help:"Dump the raw contents of a file."`
Nakedos cmd.NakedOSCmd `cmd:"" help:"Work with NakedOS-format disks."`
Mksd cmd.SDCmd `cmd:"" help:"Create a “Standard Delivery” disk image containing a binary."`
Applesoft cmd.ApplesoftCmd `cmd:"" help:"Work with Applesoft BASIC files."`
} }
func run() error { func run() error {
ctx := kong.Parse(&cli, ctx := kong.Parse(&cli,
kong.Name("diskii"), kong.Name("diskii"),
kong.Description("A commandline tool for working with Apple II disk images."), kong.Description("A commandline tool for working with Apple II disk images."),
kong.UsageOnError(), // kong.UsageOnError(),
kong.ConfigureHelp(kong.HelpOptions{ kong.ConfigureHelp(kong.HelpOptions{
Compact: true, Compact: true,
Summary: true, Summary: true,
}), }),
kong.NamedMapper("anybaseuint16", hexUint16Mapper{}),
) )
globals := &types.Globals{ globals := &types.Globals{
@ -48,9 +57,36 @@ func run() error {
} }
func main() { func main() {
err := run() err := run()
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err) fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1) os.Exit(1)
} }
} }
type hexUint16Mapper struct{}
func (h hexUint16Mapper) Decode(ctx *kong.DecodeContext, target reflect.Value) error {
t, err := ctx.Scan.PopValue("int")
if err != nil {
return err
}
var sv string
switch v := t.Value.(type) {
case string:
sv = v
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:
sv = fmt.Sprintf("%v", v)
default:
return fmt.Errorf("expected an int but got %q (%T)", t, t.Value)
}
n, err := strconv.ParseUint(sv, 0, 16)
if err != nil {
return fmt.Errorf("expected a valid %d bit uint but got %q", 16, sv)
}
target.SetUint(n)
return nil
}

View File

@ -1,6 +0,0 @@
go-bindata -pkg data -o data/data.go \
data/disks/ProDOS_2_4_1.dsk \
data/disks/dos33master.woz \
data/boot/prodos-new-boot0.bin \
data/boot/prodos-old-boot0.bin
goimports -w data/data.go

6
next Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
# Quick little script to add failing commands to, so I know what I'm working on next.
set -euo pipefail
set -x
# go run . nakedos mkhello supermon-audit-new.dsk DF02
# go run . put -f supermon-audit-new.dsk DF02:FWORLD audit.o

View File

@ -7,6 +7,7 @@ package prodos
import ( import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"os"
"github.com/zellyn/diskii/disk" "github.com/zellyn/diskii/disk"
"github.com/zellyn/diskii/types" "github.com/zellyn/diskii/types"
@ -611,11 +612,12 @@ func (sh SubdirectoryHeader) Name() string {
// Volume is the in-memory representation of a device's volume // Volume is the in-memory representation of a device's volume
// information. // information.
type Volume struct { type Volume struct {
keyBlock *VolumeDirectoryKeyBlock keyBlock *VolumeDirectoryKeyBlock // The key block describing the entire volume
blocks []*VolumeDirectoryBlock blocks []*VolumeDirectoryBlock // The blocks in the top-level volume
bitmap *VolumeBitMap bitmap *VolumeBitMap // Bitmap of which blocks are free
subdirsByBlock map[uint16]*Subdirectory subdirsByBlock map[uint16]*Subdirectory // A mapping of block number to subdirectory object
subdirsByName map[string]*Subdirectory subdirsByName map[string]*Subdirectory // a mapping of string to subdirectory object
firstSubdirBlocks map[uint16]uint16 // A mapping of later dir/subdir blocks to the first one in the chain
} }
// Subdirectory is the in-memory representation of a single // Subdirectory is the in-memory representation of a single
@ -652,16 +654,20 @@ func (v Volume) subdirDescriptors() []FileDescriptor {
// readVolume reads the entire volume and subdirectories from a device // readVolume reads the entire volume and subdirectories from a device
// into memory. // into memory.
func readVolume(devicebytes []byte, keyBlock uint16) (Volume, error) { func readVolume(devicebytes []byte, keyBlock uint16, debug bool) (Volume, error) {
v := Volume{ v := Volume{
keyBlock: &VolumeDirectoryKeyBlock{}, keyBlock: &VolumeDirectoryKeyBlock{},
subdirsByBlock: make(map[uint16]*Subdirectory), subdirsByBlock: make(map[uint16]*Subdirectory),
subdirsByName: make(map[string]*Subdirectory), subdirsByName: make(map[string]*Subdirectory),
firstSubdirBlocks: make(map[uint16]uint16),
} }
if err := disk.UnmarshalBlock(devicebytes, v.keyBlock, keyBlock); err != nil { if err := disk.UnmarshalBlock(devicebytes, v.keyBlock, keyBlock); err != nil {
return v, fmt.Errorf("cannot read first block of volume directory (block %d): %v", keyBlock, err) return v, fmt.Errorf("cannot read first block of volume directory (block %d): %v", keyBlock, err)
} }
// if debug {
// fmt.Fprintf(os.Stderr, "keyblock: %#v\n", v.keyBlock)
// }
if vbm, err := readVolumeBitMap(devicebytes, v.keyBlock.Header.BitMapPointer); err != nil { if vbm, err := readVolumeBitMap(devicebytes, v.keyBlock.Header.BitMapPointer); err != nil {
return v, err return v, err
@ -669,15 +675,29 @@ func readVolume(devicebytes []byte, keyBlock uint16) (Volume, error) {
v.bitmap = &vbm v.bitmap = &vbm
} }
// if debug {
// fmt.Fprintf(os.Stderr, "volume bitmap: %#v\n", v.bitmap)
// }
for block := v.keyBlock.Next; block != 0; block = v.blocks[len(v.blocks)-1].Next { for block := v.keyBlock.Next; block != 0; block = v.blocks[len(v.blocks)-1].Next {
vdb := VolumeDirectoryBlock{} vdb := VolumeDirectoryBlock{}
if err := disk.UnmarshalBlock(devicebytes, &vdb, block); err != nil { if err := disk.UnmarshalBlock(devicebytes, &vdb, block); err != nil {
return v, err return v, err
} }
v.blocks = append(v.blocks, &vdb) v.blocks = append(v.blocks, &vdb)
v.firstSubdirBlocks[block] = keyBlock
if debug {
fmt.Fprintf(os.Stderr, " firstSubdirBlocks[%d] → %d\n", block, keyBlock)
}
// if debug {
// fmt.Fprintf(os.Stderr, "block: %#v\n", vdb)
// }
} }
sdds := v.subdirDescriptors() sdds := v.subdirDescriptors()
if debug {
fmt.Fprintf(os.Stderr, "got %d top-level subdir descriptors\n", len(sdds))
}
for i := 0; i < len(sdds); i++ { for i := 0; i < len(sdds); i++ {
sdd := sdds[i] sdd := sdds[i]
@ -686,12 +706,27 @@ func readVolume(devicebytes []byte, keyBlock uint16) (Volume, error) {
return v, err return v, err
} }
v.subdirsByBlock[sdd.KeyPointer] = &sub v.subdirsByBlock[sdd.KeyPointer] = &sub
if debug {
fmt.Fprintf(os.Stderr, " subdirsByBlock[%d] → %q\n", sdd.KeyPointer, sub.keyBlock.Header.Name())
}
sdds = append(sdds, sub.subdirDescriptors()...) sdds = append(sdds, sub.subdirDescriptors()...)
for _, block := range sub.blocks {
v.firstSubdirBlocks[block.block] = sdd.KeyPointer
if debug {
fmt.Fprintf(os.Stderr, " firstSubdirBlocks[%d] → %d\n", block.block, sdd.KeyPointer)
}
}
}
if debug {
fmt.Fprintf(os.Stderr, "got %d total subdir descriptors\n", len(sdds))
} }
for _, sd := range v.subdirsByBlock { for _, sd := range v.subdirsByBlock {
name := sd.keyBlock.Header.Name() name := sd.keyBlock.Header.Name()
parentName, err := parentDirName(sd.keyBlock.Header.ParentPointer, keyBlock, v.subdirsByBlock) if debug {
fmt.Fprintf(os.Stderr, "processing subdir %q\n", name)
}
parentName, err := parentDirName(sd.keyBlock.Header.ParentPointer, keyBlock, v.subdirsByBlock, v.firstSubdirBlocks)
if err != nil { if err != nil {
return v, err return v, err
} }
@ -701,6 +736,9 @@ func readVolume(devicebytes []byte, keyBlock uint16) (Volume, error) {
v.subdirsByName[name] = sd v.subdirsByName[name] = sd
} }
if debug {
fmt.Fprintf(os.Stderr, "HERE2\n")
}
return v, nil return v, nil
} }
@ -729,16 +767,23 @@ func (s Subdirectory) subdirDescriptors() []FileDescriptor {
return descs return descs
} }
// fullDirName returns the full recursive directory name of the given parent directory. // parentDirName returns the full recursive directory name of the given parent directory.
func parentDirName(parentDirectoryBlock uint16, keyBlock uint16, subdirMap map[uint16]*Subdirectory) (string, error) { func parentDirName(parentDirectoryBlock uint16, keyBlock uint16, subdirMap map[uint16]*Subdirectory, firstSubdirBlockMap map[uint16]uint16) (string, error) {
if parentDirectoryBlock == keyBlock { if parentDirectoryBlock == keyBlock || firstSubdirBlockMap[parentDirectoryBlock] == keyBlock {
return "", nil return "", nil
} }
sd := subdirMap[parentDirectoryBlock] sd := subdirMap[parentDirectoryBlock]
if sd == nil {
parentFirstBlock, ok := firstSubdirBlockMap[parentDirectoryBlock]
if ok {
sd = subdirMap[parentFirstBlock]
}
}
if sd == nil { if sd == nil {
return "", fmt.Errorf("Unable to find subdirectory for block %d", parentDirectoryBlock) return "", fmt.Errorf("Unable to find subdirectory for block %d", parentDirectoryBlock)
} }
parentName, err := parentDirName(sd.keyBlock.Header.ParentPointer, keyBlock, subdirMap)
parentName, err := parentDirName(sd.keyBlock.Header.ParentPointer, keyBlock, subdirMap, firstSubdirBlockMap)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -807,10 +852,12 @@ func (o operator) HasSubdirs() bool {
// Catalog returns a catalog of disk entries. subdir should be empty // Catalog returns a catalog of disk entries. subdir should be empty
// for operating systems that do not support subdirectories. // for operating systems that do not support subdirectories.
func (o operator) Catalog(subdir string) ([]types.Descriptor, error) { func (o operator) Catalog(subdir string) ([]types.Descriptor, error) {
if o.debug {
vol, err := readVolume(o.data, 2) fmt.Fprintf(os.Stderr, "Catalog of %q\n", subdir)
}
vol, err := readVolume(o.data, 2, o.debug)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("error reading volume: %w", err)
} }
var result []types.Descriptor var result []types.Descriptor
@ -855,6 +902,16 @@ func (o operator) PutFile(fileInfo types.FileInfo, overwrite bool) (existed bool
return false, fmt.Errorf("%s doesn't implement PutFile yet", operatorName) return false, fmt.Errorf("%s doesn't implement PutFile yet", operatorName)
} }
// DiskOrder returns the Physical-to-Logical mapping order.
func (o operator) DiskOrder() types.DiskOrder {
return types.DiskOrderPO
}
// GetBytes returns the disk image bytes, in logical order.
func (o operator) GetBytes() []byte {
return o.data
}
// OperatorFactory is a types.OperatorFactory for ProDos disks. // OperatorFactory is a types.OperatorFactory for ProDos disks.
type OperatorFactory struct { type OperatorFactory struct {
} }
@ -868,14 +925,7 @@ func (of OperatorFactory) Name() string {
// system of this operator. // system of this operator.
func (of OperatorFactory) SeemsToMatch(devicebytes []byte, debug bool) bool { func (of OperatorFactory) SeemsToMatch(devicebytes []byte, debug bool) bool {
// For now, just return true if we can run Catalog successfully. // For now, just return true if we can run Catalog successfully.
if len(devicebytes) == disk.FloppyDiskBytes { _, err := readVolume(devicebytes, 2, debug)
swizzled, err := of.swizzle(devicebytes)
if err != nil {
return false
}
devicebytes = swizzled
}
_, err := readVolume(devicebytes, 2)
if err != nil { if err != nil {
return false return false
} }
@ -884,16 +934,10 @@ func (of OperatorFactory) SeemsToMatch(devicebytes []byte, debug bool) bool {
// Operator returns an Operator for the []byte disk image. // Operator returns an Operator for the []byte disk image.
func (of OperatorFactory) Operator(devicebytes []byte, debug bool) (types.Operator, error) { func (of OperatorFactory) Operator(devicebytes []byte, debug bool) (types.Operator, error) {
if len(devicebytes) == disk.FloppyDiskBytes {
swizzled, err := of.swizzle(devicebytes)
if err != nil {
return nil, err
}
devicebytes = swizzled
}
return operator{data: devicebytes, debug: debug}, nil return operator{data: devicebytes, debug: debug}, nil
} }
func (of OperatorFactory) swizzle(rawbytes []byte) ([]byte, error) { // DiskOrder returns the Physical-to-Logical mapping order.
return disk.Swizzle(rawbytes, disk.ProDosPhysicalToLogicalSectorMap) func (of OperatorFactory) DiskOrder() types.DiskOrder {
return operator{}.DiskOrder()
} }

25
script_test.go Normal file
View File

@ -0,0 +1,25 @@
package main
import (
"os"
"testing"
"github.com/rogpeppe/go-internal/testscript"
)
func testscriptMain() int {
main()
return 0
}
func TestMain(m *testing.M) {
os.Exit(testscript.RunMain(m, map[string]func() int{
"diskii": testscriptMain,
}))
}
func TestFoo(t *testing.T) {
testscript.Run(t, testscript.Params{
Dir: "testdata",
})
}

View File

@ -640,35 +640,35 @@ func (st SymbolTable) FilesForCompoundName(filename string) (numFile byte, named
return numFile, namedFile, parts[1], nil return numFile, namedFile, parts[1], nil
} }
// operator is a disk.Operator - an interface for performing // Operator is a disk.Operator - an interface for performing
// high-level operations on files and directories. // high-level operations on files and directories.
type operator struct { type Operator struct {
data []byte data []byte
SM SectorMap SM SectorMap
ST SymbolTable ST SymbolTable
debug bool debug bool
} }
var _ types.Operator = operator{} var _ types.Operator = Operator{}
// operatorName is the keyword name for the operator that undestands // operatorName is the keyword name for the operator that undestands
// NakedOS/Super-Mon disks. // NakedOS/Super-Mon disks.
const operatorName = "nakedos" const operatorName = "nakedos"
// Name returns the name of the Operator. // Name returns the name of the Operator.
func (o operator) Name() string { func (o Operator) Name() string {
return operatorName return operatorName
} }
// HasSubdirs returns true if the underlying operating system on the // HasSubdirs returns true if the underlying operating system on the
// disk allows subdirectories. // disk allows subdirectories.
func (o operator) HasSubdirs() bool { func (o Operator) HasSubdirs() bool {
return false return false
} }
// Catalog returns a catalog of disk entries. subdir should be empty // Catalog returns a catalog of disk entries. subdir should be empty
// for operating systems that do not support subdirectories. // for operating systems that do not support subdirectories.
func (o operator) Catalog(subdir string) ([]types.Descriptor, error) { func (o Operator) Catalog(subdir string) ([]types.Descriptor, error) {
var descs []types.Descriptor var descs []types.Descriptor
sectorsByFile := o.SM.SectorsByFile() sectorsByFile := o.SM.SectorsByFile()
for file := byte(1); file < FileReserved; file++ { for file := byte(1); file < FileReserved; file++ {
@ -689,7 +689,7 @@ func (o operator) Catalog(subdir string) ([]types.Descriptor, error) {
} }
// GetFile retrieves a file by name. // GetFile retrieves a file by name.
func (o operator) GetFile(filename string) (types.FileInfo, error) { func (o Operator) GetFile(filename string) (types.FileInfo, error) {
file, err := o.ST.FileForName(filename) file, err := o.ST.FileForName(filename)
if err != nil { if err != nil {
return types.FileInfo{}, err return types.FileInfo{}, err
@ -720,7 +720,7 @@ func (o operator) GetFile(filename string) (types.FileInfo, error) {
// Delete deletes a file by name. It returns true if the file was // Delete deletes a file by name. It returns true if the file was
// deleted, false if it didn't exist. // deleted, false if it didn't exist.
func (o operator) Delete(filename string) (bool, error) { func (o Operator) Delete(filename string) (bool, error) {
file, err := o.ST.FileForName(filename) file, err := o.ST.FileForName(filename)
if err != nil { if err != nil {
return false, err return false, err
@ -744,9 +744,9 @@ func (o operator) Delete(filename string) (bool, error) {
// PutFile writes a file by name. If the file exists and overwrite // PutFile writes a file by name. If the file exists and overwrite
// is false, it returns with an error. Otherwise it returns true if // is false, it returns with an error. Otherwise it returns true if
// an existing file was overwritten. // an existing file was overwritten.
func (o operator) PutFile(fileInfo types.FileInfo, overwrite bool) (existed bool, err error) { func (o Operator) PutFile(fileInfo types.FileInfo, overwrite bool) (existed bool, err error) {
if fileInfo.Descriptor.Type != types.FiletypeBinary { if fileInfo.Descriptor.Type != types.FiletypeBinary {
return false, fmt.Errorf("%s: only binary file type supported", operatorName) return false, fmt.Errorf("%s: only binary file type supported; got %q", operatorName, fileInfo.Descriptor.Type)
} }
if fileInfo.Descriptor.Length != len(fileInfo.Data) { if fileInfo.Descriptor.Length != len(fileInfo.Data) {
return false, fmt.Errorf("mismatch between FileInfo.Descriptor.Length (%d) and actual length of FileInfo.Data field (%d)", fileInfo.Descriptor.Length, len(fileInfo.Data)) return false, fmt.Errorf("mismatch between FileInfo.Descriptor.Length (%d) and actual length of FileInfo.Data field (%d)", fileInfo.Descriptor.Length, len(fileInfo.Data))
@ -785,25 +785,14 @@ func (o operator) PutFile(fileInfo types.FileInfo, overwrite bool) (existed bool
return existed, nil return existed, nil
} }
// XOperatorFactory is the factory that returns supermon operators // DiskOrder returns the Physical-to-Logical mapping order.
// given disk images. func (o Operator) DiskOrder() types.DiskOrder {
func XOperatorFactory(diskbytes []byte) (types.Operator, error) { return types.DiskOrderRaw
sm, err := LoadSectorMap(diskbytes) }
if err != nil {
return nil, err
}
if err := sm.Verify(); err != nil {
return nil, err
}
op := operator{data: diskbytes, SM: sm} // GetBytes returns the disk image bytes, in logical order.
func (o Operator) GetBytes() []byte {
st, err := sm.ReadSymbolTable(diskbytes) return o.data
if err == nil {
op.ST = st
}
return op, nil
} }
// OperatorFactory is a types.OperatorFactory for DOS 3.3 disks. // OperatorFactory is a types.OperatorFactory for DOS 3.3 disks.
@ -839,7 +828,7 @@ func (of OperatorFactory) Operator(diskbytes []byte, debug bool) (types.Operator
return nil, err return nil, err
} }
op := operator{data: diskbytes, SM: sm, debug: debug} op := Operator{data: diskbytes, SM: sm, debug: debug}
st, err := sm.ReadSymbolTable(diskbytes) st, err := sm.ReadSymbolTable(diskbytes)
if err == nil { if err == nil {
@ -848,3 +837,8 @@ func (of OperatorFactory) Operator(diskbytes []byte, debug bool) (types.Operator
return op, nil return op, nil
} }
// DiskOrder returns the Physical-to-Logical mapping order.
func (of OperatorFactory) DiskOrder() types.DiskOrder {
return Operator{}.DiskOrder()
}

View File

@ -52,9 +52,7 @@ func getOperator(filename string) (types.Operator, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
op, _, err := disk.OpenImage(f, "do", "nakedos", &types.Globals{ op, _, err := disk.OpenFile(f, "do", "nakedos", []types.OperatorFactory{OperatorFactory{}}, false)
DiskOperatorFactories: []types.OperatorFactory{OperatorFactory{}},
})
if err != nil { if err != nil {
return nil, err return nil, err
} }

7
testdata/cathello.txt vendored Normal file
View File

@ -0,0 +1,7 @@
# hello world
exec cat hello.text
stdout 'hello world\n'
! stderr .
-- hello.text --
hello world

View File

@ -17,11 +17,23 @@ type Descriptor struct {
Type Filetype Type Filetype
} }
type DiskOrder string
const (
DiskOrderDO = DiskOrder("do")
DiskOrderPO = DiskOrder("po")
DiskOrderRaw = DiskOrder("raw")
DiskOrderAuto = DiskOrder("auto")
DiskOrderUnknown = DiskOrder("")
)
// OperatorFactory is the interface for getting operators, and finding out a bit // OperatorFactory is the interface for getting operators, and finding out a bit
// about them before getting them. // about them before getting them.
type OperatorFactory interface { type OperatorFactory interface {
// Name returns the name of the operator. // Name returns the name of the operator.
Name() string Name() string
// DiskOrder returns the Physical-to-Logical mapping order.
DiskOrder() DiskOrder
// SeemsToMatch returns true if the []byte disk image seems to match the // SeemsToMatch returns true if the []byte disk image seems to match the
// system of this operator. // system of this operator.
SeemsToMatch(diskbytes []byte, debug bool) bool SeemsToMatch(diskbytes []byte, debug bool) bool
@ -33,6 +45,8 @@ type OperatorFactory interface {
type Operator interface { type Operator interface {
// Name returns the name of the operator. // Name returns the name of the operator.
Name() string Name() string
// DiskOrder returns the Physical-to-Logical mapping order.
DiskOrder() DiskOrder
// HasSubdirs returns true if the underlying operating system on the // HasSubdirs returns true if the underlying operating system on the
// disk allows subdirectories. // disk allows subdirectories.
HasSubdirs() bool HasSubdirs() bool
@ -48,6 +62,8 @@ type Operator interface {
// is false, it returns with an error. Otherwise it returns true if // is false, it returns with an error. Otherwise it returns true if
// an existing file was overwritten. // an existing file was overwritten.
PutFile(fileInfo FileInfo, overwrite bool) (existed bool, err error) PutFile(fileInfo FileInfo, overwrite bool) (existed bool, err error)
// GetBytes returns the disk image bytes, in logical order.
GetBytes() []byte
} }
// FileInfo represents a file descriptor plus the content. // FileInfo represents a file descriptor plus the content.