diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b5c2b0..838f60e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ - [csvtk v0.24.0](https://github.com/shenwei356/csvtk/releases/tag/v0.24.0) [![Github Releases (by Release)](https://img.shields.io/github/downloads/shenwei356/csvtk/v0.24.0/total.svg)](https://github.com/shenwei356/csvtk/releases/tag/v0.24.0) + - new command `csvtk fmtdate`: format date of selected fields. [#159](https://github.com/shenwei356/csvtk/issues/159) - `csvtk grep`: fix bug for searching with `-r -p .`. - `csvtk filter2`: fix bug for date expression. [#146](https://github.com/shenwei356/csvtk/issues/146) - `csvtk mutate2/filter2`: change the way of rexpression evaluation. - - `csvtk mutate2`: add custom functions: `len()`. + - `csvtk mutate2`: add custom functions: `len()`. [#153](https://github.com/shenwei356/csvtk/issues/153) - `csvtk cut`: new flags `-m/--allow-missing-col` and `-b/--blank-missing-col`. [#156](https://github.com/shenwei356/csvtk/issues/156) - `csvtk pretty`: still add header row for empty column. - [csvtk v0.23.0](https://github.com/shenwei356/csvtk/releases/tag/v0.23.0) diff --git a/README.md b/README.md index e638dde..640ce61 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# csvtk - A cross-platform, efficient and practical CSV/TSV toolkit +# csvtk - a cross-platform, efficient and practical CSV/TSV toolkit - **Documents:** [http://bioinf.shenwei.me/csvtk](http://bioinf.shenwei.me/csvtk/) ( [**Usage**](http://bioinf.shenwei.me/csvtk/usage/) and [**Tutorial**](http://bioinf.shenwei.me/csvtk/tutorial/)). [中文介绍](http://bioinf.shenwei.me/csvtk/chinese) @@ -64,7 +64,7 @@ It could save you lots of time in (not) writing Python/R scripts. ## Subcommands -48 subcommands in total. +49 subcommands in total. **Information** @@ -120,6 +120,7 @@ It could save you lots of time in (not) writing Python/R scripts. - [`gather`](https://bioinf.shenwei.me/csvtk/usage/#gather): gathers columns into key-value pairs - [`unfold`](https://bioinf.shenwei.me/csvtk/usage/#unfold): unfold multiple values in cells of a field - [`fold`](https://bioinf.shenwei.me/csvtk/usage/#fold): fold multiple values of a field into cells of groups +- [`fmtdate`](https://bioinf.shenwei.me/csvtk/usage/#fmtdate): format date of selected fields **Ordering** diff --git a/csvtk/cmd/csv2xlsx.go b/csvtk/cmd/csv2xlsx.go index cc066b4..d87ff40 100644 --- a/csvtk/cmd/csv2xlsx.go +++ b/csvtk/cmd/csv2xlsx.go @@ -25,8 +25,8 @@ import ( "path/filepath" "runtime" - "github.com/360EntSecGroup-Skylar/excelize/v2" "github.com/spf13/cobra" + "github.com/xuri/excelize/v2" ) // csv2xlsxCmd represents the seq command diff --git a/csvtk/cmd/fmtdate.go b/csvtk/cmd/fmtdate.go new file mode 100644 index 0000000..10cbe3c --- /dev/null +++ b/csvtk/cmd/fmtdate.go @@ -0,0 +1,283 @@ +// Copyright © 2016-2021 Wei Shen +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package cmd + +import ( + "encoding/csv" + "fmt" + "regexp" + "runtime" + "time" + + "github.com/araddon/dateparse" + "github.com/metakeule/fmtdate" + "github.com/shenwei356/xopen" + "github.com/spf13/cobra" +) + +// fmtdateCmd represents the replace command +var fmtdateCmd = &cobra.Command{ + Use: "fmtdate", + Short: "format date of selected fields", + Long: `format date of selected fields + +Date parsing is supported by: https://github.com/araddon/dateparse +Date formating is supported by: https://github.com/metakeule/fmtdate + +Time zones: + format: Asia/Shanghai + whole list: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones + +Output format is in MS Excel (TM) syntax. +Placeholders: + + M - month (1) + MM - month (01) + MMM - month (Jan) + MMMM - month (January) + D - day (2) + DD - day (02) + DDD - day (Mon) + DDDD - day (Monday) + YY - year (06) + YYYY - year (2006) + hh - hours (15) + mm - minutes (04) + ss - seconds (05) + + AM/PM hours: 'h' followed by optional 'mm' and 'ss' followed by 'pm', e.g. + + hpm - hours (03PM) + h:mmpm - hours:minutes (03:04PM) + h:mm:sspm - hours:minutes:seconds (03:04:05PM) + + Time zones: a time format followed by 'ZZZZ', 'ZZZ' or 'ZZ', e.g. + + hh:mm:ss ZZZZ (16:05:06 +0100) + hh:mm:ss ZZZ (16:05:06 CET) + hh:mm:ss ZZ (16:05:06 +01:00) + +`, + Run: func(cmd *cobra.Command, args []string) { + config := getConfigs(cmd) + files := getFileListFromArgsAndFile(cmd, args, true, "infile-list", true) + if len(files) > 1 { + checkError(fmt.Errorf("no more than one file should be given")) + } + runtime.GOMAXPROCS(config.NumCPUs) + + timezone := getFlagString(cmd, "time-zone") + outfmt := getFlagString(cmd, "format") + keepUnparsed := getFlagBool(cmd, "keep-unparsed") + + if timezone != "" { + loc, err := time.LoadLocation(timezone) + if err != nil { + checkError(fmt.Errorf("setting time zone: %s", err)) + } + time.Local = loc + } + + fieldStr := getFlagString(cmd, "fields") + if fieldStr == "" { + checkError(fmt.Errorf("flag -f (--fields) needed")) + } + fields, colnames, negativeFields, needParseHeaderRow, _ := parseFields(cmd, fieldStr, config.NoHeaderRow) + var fieldsMap map[int]struct{} + if len(fields) > 0 { + fields2 := make([]int, len(fields)) + fieldsMap = make(map[int]struct{}, len(fields)) + for i, f := range fields { + if negativeFields { + fieldsMap[f*-1] = struct{}{} + fields2[i] = f * -1 + } else { + fieldsMap[f] = struct{}{} + fields2[i] = f + } + } + fields = fields2 + } + + fuzzyFields := getFlagBool(cmd, "fuzzy-fields") + + outfh, err := xopen.Wopen(config.OutFile) + checkError(err) + defer outfh.Close() + + writer := csv.NewWriter(outfh) + if config.OutTabs || config.Tabs { + if config.OutDelimiter == ',' { + writer.Comma = '\t' + } else { + writer.Comma = config.OutDelimiter + } + } else { + writer.Comma = config.OutDelimiter + } + + for _, file := range files { + csvReader, err := newCSVReaderByConfig(config, file) + checkError(err) + csvReader.Run() + + parseHeaderRow := needParseHeaderRow // parsing header row + parseHeaderRow2 := needParseHeaderRow + var colnames2fileds map[string]int // column name -> field + var colnamesMap map[string]*regexp.Regexp + + checkFields := true + + var record2 []string // for output + + printMetaLine := true + for chunk := range csvReader.Ch { + checkError(chunk.Err) + + if printMetaLine && len(csvReader.MetaLine) > 0 { + outfh.WriteString(fmt.Sprintf("sep=%s\n", string(writer.Comma))) + printMetaLine = false + } + + for _, record := range chunk.Data { + if parseHeaderRow { // parsing header row + colnames2fileds = make(map[string]int, len(record)) + for i, col := range record { + colnames2fileds[col] = i + 1 + } + colnamesMap = make(map[string]*regexp.Regexp, len(colnames)) + for _, col := range colnames { + if !fuzzyFields { + if negativeFields { + if _, ok := colnames2fileds[col[1:]]; !ok { + checkError(fmt.Errorf(`column "%s" not existed in file: %s`, col[1:], file)) + } + } else { + if _, ok := colnames2fileds[col]; !ok { + checkError(fmt.Errorf(`column "%s" not existed in file: %s`, col, file)) + } + } + } + if negativeFields { + colnamesMap[col[1:]] = fuzzyField2Regexp(col[1:]) + } else { + colnamesMap[col] = fuzzyField2Regexp(col) + } + } + + if len(fields) == 0 { // user gives the colnames + fields = []int{} + for _, col := range record { + var ok bool + if fuzzyFields { + for _, re := range colnamesMap { + if re.MatchString(col) { + ok = true + break + } + } + } else { + _, ok = colnamesMap[col] + } + if ok { + fields = append(fields, colnames2fileds[col]) + } + } + } + + fieldsMap = make(map[int]struct{}, len(fields)) + for _, f := range fields { + fieldsMap[f] = struct{}{} + } + + parseHeaderRow = false + } + if checkFields { + for field := range fieldsMap { + if field > len(record) { + checkError(fmt.Errorf(`field (%d) out of range (%d) in file: %s`, field, len(record), file)) + } + } + fields2 := []int{} + for f := range record { + _, ok := fieldsMap[f+1] + if negativeFields { + if !ok { + fields2 = append(fields2, f+1) + } + } else { + if ok { + fields2 = append(fields2, f+1) + } + } + } + fields = fields2 + if len(fields) == 0 { + checkError(fmt.Errorf("no fields matched in file: %s", file)) + } + fieldsMap = make(map[int]struct{}, len(fields)) + for _, f := range fields { + fieldsMap[f] = struct{}{} + } + + record2 = make([]string, len(record)) + + checkFields = false + } + + if parseHeaderRow2 { // do not replace head line + checkError(writer.Write(record)) + parseHeaderRow2 = false + continue + } + for f := range record { + record2[f] = record[f] + if _, ok := fieldsMap[f+1]; ok { + t, err := dateparse.ParseLocal(record2[f]) + if err != nil { + if !keepUnparsed { + record2[f] = "" + } + // checkError(fmt.Errorf("fail to parse date: %s", err)) + } else { + record2[f] = fmtdate.Format(outfmt, t) + } + } + } + checkError(writer.Write(record2)) + } + } + + readerReport(&config, csvReader, file) + } + writer.Flush() + checkError(writer.Error()) + }, +} + +func init() { + RootCmd.AddCommand(fmtdateCmd) + fmtdateCmd.Flags().StringP("fields", "f", "1", `select only these fields. e.g -f 1,2 or -f columnA,columnB`) + fmtdateCmd.Flags().BoolP("fuzzy-fields", "F", false, `using fuzzy fields, e.g., -F -f "*name" or -F -f "id123*"`) + fmtdateCmd.Flags().StringP("format", "", "YYYY-MM-DD hh:mm:ss", `output date format in MS Excel (TM) syntax, type "csvtk fmtdate -h" for details`) + fmtdateCmd.Flags().BoolP("keep-unparsed", "k", false, "keep the key as value when no value found for the key") + fmtdateCmd.Flags().StringP("time-zone", "z", "", `timezone aka "Asia/Shanghai" or "America/Los_Angeles" formatted time-zone, type "csvtk fmtdate -h" for details`) +} diff --git a/csvtk/cmd/splitxlsx.go b/csvtk/cmd/splitxlsx.go index d41a23d..d2b2b75 100644 --- a/csvtk/cmd/splitxlsx.go +++ b/csvtk/cmd/splitxlsx.go @@ -27,8 +27,8 @@ import ( "sort" "strings" - "github.com/360EntSecGroup-Skylar/excelize/v2" "github.com/spf13/cobra" + "github.com/xuri/excelize/v2" ) // splitXlsxCmd represents the splitXlsx command diff --git a/csvtk/cmd/xlsx2csv.go b/csvtk/cmd/xlsx2csv.go index 2c86a89..07f7f31 100644 --- a/csvtk/cmd/xlsx2csv.go +++ b/csvtk/cmd/xlsx2csv.go @@ -26,9 +26,9 @@ import ( "runtime" "sort" - "github.com/360EntSecGroup-Skylar/excelize/v2" "github.com/shenwei356/xopen" "github.com/spf13/cobra" + "github.com/xuri/excelize/v2" ) // xlsx2csvCmd represents the seq command diff --git a/doc/docs/usage.md b/doc/docs/usage.md index 2491ef3..7e113de 100644 --- a/doc/docs/usage.md +++ b/doc/docs/usage.md @@ -96,7 +96,7 @@ Usage ```text csvtk -- a cross-platform, efficient and practical CSV/TSV toolkit -Version: 0.23.0 +Version: 0.24.0 Author: Wei Shen @@ -143,6 +143,7 @@ Available Commands: dim dimensions of CSV file filter filter rows by values of selected fields with arithmetic expression filter2 filter rows by awk-like artithmetic/string expressions + fmtdate format date of selected fields fold fold multiple values of a field into cells of groups freq frequencies of selected fields gather gather columns into key-value pairs @@ -2992,6 +2993,64 @@ examples Jerry sequencing center Bioinformatics Nick sequencing center Molecular Biology; Microbiology +## fmtdate + +Usage + +```text +format date of selected fields + +Date parsing is supported by: https://github.com/araddon/dateparse +Date formating is supported by: https://github.com/metakeule/fmtdate + +Time zones: + format: Asia/Shanghai + whole list: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones + +Output format is in MS Excel (TM) syntax. +Placeholders: + + M - month (1) + MM - month (01) + MMM - month (Jan) + MMMM - month (January) + D - day (2) + DD - day (02) + DDD - day (Mon) + DDDD - day (Monday) + YY - year (06) + YYYY - year (2006) + hh - hours (15) + mm - minutes (04) + ss - seconds (05) + + AM/PM hours: 'h' followed by optional 'mm' and 'ss' followed by 'pm', e.g. + + hpm - hours (03PM) + h:mmpm - hours:minutes (03:04PM) + h:mm:sspm - hours:minutes:seconds (03:04:05PM) + + Time zones: a time format followed by 'ZZZZ', 'ZZZ' or 'ZZ', e.g. + + hh:mm:ss ZZZZ (16:05:06 +0100) + hh:mm:ss ZZZ (16:05:06 CET) + hh:mm:ss ZZ (16:05:06 +01:00) + +Usage: + csvtk fmtdate [flags] + +Flags: + -f, --fields string select only these fields. e.g -f 1,2 or -f columnA,columnB (default "1") + --format string output date format in MS Excel (TM) syntax, type "csvtk fmtdate -h" for details (default "YYYY-MM-DD hh:mm:ss") + -F, --fuzzy-fields using fuzzy fields, e.g., -F -f "*name" or -F -f "id123*" + -h, --help help for fmtdate + -k, --keep-unparsed keep the key as value when no value found for the key + -z, --time-zone string timezone aka "Asia/Shanghai" or "America/Los_Angeles" formatted time-zone, type "csvtk fmtdate -h" for details +``` + +Examples + +TODO: add examples ## sort diff --git a/go.mod b/go.mod index f5920f9..1e5f16a 100644 --- a/go.mod +++ b/go.mod @@ -3,13 +3,14 @@ module github.com/shenwei356/csvtk go 1.16 require ( - github.com/360EntSecGroup-Skylar/excelize/v2 v2.3.2 github.com/Knetic/govaluate v3.0.0+incompatible + github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de github.com/bsipos/thist v1.0.0 github.com/cheggaaa/pb/v3 v3.0.6 github.com/dustin/go-humanize v1.0.0 github.com/fatih/color v1.10.0 github.com/mattn/go-colorable v0.1.8 + github.com/metakeule/fmtdate v1.1.2 github.com/mitchellh/go-homedir v1.1.0 github.com/mxschmitt/golang-combinations v1.1.0 github.com/pkg/errors v0.9.1 @@ -21,6 +22,7 @@ require ( github.com/shenwei356/xopen v0.0.0-20181203091311-f4f16ddd3992 github.com/spf13/cobra v1.1.3 github.com/tatsushid/go-prettytable v0.0.0-20141013043238-ed2d14c29939 + github.com/xuri/excelize/v2 v2.4.1 gonum.org/v1/gonum v0.8.2 gonum.org/v1/plot v0.8.1 ) diff --git a/go.sum b/go.sum index 21e7b71..5026a4a 100644 --- a/go.sum +++ b/go.sum @@ -12,8 +12,6 @@ cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2k cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= gioui.org v0.0.0-20200628203458-851255f7a67b/go.mod h1:jiUwifN9cRl/zmco43aAqh0aV+s9GbhG13KcD+gEpkU= -github.com/360EntSecGroup-Skylar/excelize/v2 v2.3.2 h1:MHu5KWWt28FzRGQgc4Ryj/lZT/W/by4NvsnstbWwkkY= -github.com/360EntSecGroup-Skylar/excelize/v2 v2.3.2/go.mod h1:xc0ybJZXcn084ZaIvQv+LfCDQjMWfxkBa2K9nLXYJtI= 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/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg= @@ -25,6 +23,8 @@ github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af h1:wVe6/Ea46ZMeNkQjj github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= 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/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA= +github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw= 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= @@ -150,9 +150,12 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg= +github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/metakeule/fmtdate v1.1.2 h1:n9M7H9HfAqp+6OA98wXGMdcAr6omshSNVct65Bks1lQ= +github.com/metakeule/fmtdate v1.1.2/go.mod h1:2JyMFlKxeoGy1qS6obQukT0AL0Y4iNANQL8scbSdT4E= 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= @@ -194,11 +197,14 @@ github.com/richardlehane/mscfb v1.0.3 h1:rD8TBkYWkObWO0oLDFCbwMeZ4KoalxQy+QgniCj github.com/richardlehane/mscfb v1.0.3/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk= github.com/richardlehane/msoleps v1.0.1 h1:RfrALnSNXzmXLbGct/P2b4xkFz4e8Gmj/0Vj9M9xC1o= github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= +github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= 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/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7PQSMz9NShzorzCiG2fk9+xuCgLkPeCvMHYR2OWg= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shenwei356/bpool v0.0.0-20160710042833-f9e0ee4d0403 h1:/3JklLnHXiWUBxWc3joQYavDQJpncRhRA909cUb7eOw= github.com/shenwei356/bpool v0.0.0-20160710042833-f9e0ee4d0403/go.mod h1:YkgdTWfNnJgv5HVJbVSDmxQtkK3/jZWDoqcG26BVU8k= @@ -231,8 +237,9 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ 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.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= 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/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tatsushid/go-prettytable v0.0.0-20141013043238-ed2d14c29939 h1:BhIUXV2ySTLrKgh/Hnts+QTQlIbWtomXt3LMdzME0A0= github.com/tatsushid/go-prettytable v0.0.0-20141013043238-ed2d14c29939/go.mod h1:omGxs4/6hNjxPKUTjmaNkPzehSnNJOJN6pMEbrlYIT4= @@ -240,8 +247,10 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1 github.com/twotwotwo/sorts v0.0.0-20160814051341-bf5c1f2b8553 h1:DRC1ubdb3ZmyyIeCSTxjZIQAnpLPfKVgYrLETQuOPjo= github.com/twotwotwo/sorts v0.0.0-20160814051341-bf5c1f2b8553/go.mod h1:Rj7Csq/tZ/egz+Ltc2IVpsA5309AmSMEswjkTZmq2Xc= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xuri/efp v0.0.0-20201016154823-031c29024257 h1:6ldmGEJXtsRMwdR2KuS3esk9wjVJNvgk05/YY2XmOj0= -github.com/xuri/efp v0.0.0-20201016154823-031c29024257/go.mod h1:uBiSUepVYMhGTfDeBKKasV4GpgBlzJ46gXUBAqV8qLk= +github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3 h1:EpI0bqf/eX9SdZDwlMmahKM+CDBgNbsXMhsN28XrM8o= +github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= +github.com/xuri/excelize/v2 v2.4.1 h1:veeeFLAJwsNEBPBlDepzPIYS1eLyBVcXNZUW79exZ1E= +github.com/xuri/excelize/v2 v2.4.1/go.mod h1:rSu0C3papjzxQA3sdK8cU544TebhrPUoTOaGPIh0Q1A= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= @@ -253,9 +262,8 @@ golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnf 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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee h1:4yd7jl+vXjalO5ztz6Vc1VADv+S/80LGJmyl1ROJ2AI= -golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -272,8 +280,8 @@ golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+o golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20201208152932-35266b937fa6 h1:nfeHNc1nAqecKCy2FCy4HY+soOOe5sDLJ/gZLbx6GYI= -golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb h1:fqpd0EBDzlHRCjiphRR5Zo/RSWWQlWv34418dnEixWk= +golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/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= @@ -299,8 +307,9 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn 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-20201016165138-7b1cca2348c0 h1:5kGOVHlq0euqwzgTC9Vu15p6fV1Wi0ArVi8da2urnVg= -golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 h1:4CSI6oo7cOjJKajidEljs9h+uP0rRZBPPPhcCbj5mw8= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 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= @@ -327,13 +336,18 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= -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-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 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 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/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/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=