diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..daeed48 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +vendor +*.DS_Store +dl +.coverage.txt +linux_386 +linux_amd64 +mac_amd64 +windows_386.exe +windows_amd64.exe +file_example_MP3_700KB.mp3 +Apex.2021.720p.WEBRip.x264.AAC-%5BYTS.MX%5D.mp4 +go1.14.2.src.tar.gz \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..924384c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,12 @@ +# Contributing + +## Must follow the guide for issues + - Use the search tool before opening a new issue. + - Please provide source code and stack trace if you found a bug. + - Please review the existing issues and provide feedback to them + +## Pull Request Process + - Open your pull request against `dev` branch + - It should pass all tests in the available continuous integrations systems such as TravisCI. + - You should add/modify tests to cover your proposed code changes. + - If your pull request contains a new feature, please document it on the README. diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..4fc3c71 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# The MIT License (MIT) + +Copyright (c) 2021 Saddam H + +> 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. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..70fa083 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +.PHONY: all test coverage +all: test build +build: + go build -o dl +binary: + go run generate-asset.go + ./build.sh +install: + go install ./... +test: + go test ./... -v -coverprofile .coverage.txt + go tool cover -func .coverage.txt +coverage: test + go tool cover -html=.coverage.txt \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7045a30 --- /dev/null +++ b/README.md @@ -0,0 +1,154 @@ +DL +--- +Command-line file downloader tool + +### Usage + +```sh +$ dl -u https://www.url.com/foo.ext +``` + +![Alt Text](example.gif) + + +#### Installation on Mac/Linux +```bash +curl https://raw.githubusercontent.com/thedevsaddam/dl/main/install.sh -o install.sh \ +&& sudo chmod +x install.sh \ +&& sudo ./install.sh \ +&& rm install.sh +``` + +#### Uninstallation +```bash +curl https://raw.githubusercontent.com/thedevsaddam/dl/main/uninstall.sh -o uninstall.sh \ +&& sudo chmod +x uninstall.sh \ +&& sudo ./uninstall.sh \ +&& rm uninstall.sh +``` + +#### Windows +**For windows download the binary and set environment variable so that you can access the binary from terminal** + +**[Download Binary](https://github.com/thedevsaddam/dl/releases)** + +### Download options + +```sh +$ dl -u https://www.url.com/foo.ext +# or with concurrency +$ dl -u https://www.url.com/foo.ext -c 10 +# with debug mode enabled (if you are curious!) +$ dl -u https://www.url.com/foo.ext -c 10 -d +# with custom output file name +$ dl -u https://www.url.com/foo.ext -c 10 -d -n bar.ext +``` +### Configurations + +**Setup destination directory** + +```sh +# set current directory path as destination directory +$ dl config -p . +# or set other directory +$ dl config -p $HOME/Downloads +``` +Note: If you have `destination` directory set then all files automatically will be saved there. If you want to override on the fly then use `-p .` flag to download in the current directory. +By default the `destination` directory value is empty that means the file will be downloaded in the current directory. + +**Setup sub-directory/extensions** + +Note: If `destination` directory is not set then the sub-directory/extensions will NOT WORK + +```sh +# set sub-directory based on extensions +# this will create a "binary" diectory inside root directory. +# all downloads with .exe, .dmg extensions will be stored there +$ dl config -s "binary:.exe,.dmg" +``` + +**Setup concurrency** + +```sh +# default concurrency is 5, you can set default value by passing -c flag in config +$ dl config -c 10 +``` + +### Default configurations + +
config.json +
+{
+	"directory":"",
+	"concurrency":5,
+	"sub_dir_map":{
+		"audio":[
+			".aif",
+			".cda",
+			".mid",
+			".midi",
+			".mp3",
+			".mpa",
+			".ogg",
+			".wav",
+			".wma",
+			".wpl"
+		],
+		"document":[
+			".xls",
+			".xlsm",
+			".xlsx",
+			".ods",
+			".doc",
+			".odt",
+			".pdf",
+			".rtf",
+			".tex",
+			".txt",
+			".wpd",
+			".md"
+		],
+		"image":[
+			".ai",
+			".bmp",
+			".ico",
+			".jpeg",
+			".jpg",
+			".png",
+			".ps",
+			".psd",
+			".svg",
+			".tif",
+			".tiff"
+		],
+		"video":[
+			".3g2",
+			".3gp",
+			".avi",
+			".flv",
+			".h264",
+			".m4v",
+			".mkv",
+			".mov",
+			".mp4",
+			".mpg",
+			".mpeg",
+			".rm",
+			".swf",
+			".vob",
+			".wmv"
+		]
+	}
+}
+
+
+ + +### Contribution +Your suggestions will be more than appreciated. +[Read the contribution guide here](CONTRIBUTING.md) + +### See all [contributors](https://github.com/thedevsaddam/dl/graphs/contributors) + +### **License** +The **dl** is an open-source software licensed under the [MIT License](LICENSE.md). diff --git a/assets/icon.png b/assets/icon.png new file mode 100644 index 0000000..23644b7 Binary files /dev/null and b/assets/icon.png differ diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..b907826 --- /dev/null +++ b/build.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +GIT_COMMIT=$(git rev-parse --short HEAD) +TAG=$(git describe --exact-match --abbrev=0 --tags ${COMMIT} 2> /dev/null || true) +DATE=$(date +'%Y-%m-%d') + +echo "Building binaries" +echo Git commit: $GIT_COMMIT Version: $TAG Build date: $DATE + +go generate + +# MAC +export GOARCH="amd64" +export GOOS="darwin" +export CGO_ENABLED=1 +go build -ldflags "-X github.com/thedevsaddam/dl/cmd.GitCommit=$GIT_COMMIT -X github.com/thedevsaddam/dl/cmd.Version=$TAG -X github.com/thedevsaddam/dl/cmd.BuildDate=$DATE" -o mac_amd64 -v . + +#LINUX +export GOARCH="amd64" +export GOOS="linux" +export CGO_ENABLED=0 +go build -ldflags "-X github.com/thedevsaddam/dl/cmd.GitCommit=$GIT_COMMIT -X github.com/thedevsaddam/dl/cmd.Version=$TAG -X github.com/thedevsaddam/dl/cmd.BuildDate=$DATE" -o linux_amd64 -v + +export GOARCH="386" +export GOOS="linux" +export CGO_ENABLED=0 +go build -ldflags "-X github.com/thedevsaddam/dl/cmd.GitCommit=$GIT_COMMIT -X github.com/thedevsaddam/dl/cmd.Version=$TAG -X github.com/thedevsaddam/dl/cmd.BuildDate=$DATE" -o linux_386 -v + +#WINDOWS +export GOARCH="386" +export GOOS="windows" +export CGO_ENABLED=0 +go build -ldflags "-X github.com/thedevsaddam/dl/cmd.GitCommit=$GIT_COMMIT -X github.com/thedevsaddam/dl/cmd.Version=$TAG -X github.com/thedevsaddam/dl/cmd.BuildDate=$DATE" -o windows_386.exe -v + +export GOARCH="amd64" +export GOOS="windows" +export CGO_ENABLED=0 +go build -ldflags "-X github.com/thedevsaddam/dl/cmd.GitCommit=$GIT_COMMIT -X github.com/thedevsaddam/dl/cmd.Version=$TAG -X github.com/thedevsaddam/dl/cmd.BuildDate=$DATE" -o windows_amd64.exe -v + +echo "Build complete" \ No newline at end of file diff --git a/cmd/config.go b/cmd/config.go new file mode 100644 index 0000000..4237066 --- /dev/null +++ b/cmd/config.go @@ -0,0 +1,72 @@ +package cmd + +import ( + "encoding/json" + "fmt" + "log" + "os" + "strings" + + "github.com/spf13/cobra" + "github.com/thedevsaddam/dl/config" +) + +var ( + path string + subPath string + + cmdConfig = &cobra.Command{ + Use: "config", + Short: "Config set configuration values", + Long: `Config set configuration values`, + Run: setConfig, + } +) + +func init() { + cmdConfig.Flags().StringVarP(&path, "path", "p", "", "destination directory where the file will be downloaded") + cmdConfig.Flags().StringVarP(&subPath, "subpath", "s", "", "sub directory map in this format subdirectoryName:.ext1,.ext2. e.g: video:.mp4,.mkv") + cmdConfig.Flags().IntVarP(&concurrent, "concurrent", "c", 0, "number of concurrent process will be running, default: 5") + cmdConfig.Flags().BoolVarP(&debug, "debug", "d", false, "display configuration") + cmdDL.AddCommand(cmdConfig) +} + +func setConfig(cmd *cobra.Command, args []string) { + // if user provide "." then set current directory as root directory + if path == "." { + dir, err := os.Getwd() + if err != nil { + log.Fatalln(err) + } + path = dir + } + + newCfg := config.Config{Directory: path, Concurrency: uint(concurrent)} + + if subPath != "" { + newCfg.SubDirMap = config.DefaultConfig().SubDirMap // assign old config + + pp := strings.Split(subPath, ":") + if len(pp) > 1 { + subDir := pp[0] + extensions := strings.Split(pp[1], ",") + for _, e := range extensions { + newCfg.SubDirMap.Add(subDir, e) + } + } + } + + if err := config.SetConfig(newCfg); err != nil { + log.Fatalln(err) + } + + if debug { + if err := config.LoadDefaultConfig(); err != nil { + log.Fatalln(err) + } + bb, err := json.MarshalIndent(config.DefaultConfig(), "", " ") + if err == nil { + fmt.Println(string(bb)) + } + } +} diff --git a/cmd/dl.go b/cmd/dl.go new file mode 100644 index 0000000..faf0665 --- /dev/null +++ b/cmd/dl.go @@ -0,0 +1,133 @@ +package cmd + +import ( + "fmt" + "log" + netUrl "net/url" + "os" + "strings" + + "github.com/spf13/cobra" + "github.com/thedevsaddam/dl/config" + "github.com/thedevsaddam/dl/downloader" + "github.com/thedevsaddam/dl/logger" + "github.com/thedevsaddam/dl/notifier" +) + +var logo = ` + _____ _ + | __ \| | + | | | | | + | | | | | + | |__| | |____ + |_____/|______| + +Command-line file downloader tool +For more info visit: https://github.com/thedevsaddam/dl +` + +var ( + url string + name string + concurrent int + debug bool + + GitCommit = "unknown" + Version = "unknown" + BuildDate = "unknown" + + // cmdDL is the root command of DL application + cmdDL = &cobra.Command{ + Use: "dl", + Short: "Command-line file downloader tool", + Long: logo, + // Args: cobra.MinimumNArgs(1), + Run: startDownload, + } +) + +// Execute executes the root command +func Execute() { + if err := cmdDL.Execute(); err != nil { + os.Exit(1) + } +} + +func init() { + cobra.OnInitialize(initConfig) + cmdDL.Flags().StringVarP(&url, "url", "u", "", "url should be the address where the file will be downloaded. e.g: https://example.com/foo.jpg") + cmdDL.Flags().StringVarP(&name, "name", "n", "", "destination name with extension. e.g: foo.jpg") + cmdDL.Flags().StringVarP(&path, "path", "p", "", "destination directory where the file will be downloaded") + cmdDL.Flags().IntVarP(&concurrent, "concurrent", "c", 0, "number of concurrent process will be running, default: 5") + cmdDL.Flags().BoolVarP(&debug, "debug", "d", false, "debug print the essential logs") +} + +func initConfig() { + err := config.LoadDefaultConfig() + if err != nil { + log.Fatalln(err) + } +} + +func startDownload(cmd *cobra.Command, args []string) { + url = strings.TrimSpace(url) + if len(url) == 0 { + return + } + + if _, err := netUrl.ParseRequestURI(url); err != nil { + log.Fatalln(err) + } + dm := downloader.New() + + if debug { + dm.ApplyOption(downloader.WithVerbose()) + dm.ApplyOption(downloader.WithLogger(logger.New(true))) + } + + cfg := config.DefaultConfig() + + con := cfg.Concurrency + if concurrent != 0 { // assuming default is 5 + con = uint(concurrent) + } + dm.ApplyOption(downloader.WithConcurrency(uint(con))) + + dm.ApplyOption(downloader.WithSubPathMap(cfg.SubDirMap)) + + if cfg.Directory != "" { + dm.ApplyOption(downloader.WithFilePath(cfg.Directory)) + } + + // if provided in flag then override the pverious path config + if path != "" { + // if user provide "." then set current directory as root directory + if path == "." { + dir, err := os.Getwd() + if err != nil { + log.Fatalln(err) + } + path = dir + } + dm.ApplyOption(downloader.WithFilePath(path)) + dm.ApplyOption(downloader.WithSkipSubPathMap()) + } + + if name != "" { + dm.ApplyOption(downloader.WithFilename(name)) + } + + errs := dm.Download(url).Errors() + if len(errs) > 0 { + log.Fatalln("Download failed") + if debug { + for _, e := range errs { + log.Println("Error:", e) + } + } + return + } + + n := notifier.New("DL [Terminal Downloader]") + n.Notify("Download complete!", fmt.Sprintf("File: %s (%s)", dm.GetFileName(), dm.GetFileSize())) +} diff --git a/cmd/version.go b/cmd/version.go new file mode 100644 index 0000000..9d89d40 --- /dev/null +++ b/cmd/version.go @@ -0,0 +1,25 @@ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +var cmdVersion = &cobra.Command{ + Use: "version", + Short: "Display application version", + Long: `Display application version`, + Run: version, +} + +func init() { + cmdDL.AddCommand(cmdVersion) +} + +func version(cmd *cobra.Command, args []string) { + fmt.Println(logo) + fmt.Println("Version:", Version) + fmt.Println("Git commit:", GitCommit) + fmt.Println("Build date:", BuildDate) +} diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..beea47e --- /dev/null +++ b/config/config.go @@ -0,0 +1,104 @@ +package config + +import ( + "encoding/json" + "errors" + "io/ioutil" + "os" + "path/filepath" + + "github.com/thedevsaddam/dl/values" +) + +const ( + configFileName = ".dl.config.json" +) + +// Config represent configurations for the download manager +type Config struct { + Directory string `json:"directory"` + Concurrency uint `json:"concurrency"` + SubDirMap values.MapStrSliceString `json:"sub_dir_map"` +} + +var defaultConfig Config + +func getConfigFileName() (string, error) { + homeDir, err := os.UserHomeDir() + if err != nil { + return "", err + } + return filepath.Join(homeDir, configFileName), nil +} + +// LoadDefaultConfig load configuration if exist +func LoadDefaultConfig() error { + fn, err := getConfigFileName() + if err != nil { + return err + } + if _, err := os.Stat(fn); errors.Is(err, os.ErrNotExist) { + subDir := make(values.MapStrSliceString) + subDir["audio"] = []string{".aif", ".cda", ".mid", ".midi", ".mp3", + ".mpa", ".ogg", ".wav", ".wma", ".wpl"} + + subDir["video"] = []string{".3g2", ".3gp", ".avi", ".flv", ".h264", + ".m4v", ".mkv", ".mov", ".mp4", ".mpg", ".mpeg", ".rm", ".swf", + ".vob", ".wmv"} + + subDir["image"] = []string{".ai", ".bmp", ".ico", ".jpeg", ".jpg", + ".png", ".ps", ".psd", ".svg", ".tif", ".tiff"} + + subDir["document"] = []string{".xls", ".xlsm", ".xlsx", ".ods", ".doc", + ".odt", ".pdf", ".rtf", ".tex", ".txt", ".wpd", ".md"} + + CreateConfig(Config{ + Concurrency: 5, + Directory: "", + SubDirMap: subDir, + }) + } + contents, err := ioutil.ReadFile(fn) + if err != nil { + return err + } + return json.Unmarshal(contents, &defaultConfig) +} + +// CreateConfig create a config file in user home directory +func CreateConfig(c Config) error { + bb, err := json.Marshal(c) + if err != nil { + return err + } + fn, err := getConfigFileName() + if err != nil { + return err + } + return ioutil.WriteFile(fn, bb, 0644) +} + +// SetConfig set specific config file in user home directory +func SetConfig(c Config) error { + oldCfg := defaultConfig + if c.Concurrency != 0 { + oldCfg.Concurrency = c.Concurrency + } + + if c.Directory != "" { + oldCfg.Directory = c.Directory + } + + for k, extensions := range c.SubDirMap { + for _, e := range extensions { + oldCfg.SubDirMap.Add(k, e) + } + } + + return CreateConfig(oldCfg) +} + +// DefaultConfig return the default config +func DefaultConfig() Config { + return defaultConfig +} diff --git a/downloader/client.go b/downloader/client.go new file mode 100644 index 0000000..97d30e4 --- /dev/null +++ b/downloader/client.go @@ -0,0 +1,9 @@ +package downloader + +import "net/http" + +// HTTPClient interface +type HTTPClient interface { + // Do sends an HTTP request and returns an HTTP response + Do(req *http.Request) (*http.Response, error) +} diff --git a/downloader/downloader.go b/downloader/downloader.go new file mode 100644 index 0000000..2118e56 --- /dev/null +++ b/downloader/downloader.go @@ -0,0 +1,311 @@ +package downloader + +import ( + "context" + "fmt" + "io" + "net/http" + "os" + "os/signal" + "path" + "path/filepath" + "strconv" + "sync" + "sync/atomic" + "syscall" + "time" + + "github.com/schollz/progressbar/v3" + "github.com/thedevsaddam/dl/logger" + "github.com/thedevsaddam/retry" +) + +const ( + defaultConcurrency = 5 +) + +// DownloadManager ... +type DownloadManager struct { + option option + client HTTPClient + + stop chan os.Signal + completed chan bool + + fileName string // filename with extension + fileSize uint64 // file size in bytes + totalDownloaded uint64 // total file downloaded in bytes + totalChunkCompleted int32 // total completed chunks + totalTimeTaken time.Duration // total time taken to complete downloading + + errors []error // contains all the errors + + mu *sync.Mutex + wg *sync.WaitGroup +} + +// New return a instance of DownloadManager with options +func New(options ...OptionFunc) *DownloadManager { + dm := &DownloadManager{ + wg: &sync.WaitGroup{}, + mu: &sync.Mutex{}, + client: http.DefaultClient, + + errors: make([]error, 0), + + stop: make(chan os.Signal, 1), + completed: make(chan bool, 1), + } + + // set default options + dm.option.concurrency = defaultConcurrency + dm.option.log = logger.New(dm.option.verbose) // enable verbose for applying options + + // apply user provided options + for _, option := range options { + if err := option(dm); err != nil { + fmt.Println("Error:", err) + } + } + + return dm +} + +// ApplyOption apply single option to the download manager +func (d *DownloadManager) ApplyOption(option OptionFunc) error { + return option(d) +} + +// addError add error to the error bag +func (d *DownloadManager) addError(e error) { + d.mu.Lock() + d.errors = append(d.errors, e) + d.mu.Unlock() +} + +// Errors return the error bag +func (d *DownloadManager) Errors() []error { + return d.errors +} + +// renderProgressBar paint & repaint progressbar +func (d *DownloadManager) renderProgressBar(ctx context.Context, maxSize int) { + pb := progressbar.NewOptions(maxSize, + progressbar.OptionSetDescription(fmt.Sprintf("[red][0/%d][reset] Downloading:", d.option.concurrency)), + progressbar.OptionFullWidth(), + progressbar.OptionEnableColorCodes(true), + progressbar.OptionShowBytes(true), + progressbar.OptionSetPredictTime(true), + progressbar.OptionShowCount(), + progressbar.OptionThrottle(500*time.Millisecond), + progressbar.OptionOnCompletion( + func() { + fmt.Printf("\nFile name: %s\n", d.fileName) + fmt.Printf("File size: %s\n", humanaReadableBytes(float64(d.fileSize))) + fmt.Printf("Total time: %s\n", d.totalTimeTaken) + fmt.Printf("Open: %s/%s\n", d.option.path, d.fileName) + }, + ), + ) + + ticker := time.NewTicker(500 * time.Millisecond) + + go func() { + for { + select { + case <-d.stop: + d.option.log.Println("Operation cancelled!") + fmt.Printf("\nOperation cancelled!\n") + ticker.Stop() + os.Exit(1) + case <-d.completed: + ticker.Stop() + d.option.log.Println("Download completed!") + return + case <-ticker.C: + pb.Describe(fmt.Sprintf("[cyan][%d/%d][reset] Downloading:", d.totalChunkCompleted, d.option.concurrency)) + pb.Set64(int64(d.totalDownloaded)) + } + } + }() +} + +// GetFileName return file name; the value will be available once the download start +func (d *DownloadManager) GetFileName() string { + return d.fileName +} + +// GetFileSize return file size in human readable format; the value will be available once the download start +func (d *DownloadManager) GetFileSize() string { + return humanaReadableBytes(float64(d.fileSize)) +} + +// populateFileInfo do a HTTP/HEAD request and gather meta information; MUST call before download +func (d *DownloadManager) populateFileInfo(ctx context.Context, url string) error { + if d.fileName == "" { + d.fileName = path.Base(url) + } + + d.option.log.Printf("Info: fetching file information: %s\n", url) + + err := retry.DoFunc(5, 1*time.Second, func() error { + ctx, cancel := context.WithTimeout(ctx, 3*time.Second) + defer cancel() + + req, err := http.NewRequestWithContext(ctx, http.MethodHead, url, nil) + if err != nil { + d.option.log.Printf("Error: failed to create HTTP/HEAD request: %s\n", err.Error()) + return err + } + + resp, err := d.client.Do(req) + if err != nil { + d.option.log.Printf("Error: failed to perform HTTP/HEAD request: %s\n", err.Error()) + return err + } + + d.fileSize = uint64(resp.ContentLength) + + return resp.Body.Close() + }) + + return err +} + +// Download download files based on configurations +func (d *DownloadManager) Download(url string) *DownloadManager { + signal.Notify(d.stop, syscall.SIGKILL, syscall.SIGINT, syscall.SIGQUIT) + startedAt := time.Now() + fmt.Println() + + ctx := context.Background() + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + if err := d.populateFileInfo(ctx, url); err != nil { // populate file information for future use + d.addError(err) + cancel() + return d + } + + chunkLen := int(d.fileSize) / d.option.concurrency + rem := int(d.fileSize) % d.option.concurrency + + fileName := d.fileName + if d.option.path != "" { + d.option.log.Printf("Info: Root directory: %s\n", d.option.path) + + if !d.option.skipSubPathMap { + subPath := "other" + if sp := d.option.subPathMap.Get(filepath.Ext(d.fileName)); sp != "" { + subPath = sp + } + + makeSubDir := fmt.Sprintf("%s/%s", d.option.path, subPath) + if _, err := os.Stat(makeSubDir); os.IsNotExist(err) { + if err := os.MkdirAll(makeSubDir, os.ModePerm); err != nil { + d.option.log.Printf("Error: failed to create sub-directory: %s\n", err.Error()) + d.addError(err) + cancel() + return d + } + d.option.log.Printf("Info: Created sub-directory: %s\n", subPath) + } + + fileName = fmt.Sprintf("%s/%s/%s", d.option.path, subPath, d.fileName) + } + + fileName = fmt.Sprintf("%s/%s", d.option.path, d.fileName) + } + + if _, err := os.Create(fileName); err != nil { + d.option.log.Printf("Error: failed to create file: %s\n", err.Error()) + d.addError(err) + cancel() + return d + } + d.option.log.Printf("Info: Created file: %s\n", fileName) + + d.option.log.Printf("Downloading file with concurrency value: %d\n", d.option.concurrency) + for i := 0; i < d.option.concurrency; i++ { + d.wg.Add(1) + + min := chunkLen * i + max := chunkLen * (i + 1) + if i == d.option.concurrency-1 { + max += rem + } + + go func(ctx context.Context, dm *DownloadManager, url string, min, max, i int) { + defer dm.wg.Done() + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + dm.option.log.Printf("Error[%d]: failed to create HTTP/GET request: %s\n", i, err.Error()) + dm.addError(err) + if err != context.Canceled { + cancel() + } + return + } + + rangeHeader := "bytes=" + strconv.Itoa(min) + "-" + strconv.Itoa(max-1) + req.Header.Add("Range", rangeHeader) + resp, err := dm.client.Do(req) + if err != nil { + dm.option.log.Printf("Error[%d]: failed to perform HTTP/GET request: %s\n", i, err.Error()) + dm.addError(err) + if err != context.Canceled { + cancel() + } + return + } + defer resp.Body.Close() + + f, err := os.OpenFile(fileName, os.O_RDWR, 0644) + if err != nil { + d.option.log.Printf("Error[%d]: failed to open file: %s\n", i, err.Error()) + dm.addError(err) + cancel() + return + } + defer f.Close() + + _, err = f.Seek(int64(min), 0) + if err != nil { + dm.option.log.Printf("Error[%d]: failed to seek file: %s\n", i, err.Error()) + dm.addError(err) + cancel() + return + } + + _, err = io.Copy(f, Reader{resp.Body, &d.totalDownloaded}) + if err != nil { + dm.option.log.Printf("Error[i]: failed to copy file content: %s\n", i, err.Error()) + dm.addError(err) + cancel() + return + } + + atomic.AddInt32(&dm.totalChunkCompleted, 1) + }(ctx, d, url, min, max, i) + } + + // run async task for refreshing progressbar + // if file size is unknown then use infinite progress bar + if d.fileSize > 0 { + d.renderProgressBar(ctx, int(d.fileSize)) + } else { + d.renderProgressBar(ctx, -1) + } + d.wg.Wait() + d.totalTimeTaken = time.Since(startedAt) + time.Sleep(600 * time.Millisecond) + fmt.Println() + d.completed <- true + + close(d.completed) + close(d.stop) + + return d +} diff --git a/downloader/human_readable_bytes.go b/downloader/human_readable_bytes.go new file mode 100644 index 0000000..099d6fa --- /dev/null +++ b/downloader/human_readable_bytes.go @@ -0,0 +1,24 @@ +package downloader + +import ( + "fmt" + "math" +) + +// humanaReadableBytes convert Bytes to human readable form +func humanaReadableBytes(s float64) string { + units := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB"} + base := 1024.0 + if s < 10 { + return fmt.Sprintf("%2.0f B", s) + } + e := math.Floor(math.Log(s) / math.Log(base)) + suffix := units[int(e)] + val := math.Floor(float64(s)/math.Pow(base, e)*10+0.5) / 10 + f := "%.0f" + if val < 10 { + f = "%.1f" + } + + return fmt.Sprintf("%s %s", fmt.Sprintf(f, val), suffix) +} diff --git a/downloader/option.go b/downloader/option.go new file mode 100644 index 0000000..2236ac1 --- /dev/null +++ b/downloader/option.go @@ -0,0 +1,87 @@ +package downloader + +import ( + "errors" + "strings" + + "github.com/thedevsaddam/dl/logger" + "github.com/thedevsaddam/dl/values" +) + +// option describes type for providing configuration options to JSONQ +type option struct { + concurrency int + path string // directory + subPathMap values.MapStrSliceString // sub directory + skipSubPathMap bool + log logger.Logger + verbose bool +} + +// OptionFunc represents a contract for option func, it basically set options to jsonq instance options +type OptionFunc func(*DownloadManager) error + +// WithConcurrency set number of concurrent request to be made +func WithConcurrency(c uint) OptionFunc { + return func(dm *DownloadManager) error { + if c == 0 { + return errors.New("dl: concurrency can't be empty") + } + dm.option.concurrency = int(c) + return nil + } +} + +// WithFilePath set the directory to save file +func WithFilePath(path string) OptionFunc { + return func(dm *DownloadManager) error { + if path == "" { + return errors.New("dl: filepath can't be empty") + } + dm.option.path = strings.TrimSpace(strings.TrimSuffix(path, "/")) + return nil + } +} + +// WithSubPathMap set the directory to save file +func WithSubPathMap(m values.MapStrSliceString) OptionFunc { + return func(dm *DownloadManager) error { + dm.option.subPathMap = m + return nil + } +} + +// WithSkipSubPathMap skip subdirectory resolving +func WithSkipSubPathMap() OptionFunc { + return func(dm *DownloadManager) error { + dm.option.skipSubPathMap = true + return nil + } +} + +// WithFilename set the filename +func WithFilename(name string) OptionFunc { + return func(dm *DownloadManager) error { + if name == "" { + return errors.New("dl: filename can't be empty") + } + dm.fileName = strings.TrimSpace(name) + return nil + } +} + +// WithVerbose enable debug output log +func WithVerbose() OptionFunc { + return func(dm *DownloadManager) error { + dm.option.verbose = true + return nil + } +} + +// WithLogger set custom logger +func WithLogger(l logger.Logger) OptionFunc { + return func(dm *DownloadManager) error { + dm.option.log = l + return nil + } +} diff --git a/downloader/reader.go b/downloader/reader.go new file mode 100644 index 0000000..d016797 --- /dev/null +++ b/downloader/reader.go @@ -0,0 +1,19 @@ +package downloader + +import ( + "io" + "sync/atomic" +) + +// Reader represents a custom reader +type Reader struct { + io.Reader + + downloaded *uint64 +} + +func (r Reader) Read(b []byte) (int, error) { + n, err := r.Reader.Read(b) + atomic.AddUint64(r.downloaded, uint64(n)) + return n, err +} diff --git a/example.gif b/example.gif new file mode 100644 index 0000000..5549da9 Binary files /dev/null and b/example.gif differ diff --git a/generate-asset.go b/generate-asset.go new file mode 100644 index 0000000..7d77a84 --- /dev/null +++ b/generate-asset.go @@ -0,0 +1,22 @@ +// +build generateasset + +package main + +import ( + "log" + "net/http" + + "github.com/shurcooL/vfsgen" +) + +func main() { + var fs http.FileSystem = http.Dir("./assets/") + err := vfsgen.Generate(fs, vfsgen.Options{ + Filename: "./notifier/asset.go", + PackageName: "notifier", + VariableName: "AssetFS", + }) + if err != nil { + log.Fatalln(err) + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..37ddefb --- /dev/null +++ b/go.mod @@ -0,0 +1,15 @@ +module github.com/thedevsaddam/dl + +go 1.16 + +require ( + github.com/deckarep/gosx-notifier v0.0.0-20180201035817-e127226297fb // indirect + github.com/martinlindhe/notify v0.0.0-20181008203735-20632c9a275a + github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect + github.com/schollz/progressbar/v3 v3.8.3 + github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect + github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 + github.com/spf13/cobra v1.2.1 + github.com/thedevsaddam/retry v0.0.0-20200324223450-9769a859cc6d + gopkg.in/toast.v1 v1.0.0-20180812000517-0a84660828b2 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..209e756 --- /dev/null +++ b/go.sum @@ -0,0 +1,603 @@ +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/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/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +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/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/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +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.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/gosx-notifier v0.0.0-20180201035817-e127226297fb h1:6S+TKObz6+Io2c8IOkcbK4Sz7nj6RpEVU7TkvmsZZcw= +github.com/deckarep/gosx-notifier v0.0.0-20180201035817-e127226297fb/go.mod h1:wf3nKtOnQqCp7kp9xB7hHnNlZ6m3NoiOxjrB9hFRq4Y= +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.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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +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-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/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +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/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/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/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= +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/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/martinlindhe/notify v0.0.0-20181008203735-20632c9a275a h1:nQcAxLK581HrmqF0TVy2GC3iFjB8X+aWGtxQ/t2uyGE= +github.com/martinlindhe/notify v0.0.0-20181008203735-20632c9a275a/go.mod h1:zL1p4SieQ27ZZ4V4KdVYdEcSkVl1OwNoi8xI1r5hJkc= +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/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +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/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= +github.com/mitchellh/go-homedir v1.0.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/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/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/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= +github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pkg/errors v0.8.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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +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/schollz/progressbar/v3 v3.8.3 h1:FnLGl3ewlDUP+YdSwveXBaXs053Mem/du+wr7XSYKl8= +github.com/schollz/progressbar/v3 v3.8.3/go.mod h1:pWnVCjSBZsT2X3nx9HfRdnCDrpbevliMeoEVhStwHko= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk= +github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 h1:pXY9qYc/MP5zdvqWEUH6SjNiu7VhSjuVFTFiTcphaLU= +github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw= +github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +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.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= +github.com/stretchr/objx v0.1.0/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/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/thedevsaddam/retry v0.0.0-20200324223450-9769a859cc6d h1:U8ZUZKRBI+Xgo3QWD/alCQ2vIysyl0Efx8yCJWPdaGQ= +github.com/thedevsaddam/retry v0.0.0-20200324223450-9769a859cc6d/go.mod h1:2rz2mY+1qEXG47loLDkV+ZJHGFwmhax5rOTpP+5aR80= +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/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.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +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/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +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-20181201002055-351d144fa1fc/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-20181026203630-95b1ffbd15a5/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/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0 h1:xrCZDmdtoloIiooiA9q0OQb9r8HejIHYoHGhGCe1pGg= +golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +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/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-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 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA= +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/check.v1 v0.0.0-20161208181325-20d25e280405/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/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/toast.v1 v1.0.0-20180812000517-0a84660828b2 h1:MZF6J7CV6s/h0HBkfqebrYfKCVEo5iN+wzE4QhV3Evo= +gopkg.in/toast.v1 v1.0.0-20180812000517-0a84660828b2/go.mod h1:s1Sn2yZos05Qfs7NKt867Xe18emOmtsO3eAKbDaon0o= +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.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +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-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +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= diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..ecebff5 --- /dev/null +++ b/install.sh @@ -0,0 +1,43 @@ +#! /bin/bash + +exec_curl(){ + echo "Found dl latest version: $VERSION" + echo "Download may take few minutes depending on your internet speed" + echo "Downloading dl to $2" + curl -L --silent --connect-timeout 30 --retry-delay 5 --retry 5 -o "$2" "$1" +} + +OS=`uname` +ARCH=`uname -m` +VERSION=$1 +URL=https://github.com/thedevsaddam/dl +TARGET=/usr/local/bin/dl +MESSAGE_START="Installing dl" +MESSAGE_END="Installation complete" + +if [ "$VERSION" == "" ]; then + LATEST_RELEASE=$(curl -L -s -H 'Accept: application/json' $URL/releases/latest) + VERSION=$(echo $LATEST_RELEASE | sed -e 's/.*"tag_name":"\([^"]*\)".*/\1/') +fi + +if [ "$OS" == "Darwin" ]; then + exec_curl $URL/releases/download/$VERSION/mac_amd64 $TARGET + echo "$MESSAGE_START" + chmod +x $TARGET + echo "$MESSAGE_END" + dl +elif [ "$OS" == "Linux" ]; then + if [ "$ARCH" == "x86_64" ]; then + exec_curl $URL/releases/download/$VERSION/linux_amd64 $TARGET + echo "$MESSAGE_START" + chmod +x $TARGET + echo "$MESSAGE_END" + dl + fi + + if [ "$ARCH" == "i368" ]; then + exec_curl $URL/releases/download/$VERSION/linux_386 $TARGET + chmod +x $TARGET + dl + fi +fi diff --git a/logger/logger.go b/logger/logger.go new file mode 100644 index 0000000..b224d3e --- /dev/null +++ b/logger/logger.go @@ -0,0 +1,33 @@ +package logger + +import ( + "fmt" + "log" +) + +type Logger interface { + Println(v ...interface{}) + Printf(format string, v ...interface{}) +} + +// defautlLogger implements the logger contract +type defautlLogger struct { + verbose bool +} + +// New return a default implementation of custom logger +func New(verbose bool) Logger { + return defautlLogger{verbose: verbose} +} + +func (d defautlLogger) Println(v ...interface{}) { + if d.verbose { + log.Println("dl:", fmt.Sprintln(v...)) + } +} + +func (d defautlLogger) Printf(format string, v ...interface{}) { + if d.verbose { + log.Println("dl:", fmt.Sprintf(format, v...)) + } +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..a4a17e3 --- /dev/null +++ b/main.go @@ -0,0 +1,9 @@ +//go:generate go run generate-asset.go + +package main + +import "github.com/thedevsaddam/dl/cmd" + +func main() { + cmd.Execute() +} diff --git a/notifier/asset.go b/notifier/asset.go new file mode 100644 index 0000000..bb3cd87 --- /dev/null +++ b/notifier/asset.go @@ -0,0 +1,184 @@ +// Code generated by vfsgen; DO NOT EDIT. + +package notifier + +import ( + "bytes" + "compress/gzip" + "fmt" + "io" + "io/ioutil" + "net/http" + "os" + pathpkg "path" + "time" +) + +// AssetFS statically implements the virtual filesystem provided to vfsgen. +var AssetFS = func() http.FileSystem { + fs := vfsgen۰FS{ + "/": &vfsgen۰DirInfo{ + name: "/", + modTime: time.Date(2021, 10, 29, 14, 13, 36, 104204240, time.UTC), + }, + "/icon.png": &vfsgen۰CompressedFileInfo{ + name: "icon.png", + modTime: time.Date(2021, 10, 29, 14, 5, 29, 244848715, time.UTC), + uncompressedSize: 9106, + + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xb4\x97\xe5\x5b\x13\x8e\xf7\xb0\xb7\xc1\x18\x8c\xd1\xdd\xe5\x50\x60\xa4\x12\x82\x48\x4a\x48\x49\x8d\xd1\x23\x95\x06\x69\x10\x18\x22\x2d\x21\x31\x11\x04\xa5\x91\x1c\xdd\x32\x62\x20\x25\x21\x20\x21\xdd\x5d\x8a\x94\xf0\x5c\x9f\xef\xf5\xfc\x0b\xbf\xb7\xf7\x75\xde\x9c\xf3\xe2\xbe\xce\x1d\xfb\x4c\x57\x9d\x02\xca\x0a\x05\x00\x00\x14\x9a\x1a\xaa\x06\x00\x00\x10\x01\x00\x00\xda\x49\x49\x00\x00\x00\x99\x98\xe2\x5d\x00\x00\x00\xf4\x36\x50\x57\x06\x54\x7e\x67\xdf\x06\x00\xb8\x01\x9a\xaa\x4a\x46\x01\x56\xfb\xd9\x90\x80\x34\xe3\xa9\xbe\x5b\x7f\x65\xd2\x37\x8c\xd4\x08\x4c\x1c\xf7\x07\x96\x4c\xde\xcf\xe5\x35\x95\x95\x21\xe9\x79\xb6\xe6\xad\xf7\xa6\x9f\x15\xc4\x31\x50\x0b\x71\x0b\xee\x9a\xe1\x6b\x04\xe3\x2c\x3d\xc1\xad\x7b\xd1\x14\xc9\xbc\xca\x8e\xfc\xd0\xd7\xf7\x74\x9e\xb2\x16\x6c\x86\x8e\x64\x4f\x48\x07\xde\x3d\x3d\x0b\x3a\x38\x5d\x63\xb1\x3b\x90\xff\xfb\xf1\xb6\xf9\x74\x55\xb8\x51\xec\x19\x0f\x58\x03\x68\x80\x87\x43\xc5\xde\x9f\x6b\xba\xa7\x80\x0a\x00\x02\x00\x10\x23\x05\xc8\x00\x43\xef\x99\x00\x22\x46\xfc\x2c\x88\x63\x87\x83\x35\x80\x20\xc6\x04\xe0\xff\x1d\x7b\x1a\x99\xff\x2f\x40\xf6\xe4\x5d\x22\x7d\x9d\xa2\xe9\xf5\x7d\x0e\x60\x41\x3e\x7b\x24\x29\x37\x53\xe1\x37\x25\xc3\x35\xde\xf8\xf4\x12\xdc\x53\x63\x4d\xe0\x1c\x03\x37\x7a\x26\x07\x94\x40\x49\x7a\x6f\x5f\x9d\x99\xdd\x46\xec\x0d\xf0\xcd\xca\xa7\x15\xff\xf5\x75\x00\xc6\x42\x6c\x0d\xc3\xc7\x84\x77\xf4\x2c\x57\x03\xb8\xe8\x27\x22\xec\x6b\x15\xd2\xb2\xf2\x32\x0b\x30\x17\x50\x6a\xdc\xd0\x4f\x54\x18\x95\xd2\x02\x14\xf6\x0f\xd0\xaf\x57\x14\xda\xad\x29\xec\x0a\xec\x63\x15\xb3\x07\x4e\x63\x5e\xbe\x4a\xfa\x34\x53\x54\x50\x51\x02\x12\x40\xa7\x80\x88\x11\xa9\x6f\x26\xdd\xa4\x52\xa3\xa9\xf1\x17\x80\xef\x44\x9e\xec\x18\xc7\x16\xb7\x1d\xe9\x67\x50\x34\x8f\x0c\x63\xaf\x82\x1d\xc2\xba\x43\xb3\x46\x11\x7a\xcf\x04\x83\x29\xb4\x10\x3a\x75\x89\x13\x12\x00\x0a\x24\xda\x28\xb2\x23\x75\x45\xc2\x7a\x3a\x09\x38\x6a\xfd\xb3\x2f\xa9\x1c\xf0\xc5\xb6\x7c\x00\x70\x90\xac\x19\x76\xdc\x01\x68\x62\x8f\x89\x28\x4d\xa5\xb3\x30\x58\x27\xea\x9b\x95\x69\x62\xde\xe0\xeb\x0a\x45\x4e\x62\x05\x53\x41\x82\xf4\xdc\xe8\x2f\xd4\x83\x47\xa5\x3c\xa1\x9c\xcc\x95\xa0\xbe\x27\x51\x73\x0d\x7d\x68\x1e\x99\x0d\xa2\x00\x0e\xf1\xb3\x74\x79\x91\x67\x55\x56\x48\x0c\xc6\x41\xdd\xaf\xdb\x42\x71\xc7\x19\x10\xd6\x98\x1f\x1c\x7f\x79\xcd\x0c\xab\xe2\xe3\x05\xf4\x0a\x22\x76\x52\x5b\x8e\x9b\x40\xc4\x08\x21\x3a\xf6\x8d\x95\x8b\x89\x00\xc0\x5d\xb3\x99\x8a\xe1\x90\x8a\x24\x6b\x2f\x86\x65\x16\x57\xc7\x87\x52\x57\xca\xf3\xad\x16\x40\x10\x96\x81\x0c\x76\xbc\xa0\xc8\x6e\x64\x62\x3a\x96\xcd\x77\x45\x3d\xd2\x2c\x53\xc4\x9b\x15\xb2\xa4\x71\xfb\x4d\xc0\xe4\x9e\x22\x5e\xe2\xbe\x4e\x76\xa0\x77\x5d\x57\x80\xa7\x36\x60\x74\x60\xa8\xd2\xc2\x2e\x6b\x95\x8c\xde\x4e\xd0\xd2\xad\x99\xdf\x2e\xf1\x65\x1a\xc6\x01\x29\xdb\x43\xe4\x8b\x66\xc5\x7c\x75\xf4\x5d\x36\x6b\xf5\xa9\x5f\x9f\x9d\x98\xd9\x97\x01\x0e\xbe\x85\xbd\xb9\xf0\xf1\xfc\xe5\x16\xe5\xa4\x37\x53\x50\x26\xac\x57\xf8\x23\x0e\x4d\x8a\x52\x2b\xb5\x78\xf8\xc9\xb9\xa5\x6f\xf1\x86\xe5\x0b\x33\x77\x65\x03\x28\x03\x43\x7a\xf5\x0b\xd5\x6d\x3f\x1c\x0f\xa5\xc6\xbd\x1d\x70\xce\x58\x04\x26\x42\x80\x0f\xa4\x07\x0a\x92\xf6\x8c\x30\x36\x8f\x78\x5d\x1b\x92\x6c\x8b\x9e\x49\xde\x53\xc4\x8f\x73\x9b\x45\xf0\xf3\xdc\x50\x63\xfa\xd5\x32\x4e\xea\x29\xa2\x98\x68\x6c\xf8\x5e\x55\x00\xc1\x8b\x25\x20\x62\x44\x3b\xd1\x9d\x6f\xcf\x23\x6c\xde\x5a\xdd\x9f\xf8\xfa\x14\x18\xc5\x10\x83\xa3\xd3\xa0\x32\x50\xd4\x05\x82\xb0\x39\x5e\x34\x2b\xf1\x00\xd8\x94\xdd\xeb\xd9\x01\xc1\x67\x31\xf4\xbf\x3b\x49\xce\xc8\xb7\x55\xa0\x13\xc6\x18\x4c\xa1\xef\xa3\x37\x4d\xd3\x4c\x3b\xf7\x2a\x86\xbf\x64\xf3\x82\x2f\xf9\x06\x90\x02\xa5\x9a\xe9\xaf\x72\x01\x40\x2d\xad\x4c\x15\x0b\x57\xe1\x8f\xa5\x85\x02\xf5\xfa\x15\x78\xfd\x98\x9a\xe1\x52\x73\x7d\x22\x3d\x41\x45\xbc\x41\xd6\x14\xf5\x22\xc9\x92\x58\xfd\x70\xc9\x57\x4a\x30\xb3\x2c\x6f\x57\xc3\x2e\x4e\x51\x47\x3e\x0f\x00\xd4\xd2\xe1\x55\xb9\xbe\x0b\x68\x9f\x78\x90\xdb\x12\x75\x0f\x47\x26\xc0\x8c\xa1\x70\xad\xe2\x99\xfa\x16\xe3\xc2\xc0\x8d\x16\xd0\xb1\x8c\x89\xff\x97\xad\xab\x6f\x96\xbd\xc3\x52\x89\xdf\x7c\x11\x67\x83\xea\x3b\x63\x73\xff\x00\x6b\x51\x03\x82\xb0\x29\x46\x91\xe7\x72\x00\x11\x23\x83\xf4\x9d\x8c\x12\xcc\xf4\xe4\x6f\x6a\x58\x9f\x01\xd2\xd1\x56\xd4\x7e\xb6\x13\x4a\x8d\x4b\x81\xdf\xed\x29\x06\x34\x29\x98\x4a\x5e\xb6\x3e\x81\x7a\xb6\xc5\x31\x9f\x1e\x4a\xc9\x33\xf6\xef\x4d\xb8\x93\xa2\x12\x1c\x8a\x5e\x76\xb7\xff\xfd\x98\xf9\x88\xeb\x4a\x12\xa8\x2f\xf5\xa3\xef\xf8\x4a\xca\x07\x84\xcc\x9b\xe0\x1a\x6e\xe5\x61\xf8\x84\xc9\xcf\xf2\x50\x8f\x4e\x25\x7a\x2e\x13\xc1\xa8\x2d\xf7\x50\x69\xe3\x5c\x0d\xff\xb4\xc0\x25\x26\x5e\x48\xa8\x98\xab\xde\xe1\x7b\x89\x67\xf4\xa4\x2f\xe9\xd2\x1d\xfb\x6a\x90\x7f\x93\x96\x15\xeb\x7f\x17\xd0\x7d\x12\xe4\xee\xd0\x33\x2d\xb1\x18\x95\xb9\x69\xca\xb3\x00\x56\x9c\xff\xc4\xb7\xfb\x4f\x64\xe1\x31\x27\x80\xfb\xb1\xcb\x6d\x96\x0d\x9f\x8c\x94\xd2\x2b\x24\x9a\x2f\xd3\x96\x2f\xd4\xf6\x6a\x88\x2a\x31\x28\xd9\x10\x83\x31\xb6\x4e\xd7\x7e\x0c\x00\x22\x88\x92\xd5\x54\x7a\x19\xa0\x6f\xd5\xd2\xfe\x95\x85\x17\xf3\x84\xf2\xca\xe8\x82\xe3\x3f\x69\xdb\xff\xde\x56\xb5\x4d\x58\xa5\xf5\x7c\x45\x99\xe8\xf1\x6e\xd8\xaf\x55\x59\x80\x4a\x46\x13\x5f\xfa\x49\xb5\x85\xc1\x67\x11\xb7\xc1\x0c\xa0\x24\x89\xba\xbf\xaa\x80\xef\x67\x84\x1c\xb3\x60\x3c\x68\xf0\xca\xf6\xd5\x92\x8c\x7f\xf7\xcb\x0e\x48\x51\xbe\x3f\x38\x36\x7e\x46\xd8\x55\x56\xa9\x01\xc0\x2e\x75\x20\x90\x55\xfc\x28\x31\x79\x75\x8e\x9b\xe4\x6c\xd3\xe2\x3e\x0d\xae\x54\x5d\x31\x23\xfe\x4f\xf8\xe0\x56\xc5\xe7\xc5\x0e\xda\x28\x82\x68\x4e\x74\xec\x7e\xf4\x82\x5a\xda\xd8\x04\x73\x84\x3d\x1c\x6d\x4c\xce\xb2\xa2\x07\x64\x76\x4b\xae\xb4\x8f\xa2\x2f\x29\xc3\x0f\x9c\x0b\x4c\x7f\x09\xe0\xd8\x9d\x16\x49\x51\x6b\x05\x11\x23\x72\x2d\x63\xfe\x12\x1d\x45\xf8\xb1\x7c\x81\x0b\x7c\xd6\x08\xcf\x3e\x36\xc4\x11\x05\x80\x4d\x5d\x2b\xf2\x18\x8d\x34\xf3\x00\xc0\x32\x5a\xd4\x08\x90\x59\xd3\x2e\x82\x1e\xa7\x11\xfe\x0a\x40\xc5\x33\xc0\x59\x5d\xa2\x30\xe2\xa3\x82\xcf\x2b\x13\x1a\x81\x39\x32\x91\xd4\xd0\xc3\xa8\x78\xba\x7a\x22\x82\x04\xa1\xf4\xdc\xe8\xb1\xc9\xf4\xd7\x36\xca\xc6\xda\x48\x34\x23\x28\x43\xb9\xf6\x2c\xb5\x6c\xcf\x03\x3d\x36\x69\x7c\x42\xa3\x2c\x59\x6e\xb0\x14\x4c\x2c\x46\x63\xaa\xad\x6d\x56\x94\xa2\x08\xec\x20\xd2\x1a\x4a\xfe\x1a\xa9\x06\x11\x58\xa2\x06\xc7\x75\x8a\xd3\x88\xf3\x2f\xa0\x0c\xdf\xe9\xe3\x3b\xf0\xd0\xe3\x08\x80\x2b\xc0\x93\x34\x01\x66\x80\xb7\x81\xb6\xbd\x35\xd0\xee\x52\xcb\x04\xe9\x2b\x88\x86\x92\x60\x03\x84\xee\x2d\x50\x1a\xf0\x80\x3f\x96\xe0\x93\x48\xd1\x0f\xe6\x79\x9f\x1a\xae\x3e\x47\x87\x80\x7a\x7e\x66\xeb\xf3\x80\x3f\x96\x62\x32\x6e\xc4\xa0\xfa\x67\x51\x86\x1c\x75\xb3\xa2\x61\x20\xa1\x21\xc8\xeb\x55\xb9\x32\x42\xd1\x8d\x06\x50\x07\xea\xf9\xeb\x0d\x73\x30\xd2\xd0\x3c\x49\xf2\xe4\x2e\x4e\xf9\x15\x09\xe6\x98\x73\x10\x1e\xb9\xea\x06\xe6\xff\xa1\x6a\x88\xaf\xc2\xc7\xc5\x5c\xec\x2f\x70\x2e\xd2\x67\x6f\xd2\x2f\x35\x11\x89\x9f\xbd\xd9\x5c\x31\xa0\x49\xbe\xc5\xa4\xf7\x27\xa9\x03\x06\x8d\x5f\xa8\x1a\x6b\x02\x37\xef\xe1\xbd\xc4\x6d\xf7\xdc\x36\x65\xec\x2b\xee\xde\x10\x21\x63\xe2\xcd\x95\xbc\xb4\x34\x22\xe9\x3d\x8b\x41\x8f\xa3\xb0\xb7\x18\x86\x0d\x5b\xf3\xb9\x1f\xbf\x1e\x1a\xf4\xbb\x18\x7c\x7e\x0a\xfc\xa4\x3c\x68\x8d\xdf\xe9\x9f\xcb\x65\x0f\x7e\x31\x9a\x0a\xe2\xd4\x5f\x72\x55\xfd\x90\x91\xb3\x9a\xb5\x22\x8a\x8e\x3c\x77\x38\xfe\x17\x53\x92\x0c\xb2\x7a\x86\x51\x6a\x7b\x24\x0b\xa1\x69\x20\x90\x2f\xdf\x8b\xed\xf4\xc0\xe7\x85\x54\xa5\xbd\x85\x96\xae\xf2\x83\x17\x54\xd2\x2c\xb7\xf8\xa3\xff\x9c\xef\x48\xa3\x63\x2d\x9f\x10\x0e\xf2\x8c\x34\x80\xa2\x02\xdc\x52\x44\x6d\x73\x5a\x40\x78\x1c\xc1\x03\xbf\x12\xaa\x21\x48\xd8\x52\x01\xcb\x54\xaa\xbe\x6d\xdf\xf8\xf3\xed\x1f\x11\x62\xf6\x6a\x60\xd7\x6e\xe6\xf0\x98\xf0\x2c\x5c\xc9\x4a\x61\x62\x52\x0f\x9f\x37\xcf\x72\x7d\x93\x7e\x16\x74\x0d\x4b\xe2\xe9\xe2\x0f\x7c\xa8\xad\x00\x8c\xe7\x6c\x0a\x0e\xbc\x63\xe8\x9a\x0e\xf5\x84\x29\xbf\x0d\x59\x35\x7e\x78\x4d\x8c\x78\xd7\x43\xd7\x9e\xa9\x11\x17\x4f\x5f\x62\x80\xa6\xc9\x73\x2d\x31\x99\x3c\xa2\xc3\xd9\x02\x24\xfe\x3f\xd4\xc7\xd8\x11\xdb\xee\x3d\x11\x15\x5c\xb9\x8b\xde\x27\xe1\x6e\x78\x52\xa4\x0c\x0d\xb0\x0c\x37\x8e\xa9\xb9\xb1\x82\x8d\x73\xe1\x77\xfa\x0c\xab\xb9\xe0\x56\xda\x9f\x89\x6c\xcd\x4a\xc7\xa3\x0d\x8d\xa6\x8a\x77\x66\xe9\xa9\xe5\xd2\x1f\x57\x55\x7c\xf1\x36\xbf\x20\x42\x7d\x68\xa3\x03\x9d\xcf\x37\x3b\x79\xd6\x3f\x37\xa4\x71\x30\xa4\x7f\x42\xbd\x92\xb7\xf0\x2f\x6e\xc7\x00\xde\x0e\x0d\x38\x11\x1c\x14\xc5\xcb\x92\x00\xcb\x27\xe5\x40\x25\xed\xe5\x20\x62\xc4\x26\x25\x6c\xc4\xd2\x21\x90\x0b\x55\x7c\xc4\x3f\x1d\x4e\x03\x78\xa1\xe7\xea\xfd\x15\x45\x8c\xf0\xf6\x91\xec\x2a\xdd\xac\xac\x69\x23\x2b\xcf\x0f\x84\x14\xac\xc8\x7a\x5e\xd3\x29\x72\xf1\x49\xe8\x49\xd1\x0a\x2a\xe2\x5f\x9e\x2d\x35\x51\xeb\x9f\xe5\xd4\x5a\x1a\x1d\x64\xfb\x63\x18\x36\xe6\x3b\xbd\x68\x30\xa7\x80\xeb\x27\xcd\xc4\x46\x86\xc5\x20\x62\x44\x36\x28\x73\xf6\xe3\xb2\xa4\xea\x74\x7a\xd1\x99\x4d\xae\x97\x3f\x51\x19\x93\x02\x7b\x61\x13\x00\x41\xf9\xe5\x87\xf0\x44\x42\x4b\xa9\x31\x06\xb3\xbe\x37\xe6\x09\x80\xc9\xb7\xd5\x3c\xc7\xca\x85\x1b\x07\x26\xf7\x30\x28\x5e\x17\x57\xd4\xf6\xc5\x6f\xb6\xf3\xa1\x1f\xca\x13\x60\xfe\xdc\x2b\x09\x3f\xfc\x7e\x81\xcb\xb9\xb9\x40\x24\x5e\x81\x72\x16\xee\x6f\xeb\x74\x2d\x3d\x06\x47\x97\x35\x94\xc0\x7a\xf1\xb7\x69\xf1\x7a\x0f\x9e\x3c\x89\x3c\xd7\xae\x25\x70\xc5\xcb\xf9\xc2\x70\x6f\x07\xc2\xac\x9c\x44\xe3\xe1\x0f\x9a\xe5\x12\x1d\x62\xaa\x53\x75\x0e\x08\xb4\xa7\xdf\x21\x48\xae\x05\x10\xbc\x09\x04\x33\xe9\x61\xf2\x93\x32\x20\x69\x50\x58\xa4\x1d\x9b\xf0\x49\xb1\x66\x55\x56\x32\x25\x05\x17\xce\xe3\x3a\xda\x84\xe2\x06\xe4\x4a\x9d\x0e\xa2\x5a\x12\x81\xc8\xcd\xdf\xe0\xad\x8f\x37\x45\x22\xc3\x35\x2f\xb9\x30\x9b\x18\x38\x3d\x19\x9a\xbb\x26\x63\x37\xa9\xd1\x5b\x04\x97\xb8\xe1\xf4\xe2\x75\xff\x92\x17\xca\xd7\x50\x02\x9a\x4d\x5a\x7e\x19\xca\xf4\x9e\xeb\xf5\x75\x0d\xf7\xcb\xa7\x97\x3c\xc5\x6b\x32\x69\xc7\xd8\xa7\xca\xde\x2f\x39\x40\xd8\xd4\x5a\xc3\xdd\x39\x7a\xd5\x19\x23\xff\xa6\xcc\x69\xad\xe7\x20\xa1\x21\x42\xe1\x78\xf6\x92\x8c\x55\x02\xde\x1d\x80\x9c\x0f\x20\x2e\x27\xae\xb3\xa0\x14\x05\x61\x33\x95\x9c\xad\xe7\xd7\x63\x6a\xc2\xcf\x7c\x3d\xb4\x47\xbe\x83\x90\xfe\x0b\x0c\x02\x4d\x74\x78\x0a\xb3\x2e\x6f\x36\xdc\x4e\x2f\xca\x20\x94\xba\x81\x89\x82\x70\xd6\xd5\x69\xa6\xdc\x58\x4b\x01\x1c\xd4\xfd\x33\xf9\x3b\xfb\xf5\xc1\x34\x3e\x54\xff\x47\x8f\x93\x6f\x36\x51\xb9\x58\x07\x98\x3d\x15\xe8\x33\x2e\x68\x10\x82\xfe\x73\xc0\xa0\x5a\x65\xa5\x54\xb1\x41\xdf\x28\x24\x22\xa8\xa4\xeb\xce\xf9\xf2\xe5\x89\xf3\x63\x6f\xef\xd3\x67\x56\x56\xb9\xd3\x6a\xbe\x84\xd7\x35\xdc\x0d\x4c\x94\x9d\x39\xb6\x3f\x5d\xe7\xd7\x5f\xa0\x2d\xfd\xb6\x93\xd5\xbc\x8f\x7a\x5f\x3f\x49\xe9\x08\x3e\x63\x41\x3a\xa4\xad\x52\x3b\x24\x95\x71\xa6\x51\x3a\xa3\x15\x70\x12\x17\xdc\x62\xda\x24\xdd\x0a\xbf\x77\x78\x21\xe5\xd1\x45\x7a\x13\x2e\x48\xef\xab\xeb\x6b\xd0\xda\xda\x46\x9f\xd2\xd9\xbc\x7f\x19\x6e\x25\x9a\xab\xda\xbb\x78\x7a\x9d\x3f\x90\x06\x4f\xbb\x44\x0b\xf0\x0e\xf0\x7a\x80\x53\xbd\x21\x28\x58\xbc\x5c\xff\x03\x26\x5f\xbe\x8f\x16\x7e\x92\x96\xbd\x73\x74\x3c\x51\x12\x7c\x06\x12\x1a\xaa\x82\xf4\x59\xe4\x13\xfb\xb0\xe2\xd6\x56\x06\xbe\x2f\xbc\x59\x17\x9a\x5a\xe9\xf3\xa5\xe9\xa9\x91\x86\x53\x58\xfe\xe2\x8d\x33\x7f\xe2\x35\xb8\x35\xaa\x8c\x7f\xf9\xc2\xd6\xfe\xd7\x6c\xc4\x3d\x97\x43\x4e\x7f\xb6\x20\x67\x2e\x9c\xf2\xb5\x08\x80\x8a\x55\x20\x87\x0d\x63\x2c\xbd\x20\x6c\x7e\x13\x13\xb1\x5b\x2b\x8a\xb5\x39\xdd\xe8\x69\x5d\xa4\xc7\xfa\x77\xf5\x5e\x8f\xe9\xb6\xcf\xf2\xa2\x59\x1e\xc6\x0c\x37\x10\x46\x69\x68\x1a\xe6\xf7\xdc\x87\x6a\x3c\xa8\x70\xca\xd7\xd6\x00\x77\x71\xd9\x7b\x8d\xc0\x32\xd9\x9b\x94\x14\x83\xeb\xbf\xf9\xa2\x2b\x0a\x61\x07\x0b\x42\x42\x5a\x4e\x4f\x48\xa4\x18\x7f\x45\x7d\x4c\xf9\xaa\x36\x58\xf4\x93\x13\xa8\x55\xf5\x1a\xd9\xf0\x5c\x86\x8e\xe6\xec\x43\xba\x25\xeb\xcc\xfb\x7a\x7c\xe9\x47\x62\x41\xca\x08\x99\xde\x6f\xdc\xa5\x6e\xcd\x0c\xa8\xc9\x9b\xc3\xf9\xf7\xe6\x44\x95\x5d\x5d\x79\x24\xb4\xc6\x47\x46\xae\x88\x26\x8e\xe0\x38\x3d\x09\x95\xc7\x15\x52\x64\x28\xb3\xf4\xda\xe2\xec\x32\xae\x36\x73\x48\x79\x4e\x1b\x64\xa0\xba\x73\x88\xbd\x99\x03\x35\x39\xeb\x3a\xdf\x42\xc1\x15\xfa\x1b\x8c\x7d\x85\xe8\xb8\x3a\x2a\x7a\x9d\x55\x5d\xb6\x05\xbb\x5f\x68\x64\x97\x85\x29\x54\x13\xbe\xda\xfd\xfa\xe6\x5e\xeb\xf7\x50\xe9\xba\x40\x34\x05\xae\xab\x8d\x49\x26\x74\x7c\x23\xef\x04\xe9\x1c\xee\xfb\x53\x3e\x69\xb9\xf8\xcf\x8a\x18\x47\x08\x5c\xb8\x42\xc0\xac\xd1\x39\x16\x59\x61\xde\xab\x60\x6e\x12\x12\xb7\x08\xf9\xbd\x1b\x71\x30\x9f\x34\x3e\xd1\x09\x21\x57\x20\x90\x8b\xf6\x8b\x4a\x5e\xb8\xdd\x4e\x4e\x23\x65\xb4\x53\x2d\x23\xd8\x68\x70\x30\xc6\x09\x23\x6f\x11\x6b\x93\x17\x8f\x71\xaf\xdb\x18\x98\x4f\xb4\x75\x94\xd3\xbd\x5a\x31\xe9\x88\x06\x4a\x8e\xd9\xdc\xc3\xea\xf6\xd1\xbf\xd3\x39\xcc\xa3\x1d\xd2\xe3\xe3\x69\xa2\x71\x37\xd7\xf1\x55\xc7\x6b\x1f\xdf\xdb\xb7\x4e\xd7\xdc\xce\x9e\x4f\x40\xb2\xc8\x81\x83\x1b\xc4\x25\x7b\xa1\x92\x79\xe5\x9f\x06\xa4\x12\xbf\xb8\x3f\xc6\x29\x5b\xb4\xb5\xfe\xf4\x8b\xcd\x35\xe0\x2f\x06\x95\xb9\x33\xaf\xec\xec\x56\x45\x24\xf6\xe1\x72\x9f\xaf\x8c\xaa\xc8\xde\x8b\x3b\xba\x5a\x77\x39\x5a\xea\x5e\x91\x8f\xac\xf3\x7c\xa0\x74\xc7\x1f\x7a\xf2\x34\x58\xb0\xc6\xce\x00\x0e\xc2\x6a\x76\x65\xda\x4b\xc5\xdd\x23\xcf\xb2\x9f\xf3\xa9\xdd\x00\x09\xf5\x10\xe6\x48\x07\xa5\xa6\xbc\x89\x70\xa5\xf7\x33\xdf\x8d\xb1\x6e\x52\xc9\x0b\x51\x56\x2a\x72\x27\x3f\x18\x5b\x99\x32\xfe\xd5\x35\x25\x6a\x2b\x1d\xa3\xb1\x60\x64\x74\x54\xa4\xe9\x96\x61\x14\x8e\x71\x48\xc1\x15\x65\xac\x4f\xc7\x31\xcb\x75\xd1\xcf\x31\x32\x4b\x52\xa1\x78\x44\x28\x43\x98\x1d\x94\x60\x92\x96\xcc\x40\x84\xb0\x79\x7c\x01\x8e\xb7\x80\xe4\xe5\x8a\x02\xcc\xa1\x54\xf9\xfb\xd0\x5e\xdc\x69\x74\x4e\xac\xd2\x5d\x0a\x8d\x59\x11\x9a\x3a\x3f\xfa\x9c\xe8\xe1\x2b\xc2\x43\xb6\x06\x7a\x10\x56\xb8\xc6\xe5\x60\x62\x32\x55\x7d\x18\x88\x4c\xd6\x03\xa8\x74\x0f\x02\x87\x59\x85\x5c\x5e\x10\xe3\xbe\x2e\xfe\xfb\x5a\xf3\x9d\x76\xc2\xb9\x0b\x9a\x9c\x99\x12\x61\x84\x25\xaa\xce\xb5\xd8\x9d\xa0\x38\x1e\xb1\x5f\x5f\x59\xde\x5c\x19\x10\x12\xd1\x40\x52\x88\xfe\xdb\x74\x6b\xfb\x7b\xd3\x47\xb1\xf3\xcf\x40\x8c\xa4\x35\xfe\x06\x5b\xd7\x4e\xc6\x40\x8a\xe2\x8f\x71\xce\xeb\xe7\x55\x35\xf5\xa6\xdb\xcf\x72\x9e\x0d\x40\x47\x36\x4d\xbb\x2b\xb6\xe4\x4d\x4c\x50\x3b\x27\xc8\x01\x51\x2f\x73\xa5\x6c\x2e\xbc\x3c\x1d\x0a\x2a\x7a\x3b\x9d\x62\x37\xf7\x28\x58\x5e\xc9\xba\x33\x7b\x99\x1a\xd4\xf3\x2f\x5c\x88\xf1\xea\x6f\xe7\x05\x57\xfb\xa8\xff\x62\x8d\x33\x3d\x66\x64\x02\x61\x09\xaf\xd9\x46\xb3\x99\x1f\xe9\xf1\x80\x4f\xab\xc3\xfb\x47\x8c\xa4\x3e\xd3\xdd\xd7\x66\xa6\x2a\xe7\xb6\x86\x45\x79\x0f\x79\x4a\x7d\xd0\x29\x06\x95\x55\x2e\xba\x19\x84\xf5\xd8\x0c\xdf\xc6\xbf\x2d\x52\xf8\x16\xf5\xa3\x58\x8f\x99\x4a\x97\x6d\xf1\x45\x09\x81\x40\x68\xb2\x99\xb0\xdf\x1b\xec\x4f\x9f\x98\x33\x97\xa0\x9e\x09\x4c\x4d\xe9\xb7\xff\xbd\x48\x86\x52\x13\x72\x2e\x94\x8f\x82\x97\xe0\x5f\x3d\xe8\xa4\x95\xc6\x0f\xa2\xd0\xe0\x0b\x4f\xb1\x36\xb7\xc2\x05\xdf\xab\x97\x44\xb8\xd2\x7f\x6e\x9f\x1a\xe8\x39\x7e\x2c\xaa\x07\x0d\x78\x50\xac\x39\x2f\xb4\xb1\x2c\x04\xad\x6e\xab\x39\x5c\x6f\xcc\x71\x1d\x7d\xb3\x1b\x79\x50\x92\x9a\x2e\x47\x11\x58\xd8\x5e\xa1\x0d\x04\x0e\x3e\xad\x1f\xde\x77\x79\x2c\x83\xe5\xee\xdd\xc8\x9a\x4b\xf0\xdb\xed\x05\x09\xf5\x74\x00\x8e\xfc\xf7\x0f\xb6\x5c\xb6\xf9\xd1\xb1\x1a\x59\x85\xae\x7d\x63\x15\x39\x8a\x83\xfc\x33\x14\xa0\xc3\xa0\x89\xe5\x80\x97\x67\x69\x6a\xe0\xc0\xbf\xed\xf0\x80\x8b\x74\xff\x3b\xbe\x37\x08\x59\x0a\x36\x72\xf7\xc9\xbb\x05\x2d\x53\xc4\x08\xdf\xa0\xe6\xdc\x33\x41\xc0\x08\xdf\x40\x8e\x7f\x66\x6d\x2f\x50\xe8\x9b\x68\xb4\x4c\xdd\x58\xef\x8a\x14\x9a\xec\x8b\x01\x51\xb3\x4c\xcb\xa4\x6b\x8c\x39\xe1\xd2\xe1\xdb\xd2\x7d\xcf\xee\x18\x2d\x3a\x41\x41\x46\x9d\xa4\xaf\xff\x1e\xbb\xce\x7d\x2d\x2b\x4a\x94\xe9\x7c\x3e\xff\x75\xe6\x1e\x42\xe1\x57\xa9\x36\x35\xae\xdc\x60\xf6\x32\x94\x1d\x22\xb2\x8a\x61\x58\xb1\x26\xc2\xf9\x1a\x57\xb2\x85\xc3\x7b\xd1\x98\xf4\xde\xdc\xc9\xca\x6d\x7f\x8a\xa8\xb5\xf9\x54\x0f\x02\x9e\x8e\xf6\x70\x54\xec\x36\x81\x0a\xb7\x34\x4c\x05\xdf\x6f\x60\xb0\xc2\x2c\x9e\x99\xfb\x4d\x8b\x02\x07\x83\x92\x51\xf3\xf9\x76\x78\x07\x18\xee\xf5\xb5\xac\x58\x1b\xba\x3e\xee\xcf\x95\xb7\x10\x4e\x95\xdd\x29\xdc\x72\x6b\x6c\xc3\xaa\xa0\x70\xc2\x4a\x38\xf6\x56\xd4\x9d\x82\x50\xf9\x41\xd8\xac\x60\x70\xe0\xea\xea\x70\xce\x6b\x77\xff\xaf\x66\x83\x9d\xc8\x97\x17\xf1\x9f\x5e\x3a\xe6\xd7\xe5\x25\x30\x08\xf0\xa0\x4d\x73\x6b\xe8\x2e\xd1\xd4\x4c\x70\x2a\xbe\x2e\xc6\xb9\xf5\x44\x71\x3c\xf4\x38\x1d\x70\x39\xc7\xa0\xea\xdb\xe1\x4e\x82\x8d\xc9\x55\x99\x7d\xbf\x35\xe5\xac\x4b\xc4\x52\xf5\xf5\x44\x19\xd6\x21\x76\x4c\x39\x9e\xa4\x20\x4e\x65\x2d\x9c\x6e\x95\xed\x36\x13\x46\xd1\xc0\x44\x69\x9c\x49\x4b\xa9\xb8\x8b\xc2\x41\x51\x9a\x21\x69\x72\xef\x93\x1b\x34\x90\xb2\xc4\x46\x93\xc1\xac\x0e\x01\xc4\x1d\xb8\x9e\x56\xdd\x52\x89\xe2\xb6\x9a\x29\x25\xb3\x39\x95\x8c\x4f\xb0\xc4\x5b\x81\xc3\xf1\xb6\x4c\x77\x08\xf6\x59\x91\xf9\xe0\xc3\xad\xd1\x3d\xad\x58\x0d\xcb\xc4\xbd\xb7\x0f\xf5\xf8\x1f\x1b\xb8\x4f\xee\x7c\x12\x73\x98\xa5\x4b\x91\x82\x0c\xb4\xa0\x2d\xbf\xbb\xc2\x6d\xdf\x63\x56\x5f\x12\x7b\x8a\xcb\x88\x18\x8c\x7f\xb6\xe2\x38\x0d\x87\x2f\x3c\x32\x59\x12\x16\x8b\x69\x34\x21\xfb\xc9\x4d\x83\x7b\x60\xaf\x17\x9c\x3a\x7c\x5c\x26\x1c\xcf\x35\xc4\x06\x2c\x0f\xc6\x1f\x63\xce\x9a\x12\x5c\xb6\xc1\xe8\x58\xf3\x6e\x2b\x96\xd4\x95\xc1\x57\x3b\xd8\x63\x3b\xf5\x15\x8f\xbb\x9f\x92\x9f\x95\xcb\x1d\x06\x11\xb3\xd5\x84\x62\xaf\x43\x54\x0e\x54\xbe\x89\xba\xf9\x64\xef\x86\x7a\x5e\xd3\x89\x23\x1f\x8e\x49\x0f\x2d\x8e\x03\x84\xbd\xc3\xe1\x68\x06\x1b\xa6\xbe\x7f\xe4\x27\xb9\xc6\xa3\xce\x3c\x77\x89\x81\x83\x4d\x87\x29\x50\xad\xc3\x7c\x18\xdd\x11\xf9\x5c\x49\x5e\xc2\x46\xe9\x65\xb8\xc3\x31\x68\xb3\x97\xf7\x0f\x08\xa7\xfa\x2a\xba\xb8\x23\x4a\x77\xfb\xf0\xa9\x32\xc7\x68\x07\xd5\x41\xeb\xe6\xd9\x9b\x65\x51\x8b\xdf\x02\x1b\xed\xf7\xe6\xe5\xb4\x1e\x05\x30\x51\x2d\x39\x90\x47\x73\xaf\x38\xc4\x88\x6f\xcb\x72\xfd\x19\x95\xa0\x42\xf9\xda\x18\x73\xa8\x66\xc4\x07\xdb\x89\x5b\xdf\xcb\x0f\xb5\x20\x46\x0c\xb3\x8f\xfe\x4c\xb6\x11\xc2\xcc\xd1\xd8\x5c\x4e\xd5\x0b\x1c\x29\x73\xe1\xba\xae\xc5\x3c\x5d\x0d\x47\x93\xe0\xc6\x6d\x20\x84\xb8\x42\x99\x7f\x2f\x2a\xe6\xc9\xa4\xef\x60\x3e\xd5\x62\x2c\xe7\xf2\x41\x8d\x99\xe3\xf3\xdb\x38\x2f\xba\x62\xad\x1b\x7e\xdd\xb4\xc4\x8d\x79\x3e\x93\x5b\x3d\x4f\x8b\x38\xe6\xd4\x85\xe0\x29\x65\xa5\xe1\x74\xec\x43\x7c\x4a\x84\x71\x45\x58\x71\xc4\xaa\xef\xf1\x74\x95\xbb\x27\x31\x42\xeb\xab\x63\x82\xaf\x04\x58\x1f\x7b\x3e\x13\x09\x3c\xd8\x06\x4f\xc1\x97\x50\x68\x0c\x57\x54\xc6\x11\x14\xf7\x86\xd9\xd2\x6c\xa8\x3b\x77\x58\x21\x65\x8b\xb7\x21\x8f\xc5\x6b\x1f\x4e\x56\xdf\xb2\xd1\xe2\x35\x5d\xdb\x78\x86\xac\x69\xe3\xe5\x10\xfa\x2b\x95\x51\xd7\x46\xc1\xd0\x44\x3c\xa3\xdd\x76\xac\x69\x91\x66\xed\xc4\x42\x55\xde\x8b\x36\x26\x17\x3e\xde\xfb\x4d\x01\xe0\x28\xbb\x65\x02\x0e\x26\x57\xbd\xb3\xe2\x3b\xe4\x1b\x48\xa9\x5a\xf9\x39\x1d\x6f\x85\x6e\x07\x50\xf6\xed\x51\xed\xc3\xd1\xf5\x1a\x33\x6f\x16\xdc\xfa\x34\xc7\x67\xf9\x5e\x3d\xe0\x0c\x41\xb1\x27\x0a\x5b\x3b\x0e\x05\x51\xde\x36\xba\x46\xae\x25\xfd\xd1\x95\x58\xa0\x0d\x6b\xca\x21\x14\xa4\xd3\xb2\x18\x91\x08\xdb\x85\x17\x12\x23\xeb\x47\x59\x49\x29\xbd\xb8\xd8\x17\x17\x63\x31\x85\xef\x40\x6a\xd2\x76\x19\xe1\xa4\xf7\xd7\x89\xed\x42\xf0\xd0\x63\x0e\x00\xa5\xb8\xac\x55\xc5\x59\x1b\x31\x22\x57\xe9\xf0\x2d\xd9\x8b\x31\xd5\x16\xa1\xee\x32\xd1\x91\xa8\xe9\x6b\xbd\x4a\x84\xd5\x09\x43\x4e\xa0\x6e\xcb\xf4\xd2\x5f\xa2\xf7\x4b\x7f\x89\x8e\x67\x4e\x3a\x8c\x3a\x9d\x13\x04\x43\x52\x55\x06\x65\xd0\x5f\xc2\x8d\x85\xeb\x12\xcb\x82\x22\xa6\x13\x30\x85\x82\xb5\x1b\x48\xca\x25\x1f\x7b\xf1\x6a\xa3\x91\xd1\x3c\x0e\x94\xd2\x02\x17\xcc\xf6\x26\xdd\x2e\xee\x27\xc6\xd7\x68\xf0\xb9\x97\x46\xad\xde\x9d\xcb\x85\xe0\xbf\x2f\xd8\x15\x96\x50\xa6\xc3\x04\x9b\xf2\xfc\xbe\x5f\xa2\x17\x59\xd3\xc9\x62\x42\x87\xe1\xa4\x98\x78\x1a\x9b\x7e\xe9\x8d\x94\xda\x5f\x32\x75\x6f\x81\x58\x46\xd4\xa4\x72\x19\x13\xa6\x51\x56\xda\x9a\xfa\xe0\xa3\x48\xc8\xb1\xe2\x29\xce\xf5\x5f\x10\x67\xe4\x3d\xba\x1f\x5c\x30\xa1\xd9\x70\x86\x15\x5b\x87\xca\xdf\x73\x36\x19\xe6\xb3\xb0\x40\x0a\xd4\x4b\x3a\x4d\x51\x66\x3f\xa9\xca\x76\xfe\x63\x9f\x2f\x83\x95\x4d\x14\x60\xf0\x15\x1c\x84\x74\x7b\x2a\x43\xa1\x5f\x24\x6f\x1d\x9b\x5b\xc8\x85\x0a\x42\xc3\x79\x29\x8e\xaf\x00\xda\x85\x42\x08\xb7\x45\xb6\x1f\x66\x5e\x08\xb5\xb7\xd9\x2e\x05\x21\xf2\x78\x89\xf5\xdf\x8e\xf2\x9d\x81\x14\x28\x5b\x5d\xe4\xa2\xdf\xb8\x65\x51\xab\xaf\x3c\xad\xde\x23\x91\xaf\x9f\x4e\xd6\x17\xae\x9e\xdb\xec\x27\x99\xa6\x28\x54\xfe\x3a\x65\x1d\x08\x24\xc7\xd8\xc9\xda\xee\x59\x0d\xb3\x0e\xaa\x68\x71\xe1\x7e\x77\x09\x0e\xb9\x6c\x00\x69\x71\x0f\x9e\x4f\x0d\x45\xe9\xf1\x0c\xd0\x8e\xf4\xe9\xcf\xd4\xfa\xa1\xc1\x17\x59\xe8\x92\x8f\xa3\x9b\xc9\x2b\x92\x68\x32\xd3\xab\x06\x8e\x49\x74\xc8\xf2\xd5\xe1\xa3\x24\x7e\x1d\x03\x7b\xe3\x30\x9f\xde\xda\xf3\x4b\xb6\xed\xec\xcb\xcc\xf6\x91\xdc\xa6\x95\xa5\x81\x4b\x18\x15\x6f\x97\xfd\xa6\xec\xbd\xa7\x76\x2a\x2f\x9c\x20\x58\x2b\x14\xf8\x62\x1e\x5d\xf2\x61\x50\x09\x6f\x90\xa6\xb4\x2b\x14\xcb\x40\x2f\xce\x3f\x0f\xd1\xcc\x67\xfa\xdf\xee\x94\x23\x5f\x58\xaf\x24\x0b\x3f\x30\x85\x33\xb8\xca\x73\xb8\x65\xc5\x11\x4e\xea\xd7\x15\x44\xbf\x2b\xb7\xfa\x51\x6c\xe8\xf4\x0a\x5d\x5f\x7d\x30\xa9\x5e\xa3\xdb\x8e\x1d\xdb\x3d\x93\x4f\x24\x5a\x4f\x49\x9d\xea\x49\x89\x6b\x7d\x70\x57\x09\x2a\xec\x86\x1f\x27\x2f\xa3\x66\xaa\xd2\xe2\x2a\x65\x23\x02\x6a\x79\xab\x0d\xbb\x9f\x0b\xe7\x0d\x25\x67\x5b\xfc\x06\xb8\x64\x07\xbc\x73\xf0\x2b\x70\xde\x0b\xa6\x41\x59\x9a\xcb\x27\x44\xfc\x78\xfc\xfe\x9b\xd8\x66\xec\x97\xad\xf1\xc2\xda\xf2\x07\x55\x6d\x97\x22\x0b\xa1\x26\x2d\x19\x5f\x17\x26\xa2\x06\xfc\xd8\x93\x78\x7b\x0f\x8c\xf2\xab\x0a\xdc\x85\xeb\x26\x88\xb4\x44\xcb\xbb\x5e\xd1\xca\x70\x7e\x39\x94\x03\x6a\x79\x4b\x0d\x7b\x7c\xf3\x92\xb3\xdd\x13\x68\xe7\xd8\x06\x4e\xf9\x01\xa2\x77\x7c\xf1\xdf\xce\xac\x88\xa7\x96\xb7\x4f\xc7\x04\x2c\x83\x24\xe5\x43\x66\x03\xd8\x7f\xa8\x87\x26\x2c\x05\x73\xbd\x7a\xfb\xde\x0a\x7b\x60\xc0\x31\xd8\x4a\x77\xf5\xd4\x7e\x8a\x27\x2e\x35\x81\x57\xfb\x8a\xff\x28\x7d\x74\x40\x39\x4d\xf2\xab\xa4\xb3\x6f\x0a\x21\x9e\x35\x8a\x53\xd2\x85\xa8\xfe\x4e\xc7\x3b\xba\x0f\xa4\x28\x33\xe2\xfa\xf2\x61\x47\xe2\x23\x26\x7b\x71\x71\x86\xa7\xde\x63\x94\xe5\xdc\xa2\x44\x11\xd7\x11\xf4\xc3\x07\x5b\x2e\x5b\x4f\xd0\xb1\x33\x07\xb6\x53\xc1\xf3\x12\x5e\xd7\x09\xe7\xbb\xdc\x17\xde\x30\x85\xab\x57\x2c\x39\x97\x3f\x07\x53\x2e\xd9\x4e\xd5\x57\x47\x56\xde\xc8\x99\x8c\xa8\xa6\xe9\x8c\x96\xb7\x61\x92\x59\xd1\x02\x15\x42\x9b\xcf\x62\xe2\x7f\x3c\x74\xbc\x73\x92\x8e\x29\x7c\x18\x3f\xf5\x60\x22\xd8\xb8\x2a\x90\xaa\x60\xa1\x4d\xf8\xe9\x72\xd3\x6a\x78\x1b\x69\x79\x44\x66\x68\xc2\x41\xc5\x73\x4d\x92\x89\x04\x3e\xd1\xbe\xe6\xdb\x64\xc8\xa8\xff\x62\x55\xaf\x4a\x92\x06\x15\x6e\xda\xc2\x93\xc3\x8f\x3e\xf6\xc7\x4f\x5a\x6c\x1f\x8d\xc3\xb8\xd3\x9f\x29\x98\xcd\x7a\xfb\x9b\x73\x14\xc0\x80\x67\xa7\x9e\x1f\x2d\xf0\xfe\x47\x51\x26\x1c\x7d\x4e\xce\xeb\x5a\x3f\x75\x53\x6f\x69\x13\x19\xc0\x8f\xc9\x98\xd2\x1d\x76\xde\x7c\x82\x8e\x55\x41\x11\x74\x0b\x7c\x07\x1d\xde\x53\x76\x2a\x88\xa6\x2f\x7e\xd4\x3b\xf0\xd9\x92\xad\x9d\xa7\xd3\x1a\x39\x26\xb6\xdd\xa3\xac\x7d\x99\x3f\xe8\x9e\x91\x04\x54\x1f\x1f\x6e\x27\x45\xb5\x18\x35\x94\x1e\x5b\xc6\xd4\x44\xd7\xfb\x15\x51\xa0\x94\x42\x69\x05\x1b\xb5\x7c\x8d\x8e\x79\x71\x94\x4f\xaf\x48\xe6\xcd\x87\xd3\xb6\x1e\x39\xaf\xad\xcb\x88\x76\x32\x4c\xd5\x54\x99\x2c\x55\x7f\x18\xd1\xdc\xb9\x35\x13\xa3\x95\x8b\xa7\x67\x67\xe8\x3f\xba\xc3\xeb\xfa\x36\x3f\x85\x75\xad\x51\xe9\xbc\xf0\x33\x35\x8e\x3e\xc6\x3e\x2c\x5d\x8f\xc6\xe1\xb9\x93\xaf\x0a\x1b\x4e\xf9\x9a\x1e\x60\xed\xb4\x3f\x51\xee\x67\x45\x3c\x95\x3b\xcc\x98\xaf\x35\xd8\x4c\xdb\xcf\xff\x96\x2d\x32\xf5\x36\xa8\xad\xfc\x2d\xd7\xcd\x5f\xef\x47\x0a\x7a\xae\xb6\xcf\xcc\x43\xbf\x7f\xc2\xc8\x13\xee\x0a\xa6\x87\x50\xe6\xed\x49\x15\xa6\xeb\x54\x30\xad\xac\xb4\xd5\x44\x05\xab\xdd\xdd\x4a\xc3\x38\x38\x4b\xbd\x95\xb0\x8a\xa3\xf5\xc1\xf3\xf3\xcb\x83\x51\xb9\xbe\xa0\xa9\xa0\xed\x6c\xb7\x49\x09\xc6\xc8\x93\x0f\xd6\xfb\x47\x8c\x1e\x9f\x0d\x4f\x1b\xef\x70\xc8\x8b\xf9\xb2\x27\xca\x17\x45\xbb\x6e\x56\xb5\x9d\x71\x2e\x84\xaa\xb7\x08\x27\xec\xd5\x45\xf5\x5a\x86\xb1\xea\x3b\x6e\x2f\x47\x51\xfc\x22\x3b\x35\xc7\xf3\x20\x0d\xef\x89\x10\x23\x08\x06\x33\x96\x5e\x32\x79\xda\x2d\x2a\x85\xca\x49\xa4\x28\x4a\x08\xf6\x17\x68\xeb\x2e\x57\x07\x97\x65\x6b\xaf\xbf\x91\xd3\xb3\x1e\x36\xe5\xe3\x22\x9c\xfb\x85\xd7\xa2\xe1\xce\x88\xc0\x5a\x00\x89\xb8\x5f\x6d\x97\x97\xbd\x6b\x3d\x77\x07\x19\xec\x16\xe9\x92\x86\x29\x44\x8a\xcf\xed\x28\x44\xdf\x6b\xd5\xd7\x3a\x24\x46\x44\x13\x09\xd5\xfe\xe1\x7b\xf1\xd3\xa7\xf9\x4e\xa3\xe8\xf7\xac\x70\xca\xfd\xb9\xfe\x8d\xe0\xd9\xdf\x77\xab\x4f\x20\xe2\xc5\x8d\x0d\xe5\xb3\x57\x5c\x69\xc8\x6f\x1e\x9a\x3f\xb6\x3e\xdb\x04\x30\xd2\xf8\xa5\x62\xc3\x0b\x9b\x75\x62\xe2\x09\xa9\x23\xce\x4e\x7a\xf8\xf1\xbc\x4c\x61\x37\x29\x9e\x81\x16\xa7\xed\x0f\x98\x75\x4f\xf4\x9f\xfe\x26\xa2\x6d\x9d\x02\x39\x9f\xb6\xd3\x8d\xfb\x1a\x5a\xa9\x0a\x8f\x1c\xf7\xce\x21\x47\xa7\xa2\xe3\x97\xb2\x1e\xde\x84\x77\xeb\xe3\x0c\xd3\x66\x6a\x99\x29\x52\xb2\x68\xf8\x10\x1d\x2e\x2d\x66\x2f\x59\x56\xbf\x28\x56\x3e\x93\x35\x17\xa2\x00\x64\x38\x5f\xe0\xc9\xfd\xd9\xb4\x5c\x1f\x7d\xa0\x03\x0a\xdc\x5a\x3c\x70\x8e\x1d\x8a\xe6\x9c\x05\x7a\x7f\x72\xc3\x09\x16\x16\x7d\xaf\xff\xa9\x87\x3f\x98\xaf\x37\x5c\xeb\x49\x4f\x6f\xea\x1a\x37\x66\xce\x51\xea\x59\x9b\xeb\x16\xeb\x20\xb3\xf8\xe7\x86\x9e\x6f\x22\x45\xb5\xd4\xb8\xba\xd9\x69\x85\xa7\xf7\xcf\xf1\x61\x14\x2a\x12\xc4\x02\x3d\xac\x88\xa6\x94\x9c\xac\xf3\x83\x85\xb6\x2d\xfa\xbd\xbf\x3f\x06\x4b\x2f\x66\x9c\x33\x5f\x9e\x46\x27\x29\x9b\x9a\x9a\x26\xa0\x22\xd7\xd5\x97\xfa\x42\xe2\x1c\xc1\x77\xe8\xa6\xdb\x20\xc7\x82\x8b\x24\xfc\x2f\xd3\x30\xe9\x88\x48\xca\xcb\xd6\x42\x3c\xad\x57\x74\x53\x80\xf0\x97\xe5\xce\x98\xc0\xbc\xff\x24\x0b\xd1\xd7\xce\xf4\xa4\x23\xc9\xbe\x13\xf6\xed\x0c\x2b\x1c\xd6\x93\x54\x51\x65\xbe\x22\x97\xb8\xc1\xea\xe7\x5a\x90\x1b\xcc\x46\xf8\x07\x3b\x99\xeb\xe4\x96\x07\x23\x57\xa9\x79\xd0\x4e\xf4\xdf\x13\x1d\xa5\x00\x5a\xda\x55\x87\x2e\xea\xe5\xb1\x97\xbf\x59\x71\x41\xf5\x1f\x62\xb0\x5f\xc6\xbb\xf5\xad\x33\xa5\xe9\xf6\xe7\x1a\xd3\xd3\xd1\xfd\x7d\x5a\xc7\x87\xcf\xad\xd3\xaf\x75\xc6\x10\xfe\xbe\x9a\x1f\x13\xee\xd1\x0d\xda\xff\x7e\x2f\xd6\x41\xc4\x9e\xb4\x2b\x6d\xe4\x14\x8e\x71\x48\x4b\x61\x9c\xae\x06\xa2\x6c\xb5\x30\xcb\x8c\x6f\x8a\x9a\xc8\x45\x81\x65\x81\x03\x48\xf6\x1f\x48\xd9\xb0\xfb\xf4\x7b\x51\x2c\x49\xfc\x0b\xbd\xce\x53\x7b\xcd\xa8\x4b\x85\xed\x7c\x82\xc6\x01\xfd\x1a\x96\x33\x1f\xa5\x12\xc9\xf0\x9c\x67\xa0\x47\xd9\x7e\x1f\xde\xaf\xec\x28\x1c\x45\x86\x32\x33\xaa\xfd\x92\xb0\x8e\x87\x9e\xa8\xe3\x3f\x87\xb8\xd0\xd2\xf9\x9c\xd0\xe2\x7a\xec\xf5\xc5\x9d\xea\xdc\x59\xa4\xd6\xb4\xdf\x36\x89\x1c\x37\xbf\xe1\x53\xd3\xed\xaa\xb4\x6c\x75\xc9\xf4\x2c\x40\x13\x0e\xc0\x4b\x2f\x6c\xdb\x66\xd9\x93\x78\x8a\xbc\x5c\x32\xc5\x3e\x31\x2f\x26\x0d\x2e\x29\xe3\x25\x50\xcf\xee\x0f\x9b\x52\x96\x73\x5e\x3f\x30\x52\x6c\xa9\xfd\xf8\x01\x28\x88\xdb\x87\xa3\xfb\x75\x9e\xbf\xd8\x5b\xdb\x5c\x6c\x70\xef\x16\xce\x2f\x8c\x2f\xa0\x08\x0d\x85\xbf\x07\xfe\x91\x7b\x3f\xb0\x47\x5f\xca\x5d\x1f\x57\x4a\x8d\xa3\xef\x5f\x7b\xfb\x14\x4b\xa4\xf5\x86\x63\x25\x10\x60\xf6\x50\x05\x88\x17\xc2\x3b\xcf\xf9\xc0\x5f\x57\xc0\x5b\x6f\x6d\x15\x6f\x1f\x37\x1d\xe6\xf4\x04\x5f\x84\x5d\x5e\x48\x0c\x7d\x69\xa4\x9a\xe2\x82\x44\xd9\xed\x86\x0f\x0e\xeb\x24\x4d\x1b\xca\xe7\x1d\xa1\xe3\xb9\x3b\x20\xb0\xa8\x76\x60\x09\x17\x33\x70\xf0\x97\x11\x9b\xf3\x3c\x3f\x3a\x96\xec\xb1\x09\x0b\x6b\x0c\xa5\x9d\x15\x10\xd9\x88\xd4\xcb\x55\xc9\xf4\x71\xbb\x38\xaf\xe6\x3b\x6e\x4c\x75\xf0\xa3\xa8\x18\xd7\xc2\x3f\x55\x2c\x73\x8f\xdd\x98\x4f\xf8\x48\x7b\x21\x1d\x27\x6b\x8f\x75\xc9\xbc\x26\xad\x2e\xcd\x6f\x82\x1d\x98\xd8\x26\x62\x1c\x8a\x5a\x48\xe6\x1a\xc8\x50\x3f\x01\x01\xfd\x4b\xcf\x1e\x64\x9d\x82\x70\xb3\x52\x96\x89\x68\x97\xed\x9e\x51\x11\x75\xbf\xde\x8f\x77\x8b\xf9\x27\xe0\x77\xef\x52\xd9\xf5\xea\x12\x72\xda\x1f\x4a\xfa\x0e\x04\x7a\x97\x2f\xc8\x51\xad\x3f\xb2\xac\xcd\x11\x64\xe3\x5f\x98\x93\xef\x21\x58\x2d\xe4\x1b\xcf\x1a\x5a\x66\x63\x0a\xcd\x24\xae\x58\xa7\x89\xcb\x45\x00\xa1\xf5\xa2\xce\x4e\x23\xee\x10\x24\x74\x2e\x69\x75\x36\x41\x15\x2a\xc7\x4d\xb6\xb7\x23\x24\xda\x73\x44\x7e\xfb\xee\x99\x63\xb5\x5c\xc4\x74\x61\xae\xfb\x8c\xc9\x38\x57\x75\x5b\x6b\x85\xae\x8e\xca\x0b\xb8\xc2\xce\x82\x18\x17\x19\x2a\x4a\xd3\xe9\x2b\x8f\x39\x06\xde\x55\xe3\xa9\xc8\x6f\x38\xb6\x8f\x87\xd6\xe7\x44\xbd\x2d\x72\xb9\x63\xe3\x27\xbf\xe3\x19\xb3\x3a\x65\x5e\x97\xdc\x61\x20\xeb\xf9\x99\xda\xae\x57\xb7\xfb\x8c\xa3\xf5\xce\x3e\x2d\xe7\xa3\x77\xda\xaa\xed\x61\x55\xad\x1e\x8d\x04\xbb\x08\x4c\xa1\x74\x20\x63\x43\xe3\x7f\x76\xa4\x61\x2e\x60\x93\x32\x65\xf6\x9f\xaf\xfc\x05\x43\x34\x8b\x66\xc5\xec\x1f\xf4\x37\xda\x2e\x91\xc5\x6e\x6e\x8a\xfc\xef\xbf\x3c\x2f\x52\xf5\x12\x3f\x7c\x3a\xd4\x51\x53\xdd\x06\x8b\x62\xa4\x86\xbc\x30\x43\x91\xa2\x18\xe3\x2a\xaa\xca\x86\x63\x24\xfa\x95\x3e\x3c\x1d\x76\x32\xbf\xb6\x58\x0c\x8a\xa9\x82\x8c\x1a\x3a\x15\x3b\x4e\x7a\x0b\xe1\x5a\x1a\x33\xc3\x23\xc6\xbf\xba\x71\x0f\x26\x77\x3e\x5f\x8a\xa2\x79\xcf\x9f\xa6\x55\xce\xd2\x16\xb2\xf7\xe0\xfa\x6c\x8e\x2b\x45\x56\x61\x33\xa1\x3b\x27\x45\xc9\xb1\x7f\x0f\xd5\x4a\x8c\xe8\x2b\x52\xdb\x61\xee\xb3\xed\x99\x6e\x36\x6b\x93\x84\xa2\x56\x3e\x9d\x5e\xd5\xcb\xa0\xed\xd9\xa4\x41\x42\x34\xe5\x29\xf3\x50\xe8\x3c\x63\xd8\x35\x43\x4e\xe0\x99\x64\xec\x9b\xc0\x42\xf9\x77\xe9\xe6\xde\x41\xad\xef\x4e\x64\x17\x18\x81\x83\xc7\x02\xa5\x3e\xc9\x36\x24\xbc\xae\x79\x8c\x1e\x09\x40\xa4\xde\x02\xd1\xfa\xf4\x67\x02\x90\x6f\xae\x89\x0c\x35\x6c\x78\xa3\xb8\xf9\xfb\xa7\x43\x55\x39\x28\x1c\xc0\xaf\xd7\xd2\x3c\x66\xae\x54\x1d\x39\x34\x01\xc9\xe9\xd9\x10\xee\xd0\xba\xf3\x2b\x23\x8c\xed\x06\xf1\x78\x52\xc3\xd4\xd2\x2e\x1e\xb3\x9e\x69\x44\xa1\x94\x16\x52\x42\x30\xb7\xc3\xc0\x83\x28\x4f\x8a\x3b\xd1\x23\xd8\x16\xe3\x77\xad\x60\x14\x47\x56\x47\x52\xe2\xb0\x02\x66\xfa\xb0\x34\x54\x53\xcf\x23\x91\x6c\x55\x2d\x2f\xac\xe3\x71\xc2\x86\xf7\xa5\x8a\x37\xee\x15\xc1\x4c\x33\xfb\x75\x8d\x76\xf9\x88\xf8\x2b\x42\x3c\xd6\xcb\x41\x8b\xed\xbf\xd0\x2e\xdb\x4d\xcb\x67\x17\x1e\x63\x2d\xdb\x69\x87\x9a\xbc\x20\xc8\xa0\x8d\xad\x1c\x2a\x00\xa3\xca\x36\x8b\x51\x26\xde\xb2\xb8\x1e\x98\x1f\xb0\x0c\xf9\x85\x66\x66\x9a\xca\xf9\x7d\xb8\x97\x9d\x7a\x9e\x7f\x15\x3a\x7f\x76\x28\x64\x99\x02\x71\x89\x5b\x2e\x2d\xd1\x01\x4b\xdb\x99\x8c\xb1\x44\xed\xee\x30\x46\x10\x23\x4c\xec\x77\xee\xab\xce\x7c\x30\x93\x97\xa4\x44\x75\x45\x88\x85\xc1\xd8\x67\x93\xe4\x7f\xb2\x46\x46\x54\xe1\x24\x32\x2b\xd5\xd4\x76\x04\xeb\xdc\x2e\x89\xc6\x0d\x0a\x0c\xa9\x76\xa2\xe6\xbe\xac\xe6\x32\x07\xf7\xfd\xf9\xb6\xb7\x70\x3e\x48\xd7\xec\x0d\x89\xe4\x00\x0a\x02\x11\x0a\x4c\x20\xac\x50\x8d\x47\xb7\x52\x69\xac\x0f\x99\x97\xf8\x3b\x23\x0b\x07\x5f\x9c\x8a\x2c\x5f\x25\xae\xce\xd5\x8f\x09\xfd\x44\x83\x62\x8d\x37\x7d\x1d\x19\xb2\xc1\x2d\x09\x67\xaa\xc8\x72\x05\xd8\xd5\xb7\x86\xf1\x8f\xaf\xd5\x75\x7c\x8a\x21\x8f\xca\x4e\xe0\x4b\xdc\x9a\x28\x71\x2d\x2c\x74\x68\x5a\xca\x8b\x9a\x2b\x8b\x37\x57\x5a\xf6\x07\xbf\x5f\xdc\x9c\x4f\xb4\x98\x1e\x2b\xd6\xc7\xd7\x74\xfb\x57\x84\xc4\x81\x0f\x2a\x05\x19\x64\x38\x67\x5c\x0b\x91\x9f\x12\xda\xbb\x68\xad\xde\x34\xb9\x79\xc0\x12\x00\x58\x24\x4f\x7d\x1d\x1d\x79\x26\xe4\x93\xbf\xec\x25\x67\x99\xab\xda\x37\x8a\xfc\x83\x9e\xc4\x6c\x0a\xff\x22\xab\xf7\xf7\xd9\x20\x03\x3d\x1d\x0c\x37\x22\x6a\x80\x41\x1d\xa8\xb3\x8c\xc7\xf8\xc1\x11\x23\xcf\x40\xd4\x8e\x57\x57\x00\xda\x58\x59\xab\xfc\x17\x43\xb1\x8a\xb9\xd9\x2f\x50\x39\xda\xf1\xa7\x4c\x09\xab\xf9\x90\x85\x75\xd3\x5c\xaf\x76\x67\x55\x56\xa3\xd4\xe8\x7d\x39\x0f\xda\x33\x2c\xac\xce\xe8\x79\xb1\x9f\x1a\xfe\xa5\xb3\xa3\xf3\x75\x0b\xbb\xfe\x59\x0b\xa7\xe8\x30\x08\x2b\xac\x3e\x23\xc7\x82\xb2\x05\xd6\x36\xa5\xec\xcc\x35\x16\xaf\x08\x09\xbe\x9b\x76\x9b\xf3\xb7\xe9\x2a\x80\xbc\x7b\x6f\x32\xca\x3d\x22\x17\xff\xbd\xab\x0a\x9c\xf9\x3d\x7f\xe2\xbe\x23\xfb\x1c\x16\xb3\x3e\x3d\x41\xda\x97\x17\x93\xc7\x84\x1f\xf8\x13\xe0\x44\x89\x73\x6d\x91\xf4\x81\xe2\x0c\x0c\x0c\x46\x73\x55\x5a\xcf\x6d\x8a\x6d\x83\x94\x6f\x6f\x42\x3c\x7b\x96\x39\x8c\x37\x9d\xfe\x97\x92\x99\xd7\x17\xb0\x28\xf6\xc5\xc2\x59\xbe\xe7\xd2\xdc\xe8\x87\xb2\x0a\xb1\xfe\xa7\xcf\x96\x1b\x02\xf1\x35\xcb\x53\xcf\x84\x71\x56\xd6\xb8\x67\x91\x46\xb1\x65\x0d\x1a\x7a\xea\x57\x67\xfb\xce\xdc\x93\x0d\x6e\x6c\xf3\x7e\x0a\xd7\x5b\xe4\x8f\x14\x4c\x6e\x76\x9a\x0b\xf2\xe4\x91\x87\xd9\x65\xad\x54\x55\x2c\xa3\x20\x84\xb4\xd3\x51\xef\xeb\x27\xb4\xfe\x96\xbf\x61\x2e\x02\x79\x43\xc9\x33\x43\x1b\x20\xa1\xa1\x24\xa2\xe8\xcf\xca\xcf\x85\x48\xa2\xcc\xd0\xa6\xcb\xa9\xb3\x8f\x91\x55\xa6\x49\x04\x2d\xac\xed\x05\x74\xbb\x92\x62\xd2\xef\xa5\xd6\x15\x77\x4a\x56\x80\x07\xa2\xfe\x5f\xe0\x97\xaf\x66\xe8\x66\x01\xbf\xe3\xa4\xb2\xf8\x70\x5f\xc1\x3c\xd7\x2f\x34\x41\x59\xe4\xe5\x03\x65\x88\xe3\x47\xbb\x74\x80\xa2\x0e\x6f\xff\xfb\xb8\x29\x8f\x18\x82\x12\x7c\xc3\x14\x2e\x28\x47\x3e\xd2\x5b\x75\x55\xf1\x50\x72\x21\xa6\xd3\xa1\x9e\x02\x84\x9d\x8c\x13\xda\x19\x49\x36\xef\xdc\xc9\x19\x82\x20\x85\xeb\x0a\x82\x6f\x04\xe3\x8c\x2d\xe1\xd2\x20\x21\xb9\x60\x3a\xc6\xb0\x36\x7a\xeb\x57\x17\x3a\xf9\x9d\xee\x02\x4d\x94\x73\xf1\x24\x65\x74\x3d\xcf\xeb\xc9\x50\x89\x5a\x4d\x36\x8d\xaf\xa7\x40\x83\xbc\x2f\x9a\xc1\x28\x39\xbf\xeb\x58\x49\x17\x69\x45\x0b\xe3\x7f\x8b\x35\x3d\x26\x46\xca\x0d\x79\x27\xdd\xb8\x66\x34\xf1\xcb\xa7\x57\x0f\xdd\x1f\xc8\x0e\xf3\x80\xb0\x3f\x24\x40\xdd\xee\xe0\x0a\x08\x12\x5e\xd7\xd3\x78\x00\xa9\xb5\xf7\x95\xc0\xd5\x84\xdd\x48\xde\x58\xec\xf4\xf9\xd2\xf4\xd8\x66\xa5\x3c\xe5\xfe\x4e\xfb\xcb\x2a\x40\xc4\x8f\x9e\x42\x4d\xf3\x42\x49\x73\xd7\x10\xfc\xe7\xae\x42\xab\xe6\x7d\xa6\xc7\xdd\x12\xbf\x91\xa3\x9c\xe8\x58\x2b\x9d\x5f\x71\xbd\x22\x68\x06\x06\x06\xbb\xc5\xaf\x16\x7b\x83\xfd\x15\x97\x43\x2a\xba\xc3\x87\x81\xe7\x0e\xab\x1b\xe7\xb7\x26\x66\x37\x88\xc7\x60\x39\x28\xc4\x2e\xcc\xd4\xa4\x50\xa7\x24\x27\x2a\x7f\x67\xfe\x4e\x66\x19\x86\x70\xcc\x6f\x8b\x90\x77\xdb\xc9\x01\x00\x88\x14\x35\x55\x95\x8c\x8e\xbf\xa7\xca\xbe\x69\xdc\x60\x41\x86\x40\x84\x72\xe1\x67\xdd\xe2\xbf\xd9\x4c\xb9\x50\xb2\x3e\xd5\x85\x4e\xba\x9a\x8b\xe7\x0c\xe9\xe7\x05\x79\x56\xe1\xaa\x73\xda\x65\x8d\x6b\x89\x8c\x94\xd9\x53\x47\xd0\xbc\x3d\xe7\x5a\xfa\x3a\x08\x6a\xd2\xc4\xcc\x21\x83\x2a\xca\x2e\x01\xfa\xbd\x02\x4f\x1b\xff\xde\x9f\x31\x87\xc8\xcb\xe1\xc9\x93\x56\x10\x31\x62\x7f\x96\x65\xe2\xa5\x48\x9e\x6b\x81\x52\x83\xfd\xf0\x34\x04\xb1\xac\xcb\x94\x13\xfe\xe0\x17\x55\x94\xb8\x1a\xf1\x36\x23\x3a\xfd\x04\xb6\x46\xff\x57\xc5\xca\x94\xf9\x02\x2e\xff\xcc\xc8\x2b\x83\x66\xf9\x6a\x81\x04\x38\x38\xc5\x23\x06\xd1\xf7\xcb\x9a\xe1\x9c\x26\x2f\xdf\xd9\x92\xb8\x10\xc3\xc9\x34\xf9\x58\xba\x3d\x64\x41\x81\x1d\x94\xd6\xd2\xd8\xa3\x3f\xa6\xd8\xf1\x54\x96\x94\x30\x57\x01\x80\x83\x01\x3a\x0c\x66\x1f\x63\xef\xd5\xda\x73\x3d\x7a\x0e\x18\xfc\x5c\x56\xc1\xe9\x76\x60\x5c\x52\x55\x3d\x29\x18\x70\x3f\x0d\x59\xa7\x24\xe0\x61\x79\x61\x3a\x46\xe2\xd0\x76\x52\x5b\xc7\xcb\x77\xd3\xff\xce\xd6\xb5\xd8\xbe\x22\x1c\x04\x42\x55\x18\xba\x29\x98\xe1\x6b\x86\xae\x43\x97\x68\xa7\xbf\x72\x31\x76\xfb\xa8\x66\x38\x58\x3f\xda\x04\x94\xc9\x0e\xf3\x84\x32\x62\x34\x01\x30\xd3\x60\xfb\x99\xad\xdc\x44\x0d\x60\x98\x00\x8e\x16\x56\x4b\x6d\x33\xae\x22\xae\x33\x85\x0f\xc4\x97\x82\x7f\x4e\x0b\x7a\x72\xb8\xd6\x90\xd8\xe7\xd0\x73\x83\xd3\x84\x70\x10\x3c\xa2\x0e\xaf\x5d\x6e\x5b\x38\x90\xc5\x62\xf8\xa3\x19\x4f\x7b\x1c\x19\xc0\xcf\x7c\x00\xe8\x33\x06\xac\x8d\x38\x4b\xab\x41\x6a\x94\xa1\xc9\xa0\x7e\xfa\xa5\x0c\x08\x9a\xdf\x16\x81\x2d\x2f\x35\x0d\xf3\x97\xc2\x95\xe6\x1f\xf4\x27\xa9\xb1\x54\x82\xe2\x23\x76\x35\x6a\x7b\xb8\x5b\x0b\x00\x02\xdc\x65\xf8\xf7\x25\x78\x6d\xfb\x5a\xb8\xdf\xee\x2a\x25\xda\xb8\xec\x4e\x91\xd2\x83\xee\xf4\xa5\x26\x10\xac\x6f\x4e\x98\xf3\x8f\x1e\x34\x00\x05\xf4\x6a\x6d\x24\x85\x91\xd3\xd8\x54\xc9\xc2\x75\xfd\x81\x65\x95\xce\x1f\x5e\x51\x33\x7f\x8f\xbf\x05\x0c\xe8\x7a\x79\xc6\xed\xac\x41\x04\x96\x2c\xc0\xd8\xd7\x36\x34\x03\x38\x6a\x85\xda\xb5\x78\x2b\xe1\xc4\xee\x76\x7c\xa9\x90\xd1\x7a\xd6\x13\xaf\xd7\x5b\x5e\xc6\x0a\x97\x8d\xd7\x75\x32\x34\x13\x1c\x02\xe8\x7c\xd0\xee\xaa\x89\xc1\x3a\xea\x8d\xeb\xd4\xf9\x19\x8f\x94\xac\x40\xcb\x19\x09\x6e\x27\x6e\x3a\xa9\xd8\x56\x81\x04\x93\xaf\x80\xa2\xc0\x07\xcd\x95\xdf\xf7\xd5\x83\xca\xa8\x03\x13\x13\xd0\xd4\x3f\x68\xa7\x30\x76\xc2\x79\x7b\x86\x9b\x32\x3f\x9b\xee\x2e\x10\x61\x2d\xda\x56\x66\x4c\x4e\x65\x7a\x04\xc3\x98\x49\x00\x2f\xae\x27\x0c\x1a\xed\x93\xaf\xef\x80\x59\x4d\x3e\x33\xe3\xfd\x01\x5f\x21\x38\x5a\x76\x17\x6a\xbb\x8e\x16\xe3\x07\x61\x00\x2d\x4e\xdb\xe1\xe4\x44\x58\x5a\x9e\xb0\x41\x72\x38\xd4\x9e\x1b\xd3\x80\xfe\x06\x50\x57\xbb\xae\xcd\xdb\xf1\xe7\x26\x52\xa4\x6b\xe4\xff\x70\x7d\x96\x01\x62\x5f\x29\x29\x7f\x05\x58\xd9\x93\x3e\x36\xfd\x67\x78\x25\xa7\xfe\xd8\x00\x47\x47\xd3\x30\xab\x35\x76\xc5\x84\xb2\x1a\xe0\x25\x28\x43\xcf\x55\x81\x20\xac\x1e\xad\x8e\x4d\x0a\xc8\xea\x19\x06\xb3\x1e\x89\x30\x80\x15\x60\xf4\xe8\xb9\xd1\x17\x77\xc6\xe8\xf9\x05\x96\xc0\x60\x52\x94\xd5\x37\x5e\x82\xe2\xff\xd9\x68\xf8\x2d\xa4\x4f\x2a\xea\x53\xd3\xaa\xce\x34\x00\x00\x00\x68\x3e\xd1\x55\xad\x54\x46\xbf\xfe\x7f\x01\x00\x00\xff\xff\xce\x71\x20\x86\x92\x23\x00\x00"), + }, + } + fs["/"].(*vfsgen۰DirInfo).entries = []os.FileInfo{ + fs["/icon.png"].(os.FileInfo), + } + + return fs +}() + +type vfsgen۰FS map[string]interface{} + +func (fs vfsgen۰FS) Open(path string) (http.File, error) { + path = pathpkg.Clean("/" + path) + f, ok := fs[path] + if !ok { + return nil, &os.PathError{Op: "open", Path: path, Err: os.ErrNotExist} + } + + switch f := f.(type) { + case *vfsgen۰CompressedFileInfo: + gr, err := gzip.NewReader(bytes.NewReader(f.compressedContent)) + if err != nil { + // This should never happen because we generate the gzip bytes such that they are always valid. + panic("unexpected error reading own gzip compressed bytes: " + err.Error()) + } + return &vfsgen۰CompressedFile{ + vfsgen۰CompressedFileInfo: f, + gr: gr, + }, nil + case *vfsgen۰DirInfo: + return &vfsgen۰Dir{ + vfsgen۰DirInfo: f, + }, nil + default: + // This should never happen because we generate only the above types. + panic(fmt.Sprintf("unexpected type %T", f)) + } +} + +// vfsgen۰CompressedFileInfo is a static definition of a gzip compressed file. +type vfsgen۰CompressedFileInfo struct { + name string + modTime time.Time + compressedContent []byte + uncompressedSize int64 +} + +func (f *vfsgen۰CompressedFileInfo) Readdir(count int) ([]os.FileInfo, error) { + return nil, fmt.Errorf("cannot Readdir from file %s", f.name) +} +func (f *vfsgen۰CompressedFileInfo) Stat() (os.FileInfo, error) { return f, nil } + +func (f *vfsgen۰CompressedFileInfo) GzipBytes() []byte { + return f.compressedContent +} + +func (f *vfsgen۰CompressedFileInfo) Name() string { return f.name } +func (f *vfsgen۰CompressedFileInfo) Size() int64 { return f.uncompressedSize } +func (f *vfsgen۰CompressedFileInfo) Mode() os.FileMode { return 0444 } +func (f *vfsgen۰CompressedFileInfo) ModTime() time.Time { return f.modTime } +func (f *vfsgen۰CompressedFileInfo) IsDir() bool { return false } +func (f *vfsgen۰CompressedFileInfo) Sys() interface{} { return nil } + +// vfsgen۰CompressedFile is an opened compressedFile instance. +type vfsgen۰CompressedFile struct { + *vfsgen۰CompressedFileInfo + gr *gzip.Reader + grPos int64 // Actual gr uncompressed position. + seekPos int64 // Seek uncompressed position. +} + +func (f *vfsgen۰CompressedFile) Read(p []byte) (n int, err error) { + if f.grPos > f.seekPos { + // Rewind to beginning. + err = f.gr.Reset(bytes.NewReader(f.compressedContent)) + if err != nil { + return 0, err + } + f.grPos = 0 + } + if f.grPos < f.seekPos { + // Fast-forward. + _, err = io.CopyN(ioutil.Discard, f.gr, f.seekPos-f.grPos) + if err != nil { + return 0, err + } + f.grPos = f.seekPos + } + n, err = f.gr.Read(p) + f.grPos += int64(n) + f.seekPos = f.grPos + return n, err +} +func (f *vfsgen۰CompressedFile) Seek(offset int64, whence int) (int64, error) { + switch whence { + case io.SeekStart: + f.seekPos = 0 + offset + case io.SeekCurrent: + f.seekPos += offset + case io.SeekEnd: + f.seekPos = f.uncompressedSize + offset + default: + panic(fmt.Errorf("invalid whence value: %v", whence)) + } + return f.seekPos, nil +} +func (f *vfsgen۰CompressedFile) Close() error { + return f.gr.Close() +} + +// vfsgen۰DirInfo is a static definition of a directory. +type vfsgen۰DirInfo struct { + name string + modTime time.Time + entries []os.FileInfo +} + +func (d *vfsgen۰DirInfo) Read([]byte) (int, error) { + return 0, fmt.Errorf("cannot Read from directory %s", d.name) +} +func (d *vfsgen۰DirInfo) Close() error { return nil } +func (d *vfsgen۰DirInfo) Stat() (os.FileInfo, error) { return d, nil } + +func (d *vfsgen۰DirInfo) Name() string { return d.name } +func (d *vfsgen۰DirInfo) Size() int64 { return 0 } +func (d *vfsgen۰DirInfo) Mode() os.FileMode { return 0755 | os.ModeDir } +func (d *vfsgen۰DirInfo) ModTime() time.Time { return d.modTime } +func (d *vfsgen۰DirInfo) IsDir() bool { return true } +func (d *vfsgen۰DirInfo) Sys() interface{} { return nil } + +// vfsgen۰Dir is an opened dir instance. +type vfsgen۰Dir struct { + *vfsgen۰DirInfo + pos int // Position within entries for Seek and Readdir. +} + +func (d *vfsgen۰Dir) Seek(offset int64, whence int) (int64, error) { + if offset == 0 && whence == io.SeekStart { + d.pos = 0 + return 0, nil + } + return 0, fmt.Errorf("unsupported Seek in directory %s", d.name) +} + +func (d *vfsgen۰Dir) Readdir(count int) ([]os.FileInfo, error) { + if d.pos >= len(d.entries) && count > 0 { + return nil, io.EOF + } + if count <= 0 || count > len(d.entries)-d.pos { + count = len(d.entries) - d.pos + } + e := d.entries[d.pos : d.pos+count] + d.pos += count + return e, nil +} diff --git a/notifier/icon.go b/notifier/icon.go new file mode 100644 index 0000000..8784d61 --- /dev/null +++ b/notifier/icon.go @@ -0,0 +1,42 @@ +package notifier + +import ( + "io/ioutil" + "log" + "os" + "path/filepath" +) + +const ( + icon = ".dl101.png" +) + +func getIconPath() (string, error) { + homeDir, err := os.UserHomeDir() + if err != nil { + return "", err + } + return filepath.Join(homeDir, icon), nil +} + +func writeIcon() { + iconPath, _ := getIconPath() + if _, err := os.Stat(iconPath); err == nil { + return + } + + fp, err := AssetFS.Open("/icon.png") + if err != nil { + log.Fatal(err) + } + bs, err := ioutil.ReadAll(fp) + if err != nil { + log.Fatal(err) + } + if err == nil { + err := ioutil.WriteFile(iconPath, bs, 0644) + if err != nil { + log.Println(err) + } + } +} diff --git a/notifier/notifier.go b/notifier/notifier.go new file mode 100644 index 0000000..25f3356 --- /dev/null +++ b/notifier/notifier.go @@ -0,0 +1,23 @@ +package notifier + +import "github.com/martinlindhe/notify" + +// Notifier represents a notifier type +type Notifier struct { + appName string + iconPath string +} + +// New return a new notifier +func New(name string) *Notifier { + writeIcon() // call every time + return &Notifier{ + appName: name, + } +} + +// Notify send a notification to device +func (n *Notifier) Notify(title, text string) { + iconPath, _ := getIconPath() + notify.Notify(n.appName, title, text, iconPath) +} diff --git a/uninstall.sh b/uninstall.sh new file mode 100755 index 0000000..0d6b8c8 --- /dev/null +++ b/uninstall.sh @@ -0,0 +1,9 @@ +#! /bin/bash + +TARGET=/usr/local/bin/dl +MESSAGE_START="Removing dl" +MESSAGE_END="dl removed" + +echo "$MESSAGE_START" +rm $TARGET +echo "$MESSAGE_END" diff --git a/values/values.go b/values/values.go new file mode 100644 index 0000000..0ffecac --- /dev/null +++ b/values/values.go @@ -0,0 +1,32 @@ +package values + +import "strings" + +// MapStrSliceString maps a string key to a list of MapStrSliceString. +type MapStrSliceString map[string][]string + +// Get return the keys name based on extension. +func (v MapStrSliceString) Get(ext string) string { + if v == nil { + return "" + } + for k, extensions := range v { + for _, e := range extensions { + if strings.ToLower(strings.TrimSpace(e)) == strings.ToLower(strings.TrimSpace(ext)) { + return k + } + } + } + return "" +} + +// Add adds the value to key. It appends to any existing +// MapStrSliceString associated with key. +func (v MapStrSliceString) Add(key, value string) { + for _, e := range v[key] { + if strings.ToLower(strings.TrimSpace(e)) == strings.ToLower(strings.TrimSpace(value)) { + return + } + } + v[key] = append(v[key], value) +}