summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/rescribe/TODO8
-rw-r--r--cmd/rescribe/embed_darwin.go4
-rw-r--r--cmd/rescribe/embed_darwin_amd64.go2
-rw-r--r--cmd/rescribe/embed_darwin_arm64.go2
-rw-r--r--cmd/rescribe/embed_linux.go2
-rw-r--r--cmd/rescribe/embed_other.go7
-rw-r--r--cmd/rescribe/embed_tessdata.go12
-rw-r--r--cmd/rescribe/embed_windows.go2
-rw-r--r--cmd/rescribe/gbook.go16
-rw-r--r--cmd/rescribe/gbook_test.go19
-rw-r--r--cmd/rescribe/getembeds.go8
-rw-r--r--cmd/rescribe/gui.go442
-rw-r--r--cmd/rescribe/gui_test.go77
-rw-r--r--cmd/rescribe/icon.256.pngbin0 -> 5945 bytes
-rw-r--r--cmd/rescribe/icon.pngbin0 -> 13997 bytes
-rw-r--r--cmd/rescribe/icon.svg60
-rw-r--r--cmd/rescribe/main.go276
-rw-r--r--cmd/rescribe/makefile32
-rw-r--r--cmd/rescribe/testdata/fuzz/FuzzGetBookIdFromUrl/174f82f558636f2a2
-rw-r--r--cmd/rescribe/testdata/fuzz/FuzzGetBookIdFromUrl/60892155cf2f79632
-rw-r--r--cmd/rescribe/xyz.rescribe.rescribe.appdata.xml43
-rw-r--r--cmd/rescribe/xyz.rescribe.rescribe.desktop9
-rw-r--r--cmd/rescribe/xyz.rescribe.rescribe.yml65
-rw-r--r--go.mod47
-rw-r--r--go.sum674
-rw-r--r--internal/pipeline/put.go3
26 files changed, 1485 insertions, 329 deletions
diff --git a/cmd/rescribe/TODO b/cmd/rescribe/TODO
index 0b17c4b..2a31b9a 100644
--- a/cmd/rescribe/TODO
+++ b/cmd/rescribe/TODO
@@ -2,8 +2,12 @@ Add option to choose multiple languages (easy on tesseract level, slightly trick
Write to PDF as we go along, so memory requirements are reduced. Would require further modifying fpdf: https://github.com/jung-kurt/gofpdf/issues/110
-We had reported (with video) a bug with permissions requests repeatedly being displayed on a new Mac, may be related to this: https://github.com/fyne-io/fyne/issues/2799
-
Maybe pay apple $100 for a certificate to avoid their security warnings (can be easily included in 'fyne package')
Add more tests.
+
+Improve progress bar by finding how many files will be ocred and counting the number done to provide an accurate count
+
+Maybe parse CropBox from PDF as we do rotate, to crop images appropriately
+
+Add to "microsoft store"
diff --git a/cmd/rescribe/embed_darwin.go b/cmd/rescribe/embed_darwin.go
index da781c3..4f43b87 100644
--- a/cmd/rescribe/embed_darwin.go
+++ b/cmd/rescribe/embed_darwin.go
@@ -2,9 +2,11 @@
// Use of this source code is governed by the GPLv3
// license that can be found in the LICENSE file.
+//go:build embed
+
package main
import _ "embed"
-//go:embed getgbook-darwin-cac42fb.zip
+//go:embed getgbook-darwin-b14f62f.zip
var gbookzip []byte
diff --git a/cmd/rescribe/embed_darwin_amd64.go b/cmd/rescribe/embed_darwin_amd64.go
index 719c9cc..1f7f8c2 100644
--- a/cmd/rescribe/embed_darwin_amd64.go
+++ b/cmd/rescribe/embed_darwin_amd64.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by the GPLv3
// license that can be found in the LICENSE file.
+//go:build embed
+
package main
import _ "embed"
diff --git a/cmd/rescribe/embed_darwin_arm64.go b/cmd/rescribe/embed_darwin_arm64.go
index a1ca9b8..4c154be 100644
--- a/cmd/rescribe/embed_darwin_arm64.go
+++ b/cmd/rescribe/embed_darwin_arm64.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by the GPLv3
// license that can be found in the LICENSE file.
+//go:build embed
+
package main
import _ "embed"
diff --git a/cmd/rescribe/embed_linux.go b/cmd/rescribe/embed_linux.go
index eb09dce..3cfd18b 100644
--- a/cmd/rescribe/embed_linux.go
+++ b/cmd/rescribe/embed_linux.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by the GPLv3
// license that can be found in the LICENSE file.
+//go:build embed
+
package main
import _ "embed"
diff --git a/cmd/rescribe/embed_other.go b/cmd/rescribe/embed_other.go
index 86848d2..ac9ce3a 100644
--- a/cmd/rescribe/embed_other.go
+++ b/cmd/rescribe/embed_other.go
@@ -2,13 +2,12 @@
// Use of this source code is governed by the GPLv3
// license that can be found in the LICENSE file.
-// +build !darwin
-// +build !linux
-// +build !windows
+//go:build (!darwin && !linux && !windows) || !embed
package main
// if not one of the above platforms, we won't embed anything, so
-// just create an empty byte slice
+// just create empty byte slices
var tesszip []byte
var gbookzip []byte
+var tessdatazip []byte
diff --git a/cmd/rescribe/embed_tessdata.go b/cmd/rescribe/embed_tessdata.go
new file mode 100644
index 0000000..ea9ce8f
--- /dev/null
+++ b/cmd/rescribe/embed_tessdata.go
@@ -0,0 +1,12 @@
+// Copyright 2022 Nick White.
+// Use of this source code is governed by the GPLv3
+// license that can be found in the LICENSE file.
+
+//go:build embed
+
+package main
+
+import _ "embed"
+
+//go:embed tessdata.20220322.zip
+var tessdatazip []byte
diff --git a/cmd/rescribe/embed_windows.go b/cmd/rescribe/embed_windows.go
index 3e49161..f3fe193 100644
--- a/cmd/rescribe/embed_windows.go
+++ b/cmd/rescribe/embed_windows.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by the GPLv3
// license that can be found in the LICENSE file.
+//go:build embed
+
package main
import _ "embed"
diff --git a/cmd/rescribe/gbook.go b/cmd/rescribe/gbook.go
index fe2f4b8..a011181 100644
--- a/cmd/rescribe/gbook.go
+++ b/cmd/rescribe/gbook.go
@@ -41,7 +41,9 @@ func formatAuthors(authors []string) string {
s = strings.ToUpper(s)
if len(s) > maxPartLength {
- s = s[:maxPartLength]
+ // truncate to maxPartLength
+ m := fmt.Sprintf("%%.%ds", maxPartLength)
+ s = fmt.Sprintf(m, s)
}
s = strings.Map(stripNonLetters, s)
@@ -63,7 +65,9 @@ func stripNonLetters(r rune) rune {
func formatTitle(title string) string {
s := strings.Map(stripNonLetters, title)
if len(s) > maxPartLength {
- s = s[:maxPartLength]
+ // truncate to maxPartLength
+ m := fmt.Sprintf("%%.%ds", maxPartLength)
+ s = fmt.Sprintf(m, s)
}
return s
}
@@ -77,8 +81,8 @@ func getMetadata(id string) (string, string, string, error) {
// designed to be unmarshalled by encoding/json's Unmarshal()
type bookInfo struct {
VolumeInfo struct {
- Title string
- Authors []string
+ Title string
+ Authors []string
PublishedDate string
}
}
@@ -232,7 +236,7 @@ func getBookIdFromUrl(url string) (string, error) {
if start >= 0 {
start += 4
- if len(url[start:]) < 12 {
+ if len(url) - start < 12 {
return "", fmt.Errorf("Could not find book ID in URL")
}
return url[start : start+12], nil
@@ -245,7 +249,7 @@ func getBookIdFromUrl(url string) (string, error) {
if start >= 0 {
start += 10
- if len(url[start:]) < 12 {
+ if len(url) - start < 12 {
return "", fmt.Errorf("Could not find book ID in URL")
}
return url[start : start+12], nil
diff --git a/cmd/rescribe/gbook_test.go b/cmd/rescribe/gbook_test.go
index 6cd5a63..f7df595 100644
--- a/cmd/rescribe/gbook_test.go
+++ b/cmd/rescribe/gbook_test.go
@@ -8,10 +8,10 @@ import (
"testing"
)
-func Test_getBookIdFromUrl(t *testing.T) {
+func TestGetBookIdFromUrl(t *testing.T) {
cases := []struct {
url string
- id string
+ id string
}{
{"https://books.google.it/books?id=QjQepCuN8JYC", "QjQepCuN8JYC"},
{"https://www.google.it/books/edition/_/VJbr-Oe2au0C", "VJbr-Oe2au0C"},
@@ -29,3 +29,18 @@ func Test_getBookIdFromUrl(t *testing.T) {
})
}
}
+
+func FuzzGetBookIdFromUrl(f *testing.F) {
+ cases := []string {
+ "https://books.google.it/books?id=QjQepCuN8JYC",
+ "https://www.google.it/books/edition/_/VJbr-Oe2au0C",
+ }
+
+ for _, c := range cases {
+ f.Add(c)
+ }
+
+ f.Fuzz(func(t *testing.T, url string) {
+ getBookIdFromUrl(url)
+ })
+}
diff --git a/cmd/rescribe/getembeds.go b/cmd/rescribe/getembeds.go
index eb44d37..57c7ce0 100644
--- a/cmd/rescribe/getembeds.go
+++ b/cmd/rescribe/getembeds.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by the GPLv3
// license that can be found in the LICENSE file.
-// +build ignore
+//go:build ignore
// this downloads the needed files to embed into the binary,
// and is run by `go generate`
@@ -81,16 +81,16 @@ func present(url string, sum string) bool {
}
func main() {
- urls := []struct{
+ urls := []struct {
url string
sum string
}{
- {"https://rescribe.xyz/rescribe/embeds/tessdata.20220321.zip", "c6dddf99ad719b29fd6bde1a416a51674bd1834d2df8e519313d584e759a8e0e"},
+ {"https://rescribe.xyz/rescribe/embeds/tessdata.20220322.zip", "725fd570a3c3dc0eba9463248ce47a8646db8bafb198d428d6bb8f0be18540ee"},
{"https://rescribe.xyz/rescribe/embeds/tesseract-linux-v5.0.0-alpha.20210510.zip", "81cfba632b8aaf0a00180b1aa62d357d50f343b0e9bd51b941ee14c289ccd889"},
{"https://rescribe.xyz/rescribe/embeds/tesseract-osx-v4.1.1.20191227.zip", "5f567b95f1dea9d0581ad42ada4d1f1160a38ea22ae338f9efe190015265636b"},
{"https://rescribe.xyz/rescribe/embeds/tesseract-osx-m1-v4.1.1.20210802.zip", "c9a454633f7e5175e2d50dd939d30a6e5bdfb3b8c78590a08b5aa21edbf32ca4"},
{"https://rescribe.xyz/rescribe/embeds/tesseract-w32-v5.0.0-alpha.20210506.zip", "96734f3db4bb7c3b9a241ab6d89ab3e8436cea43b1cbbcfb13999497982f63e3"},
- {"https://rescribe.xyz/rescribe/embeds/getgbook-darwin-cac42fb.zip", "b41fd429be53cdce13ecc7991fe6f8913428657ad70a7790cfcc776e56060887"},
+ {"https://rescribe.xyz/rescribe/embeds/getgbook-darwin-b14f62f.zip", "d21bc4d51c5f43af68d77ef257061a0635cce0610b769d23a340b3be528a92d8"},
{"https://rescribe.xyz/rescribe/embeds/getgbook-linux-cac42fb.zip", "c3b40a1c13da613d383f990bda5dd72425a7f26b89102d272a3388eb3d05ddb6"},
{"https://rescribe.xyz/rescribe/embeds/getgbook-w32-c2824685.zip", "1c258a77a47d6515718fbbd7e54d5c2b516291682a878d122add55901c9f2914"},
}
diff --git a/cmd/rescribe/gui.go b/cmd/rescribe/gui.go
index f4a622d..73f1db2 100644
--- a/cmd/rescribe/gui.go
+++ b/cmd/rescribe/gui.go
@@ -35,9 +35,9 @@ var progressPoints = map[float64]string{
}
var trainingNames = map[string]string{
- "eng": "English (modern print)",
- "lat": "Latin (modern print)",
- "rescribev9_fast": "Latin/English/French (printed ca 1500-1800)",
+ "eng": "English (modern print)",
+ "lat": "Latin (modern print)",
+ "rescribev9_fast": "Latin/English/French (printed ca 1500-1800)",
}
// copyStdoutToChan creates a pipe to copy anything written
@@ -78,7 +78,7 @@ func copyStdoutToChan() (chan rune, error) {
// copyStderrToChan creates a pipe to copy anything written
// to the file also to a rune channel.
// TODO: would be nice to merge this with copyStdoutToChan,
-// but a naive version using *os.File didn't work.
+// but a naive version using *os.File didn't work.
func copyStderrToChan() (chan rune, error) {
c := make(chan rune)
@@ -134,14 +134,18 @@ func trainingSelectOnChange(sel *widget.Select, parent fyne.Window) func(string)
newpath := filepath.Join(os.Getenv("TESSDATA_PREFIX"), name)
f, err := os.Create(newpath)
if err != nil {
- // TODO: surface error somewhere, prob with a dialog box
+ msg := fmt.Sprintf("Error creating temporary file to store custom training: %v\n", err)
+ dialog.ShowError(errors.New(msg), parent)
+ fmt.Fprintf(os.Stderr, msg)
sel.SetSelectedIndex(0)
return
}
defer f.Close()
_, err = io.Copy(f, uri)
if err != nil {
- // TODO: surface error somewhere, prob with a dialog box
+ msg := fmt.Sprintf("Error copying custom training to temporary file: %v\n", err)
+ dialog.ShowError(errors.New(msg), parent)
+ fmt.Fprintf(os.Stderr, msg)
sel.SetSelectedIndex(0)
return
}
@@ -198,9 +202,9 @@ func mkTrainingSelect(extras []string, parent fyne.Window) *widget.Select {
return s
}
-// formatProgressBarText uses the progressPoints map to set the text for the progress bar
+// formatProgressBar uses the progressPoints map to set the text for the progress bar
// appropriately
-func formatProgressBarText(bar *widget.ProgressBar) func() string {
+func formatProgressBar(bar *widget.ProgressBar) func() string {
return func() string {
for i, v := range progressPoints {
if bar.Value == i {
@@ -218,15 +222,227 @@ func formatProgressBarText(bar *widget.ProgressBar) func() string {
}
}
+// updateProgress parses the last line of a log and updates a progress
+// bar appropriately.
+func updateProgress(log string, progressBar *widget.ProgressBar) {
+ lines := strings.Split(log, "\n")
+ lastline := lines[len(lines)-1]
+ for i, v := range progressPoints {
+ if strings.HasPrefix(lastline, " "+v) {
+ // OCRing has a number of dots after it showing how many pages have been processed,
+ // which we can use to update progress bar more often
+ // TODO: calculate number of pages we expect, so this can be set accurately
+ if v == "OCRing" {
+ if progressBar.Value < 0.5 {
+ progressBar.SetValue(0.5)
+ }
+ numdots := strings.Count(lastline, ".")
+ newval := float64(0.5) + (float64(numdots) * float64(0.01))
+ if newval >= 0.9 {
+ newval = 0.89
+ }
+ progressBar.SetValue(newval)
+ break
+ }
+ progressBar.SetValue(i)
+ }
+ }
+}
+
+// start sets up the gui to start the core process, and if all is well
+// it starts it
+func start(ctx context.Context, log *log.Logger, cmd string, tessdir string, gbookcmd string, dir string, training string, win fyne.Window, logarea *widget.Entry, progressBar *widget.ProgressBar, abortbtn *widget.Button, wipe bool, bigpdf bool, disableWidgets []fyne.Disableable) {
+ if dir == "" {
+ return
+ }
+
+ stdout, err := copyStdoutToChan()
+ if err != nil {
+ msg := fmt.Sprintf("Internal error\n\nError copying stdout to chan: %v\n", err)
+ dialog.ShowError(errors.New(msg), win)
+ fmt.Fprintf(os.Stderr, msg)
+ return
+ }
+ go func() {
+ for r := range stdout {
+ logarea.SetText(logarea.Text + string(r))
+ logarea.CursorRow = strings.Count(logarea.Text, "\n")
+ updateProgress(logarea.Text, progressBar)
+ }
+ }()
+
+ stderr, err := copyStderrToChan()
+ if err != nil {
+ msg := fmt.Sprintf("Internal error\n\nError copying stdout to chan: %v\n", err)
+ dialog.ShowError(errors.New(msg), win)
+ fmt.Fprintf(os.Stderr, msg)
+ return
+ }
+ go func() {
+ for r := range stderr {
+ logarea.SetText(logarea.Text + string(r))
+ logarea.CursorRow = strings.Count(logarea.Text, "\n")
+ }
+ }()
+
+ // Do this in a goroutine so the GUI remains responsive
+ go func() {
+ letsGo(ctx, log, cmd, tessdir, gbookcmd, dir, training, win, logarea, progressBar, abortbtn, wipe, bigpdf, disableWidgets)
+ }()
+}
+
+// letsGo starts the core process
+func letsGo(ctx context.Context, log *log.Logger, cmd string, tessdir string, gbookcmd string, dir string, training string, win fyne.Window, logarea *widget.Entry, progressBar *widget.ProgressBar, abortbtn *widget.Button, wipe bool, bigpdf bool, disableWidgets []fyne.Disableable) {
+ bookdir := dir
+ savedir := dir
+ bookname := strings.ReplaceAll(filepath.Base(dir), " ", "_")
+
+ f, err := os.Stat(bookdir)
+ if err != nil && !strings.HasPrefix(bookdir, "Google Book: ") {
+ msg := fmt.Sprintf("Error opening %s: %v", bookdir, err)
+ dialog.ShowError(errors.New(msg), win)
+ fmt.Fprintf(os.Stderr, msg)
+
+ progressBar.SetValue(0.0)
+ for _, v := range disableWidgets {
+ v.Enable()
+ }
+ abortbtn.Disable()
+ return
+ }
+
+ for _, v := range disableWidgets {
+ v.Disable()
+ }
+
+ abortbtn.Enable()
+
+ progressBar.SetValue(0.1)
+
+ if strings.HasPrefix(dir, "Google Book: ") {
+ if gbookcmd == "" {
+ msg := fmt.Sprintf("No getgbook found, can't download Google Book. Either set -gbookcmd on the command line, or use the official build which includes an embedded copy of getgbook.\n")
+ dialog.ShowError(errors.New(msg), win)
+ fmt.Fprintf(os.Stderr, msg)
+ progressBar.SetValue(0.0)
+ for _, v := range disableWidgets {
+ v.Enable()
+ }
+ abortbtn.Disable()
+ return
+ }
+ progressBar.SetValue(0.11)
+ start := len("Google Book: ")
+ bookname = dir[start : start+12]
+
+ start = start + 12 + len(" Save to: ")
+ bookdir = dir[start:]
+ savedir = bookdir
+
+ fmt.Printf("Downloading Google Book\n")
+ d, err := getGoogleBook(ctx, gbookcmd, bookname, bookdir)
+ if err != nil {
+ if !strings.HasSuffix(err.Error(), "signal: killed") {
+ msg := fmt.Sprintf("Error downloading Google Book %s\n", bookname)
+ dialog.ShowError(errors.New(msg), win)
+ fmt.Fprintf(os.Stderr, msg)
+ }
+ progressBar.SetValue(0.0)
+ for _, v := range disableWidgets {
+ v.Enable()
+ }
+ abortbtn.Disable()
+ return
+ }
+ bookdir = d
+ savedir = d
+ bookname = filepath.Base(d)
+ }
+
+ if strings.HasSuffix(dir, ".pdf") && !f.IsDir() {
+ progressBar.SetValue(0.12)
+ bookdir, err = extractPdfImgs(ctx, bookdir)
+ if err != nil {
+ if !strings.HasSuffix(err.Error(), "context canceled") {
+ msg := fmt.Sprintf("Error opening PDF %s: %v\n", bookdir, err)
+ dialog.ShowError(errors.New(msg), win)
+ fmt.Fprintf(os.Stderr, msg)
+ }
+
+ progressBar.SetValue(0.0)
+ for _, v := range disableWidgets {
+ v.Enable()
+ }
+ abortbtn.Disable()
+ return
+ }
+
+ // happens if extractPdfImgs recovers from a PDF panic,
+ // which will occur if we encounter an image we can't decode
+ if bookdir == "" {
+ msg := fmt.Sprintf("Error opening PDF\nThe format of this PDF is not supported, extract the images to .jpg manually into a\nfolder first, using a tool like the PDF image extractor at https://pdfcandy.com/extract-images.html.\n")
+ dialog.ShowError(errors.New(msg), win)
+ fmt.Fprintf(os.Stderr, msg)
+
+ progressBar.SetValue(0.0)
+ for _, v := range disableWidgets {
+ v.Enable()
+ }
+ abortbtn.Disable()
+ return
+ }
+
+ savedir = strings.TrimSuffix(savedir, ".pdf")
+ bookname = strings.TrimSuffix(bookname, ".pdf")
+ }
+
+ if strings.Contains(training, "[") {
+ start := strings.Index(training, "[") + 1
+ end := strings.Index(training, "]")
+ training = training[start:end]
+ }
+
+ err = startProcess(ctx, log, cmd, bookdir, bookname, training, savedir, tessdir, wipe, bigpdf)
+ if err != nil && strings.HasSuffix(err.Error(), "context canceled") {
+ progressBar.SetValue(0.0)
+ return
+ }
+ if err != nil {
+ msg := fmt.Sprintf("Error during processing: %v\n", err)
+ if strings.HasSuffix(err.Error(), "No images found") && strings.HasSuffix(dir, ".pdf") && !f.IsDir() {
+ msg = fmt.Sprintf("Error opening PDF\nNo images found in the PDF. Most likely the format of this PDF is not supported,\nextract the images to .jpg manually into a folder first, using a tool like\nthe PDF image extractor at https://pdfcandy.com/extract-images.html.\n")
+ }
+ dialog.ShowError(errors.New(msg), win)
+ fmt.Fprintf(os.Stderr, msg)
+
+ progressBar.SetValue(0.0)
+ for _, v := range disableWidgets {
+ v.Enable()
+ }
+ abortbtn.Disable()
+ return
+ }
+
+ progressBar.SetValue(1.0)
+
+ for _, v := range disableWidgets {
+ v.Enable()
+ }
+ abortbtn.Disable()
+
+ msg := fmt.Sprintf("OCR process finished successfully.\n\nYour completed files have been saved in:\n%s", savedir)
+ dialog.ShowInformation("OCR Complete", msg, win)
+}
+
// startGui starts the gui process
-func startGui(log log.Logger, cmd string, gbookcmd string, training string, tessdir string) error {
+func startGui(log *log.Logger, cmd string, gbookcmd string, training string, tessdir string) error {
myApp := app.New()
myWindow := myApp.NewWindow("Rescribe OCR")
myWindow.Resize(fyne.NewSize(800, 400))
var abortbtn, gobtn *widget.Button
- var fullContent *fyne.Container
+ var chosen *fyne.Container
dir := widget.NewLabel("")
@@ -239,7 +455,7 @@ func startGui(log log.Logger, cmd string, gbookcmd string, training string, tess
}
dir.SetText(uri.Path())
dirIcon.SetResource(theme.FolderIcon())
- myWindow.SetContent(fullContent)
+ chosen.Show()
gobtn.Enable()
}, myWindow)
d.Resize(fyne.NewSize(740, 600))
@@ -254,7 +470,7 @@ func startGui(log log.Logger, cmd string, gbookcmd string, training string, tess
uri.Close()
dir.SetText(uri.URI().Path())
dirIcon.SetResource(theme.DocumentIcon())
- myWindow.SetContent(fullContent)
+ chosen.Show()
gobtn.Enable()
}, myWindow)
d.SetFilter(storage.NewExtensionFileFilter([]string{".pdf"}))
@@ -305,7 +521,7 @@ func startGui(log log.Logger, cmd string, gbookcmd string, training string, tess
}
dir.SetText(fmt.Sprintf("Google Book: %s Save to: %s", id, dirEntry.Text))
dirIcon.SetResource(theme.SearchIcon())
- myWindow.SetContent(fullContent)
+ chosen.Show()
gobtn.Enable()
}, myWindow)
d.Resize(fyne.NewSize(600, 200))
@@ -322,10 +538,9 @@ func startGui(log log.Logger, cmd string, gbookcmd string, training string, tess
trainingOpts := mkTrainingSelect([]string{training}, myWindow)
progressBar := widget.NewProgressBar()
- progressBar.TextFormatter = formatProgressBarText(progressBar)
+ progressBar.TextFormatter = formatProgressBar(progressBar)
logarea := widget.NewMultiLineEntry()
- logarea.Disable()
detail := widget.NewAccordion(widget.NewAccordionItem("Log", logarea))
@@ -350,205 +565,20 @@ func startGui(log log.Logger, cmd string, gbookcmd string, training string, tess
abortbtn.Disable()
gobtn.OnTapped = func() {
- if dir.Text == "" {
- return
- }
-
- stdout, err := copyStdoutToChan()
- if err != nil {
- msg := fmt.Sprintf("Internal error\n\nError copying stdout to chan: %v\n", err)
- dialog.ShowError(errors.New(msg), myWindow)
- fmt.Fprintf(os.Stderr, msg)
- return
- }
-
- // update log area with stdout in a concurrent goroutine, and parse it to update the progress bar
- go func() {
- for r := range stdout {
- logarea.SetText(logarea.Text + string(r))
- logarea.CursorRow = strings.Count(logarea.Text, "\n")
-
- lines := strings.Split(logarea.Text, "\n")
- lastline := lines[len(lines)-1]
- for i, v := range progressPoints {
- if strings.HasPrefix(lastline, " "+v) {
- // OCRing has a number of dots after it showing how many pages have been processed,
- // which we can use to update progress bar more often
- // TODO: calculate number of pages we expect, so this can be set accurately
- if v == "OCRing" {
- if progressBar.Value < 0.5 {
- progressBar.SetValue(0.5)
- }
- numdots := strings.Count(lastline, ".")
- newval := float64(0.5) + (float64(numdots) * float64(0.01))
- if newval >= 0.9 {
- newval = 0.89
- }
- progressBar.SetValue(newval)
- break
- }
- progressBar.SetValue(i)
- }
- }
- }
- }()
-
- stderr, err := copyStderrToChan()
- if err != nil {
- msg := fmt.Sprintf("Internal error\n\nError copying stdout to chan: %v\n", err)
- dialog.ShowError(errors.New(msg), myWindow)
- fmt.Fprintf(os.Stderr, msg)
- return
- }
-
- // update log area with stderr in a concurrent goroutine
- go func() {
- for r := range stderr {
- logarea.SetText(logarea.Text + string(r))
- logarea.CursorRow = strings.Count(logarea.Text, "\n")
- }
- }()
-
- bookdir := dir.Text
- savedir := dir.Text
- bookname := strings.ReplaceAll(filepath.Base(dir.Text), " ", "_")
-
- f, err := os.Stat(bookdir)
- if err != nil && !strings.HasPrefix(bookdir, "Google Book: ") {
- msg := fmt.Sprintf("Error opening %s: %v", bookdir, err)
- dialog.ShowError(errors.New(msg), myWindow)
- fmt.Fprintf(os.Stderr, msg)
-
- progressBar.SetValue(0.0)
- for _, v := range disableWidgets {
- v.Enable()
- }
- abortbtn.Disable()
- return
- }
-
- // Do this in a goroutine so the GUI remains responsive
- go func() {
- for _, v := range disableWidgets {
- v.Disable()
- }
-
- abortbtn.Enable()
-
- progressBar.SetValue(0.1)
-
- if strings.HasPrefix(dir.Text, "Google Book: ") {
- progressBar.SetValue(0.11)
- start := len("Google Book: ")
- bookname = dir.Text[start : start+12]
-
- start = start + 12 + len(" Save to: ")
- bookdir = dir.Text[start:]
- savedir = bookdir
-
- fmt.Printf("Downloading Google Book\n")
- d, err := getGoogleBook(ctx, gbookcmd, bookname, bookdir)
- if err != nil {
- if !strings.HasSuffix(err.Error(), "signal: killed") {
- msg := fmt.Sprintf("Error downloading Google Book %s\n", bookname)
- dialog.ShowError(errors.New(msg), myWindow)
- fmt.Fprintf(os.Stderr, msg)
- }
- progressBar.SetValue(0.0)
- for _, v := range disableWidgets {
- v.Enable()
- }
- abortbtn.Disable()
- return
- }
- bookdir = d
- savedir = d
- bookname = filepath.Base(d)
- }
-
- if strings.HasSuffix(dir.Text, ".pdf") && !f.IsDir() {
- progressBar.SetValue(0.12)
- bookdir, err = extractPdfImgs(ctx, bookdir)
- if err != nil {
- if !strings.HasSuffix(err.Error(), "context canceled") {
- msg := fmt.Sprintf("Error opening PDF %s: %v\n", bookdir, err)
- dialog.ShowError(errors.New(msg), myWindow)
- fmt.Fprintf(os.Stderr, msg)
- }
-
- progressBar.SetValue(0.0)
- for _, v := range disableWidgets {
- v.Enable()
- }
- abortbtn.Disable()
- return
- }
-
- // happens if extractPdfImgs recovers from a PDF panic,
- // which will occur if we encounter an image we can't decode
- if bookdir == "" {
- msg := fmt.Sprintf("Error opening PDF\nThe format of this PDF is not supported, extract the images to .jpg manually into a folder first.\n")
- dialog.ShowError(errors.New(msg), myWindow)
- fmt.Fprintf(os.Stderr, msg)
-
- progressBar.SetValue(0.0)
- for _, v := range disableWidgets {
- v.Enable()
- }
- abortbtn.Disable()
- return
- }
-
- savedir = strings.TrimSuffix(savedir, ".pdf")
- bookname = strings.TrimSuffix(bookname, ".pdf")
- }
-
- training := trainingOpts.Selected
- if strings.Contains(training, "[") {
- start := strings.Index(training, "[") + 1
- end := strings.Index(training, "]")
- training = training[start:end]
- }
-
- err = startProcess(ctx, log, cmd, bookdir, bookname, training, savedir, tessdir, !wipe.Checked, bigpdf.Checked)
- if err != nil && strings.HasSuffix(err.Error(), "context canceled") {
- progressBar.SetValue(0.0)
- return
- }
- if err != nil {
- msg := fmt.Sprintf("Error during processing: %v\n", err)
- dialog.ShowError(errors.New(msg), myWindow)
- fmt.Fprintf(os.Stderr, msg)
-
- progressBar.SetValue(0.0)
- for _, v := range disableWidgets {
- v.Enable()
- }
- abortbtn.Disable()
- return
- }
-
- progressBar.SetValue(1.0)
-
- for _, v := range disableWidgets {
- v.Enable()
- }
- abortbtn.Disable()
-
- msg := fmt.Sprintf("OCR process finished successfully.\n\nYour completed files have been saved in:\n%s", savedir)
- dialog.ShowInformation("OCR Complete", msg, myWindow)
- }()
+ start(ctx, log, cmd, tessdir, gbookcmd, dir.Text, trainingOpts.Selected, myWindow, logarea, progressBar, abortbtn, !wipe.Checked, bigpdf.Checked, disableWidgets)
}
+
gobtn.Disable()
choices := container.New(layout.NewGridLayout(3), folderBtn, pdfBtn, gbookBtn)
- chosen := container.New(layout.NewBorderLayout(nil, nil, dirIcon, nil), dirIcon, dir)
+ chosen = container.New(layout.NewBorderLayout(nil, nil, dirIcon, nil), dirIcon, dir)
+ chosen.Hide()
trainingBits := container.New(layout.NewBorderLayout(nil, nil, trainingLabel, nil), trainingLabel, trainingOpts)
- fullContent = container.NewVBox(choices, chosen, trainingBits, wipe, bigpdf, gobtn, abortbtn, progressBar, detail)
- startContent := container.NewVBox(choices, trainingBits, wipe, bigpdf, gobtn, abortbtn, progressBar, detail)
+ startBox := container.NewVBox(choices, chosen, trainingBits, wipe, bigpdf, gobtn, abortbtn, progressBar)
+ startContent := container.NewBorder(startBox, nil, nil, nil, detail)
myWindow.SetContent(startContent)
diff --git a/cmd/rescribe/gui_test.go b/cmd/rescribe/gui_test.go
new file mode 100644
index 0000000..99a924f
--- /dev/null
+++ b/cmd/rescribe/gui_test.go
@@ -0,0 +1,77 @@
+// Copyright 2022 Nick White.
+// Use of this source code is governed by the GPLv3
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "strings"
+ "testing"
+
+ "fyne.io/fyne/v2/app"
+ "fyne.io/fyne/v2/widget"
+)
+
+func TestFormatProgressBar(t *testing.T) {
+ cases := []struct {
+ val float64
+ str string
+ }{
+ {0.0, ""},
+ {0.01, "Processing"},
+ {0.11, "Downloading"},
+ {0.12, "Processing PDF"},
+ {0.2, "Preprocessing"},
+ {0.5, "OCRing"},
+ {0.55, "OCRing"},
+ {0.89, "OCRing"},
+ {0.9, "Analysing"},
+ {1.0, "Done"},
+ {1.1, "Processing"},
+ }
+
+ _ = app.New() // shouldn't be needed for test but we get a panic without it
+ bar := widget.NewProgressBar()
+
+ for _, c := range cases {
+ t.Run(fmt.Sprintf("%s_%.1f", c.str, c.val), func(t *testing.T) {
+ bar.Value = c.val
+ got := formatProgressBar(bar)()
+ if got != c.str {
+ t.Fatalf("Expected %s, got %s", c.str, got)
+ }
+ })
+ }
+}
+
+func TestUpdateProgress(t *testing.T) {
+ cases := []struct {
+ log string
+ val float64
+ }{
+ {"Downloading", 0.11},
+ {"Preprocessing", 0.2},
+ {"Preprocessing\nOCRing", 0.5},
+ {"Preprocessing\nOCRing...", 0.53},
+ {"OCRing........................................", 0.89},
+ {"OCRing..\nAnalysing", 0.9},
+ {"Done", 1.0},
+ {"Weirdness", 0.0},
+ }
+
+ _ = app.New() // shouldn't be needed for test but we get a panic without it
+ bar := widget.NewProgressBar()
+
+ for _, c := range cases {
+ t.Run(c.log, func(t *testing.T) {
+ l := strings.ReplaceAll(" "+c.log, "\n", "\n ")
+ bar.Value = 0.0
+ updateProgress(l, bar)
+ got := bar.Value
+ if got != c.val {
+ t.Fatalf("Expected %f, got %f", c.val, got)
+ }
+ })
+ }
+}
diff --git a/cmd/rescribe/icon.256.png b/cmd/rescribe/icon.256.png
new file mode 100644
index 0000000..79e922e
--- /dev/null
+++ b/cmd/rescribe/icon.256.png
Binary files differ
diff --git a/cmd/rescribe/icon.png b/cmd/rescribe/icon.png
new file mode 100644
index 0000000..dcfb0f5
--- /dev/null
+++ b/cmd/rescribe/icon.png
Binary files differ
diff --git a/cmd/rescribe/icon.svg b/cmd/rescribe/icon.svg
new file mode 100644
index 0000000..d60a36c
--- /dev/null
+++ b/cmd/rescribe/icon.svg
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ id="svg2"
+ width="204.8"
+ height="204.8"
+ viewBox="0 0 204.8 204.8"
+ sodipodi:docname="icon-trans.svg"
+ inkscape:version="1.0.2 (e86c870879, 2021-01-15)">
+ <metadata
+ id="metadata8">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs6" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1051"
+ inkscape:window-height="1058"
+ id="namedview4"
+ showgrid="false"
+ inkscape:zoom="1.52608"
+ inkscape:cx="103.24875"
+ inkscape:cy="65.817935"
+ inkscape:window-x="0"
+ inkscape:window-y="17"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="g10" />
+ <g
+ inkscape:groupmode="layer"
+ inkscape:label="Image"
+ id="g10">
+ <path
+ style="fill:#000000;stroke-width:0.16"
+ d="m 165.46012,194.36098 c 0.506,-0.0317 1.334,-0.0317 1.84,0 0.506,0.0318 0.092,0.0577 -0.92,0.0577 -1.012,0 -1.426,-0.026 -0.92,-0.0577 z m 11.92286,0.002 c 0.28759,-0.0356 0.71959,-0.0349 0.96,0.002 0.24044,0.0365 0.005,0.0656 -0.52286,0.0647 -0.528,-0.002 -0.7247,-0.0308 -0.43714,-0.0664 z m -13.08286,-0.76181 c -0.132,-0.0342 -0.66331,-0.10904 -1.1807,-0.16621 -0.71693,-0.0792 -1.02946,-0.19971 -1.3138,-0.50651 -0.24372,-0.26297 -0.76884,-0.50646 -1.51445,-0.70221 -0.62775,-0.16481 -1.37025,-0.44112 -1.65001,-0.61401 -0.79923,-0.49395 -2.30109,-0.65095 -6.18104,-0.6461 -3.91542,0.005 -6.65774,0.18683 -6.93072,0.45981 -0.21841,0.21842 -1.89226,0.22682 -2.38175,0.012 -0.20214,-0.0887 -1.19507,-0.30016 -2.2065,-0.46986 -1.53368,-0.25731 -1.89227,-0.37251 -2.16,-0.69388 -0.17657,-0.21196 -0.4528,-0.43248 -0.61386,-0.49005 -0.16106,-0.0576 -0.39937,-0.37589 -0.52957,-0.70735 -0.13428,-0.34184 -0.44096,-0.71987 -0.70861,-0.87348 -0.25954,-0.14896 -0.54282,-0.45741 -0.62952,-0.68544 -0.0883,-0.23229 -0.35766,-0.48434 -0.6125,-0.57319 -0.27445,-0.0957 -0.54453,-0.36221 -0.68092,-0.672 -0.12433,-0.28238 -0.41896,-0.60491 -0.65473,-0.71673 -0.26127,-0.12391 -0.50117,-0.42293 -0.61428,-0.76567 -0.10208,-0.30929 -0.35917,-0.67609 -0.57132,-0.81509 -0.21215,-0.139 -0.38572,-0.34692 -0.38572,-0.46206 0,-0.11512 -0.18,-0.42323 -0.4,-0.68469 -0.22,-0.26145 -0.4,-0.55499 -0.4,-0.65229 0,-0.0973 -0.11737,-0.17689 -0.26082,-0.17689 -0.2926,0 -1.75977,-1.42295 -2.22713,-2.16 -0.1674,-0.264 -0.40148,-0.54059 -0.52017,-0.61464 -0.1187,-0.0741 -0.3533,-0.45541 -0.52135,-0.84746 -0.22145,-0.51661 -0.43836,-0.7591 -0.78804,-0.88101 -0.26537,-0.0925 -0.48249,-0.2738 -0.48249,-0.40288 0,-0.57 -0.70555,-1.83969 -1.15,-2.06953 -0.25513,-0.13192 -0.53745,-0.40136 -0.62738,-0.59874 -0.0899,-0.19737 -0.31543,-0.4279 -0.5011,-0.5123 -0.18568,-0.0844 -0.47244,-0.4165 -0.63725,-0.73802 -0.16691,-0.32565 -0.45911,-0.62461 -0.65965,-0.67494 -0.19889,-0.0499 -0.52144,-0.3776 -0.72073,-0.73218 -0.1984,-0.35301 -0.47056,-0.70329 -0.60481,-0.77843 -0.13426,-0.0751 -0.39037,-0.70658 -0.56916,-1.40323 -0.17878,-0.69666 -0.415,-1.37464 -0.52494,-1.50664 -0.26978,-0.32394 -0.50169,-1.36013 -0.73408,-3.28 -0.19763,-1.63275 -0.57683,-2.68362 -1.03131,-2.85802 -0.13972,-0.0536 -0.36701,-0.36785 -0.50508,-0.69832 -0.13808,-0.33045 -0.42283,-0.76003 -0.63278,-0.95461 -0.20995,-0.19457 -0.38428,-0.51921 -0.3874,-0.72141 -0.003,-0.20225 -0.10857,-0.54769 -0.23433,-0.76769 -0.12576,-0.22 -0.23121,-0.55947 -0.23433,-0.75437 -0.003,-0.19491 -0.14967,-0.43144 -0.32567,-0.52563 -0.176,-0.0942 -0.32244,-0.29472 -0.32543,-0.44563 -0.003,-0.1509 -0.14454,-0.56237 -0.31457,-0.91437 -0.17003,-0.352 -0.31159,-0.72428 -0.31457,-0.82729 -0.003,-0.103 -0.21646,-0.23363 -0.47437,-0.29028 -0.52059,-0.11434 -0.74819,-0.32983 -0.83384,-0.78948 -0.0315,-0.16888 -0.26684,-0.4232 -0.52304,-0.56516 -0.46283,-0.25646 -0.63103,-0.46923 -0.79854,-1.01019 -0.0481,-0.15532 -0.26495,-0.34989 -0.48192,-0.43238 -0.2626,-0.0998 -0.44829,-0.34491 -0.55547,-0.73306 -0.0885,-0.32069 -0.41116,-0.82603 -0.71692,-1.12298 -0.36358,-0.3531 -0.64409,-0.84318 -0.81073,-1.4164 -0.14014,-0.48207 -0.32162,-0.91779 -0.40329,-0.96826 -0.19777,-0.12223 -0.76117,-1.33123 -0.88084,-1.89018 -0.0586,-0.27356 -0.24668,-0.50317 -0.48713,-0.59459 -0.21545,-0.0819 -0.51958,-0.42047 -0.67585,-0.75234 -0.15627,-0.33187 -0.47465,-0.69472 -0.70752,-0.80633 -0.24035,-0.1152 -0.61102,-0.56175 -0.85738,-1.03289 -0.23868,-0.45648 -0.60333,-0.96319 -0.81033,-1.12601 -0.207,-0.16283 -0.42412,-0.55061 -0.48249,-0.86174 -0.0719,-0.38349 -0.23169,-0.6229 -0.496,-0.74332 -0.21695,-0.0988 -0.42633,-0.35994 -0.47208,-0.58865 -0.0452,-0.22605 -0.44066,-0.80643 -0.87879,-1.28974 -0.43813,-0.4833 -0.83797,-1.07849 -0.88853,-1.32263 -0.0506,-0.24415 -0.29307,-0.58713 -0.53892,-0.76219 -0.24584,-0.17505 -0.49402,-0.53242 -0.5515,-0.79415 -0.0575,-0.26172 -0.26346,-0.60274 -0.45772,-0.75781 -0.19426,-0.15507 -0.59686,-0.65995 -0.89466,-1.12195 -0.29781,-0.462 -0.596191,-0.84 -0.663091,-0.84 -0.26013,0 -0.6238,-0.52327 -0.788332,-1.13431 -0.111492,-0.41405 -0.305253,-0.70049 -0.54896,-0.81153 -0.26961,-0.12284 -0.4771,-0.47322 -0.730103,-1.23289 -0.194398,-0.5837 -0.478317,-1.20527 -0.630929,-1.38127 -0.152612,-0.176 -0.44348,-0.84829 -0.646375,-1.49398 -0.218997,-0.69694 -0.494358,-1.24957 -0.677645,-1.36 -0.330003,-0.19883 -0.815212,-1.04979 -0.972753,-1.70602 -0.05282,-0.22 -0.261032,-0.472 -0.462704,-0.56 -0.223637,-0.0976 -0.446171,-0.40966 -0.570459,-0.8 -0.112079,-0.352 -0.328079,-0.748 -0.48,-0.88 -0.15192,-0.132 -0.519188,-0.72245 -0.816149,-1.31211 -0.296963,-0.58965 -0.644237,-1.09365 -0.77172,-1.12 -0.231253,-0.0478 -0.833223,-1.54669 -0.843125,-2.0994 -0.0085,-0.47195 -0.794578,-1.6798 -1.340358,-2.0594 -0.277676,-0.19313 -0.744477,-0.62519 -1.037333,-0.96012 -0.292858,-0.33493 -0.621387,-0.60897 -0.730066,-0.60897 -0.108678,0 -0.400987,-0.21229 -0.649573,-0.47176 -0.248585,-0.25947 -0.604056,-0.49347 -0.789934,-0.52 -0.220666,-0.0315 -0.397059,-0.23108 -0.508245,-0.57506 -0.09366,-0.28976 -0.309656,-0.6837 -0.48,-0.87544 -0.170342,-0.19173 -0.381715,-0.47144 -0.469715,-0.62157 -0.088,-0.15013 -0.484,-0.64146 -0.88,-1.09184 -0.396,-0.45037 -0.796198,-1.0856 -0.889328,-1.4116 -0.120624,-0.42224 -0.31471,-0.66176 -0.674765,-0.83273 -0.277989,-0.132 -0.574342,-0.43311 -0.65856,-0.66914 -0.108502,-0.30407 -0.324571,-0.47647 -0.741438,-0.59157 -0.323571,-0.0893 -0.6766,-0.28318 -0.784507,-0.43076 -0.186928,-0.25564 -1.122752,-0.49761 -3.371402,-0.87174 -1.623947,-0.27019 -1.642797,-0.27926 -1.843251,-0.88664 -0.112922,-0.34216 -0.336261,-0.62632 -0.558741,-0.71091 -0.203845,-0.0775 -0.415181,-0.28129 -0.469637,-0.45287 -0.05446,-0.17157 -0.294617,-0.38165 -0.533691,-0.46684 -0.916472,-0.32656 -1.58611,-0.51957 -1.80604,-0.52054 -0.125752,-4.8e-4 -0.34691,-0.20892 -0.491462,-0.46304 -0.144552,-0.25411 -0.467672,-0.5602 -0.718044,-0.6802 -0.250371,-0.119999 -0.481849,-0.361639 -0.514395,-0.536959 -0.07988,-0.43034 -0.336853,-0.72371 -0.782264,-0.89305 -0.203872,-0.0775 -0.399901,-0.23201 -0.435621,-0.34333 -0.03572,-0.11133 -0.178537,-0.61176 -0.317371,-1.11209 -0.175254,-0.63158 -0.349691,-0.94056 -0.570582,-1.01067 -0.442239,-0.14036 -0.573287,-0.79176 -0.256539,-1.27518 0.1417,-0.21626 0.257638,-0.50374 0.257638,-0.63884 0,-0.13509 0.06558,-0.24563 0.145726,-0.24563 0.08015,0 0.302573,-0.324 0.494274,-0.72 0.232416,-0.4801 0.450296,-0.72 0.653933,-0.72 0.167961,0 0.788699,-0.252 1.379414,-0.56 0.590717,-0.308001 1.188471,-0.560001 1.328341,-0.560001 0.139872,0 0.338722,-0.0844 0.44189,-0.18757 0.1276,-0.1276 1.608691,-0.22996 4.632,-0.32011 6.455761,-0.19251 8.595198,-0.33908 8.923228,-0.61133 0.205885,-0.17087 1.017452,-0.25563 3.187796,-0.33294 1.662859,-0.0592 3.057577,-0.18184 3.251976,-0.28588 0.187212,-0.10019 0.491547,-0.18217 0.676299,-0.18217 0.213065,0 0.454461,-0.20092 0.660059,-0.54938 0.209195,-0.35456 0.490286,-0.58587 0.792654,-0.65228 0.25768,-0.0566 0.618082,-0.29305 0.80089,-0.52546 0.182808,-0.2324 0.535539,-0.50797 0.783845,-0.61238 0.248305,-0.1044 0.5734,-0.39624 0.722432,-0.64853 0.239653,-0.40571 0.755515,-0.69784 1.899278,-1.07559 0.16172,-0.0534 0.374835,-0.31117 0.473593,-0.5728 0.10965,-0.29051 0.35547,-0.53702 0.63145,-0.63322 0.2905,-0.10127 0.536001,-0.35882 0.687381,-0.72114 0.15234,-0.3646 0.37688,-0.5991 0.63591,-0.66411 0.26026,-0.0653 0.43451,-0.24831 0.49781,-0.5228 0.28205,-1.223 0.59068,-1.91545 0.93612,-2.10033 0.22303,-0.11936 0.40954,-0.40124 0.46373,-0.70082 0.0499,-0.27564 0.1374,-0.77792 0.19456,-1.11619 0.0809,-0.47895 0.19972,-0.64843 0.53682,-0.76595 0.37969,-0.13236 0.46776,-0.30255 0.71669,-1.38496 0.15609,-0.67873 0.4659,-1.50332 0.68847,-1.83242 0.39281,-0.58081 0.83586,-2.061488 0.84093,-2.810415 10e-4,-0.202828 0.1468,-0.685528 0.32316,-1.072665 0.46654,-1.024115 0.77318,-2.665963 0.96165,-5.148922 0.18858,-2.484496 0.24991,-2.821045 0.63593,-3.489635 0.15243,-0.264 0.36507,-0.948 0.47253,-1.52 0.38313,-2.03931 0.55564,-2.643752 0.83318,-2.919368 0.15472,-0.153653 0.319,-0.513653 0.36506,-0.8 0.26373,-1.639546 0.43072,-4.370296 0.33514,-5.480363 -0.0936,-1.087058 -0.19276,-1.405051 -0.65702,-2.107112 -0.30072,-0.454763 -0.63685,-1.097456 -0.74695,-1.428205 -0.12611,-0.378854 -0.37615,-0.698438 -0.67575,-0.863723 -0.39396,-0.217335 -0.52378,-0.449922 -0.7564,-1.355219 -0.15446,-0.601072 -0.38158,-1.208317 -0.50471,-1.349434 -0.26351,-0.301987 -0.90332,-1.729424 -0.90332,-2.015338 0,-0.108945 -0.13482,-0.369793 -0.29959,-0.57966 -0.16478,-0.209868 -0.42793,-0.813578 -0.58479,-1.341578 -0.15685,-0.528 -0.37327,-1.248 -0.48092,-1.6 -0.12587,-0.41156 -0.3439,-0.713754 -0.61084,-0.84663 -0.27195,-0.135373 -0.47191,-0.417623 -0.57985,-0.818461 -0.0906,-0.336507 -0.37869,-0.881045 -0.64018,-1.210083 -0.26148,-0.32904 -0.59802,-0.876117 -0.74786,-1.215728 -0.16014,-0.36297 -0.44214,-0.684943 -0.6842,-0.781165 -0.43059,-0.171173 -1.135431,-0.563855 -1.835991,-1.022879 -0.227149,-0.148836 -1.187628,-0.388396 -2.134391,-0.532355 -1.059745,-0.161137 -2.090377,-0.430049 -2.681387,-0.699627 -0.947051,-0.431978 -1.407837,-0.571677 -2.452046,-0.743398 -0.355965,-0.05854 -0.590092,-0.214888 -0.707431,-0.472421 -0.09646,-0.211709 -0.36104,-0.426034 -0.587953,-0.476279 -1.080445,-0.239236 -1.800564,-0.611 -2.025282,-1.045556 -0.129216,-0.249876 -0.470499,-0.552744 -0.758408,-0.67304 -0.287909,-0.120296 -0.641312,-0.398568 -0.785339,-0.618381 -0.144027,-0.219815 -0.472408,-0.44177 -0.729735,-0.493235 -0.319774,-0.06396 -0.529201,-0.241655 -0.661649,-0.561413 -0.106583,-0.257311 -0.363674,-0.545245 -0.571317,-0.639853 -0.207642,-0.09461 -0.498979,-0.427949 -0.647416,-0.740755 -0.155971,-0.328685 -0.38679,-0.568741 -0.546856,-0.568741 -0.362566,0 -0.806568,-0.499728 -0.806568,-0.9078 0,-0.364202 -0.392246,-0.763336 -0.902725,-0.918574 -0.188499,-0.05732 -0.375219,-0.228485 -0.414936,-0.38036 -0.07688,-0.294007 -1.038656,-0.55521 -3.025982,-0.82181 -0.585003,-0.07848 -1.210271,-0.221162 -1.389482,-0.317072 -0.179211,-0.09591 -0.924571,-0.174786 -1.656357,-0.175277 -0.731785,-4.8e-4 -1.60827,-0.07801 -1.947745,-0.172277 -0.715248,-0.198601 -2.93101,-0.0076 -5.862773,0.50537 -2.699179,0.47228 -3.00511,0.585914 -3.310595,1.229675 -0.143043,0.30144 -0.416776,0.619471 -0.608298,0.706733 -0.191521,0.08726 -0.473161,0.370168 -0.625867,0.628678 -0.152706,0.258511 -0.455418,0.586498 -0.672693,0.728863 -0.385229,0.252411 -0.884523,1.169486 -1.074648,1.973851 -0.052,0.22 -0.25471,0.472 -0.450467,0.56 -0.858486,0.385923 -1.153374,2.905253 -0.709261,6.059466 0.482659,3.427966 0.603747,6.134964 0.351611,7.860534 -0.271,1.85468 -0.773497,4.283797 -0.910201,4.4 -0.248987,0.211646 -0.653117,4.35011 -0.794581,8.136843 -0.15948,4.269018 -0.351574,6.188768 -0.689211,6.887823 -0.275059,0.569494 -0.246151,5.8951 0.03472,6.396627 0.170552,0.304539 0.223048,2.478576 0.260781,10.800004 0.03898,8.59637 0.09122,10.67057 0.298669,11.8587 0.138284,0.792 0.361278,2.232 0.49554,3.200001 0.134263,0.968 0.285978,1.904 0.337146,2.08 0.05117,0.176 0.121594,0.824 0.156502,1.44 0.03491,0.616 0.145855,1.8271 0.246546,2.69132 0.165278,1.418559 0.109611,3.115959 -0.121981,3.719479 -0.04837,0.12606 -0.186877,0.2292 -0.307785,0.2292 -0.120908,0 -0.264426,0.198 -0.318927,0.44 -0.0545,0.242 -0.157294,0.692 -0.22843,1 -0.07113,0.308 -0.174304,0.92 -0.229263,1.36 -0.124932,1.0002 -0.442713,2.16 -0.591832,2.16 -0.199993,0 -0.434979,0.99029 -0.777235,3.27545 -0.194677,1.29981 -0.432213,2.34308 -0.567526,2.4926 -0.365883,0.40429 -0.313159,3.22572 0.08728,4.67076 0.176,0.63512 0.32,1.4614 0.32,1.83619 0,0.37479 0.113642,1.70824 0.252538,2.96322 0.182758,1.65128 0.334057,2.39692 0.547556,2.69847 0.466901,0.65946 0.602631,1.45779 0.798196,4.69482 0.209596,3.46928 0.341625,4.34739 0.694172,4.61689 0.44898,0.34322 0.766951,3.34972 0.883272,8.3516 0.128058,5.50655 0.126464,5.92129 -0.04461,11.6 -0.142469,4.72915 0.01435,7.17776 0.493624,7.70734 0.137221,0.15164 0.371987,0.83751 0.521701,1.52418 0.227876,1.04515 0.338984,1.28086 0.682244,1.44733 0.291381,0.14129 0.440704,0.3728 0.516013,0.8 0.16748,0.95005 0.60905,1.71433 1.024576,1.77337 0.233408,0.0332 0.462898,0.25216 0.628773,0.6 0.143666,0.30128 0.353072,0.54778 0.465346,0.54778 0.297598,0 0.856598,0.65149 0.856598,0.99834 0,0.18916 0.203941,0.3832 0.558485,0.53134 0.373872,0.15621 0.633841,0.4137 0.786445,0.77893 0.151769,0.36323 0.352808,0.56326 0.601513,0.59848 0.256274,0.0363 0.425088,0.21233 0.537687,0.56067 0.192532,0.59565 0.674905,1.17224 0.980668,1.17224 0.11836,0 0.215202,0.0968 0.215202,0.2152 0,0.11837 0.126,0.32808 0.28,0.46603 0.226944,0.20331 0.68929,0.24803 2.44,0.236 1.188,-0.008 2.540133,0.0412 3.004741,0.10963 0.784417,0.11559 0.86879,0.17191 1.181533,0.7888 0.185235,0.3654 0.540011,0.89733 0.78839,1.18208 0.248381,0.28477 0.555413,0.86077 0.682296,1.28 0.126883,0.41925 0.388062,1.12226 0.580397,1.56226 0.381443,0.87262 0.358291,1.94536 -0.06215,2.88 -0.265611,0.59045 -0.551843,1.40848 -0.768037,2.19499 -0.09491,0.3453 -0.290049,0.63514 -0.464985,0.69066 -0.165791,0.0526 -0.347275,0.28888 -0.403299,0.52502 -0.141876,0.59799 -0.521444,0.98933 -0.959572,0.98933 -0.250099,0 -0.451632,0.15574 -0.618112,0.47768 -0.13586,0.26272 -0.426817,0.52282 -0.646571,0.57797 -0.219752,0.0551 -0.560443,0.30406 -0.757089,0.55312 -0.314512,0.39835 -0.540453,0.48136 -1.877538,0.68976 -2.691163,0.41945 -7.520941,0.62888 -10.174398,0.44117 -1.31208,-0.0928 -3.213602,-0.21245 -4.225602,-0.26584 -2.640154,-0.13932 -3.51511,-0.30495 -4.415603,-0.83589 -0.438056,-0.25829 -1.056515,-0.5184 -1.374354,-0.57802 -0.317838,-0.0596 -0.665939,-0.21451 -0.773557,-0.34419 -0.107614,-0.12966 -0.297861,-0.23576 -0.422765,-0.23576 -0.124904,0 -0.367323,-0.13064 -0.538708,-0.2903 -0.213912,-0.1993 -0.87649,-0.37368 -2.113309,-0.5562 -2.937026,-0.43342 -3.919114,-0.47032 -5.641701,-0.21193 -0.88,0.13198 -3.076,0.32365 -4.88,0.42589 -2.836818,0.1608 -3.32463,0.22689 -3.610312,0.48923 -0.181672,0.16681 -0.422563,0.30331 -0.535314,0.30331 -0.11275,0 -0.39611,0.0999 -0.629688,0.22197 -0.233577,0.12208 -0.624132,0.3012 -0.867899,0.39803 -0.243766,0.0968 -0.505313,0.33894 -0.581216,0.53803 -0.116958,0.30677 -0.395352,0.41765 -1.825558,0.72711 -1.458335,0.31553 -1.792311,0.33956 -2.458784,0.17689 -0.920535,-0.22465 -1.171229,-0.39787 -1.171229,-0.80926 0,-0.16943 -0.193232,-0.48714 -0.429403,-0.706 -0.550967,-0.51063 -0.70364,-1.56125 -0.509591,-3.50677 0.112396,-1.12686 0.211263,-1.49219 0.454647,-1.68 0.171059,-0.132 0.404017,-0.528 0.517683,-0.88 0.12344,-0.38227 0.351637,-0.7036 0.566664,-0.79794 0.198,-0.0869 0.36,-0.21905 0.36,-0.29374 0,-0.29661 1.198315,-1.82742 1.61991,-2.06938 0.246732,-0.14161 0.490644,-0.42496 0.542024,-0.62969 0.05138,-0.20472 0.306618,-0.49458 0.567191,-0.64411 0.260573,-0.14956 0.543334,-0.4549 0.628361,-0.67853 0.08503,-0.22363 0.252447,-0.40661 0.372047,-0.40661 0.119598,0 0.544233,-0.34514 0.94363,-0.76698 0.399399,-0.42184 1.059327,-0.94372 1.466507,-1.15972 0.407181,-0.21602 0.74033,-0.47647 0.74033,-0.5788 0,-0.10232 0.231173,-0.38058 0.513718,-0.61832 0.502255,-0.42261 1.086282,-1.47213 1.086282,-1.95207 0,-0.13253 0.238528,-0.46667 0.530061,-0.74253 0.525169,-0.49696 0.714664,-0.95915 1.0912,-2.66158 0.107049,-0.484 0.32704,-1.10608 0.488865,-1.38242 0.419732,-0.7167 0.599647,-2.43051 0.60233,-5.73758 0.0029,-3.58661 -0.205211,-6.19294 -0.568931,-7.12481 -0.172877,-0.44292 -0.303091,-1.31052 -0.342043,-2.27898 -0.05378,-1.33715 -0.01778,-1.6386 0.248424,-2.08 0.292256,-0.4846 0.448665,-1.4733 0.916942,-5.79621 0.0572,-0.528 0.159405,-1.032 0.227131,-1.12 0.265983,-0.3456 0.644075,-3.73301 0.901867,-8.08 0.222023,-3.74385 0.249861,-5.87729 0.155536,-11.92 -0.203592,-13.04284 -0.40428,-17.63254 -0.797558,-18.24 -0.135587,-0.20943 -0.271862,-1.50863 -0.394392,-3.76 -0.20999,-3.858349 -0.06674,-6.178229 0.449186,-7.274379 0.184046,-0.39104 0.435003,-1.655081 0.636425,-3.205621 0.290786,-2.23845 0.312047,-2.8313 0.169259,-4.72 -0.08981,-1.188 -0.230908,-3.40231 -0.313545,-4.9207 -0.08264,-1.51838 -0.224613,-2.89965 -0.315503,-3.06948 -0.09089,-0.16983 -0.165254,-0.45151 -0.165254,-0.62597 0,-0.17445 -0.07358,-0.34171 -0.163504,-0.37168 -0.350392,-0.1168 -0.491906,-2.04264 -0.574048,-7.812167 -0.05964,-4.189254 -0.01933,-7.03816 0.133574,-9.44 0.323008,-5.073798 -0.08867,-11.863782 -0.92644,-15.28 -0.343,-1.398675 -0.412467,-2.193906 -0.552089,-6.32 -0.137283,-4.056954 -0.123547,-5.000952 0.09778,-6.72 0.512008,-3.976706 0.442685,-6.059803 -0.233256,-7.009074 -0.318431,-0.447203 -1.759841,-1.310926 -2.18771,-1.310926 -0.118889,0 -0.310245,-0.129768 -0.425235,-0.288373 -0.182963,-0.25236 -0.879309,-0.4656 -2.529072,-0.774469 -1.062438,-0.198908 -1.6,-0.407611 -1.6,-0.621177 0,-0.127427 -0.234,-0.339307 -0.52,-0.470845 -0.956173,-0.439765 -1.561227,-0.843541 -1.88961,-1.261011 -0.179092,-0.22768 -0.510494,-0.506251 -0.736446,-0.619045 -0.478019,-0.238624 -0.768453,-0.980603 -0.907034,-2.317221 -0.141195,-1.361835 0.343932,-2.920038 0.91268,-2.931492 0.09923,-0.002 0.294247,-0.235999 0.433381,-0.52 0.158304,-0.32313 0.440269,-0.578477 0.753466,-0.682337 0.275272,-0.09128 0.665433,-0.319883 0.867029,-0.507998 0.285508,-0.26642 0.709988,-0.380049 1.920228,-0.51403 2.054674,-0.227463 8.044392,-0.219867 11.246306,0.01426 2.060832,0.150692 3.293154,0.143007 6.32,-0.03941 2.501347,-0.150749 6.143408,-0.212951 10.88,-0.185818 7.314414,0.0419 10.413752,-0.109958 10.889712,-0.533565 0.250366,-0.222828 1.150192,-0.337126 5.830288,-0.7405764 2.971763,-0.256183 10.731882,-0.234943 14.764398,0.04041 2.701808,0.184489 3.008298,0.235474 3.306708,0.5500784 0.309217,0.325998 1.153246,0.617664 2.248894,0.777134 0.264,0.03843 0.876,0.186904 1.36,0.329952 1.879128,0.555385 5.576279,0.928045 7.769529,0.78314 1.10414,-0.07295 1.38502,-0.03649 1.95363,0.253597 0.36525,0.186337 0.77243,0.338794 0.90484,0.338794 0.13241,0 0.32085,0.14969 0.41877,0.332645 0.0979,0.182954 0.37672,0.401911 0.61958,0.48657 0.25072,0.0874 0.53924,0.367387 0.6676,0.647838 0.21264,0.464607 0.61264,0.693978 1.82605,1.047106 0.176,0.05122 0.54571,0.334487 0.82158,0.629484 0.27587,0.294997 0.64897,0.536357 0.8291,0.536357 0.1813,0 0.48013,0.214302 0.66932,0.48 0.18798,0.264 0.42689,0.480658 0.53089,0.481462 0.10401,8e-4 0.52898,0.166079 0.94438,0.367274 0.58542,0.283546 0.84936,0.544075 1.17369,1.158536 0.23014,0.436 0.58504,0.936728 0.78868,1.112728 0.20364,0.176 0.49402,0.518414 0.64531,0.76092 0.26778,0.429254 1.45559,1.078059 1.97739,1.080091 0.14281,4.8e-4 0.37807,0.20917 0.5228,0.463584 0.16832,0.295898 0.44824,0.503227 0.77686,0.575405 0.31817,0.06988 0.60936,0.279464 0.76495,0.550571 0.13818,0.240755 0.39521,0.503368 0.57118,0.583584 0.17597,0.08021 0.45839,0.415845 0.6276,0.745845 0.1692,0.33 0.38919,0.6 0.48886,0.6 0.0997,0 0.55399,0.154501 1.00958,0.343334 0.63923,0.264944 0.84698,0.438469 0.90993,0.76 0.22062,1.127008 0.43652,1.68904 0.79694,2.074528 0.26514,0.283591 0.51723,0.913581 0.76808,1.919504 0.30472,1.221941 0.43967,1.522564 0.73368,1.634343 0.21136,0.08036 0.39844,0.321163 0.45264,0.582632 0.23084,1.113643 0.50341,1.755806 0.90226,2.125659 0.23724,0.22 0.48052,0.598798 0.54062,0.841773 0.0601,0.242974 0.30919,0.584137 0.55356,0.758139 0.35896,0.255603 0.47657,0.508787 0.61236,1.318227 0.0924,0.551024 0.21287,1.217861 0.26762,1.481861 0.0548,0.264 0.1313,0.636965 0.17009,0.828811 0.0388,0.191847 0.16042,0.445165 0.27029,0.562931 0.39387,0.422178 0.71627,1.185031 0.91996,2.176772 0.11393,0.554683 0.35849,1.199889 0.54347,1.433793 0.18911,0.239125 0.41538,0.883229 0.51692,1.471487 0.41492,2.403811 0.57999,2.996137 1.00503,3.606206 0.24523,0.352 0.49339,0.885987 0.55146,1.186638 0.0581,0.300652 0.28703,0.78454 0.50881,1.075309 0.65607,0.860149 0.79216,1.987418 0.7893,6.538053 -0.003,4.99048 -0.21416,6.982606 -0.80193,7.570379 -0.2163,0.216291 -0.39326,0.462359 -0.39326,0.546815 0,0.08446 -0.11433,0.546824 -0.25406,1.027486 -0.18641,0.641238 -0.35453,0.912128 -0.63139,1.017392 -0.25883,0.09841 -0.41001,0.317611 -0.48137,0.69799 -0.0572,0.304989 -0.29509,0.73844 -0.5286,0.963224 -0.23352,0.224784 -0.60307,0.590501 -0.82122,0.812706 -0.21814,0.222205 -0.52311,0.404008 -0.67769,0.404008 -0.18253,0 -0.44839,0.331478 -0.75838,0.945552 -0.26252,0.520053 -0.68605,1.094187 -0.94117,1.275847 -0.25512,0.18167 -0.55126,0.54131 -0.65809,0.79921 -0.10683,0.25791 -0.3233,0.50267 -0.48105,0.54393 -0.16565,0.0433 -0.38447,0.36792 -0.51794,0.76833 -0.1544,0.46321 -0.38675,0.77956 -0.70007,0.95317 -0.25793,0.14292 -0.4944,0.39803 -0.52549,0.56691 -0.0709,0.38524 -0.48905,0.86705 -0.75247,0.86705 -0.10967,0 -0.34874,0.25311 -0.53126,0.56246 -0.18252,0.30936 -0.50779,0.62935 -0.72281,0.7111 -0.21502,0.0818 -0.48679,0.35064 -0.60394,0.59754 -0.11715,0.2469 -0.43777,0.5569 -0.71248,0.6889 -0.27472,0.132 -0.61522,0.44122 -0.75667,0.68716 -0.14145,0.24594 -0.45669,0.51704 -0.70052,0.60245 -0.24383,0.0854 -0.56598,0.37018 -0.71589,0.63284 -0.15419,0.27016 -0.40625,0.47755 -0.58041,0.47755 -0.31999,0 -0.61639,0.27834 -0.90078,0.84591 -0.0914,0.18248 -0.36532,0.38486 -0.60862,0.44973 -0.46338,0.12356 -3.63763,3.16112 -3.63763,3.48099 0,0.10085 -0.13145,0.18337 -0.29211,0.18337 -0.16066,0 -0.46121,0.18 -0.66789,0.4 -0.20668,0.22 -0.51067,0.4 -0.67553,0.4 -0.16486,0 -0.45831,0.16976 -0.65211,0.37724 -0.42544,0.45547 -1.1108,0.57414 -4.23351,0.73305 -2.02918,0.10327 -2.32192,0.15439 -2.65031,0.4629 -0.20304,0.19075 -0.47612,0.34681 -0.60685,0.34681 -0.13073,0 -0.30609,0.0664 -0.38969,0.14748 -0.0836,0.0811 -0.3991,0.21042 -0.70112,0.28735 -0.40908,0.1042 -0.58797,0.26041 -0.70148,0.61252 -0.20374,0.632001 -0.41108,0.872651 -0.75187,0.872651 -0.43035,0 -0.49951,0.33632 -0.67455,3.28 -0.12766,2.147 -0.11552,3.03938 0.0576,4.23609 0.19551,1.351149 0.2629,1.537629 0.61938,1.714129 0.25344,0.12549 0.44078,0.39072 0.51131,0.72392 0.35673,1.68523 0.45789,1.88586 0.95087,1.88586 0.18757,0 0.40269,0.20905 0.56468,0.54875 0.15473,0.32447 0.41869,0.58815 0.64585,0.64516 0.2113,0.053 0.53149,0.3461 0.71154,0.65126 0.22321,0.37831 0.44485,0.55483 0.69668,0.55483 0.53839,0 2.66603,2.17619 3.20532,3.27846 0.3386,0.69206 0.51121,0.88154 0.80308,0.88154 0.40791,0 0.55008,0.15824 0.79067,0.88 0.1068,0.32039 0.28421,0.49759 0.53356,0.5329 0.24895,0.0353 0.4498,0.2354 0.60214,0.6 0.12573,0.30091 0.34081,0.5471 0.47796,0.5471 0.38659,0 1.70258,0.82311 2.13639,1.33624 0.21453,0.25376 0.6643,0.75548 0.99949,1.11495 0.3352,0.35946 0.65568,0.801 0.71219,0.98119 0.0565,0.18019 0.27274,0.48618 0.48051,0.67998 0.20777,0.1938 0.37776,0.527 0.37776,0.74046 0,0.6075 0.42553,1.47468 0.86489,1.76257 0.23756,0.15565 0.44067,0.47816 0.49987,0.79371 0.0548,0.29234 0.34119,0.83667 0.63632,1.20963 0.29514,0.37296 0.69151,1.16032 0.88083,1.74969 0.18931,0.58937 0.48533,1.22341 0.65781,1.40898 0.17247,0.18557 0.39008,0.61757 0.48357,0.96 0.20873,0.76455 0.40779,1.0226 0.78881,1.0226 0.19358,0 0.40159,0.24566 0.61333,0.72432 0.17622,0.39838 0.88983,1.31892 1.5858,2.04563 0.69596,0.72672 1.316,1.48078 1.37786,1.67568 0.0619,0.1949 0.22947,0.35437 0.37247,0.35437 0.32903,0 1.93896,1.67694 2.19537,2.28674 0.10608,0.2523 0.36165,0.543 0.56792,0.64599 0.22977,0.11473 0.42579,0.40419 0.50605,0.74727 0.31144,1.33139 0.47478,1.76 0.67072,1.76 0.30322,0 0.73838,0.53329 0.73838,0.90488 0,0.17583 0.324,0.67259 0.72,1.10392 0.396,0.43132 0.72,0.83275 0.72,0.89206 0,0.0593 0.20605,0.17967 0.45789,0.26746 0.39261,0.13686 0.49902,0.31155 0.74632,1.22515 0.22845,0.84394 0.3783,1.11201 0.72056,1.289 0.35865,0.18546 0.45074,0.3675 0.54153,1.0705 0.16133,1.24911 0.61092,2.51415 0.93013,2.61714 0.15697,0.0506 0.35386,0.37888 0.45561,0.75954 0.0986,0.36869 0.43365,1.02574 0.74468,1.46011 0.31103,0.43437 0.62991,1.023 0.70862,1.30808 0.0957,0.3465 0.28016,0.564 0.55656,0.65613 0.33406,0.11135 0.48244,0.35173 0.77278,1.25192 0.23078,0.71553 0.47594,1.17359 0.68526,1.28036 0.564,0.28768 0.84006,0.58255 0.84006,0.8973 0,0.17826 0.16743,0.36803 0.4041,0.45801 0.22226,0.0845 0.44478,0.28072 0.49451,0.43604 0.21988,0.68683 0.45762,0.99767 0.87407,1.14284 0.24574,0.0857 0.55722,0.36931 0.6922,0.63031 0.13672,0.2644 0.46052,0.54955 0.73118,0.6439 0.2735,0.0953 0.55122,0.34149 0.63555,0.56329 0.11249,0.29586 0.36736,0.45719 1.02371,0.648 0.48066,0.13973 0.98788,0.25406 1.12716,0.25406 0.13927,0 0.35845,0.25184 0.48706,0.55965 0.12861,0.30779 0.41399,0.64173 0.63418,0.74205 0.2202,0.10032 0.47103,0.38515 0.55741,0.63296 0.1094,0.3138 0.31232,0.49076 0.66864,0.5831 0.3929,0.10181 0.55317,0.26128 0.6909,0.68741 0.12674,0.39211 0.28871,0.57032 0.55229,0.60766 0.22262,0.0315 0.50452,0.27579 0.6993,0.60591 0.17948,0.3042 0.55902,0.65032 0.84343,0.76915 0.38294,0.16 0.54364,0.34875 0.61939,0.72749 0.0735,0.36764 0.23044,0.55979 0.55813,0.68348 0.25478,0.0962 0.52743,0.3617 0.61813,0.60197 0.11568,0.30648 0.31518,0.46048 0.69496,0.53643 0.59263,0.11853 1.1137,0.51668 1.1137,0.85096 0,0.12026 0.17653,0.29908 0.39229,0.39738 0.21576,0.0983 0.50714,0.42077 0.64751,0.71658 0.1418,0.29881 0.37631,0.53828 0.52771,0.53888 0.14987,0 0.48849,0.14409 0.75249,0.31894 0.264,0.17485 0.59772,0.31837 0.7416,0.31894 0.14388,0 0.37954,0.18106 0.52369,0.40106 0.16728,0.2553 0.41117,0.4 0.6742,0.4 0.24669,0 0.58294,0.18286 0.83763,0.4555 0.42947,0.45976 1.86006,1.3045 2.2092,1.3045 0.10387,0 0.27323,0.25562 0.37634,0.56805 0.10312,0.31243 0.3247,0.65376 0.49241,0.75849 0.16771,0.10474 0.30493,0.26765 0.30493,0.36202 0,0.0944 0.216,0.37851 0.48,0.63144 0.264,0.25293 0.48,0.5904 0.48,0.74994 0,0.15953 0.0955,0.29006 0.21211,0.29006 0.11666,0 0.38296,0.18186 0.59178,0.40413 0.89246,0.95 2.34227,1.32553 5.65206,1.46405 1.94954,0.0816 2.42333,0.14878 2.64,0.37438 0.38042,0.39613 1.16914,0.60496 2.95687,0.78294 0.86505,0.0861 1.66318,0.23159 1.77363,0.32325 0.23795,0.19749 0.48189,0.98327 0.74854,2.41125 0.10946,0.58611 0.32314,1.16491 0.48962,1.32624 0.16656,0.16139 0.29529,0.51029 0.29518,0.8 -1.1e-4,0.28256 0.0827,1.10674 0.18394,1.83149 0.13849,0.99117 0.1388,1.76437 0.002,3.12 -0.16573,1.63315 -0.22053,1.82979 -0.58392,2.09561 -0.22056,0.16135 -0.40103,0.3925 -0.40103,0.51367 0,0.12117 -0.12129,0.61424 -0.26955,1.09571 l -0.26955,0.87538 -0.80674,0.11096 c -0.44369,0.061 -2.7164,0.0916 -5.05044,0.0679 -2.33404,-0.0236 -5.46772,0 -6.96372,0.0521 -1.496,0.0523 -2.828,0.0671 -2.96,0.0328 z"
+ id="path32" />
+ </g>
+</svg>
diff --git a/cmd/rescribe/main.go b/cmd/rescribe/main.go
index fd5b33b..96f2853 100644
--- a/cmd/rescribe/main.go
+++ b/cmd/rescribe/main.go
@@ -13,9 +13,10 @@ import (
"archive/zip"
"bytes"
"context"
- _ "embed"
"flag"
"fmt"
+ "image"
+ "image/draw"
"image/jpeg"
"image/png"
"io"
@@ -29,13 +30,14 @@ import (
"strings"
"time"
+ "golang.org/x/image/tiff"
"rescribe.xyz/bookpipeline"
"rescribe.xyz/bookpipeline/internal/pipeline"
"rescribe.xyz/pdf"
"rescribe.xyz/utils/pkg/hocr"
)
-const usage = `Usage: rescribe [-v] [-gui] [-systess] [-tesscmd] [-t training] bookdir/book.pdf [savedir]
+const usage = `Usage: rescribe [-v] [-gui] [-systess] [-tesscmd cmd] [-gbookcmd cmd] [-t training] bookdir/book.pdf [savedir]
Process and OCR a book using the Rescribe pipeline on a local machine.
@@ -43,9 +45,6 @@ OCR results are saved into the bookdir directory unless savedir is
specified.
`
-//go:embed tessdata.20220322.zip
-var tessdatazip []byte
-
const QueueTimeoutSecs = 2 * 60
const PauseBetweenChecks = 1 * time.Second
const LogSaveTime = 1 * time.Minute
@@ -95,7 +94,7 @@ func resetTimer(t *time.Timer, d time.Duration) {
}
}
-// unpackTessZip unpacks a byte array of a zip file into a directory
+// unpackZip unpacks a byte array of a zip file into a directory
func unpackZip(b []byte, dir string) error {
br := bytes.NewReader(b)
zr, err := zip.NewReader(br, br.Size())
@@ -140,8 +139,10 @@ func unpackZip(b []byte, dir string) error {
func main() {
deftesscmd := "tesseract"
+ defgbookcmd := "getgbook"
if runtime.GOOS == "windows" {
deftesscmd = "C:\\Program Files\\Tesseract-OCR\\tesseract.exe"
+ defgbookcmd = "getgbook.exe"
}
verbose := flag.Bool("v", false, "verbose")
@@ -153,6 +154,7 @@ These training files are included in rescribe, and are always available:
- lat.traineddata (Latin, modern print)
- rescribev9_fast.traineddata (Latin/English/French, printed ca 1500-1800)
`)
+ gbookcmd := flag.String("gbookcmd", defgbookcmd, "The getgbook executable to run. You may need to set this to the full path of getgbook.exe if you're on Windows.")
tesscmd := flag.String("tesscmd", deftesscmd, "The Tesseract executable to run. You may need to set this to the full path of Tesseract.exe if you're on Windows.")
wipe := flag.Bool("wipe", false, "Use wiper tool to remove noise like gutters from page before processing.")
fullpdf := flag.Bool("fullpdf", false, "Use highest image quality for searchable PDF (requires lots of RAM).")
@@ -187,7 +189,7 @@ These training files are included in rescribe, and are always available:
log.Fatalln("Error setting up tesseract directory:", err)
}
- if !*systess {
+ if !*systess && len(tesszip) > 0 {
err = unpackZip(tesszip, tessdir)
if err != nil {
log.Fatalln("Error unpacking embedded Tesseract zip:", err)
@@ -202,18 +204,31 @@ These training files are included in rescribe, and are always available:
}
}
- err = unpackZip(gbookzip, tessdir)
+ _, err = exec.LookPath(tessCommand)
if err != nil {
- log.Fatalln("Error unpacking embedded getgbook zip:", err)
+ log.Fatalf("No tesseract executable found [tried %s], either set -tesscmd and -systess on the command line or use the official build which includes an embedded copy of Tesseract.", tessCommand)
+ }
+
+ gbookCommand := *gbookcmd
+ if len(gbookzip) > 0 {
+ err = unpackZip(gbookzip, tessdir)
+ if err != nil {
+ log.Fatalln("Error unpacking embedded getgbook zip:", err)
+ }
+ switch runtime.GOOS {
+ case "darwin":
+ gbookCommand = filepath.Join(tessdir, "getgbook")
+ case "linux":
+ gbookCommand = filepath.Join(tessdir, "getgbook")
+ case "windows":
+ gbookCommand = filepath.Join(tessdir, "getgbook.exe")
+ }
}
- var gbookCommand string
- switch runtime.GOOS {
- case "darwin":
- gbookCommand = filepath.Join(tessdir, "getgbook")
- case "linux":
- gbookCommand = filepath.Join(tessdir, "getgbook")
- case "windows":
- gbookCommand = filepath.Join(tessdir, "getgbook.exe")
+
+ _, err = exec.LookPath(gbookCommand)
+ if err != nil {
+ log.Printf("No getgbook found [tried %s], google book downloading will be disabled, either set -gbookcmd on the command line or use the official build which includes an embedded getgbook.", gbookCommand)
+ gbookCommand = ""
}
tessdatadir := filepath.Join(tessdir, "tessdata")
@@ -221,25 +236,41 @@ These training files are included in rescribe, and are always available:
if err != nil {
log.Fatalln("Error setting up tessdata directory:", err)
}
- err = unpackZip(tessdatazip, tessdatadir)
- if err != nil {
- log.Fatalln("Error unpacking embedded tessdata zip:", err)
+ if len(tessdatazip) > 0 {
+ err = unpackZip(tessdatazip, tessdatadir)
+ if err != nil {
+ log.Fatalln("Error unpacking embedded tessdata zip:", err)
+ }
}
- // if trainingPath doesn't exist, set it to the embedded training instead
- _, err = os.Stat(trainingPath)
- if err != nil && !os.IsExist(err) {
- trainingPath = filepath.Base(trainingPath)
- trainingPath = filepath.Join(tessdatadir, trainingPath)
+ // copy training path to the tessdir directory, so that we can keep that a
+ // writeable space, which is needed opening other trainings in sandboxes
+ // like flatpak
+ in, err := os.Open(trainingPath)
+ trainingPath = filepath.Join(tessdatadir, filepath.Base(trainingPath))
+ if err != nil {
+ in, err = os.Open(trainingPath)
+ if err != nil {
+ log.Fatalf("Error opening training file %s: %v", trainingPath, err)
+ }
}
-
- f, err := os.Open(trainingPath)
+ defer in.Close()
+ newPath := trainingPath + ".new"
+ out, err := os.Create(newPath)
if err != nil {
- fmt.Fprintf(os.Stderr, "Error: Training files %s or %s could not be opened.\n", *training, trainingPath)
- fmt.Fprintf(os.Stderr, "Set the `-t` flag with path to a tesseract .traineddata file.\n")
- os.Exit(1)
+ log.Fatalf("Error creating training file %s: %v", newPath, err)
+ }
+ defer out.Close()
+ _, err = io.Copy(out, in)
+ if err != nil {
+ log.Fatalf("Error copying training file to %s: %v", newPath, err)
+ }
+ in.Close()
+ out.Close()
+ err = os.Rename(newPath, trainingPath)
+ if err != nil {
+ log.Fatalf("Error moving new training file to %s: %v", trainingPath, err)
}
- f.Close()
abstraining, err := filepath.Abs(trainingPath)
if err != nil {
@@ -253,7 +284,7 @@ These training files are included in rescribe, and are always available:
}
if flag.NArg() < 1 || *usegui {
- err := startGui(*verboselog, tessCommand, gbookCommand, trainingName, tessdir)
+ err := startGui(verboselog, tessCommand, gbookCommand, trainingName, tessdir)
err = os.RemoveAll(tessdir)
if err != nil {
log.Printf("Error removing tesseract directory %s: %v", tessdir, err)
@@ -265,6 +296,14 @@ These training files are included in rescribe, and are always available:
return
}
+ f, err := os.Open(trainingPath)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error: Training files %s or %s could not be opened.\n", *training, trainingPath)
+ fmt.Fprintf(os.Stderr, "Set the `-t` flag with path to a tesseract .traineddata file.\n")
+ os.Exit(1)
+ }
+ f.Close()
+
bookdir := flag.Arg(0)
bookname := strings.ReplaceAll(filepath.Base(bookdir), " ", "_")
savedir := bookdir
@@ -305,7 +344,7 @@ These training files are included in rescribe, and are always available:
ispdf = true
}
- err = startProcess(ctx, *verboselog, tessCommand, bookdir, bookname, trainingName, savedir, tessdir, !*wipe, *fullpdf)
+ err = startProcess(ctx, verboselog, tessCommand, bookdir, bookname, trainingName, savedir, tessdir, !*wipe, *fullpdf)
if err != nil {
log.Fatalln(err)
}
@@ -360,6 +399,12 @@ func extractPdfImgs(ctx context.Context, path string) (string, error) {
if p.Page(pgnum).V.IsNull() {
continue
}
+ var rotate int64
+ for v := p.Page(pgnum).V; !v.IsNull(); v = v.Key("Parent") {
+ if r := v.Key("Rotate"); !r.IsNull() {
+ rotate = r.Int64()
+ }
+ }
res := p.Page(pgnum).Resources()
if res.Kind() != pdf.Dict {
continue
@@ -395,6 +440,13 @@ func extractPdfImgs(ctx context.Context, path string) (string, error) {
if err != nil {
return tempdir, fmt.Errorf("Error removing extracted image %s from PDF: %v\n", fn, err)
}
+
+ if rotate != 0 {
+ err = rotateImage(path, rotate)
+ if err != nil {
+ return tempdir, fmt.Errorf("Error rotating extracted image %s from PDF: %v\n", fn, err)
+ }
+ }
}
}
// TODO: check for places where there are multiple images per page, and only keep largest ones where that's the case
@@ -410,7 +462,9 @@ func extractPdfImgs(ctx context.Context, path string) (string, error) {
// rmIfNotImage attempts to decode a given file as an image. If it is
// decode-able as PNG, then rename file extension from .jpg to .png,
-// if it fails to be read as PNG or JPEG it will be deleted.
+// if it is decode-able as TIFF then convert to PNG and rename file
+// extension appropriately, if it fails to be read as PNG, TIFF or
+// JPEG it will just be deleted.
func rmIfNotImage(f string) error {
r, err := os.Open(f)
defer r.Close()
@@ -421,9 +475,9 @@ func rmIfNotImage(f string) error {
r.Close()
if err == nil {
b := strings.TrimSuffix(f, ".jpg")
- err = os.Rename(f, b + ".png")
+ err = os.Rename(f, b+".png")
if err != nil {
- return fmt.Errorf("Error renaming %s to %s: %v", f, b + ".png", err)
+ return fmt.Errorf("Error renaming %s to %s: %v", f, b+".png", err)
}
return nil
}
@@ -434,18 +488,131 @@ func rmIfNotImage(f string) error {
return fmt.Errorf("Failed to open image %s: %v\n", f, err)
}
_, err = jpeg.Decode(r)
+ r.Close()
+ if err == nil {
+ return nil
+ }
+
+ r, err = os.Open(f)
+ defer r.Close()
if err != nil {
+ return fmt.Errorf("Failed to open image %s: %v\n", f, err)
+ }
+ t, err := tiff.Decode(r)
+ if err == nil {
+ b := strings.TrimSuffix(f, ".jpg")
+ n, err := os.Create(b + ".png")
+ defer n.Close()
+ if err != nil {
+ return fmt.Errorf("Failed to create file to store new png %s from tiff %s: %v\n", b+".png", f, err)
+ }
+ err = png.Encode(n, t)
+ if err != nil {
+ return fmt.Errorf("Failed to encode tiff as png for %s: %v\n", f, err)
+ }
r.Close()
err = os.Remove(f)
if err != nil {
- return fmt.Errorf("Failed to remove invalid image %s: %v", f, err)
+ return fmt.Errorf("Failed to remove original tiff %s: %v\n", f, err)
+ }
+ return nil
+ }
+
+ r.Close()
+ err = os.Remove(f)
+ if err != nil {
+ return fmt.Errorf("Failed to remove invalid image %s: %v", f, err)
+ }
+
+ return nil
+}
+
+// rotateImage rotates an image at the given path by the given angle
+func rotateImage(path string, angle int64) error {
+ switch angle {
+ case 90:
+ // proceed with the rest of the function
+ case 180, 270:
+ // rotate the image again first, as many times as necessary.
+ // this is inefficient but easy.
+ err := rotateImage(path, angle-90)
+ if err != nil {
+ return fmt.Errorf("error with a rotation run: %w", err)
}
+ default:
+ return fmt.Errorf("Rotation angle of %d is not supported", angle)
+ }
+
+ r, err := os.Open(path)
+ defer r.Close()
+ if err != nil {
+ return fmt.Errorf("Failed to open image: %w", err)
+ }
+ img, err := png.Decode(r)
+ if err != nil {
+ r.Close()
+ r, err = os.Open(path)
+ defer r.Close()
+ if err != nil {
+ return fmt.Errorf("Failed to open image: %w", err)
+ }
+ img, err = jpeg.Decode(r)
+ }
+ if err != nil {
+ r.Close()
+ r, err = os.Open(path)
+ defer r.Close()
+ if err != nil {
+ return fmt.Errorf("Failed to open image: %w", err)
+ }
+ img, err = tiff.Decode(r)
+ }
+ if err != nil {
+ return fmt.Errorf("Failed to decode image as png, jpeg or tiff: %w", err)
+ }
+
+ b := img.Bounds()
+
+ orig := image.NewRGBA(b)
+ draw.Draw(orig, b, img, b.Min, draw.Src)
+
+ newb := image.Rectangle{
+ Min: image.Point{X: 0, Y: 0},
+ Max: image.Point{X: b.Dy(), Y: b.Dx()},
+ }
+ new := image.NewRGBA(newb)
+
+ for x := b.Min.X; x < b.Max.X; x++ {
+ desty := newb.Min.Y + x
+ for y := b.Max.Y; y > b.Min.Y; y-- {
+ destx := b.Dy() - y + newb.Min.X
+ new.SetRGBA(destx, desty, orig.RGBAAt(x, y))
+ }
+ }
+
+ err = r.Close()
+ if err != nil {
+ return fmt.Errorf("Failed to close image: %w", err)
+ }
+ w, err := os.Create(path)
+ if err != nil {
+ return fmt.Errorf("Failed to create rotated image: %w", err)
+ }
+ defer w.Close()
+
+ if !strings.HasSuffix(path, ".jpg") {
+ err = jpeg.Encode(w, new, nil)
+ } else {
+ err = png.Encode(w, new)
+ }
+ if err != nil {
+ return fmt.Errorf("Failed to encode rotated image: %w", err)
}
return nil
}
-func startProcess(ctx context.Context, logger log.Logger, tessCommand string, bookdir string, bookname string, trainingName string, savedir string, tessdir string, nowipe bool, fullpdf bool) error {
+func startProcess(ctx context.Context, logger *log.Logger, tessCommand string, bookdir string, bookname string, trainingName string, savedir string, tessdir string, nowipe bool, fullpdf bool) error {
cmd := exec.Command(tessCommand, "--help")
pipeline.HideCmd(cmd)
_, err := cmd.Output()
@@ -464,7 +631,7 @@ func startProcess(ctx context.Context, logger log.Logger, tessCommand string, bo
}
var conn Pipeliner
- conn = &bookpipeline.LocalConn{Logger: &logger, TempDir: tempdir}
+ conn = &bookpipeline.LocalConn{Logger: logger, TempDir: tempdir}
conn.Log("Setting up session")
err = conn.Init()
@@ -509,6 +676,11 @@ func startProcess(ctx context.Context, logger log.Logger, tessCommand string, bo
return fmt.Errorf("Error looking for .hocr files: %v", err)
}
+ err = addFullTxt(hocrs, bookname)
+ if err != nil {
+ log.Fatalf("Error creating full txt version: %v", err)
+ }
+
for _, v := range hocrs {
err = addTxtVersion(v)
if err != nil {
@@ -594,6 +766,32 @@ func addTxtVersion(hocrfn string) error {
return nil
}
+func addFullTxt(hocrs []string, bookname string) error {
+ if len(hocrs) == 0 {
+ return nil
+ }
+ var full string
+ for i, v := range hocrs {
+ t, err := hocr.GetText(v)
+ if err != nil {
+ return fmt.Errorf("Error getting text from hocr file %s: %v", v, err)
+ }
+ if i > 0 {
+ full += "\n"
+ }
+ full += t
+ }
+
+ dir := filepath.Dir(hocrs[0])
+ fn := filepath.Join(dir, bookname+".txt")
+ err := ioutil.WriteFile(fn, []byte(full), 0644)
+ if err != nil {
+ return fmt.Errorf("Error creating text file %s: %v", fn, err)
+ }
+
+ return nil
+}
+
func uploadbook(ctx context.Context, dir string, name string, conn Pipeliner, nowipe bool) error {
_, err := os.Stat(dir)
if err != nil && !os.IsExist(err) {
diff --git a/cmd/rescribe/makefile b/cmd/rescribe/makefile
index a40dce3..4047ff0 100644
--- a/cmd/rescribe/makefile
+++ b/cmd/rescribe/makefile
@@ -18,25 +18,31 @@
# perfectly for us.
OSXCROSSBIN=$(HOME)/src/osxcross/target/bin
-EMBEDS=embed_darwin_amd64.go embed_linux.go embed_windows.go gui.go embed_darwin_arm64.go embed_other.go
+EMBEDS=embed_darwin.go embed_darwin_amd64.go embed_darwin_arm64.go embed_linux.go embed_windows.go embed_other.go
GODEPS=gui.go main.go $(EMBEDS)
+VERSION=1.3.0
-all: dist/linux/rescribe dist/darwin/rescribe.zip dist/windows/rescribe.exe
+all: dist/linux/rescribe dist/linux/wayland/rescribe dist/darwin/rescribe.zip dist/windows/rescribe.exe
dist/linux/rescribe: $(GODEPS)
go generate
mkdir -p dist/linux
- GOOS=linux GOARCH=amd64 go build -o $@ .
+ GOOS=linux GOARCH=amd64 go build -tags embed -o $@ .
+
+dist/linux/wayland/rescribe: $(GODEPS)
+ go generate
+ mkdir -p dist/linux
+ GOOS=linux GOARCH=amd64 go build -tags embed,wayland -o $@ .
build/darwin_amd64/rescribe: $(GODEPS)
go generate
mkdir -p build/darwin_amd64
- PATH="$(PATH):$(OSXCROSSBIN)" CC="o64-clang" CGO_ENABLED=1 GOOS=darwin GOARCH=amd64 go build -o $@ .
+ PATH="$(PATH):$(OSXCROSSBIN)" CC="o64-clang" CGO_ENABLED=1 GOOS=darwin GOARCH=amd64 go build -tags embed -o $@ .
build/darwin_arm64/rescribe: $(GODEPS)
go generate
mkdir -p build/darwin_arm64
- PATH="$(PATH):$(OSXCROSSBIN)" CC="oa64-clang" CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 go build -o $@ .
+ PATH="$(PATH):$(OSXCROSSBIN)" CC="oa64-clang" CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 go build -tags embed -o $@ .
build/darwin/rescribe: build/darwin_amd64/rescribe build/darwin_arm64/rescribe
mkdir -p build/darwin
@@ -44,7 +50,8 @@ build/darwin/rescribe: build/darwin_amd64/rescribe build/darwin_arm64/rescribe
build/darwin/Rescribe.app: build/darwin/rescribe
go install fyne.io/fyne/v2/cmd/fyne@v2.1.2
- fyne package --name Rescribe --exe build/darwin/rescribe --os darwin --icon icon.png
+ fyne package --release --certificate Rescribe --id xyz.rescribe.rescribe --tags embed --name Rescribe --exe build/darwin/rescribe --os darwin --icon icon.png --appVersion $VERSION
+ codesign -s Rescribe Rescribe.app
mv Rescribe.app $@
dist/darwin/rescribe.zip: build/darwin/Rescribe.app
@@ -54,9 +61,18 @@ dist/darwin/rescribe.zip: build/darwin/Rescribe.app
build/windows/rescribe-bin.exe: $(GODEPS)
go generate
mkdir -p build/windows
- CC="x86_64-w64-mingw32-gcc" CGO_ENABLED=1 GOOS=windows GOARCH=amd64 go build -o $@ .
+ CC="x86_64-w64-mingw32-gcc" CGO_ENABLED=1 GOOS=windows GOARCH=amd64 go build -tags embed -o $@ .
dist/windows/rescribe.exe: build/windows/rescribe-bin.exe
mkdir -p dist/windows
- CC="x86_64-w64-mingw32-gcc" fyne package --name Rescribe --exe build/windows/rescribe-bin.exe --os windows --icon icon.png
+ CC="x86_64-w64-mingw32-gcc" fyne package --tags embed --name Rescribe --exe build/windows/rescribe-bin.exe --os windows --icon icon.png --appVersion $VERSION
mv rescribe.exe $@
+
+# used for flatpak building
+modules.tar.xz: ../../go.mod
+ go mod vendor
+ cd ../.. && tar c vendor | xz > cmd/rescribe/$@
+
+clean:
+ rm -rf dist build
+ rm -rf ../../vendor
diff --git a/cmd/rescribe/testdata/fuzz/FuzzGetBookIdFromUrl/174f82f558636f2a b/cmd/rescribe/testdata/fuzz/FuzzGetBookIdFromUrl/174f82f558636f2a
new file mode 100644
index 0000000..1a7ed9c
--- /dev/null
+++ b/cmd/rescribe/testdata/fuzz/FuzzGetBookIdFromUrl/174f82f558636f2a
@@ -0,0 +1,2 @@
+go test fuzz v1
+string("https://www0google\xf7/books/edition/_/")
diff --git a/cmd/rescribe/testdata/fuzz/FuzzGetBookIdFromUrl/60892155cf2f7963 b/cmd/rescribe/testdata/fuzz/FuzzGetBookIdFromUrl/60892155cf2f7963
new file mode 100644
index 0000000..b637539
--- /dev/null
+++ b/cmd/rescribe/testdata/fuzz/FuzzGetBookIdFromUrl/60892155cf2f7963
@@ -0,0 +1,2 @@
+go test fuzz v1
+string("https://Books.google\xc1&id=")
diff --git a/cmd/rescribe/xyz.rescribe.rescribe.appdata.xml b/cmd/rescribe/xyz.rescribe.rescribe.appdata.xml
new file mode 100644
index 0000000..98916b5
--- /dev/null
+++ b/cmd/rescribe/xyz.rescribe.rescribe.appdata.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<component type="desktop-application">
+ <id>xyz.rescribe.rescribe</id>
+
+ <name>Rescribe</name>
+ <developer_name>Rescribe Ltd</developer_name>
+ <summary>High quality OCR for images, PDFs and Google Books.</summary>
+
+ <description><p>An easy-to-use desktop tool for OCR of images, PDFs and Google Books. It uses the Tesseract OCR engine, combined with modern and efficient preprocessing and analysis pipelines, to produce high quality output in plain text, hOCR and searchable PDF format. The tool has been built with a focus on OCR of historical printed works, but it includes modern language options and also works well on modern printed works.</p></description>
+
+ <screenshots>
+ <screenshot type="default"><image>https://rescribe.xyz/rescribe/screenshot-03.png</image></screenshot>
+ <screenshot><image>https://rescribe.xyz/rescribe/screenshot-04.png</image></screenshot>
+ </screenshots>
+
+ <url type="homepage">https://rescribe.xyz/rescribe</url>
+
+ <metadata_license>MIT</metadata_license>
+ <project_license>GPL-3.0</project_license>
+
+ <launchable type="desktop-id">xyz.rescribe.rescribe.desktop</launchable>
+
+ <content_rating type="oars-1.1" />
+
+ <releases>
+ <release version="1.2.0" date="2024-02-16" type="stable">
+ <description>
+ <p>Fixed bug with directories containing files with spaces causing the process to fail, added concatenated text output named bookname.txt, fixed selecting a custom training in flatpak build, fixed getgbook on arm64 MacOS, improved layout of log area to fill all available space in the window, improved readability of log area text.</p>
+ </description>
+ </release>
+ <release version="1.1.0" date="2023-02-13" type="stable">
+ <description>
+ <p>Improved PDF reading by adding support for embedded CCITT images. Improved PDF parsing to prevent a possible crash with bad PDF files. Improved error messages for unreadable PDFs. Improved GUI theme thanks to an update to Fyne.</p>
+ </description>
+ </release>
+ <release version="1.0.0" date="2022-03-22" type="stable">
+ <description>
+ <p>Thanks to our fabulous Kickstarter backers, lots of improvements! Added GUI, added PDF extractor, added Google Book downloader, created a single binary for OSX for M1 and amd64, added file renamer so page files no longer need a particular naming format, added option to disable page wiping, added option to create full size PDF.</p>
+ </description>
+ </release>
+ </releases>
+
+</component>
diff --git a/cmd/rescribe/xyz.rescribe.rescribe.desktop b/cmd/rescribe/xyz.rescribe.rescribe.desktop
new file mode 100644
index 0000000..331079f
--- /dev/null
+++ b/cmd/rescribe/xyz.rescribe.rescribe.desktop
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Version=1.0
+Type=Application
+Name=Rescribe
+Comment=An easy-to-use desktop tool for performing OCR on image files, PDFs and Google Books.
+Categories=Office;Literature;OCR;Scanning;TextTools
+Icon=xyz.rescribe.rescribe
+Exec=rescribe
+Terminal=false
diff --git a/cmd/rescribe/xyz.rescribe.rescribe.yml b/cmd/rescribe/xyz.rescribe.rescribe.yml
new file mode 100644
index 0000000..bd8faf4
--- /dev/null
+++ b/cmd/rescribe/xyz.rescribe.rescribe.yml
@@ -0,0 +1,65 @@
+app-id: xyz.rescribe.rescribe
+runtime: org.freedesktop.Platform
+runtime-version: '23.08'
+sdk: org.freedesktop.Sdk
+sdk-extensions: org.freedesktop.Sdk.Extension.golang
+build-options:
+ append-path: /usr/lib/sdk/golang/bin
+finish-args:
+ - --socket=fallback-x11
+ - --share=ipc # needed for X11
+ - --socket=wayland
+ - --device=dri # OpenGL
+ - --share=network # Used for google book downloading
+ - --filesystem=home
+command: rescribe
+modules:
+ - name: rescribe
+ buildsystem: simple
+ build-commands:
+ - cd cmd/rescribe && go build .
+ - cd cmd/rescribe && go build -tags wayland -o rescribe-wayland .
+ - install -Dm00755 cmd/rescribe/rescribe $FLATPAK_DEST/bin/rescribe-bin
+ - install -Dm00755 cmd/rescribe/rescribe-wayland $FLATPAK_DEST/bin/rescribe-bin-wayland
+ - install -Dm00644 cmd/rescribe/icon.256.png $FLATPAK_DEST/share/icons/hicolor/256x256/apps/xyz.rescribe.rescribe.png
+ - install -Dm00644 cmd/rescribe/xyz.rescribe.rescribe.desktop $FLATPAK_DEST/share/applications/xyz.rescribe.rescribe.desktop
+ - install -Dm00644 cmd/rescribe/xyz.rescribe.rescribe.appdata.xml $FLATPAK_DEST/share/appdata/xyz.rescribe.rescribe.appdata.xml
+ - printf '#!/bin/sh\nexport TMPDIR=$XDG_RUNTIME_DIR\nbin=rescribe-bin\ntest -n "$WAYLAND_DISPLAY" && bin=rescribe-bin-wayland\n"$bin" -gbookcmd "/app/bin/getgbook" -tesscmd "/app/bin/tesseract" -t "/app/share/tessdata/rescribev9_fast.traineddata"\n' > $FLATPAK_DEST/bin/rescribe
+ - chmod 755 $FLATPAK_DEST/bin/rescribe
+ - mkdir -p $FLATPAK_DEST/share/tessdata
+ - cp -r tessdata/* $FLATPAK_DEST/share/tessdata/
+ sources:
+ - type: git
+ url: https://github.com/rescribe/bookpipeline
+ tag: v1.2.0
+ commit: bf6e4762191aee0c27242f1d9cbbc2b8972c12f9
+ - type: archive
+ url: https://rescribe.xyz/rescribe/modules-20240206-d2399a.tar.xz
+ sha256: 682820d4cb6129c564cf8df494dc12d35ab059ed99dba34c0b3d6260f7fc30fb
+ strip-components: 0
+ - type: archive
+ url: https://rescribe.xyz/rescribe/embeds/tessdata.20220322.zip
+ sha256: 725fd570a3c3dc0eba9463248ce47a8646db8bafb198d428d6bb8f0be18540ee
+ strip-components: 0
+ dest: tessdata
+ - name: leptonica
+ sources:
+ - type: git
+ url: https://github.com/DanBloomberg/leptonica
+ tag: 1.82.0
+ commit: f4138265b390f1921b9891d6669674d3157887d8
+ - name: tesseract-ocr
+ sources:
+ - type: git
+ url: https://github.com/tesseract-ocr/tesseract
+ tag: 5.2.0
+ commit: 5ad5325a0aa8effc47ca033625b6a51682f82767
+ - name: getxbook
+ buildsystem: simple
+ build-commands:
+ - make PREFIX=$FLATPAK_DEST install
+ sources:
+ - type: git
+ url: https://git.njw.name/getxbook.git
+ commit: c770a86cca74f3b6235000c77c2ab74487e2ac2a
+ disable-shallow-clone: true
diff --git a/go.mod b/go.mod
index 8ccafd9..c17f4c7 100644
--- a/go.mod
+++ b/go.mod
@@ -1,15 +1,48 @@
module rescribe.xyz/bookpipeline
-go 1.16
+go 1.21
require (
- fyne.io/fyne/v2 v2.1.2
+ fyne.io/fyne/v2 v2.4.3
github.com/aws/aws-sdk-go v1.40.6
- github.com/nickjwhite/gofpdf v1.12.7-0.20210817123627-3cbaeb9797ef
+ github.com/nickjwhite/gofpdf v1.12.7-0.20240307131705-b017c7c7e41b
github.com/wcharczuk/go-chart/v2 v2.1.0
- golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d
- golang.org/x/sys v0.0.0-20211023085530-d6a326fbbf70 // indirect
- rescribe.xyz/pdf v0.1.3
- rescribe.xyz/preproc v0.4.2
+ golang.org/x/image v0.11.0
+ rescribe.xyz/pdf v0.1.6
+ rescribe.xyz/preproc v0.4.3
rescribe.xyz/utils v0.1.3
)
+
+require (
+ fyne.io/systray v1.10.1-0.20231115130155-104f5ef7839e // indirect
+ github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/fredbi/uri v1.0.0 // indirect
+ github.com/fsnotify/fsnotify v1.6.0 // indirect
+ github.com/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe // indirect
+ github.com/fyne-io/glfw-js v0.0.0-20220120001248-ee7290d23504 // indirect
+ github.com/fyne-io/image v0.0.0-20220602074514-4956b0afb3d2 // indirect
+ github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6 // indirect
+ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b // indirect
+ github.com/go-text/render v0.0.0-20230619120952-35bccb6164b8 // indirect
+ github.com/go-text/typesetting v0.0.0-20230616162802-9c17dd34aa4a // indirect
+ github.com/godbus/dbus/v5 v5.1.0 // indirect
+ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
+ github.com/gopherjs/gopherjs v1.17.2 // indirect
+ github.com/jmespath/go-jmespath v0.4.0 // indirect
+ github.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e // indirect
+ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
+ github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect
+ github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect
+ github.com/stretchr/testify v1.8.4 // indirect
+ github.com/tevino/abool v1.2.0 // indirect
+ github.com/yuin/goldmark v1.5.5 // indirect
+ golang.org/x/mobile v0.0.0-20230531173138-3c911d8e3eda // indirect
+ golang.org/x/net v0.17.0 // indirect
+ golang.org/x/sys v0.13.0 // indirect
+ golang.org/x/text v0.13.0 // indirect
+ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+ honnef.co/go/js/dom v0.0.0-20210725211120-f030747120f2 // indirect
+ rescribe.xyz/integral v0.6.1 // indirect
+)
diff --git a/go.sum b/go.sum
index 69c51fc..de18345 100644
--- a/go.sum
+++ b/go.sum
@@ -1,121 +1,697 @@
-fyne.io/fyne/v2 v2.1.2 h1:avp9CvLAUdvE7fDMtH1tVKyjxEWHWcpow6aI6L7Kvvw=
-fyne.io/fyne/v2 v2.1.2/go.mod h1:p+E/Dh+wPW8JwR2DVcsZ9iXgR9ZKde80+Y+40Is54AQ=
+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=
+fyne.io/fyne/v2 v2.4.3 h1:v2wncjEAcwXZ8UNmTCWTGL9+sGyPc5RuzBvM96GcC78=
+fyne.io/fyne/v2 v2.4.3/go.mod h1:1h3BKxmQYRJlr2g+RGVxedzr6vLVQ/AJmFWcF9CJnoQ=
+fyne.io/systray v1.10.1-0.20231115130155-104f5ef7839e h1:Hvs+kW2VwCzNToF3FmnIAzmivNgrclwPgoUdVSrjkP8=
+fyne.io/systray v1.10.1-0.20231115130155-104f5ef7839e/go.mod h1:oM2AQqGJ1AMo4nNqZFYU8xYygSBZkW2hmdJ7n4yjedE=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
-github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9/go.mod h1:7uhhqiBaR4CpN0k9rMjOtjpcfGd6DG2m04zQxKnWQ0I=
-github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
+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/aws/aws-sdk-go v1.40.6 h1:JCQfi5MD8cW0PCAzr88hj9tj4BdEJkAy8EyAJ6c8I/k=
github.com/aws/aws-sdk-go v1.40.6/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
+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/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
-github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+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/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 h1:FDqhDm7pcsLhhWl1QtD8vlzI4mm59llRvNzrFg6/LAA=
-github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3/go.mod h1:CzM2G82Q9BDUvMTGHnXf/6OExw/Dz2ivDj48nVg7Lg8=
-github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
+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/fredbi/uri v1.0.0 h1:s4QwUAZ8fz+mbTsukND+4V5f+mJ/wjaTokwstGUAemg=
+github.com/fredbi/uri v1.0.0/go.mod h1:1xC40RnIOGCaQzswaOvrzvG/3M3F0hyDVb3aO/1iGy0=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
-github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f h1:s0O46d8fPwk9kU4k1jj76wBquMVETx7uveQD9MCIQoU=
-github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f/go.mod h1:wjpnOv6ONl2SuJSxqCPVaPZibGFdSci9HFocT9qtVYM=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211024062804-40e447a793be h1:Z28GdQBfKOL8tNHjvaDn3wHDO7AzTRkmAXvHvnopp98=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211024062804-40e447a793be/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
-github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
+github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
+github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
+github.com/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe h1:A/wiwvQ0CAjPkuJytaD+SsXkPU0asQ+guQEIg1BJGX4=
+github.com/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe/go.mod h1:d4clgH0/GrRwWjRzJJQXxT/h1TyuNSfF/X64zb/3Ggg=
+github.com/fyne-io/glfw-js v0.0.0-20220120001248-ee7290d23504 h1:+31CdF/okdokeFNoy9L/2PccG3JFidQT3ev64/r4pYU=
+github.com/fyne-io/glfw-js v0.0.0-20220120001248-ee7290d23504/go.mod h1:gLRWYfYnMA9TONeppRSikMdXlHQ97xVsPojddUv3b/E=
+github.com/fyne-io/image v0.0.0-20220602074514-4956b0afb3d2 h1:hnLq+55b7Zh7/2IRzWCpiTcAvjv/P8ERF+N7+xXbZhk=
+github.com/fyne-io/image v0.0.0-20220602074514-4956b0afb3d2/go.mod h1:eO7W361vmlPOrykIg+Rsh1SZ3tQBaOsfzZhsIOb/Lm0=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6 h1:zDw5v7qm4yH7N8C8uWd+8Ii9rROdgWxQuGoJ9WDXxfk=
+github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211213063430-748e38ca8aec/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b h1:GgabKamyOYguHqHjSkDACcgoPIz3w0Dis/zJ1wyHHHU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-text/render v0.0.0-20230619120952-35bccb6164b8 h1:VkKnvzbvHqgEfm351rfr8Uclu5fnwq8HP2ximUzJsBM=
+github.com/go-text/render v0.0.0-20230619120952-35bccb6164b8/go.mod h1:h29xCucjNsDcYb7+0rJokxVwYAq+9kQ19WiFuBKkYtc=
+github.com/go-text/typesetting v0.0.0-20230616162802-9c17dd34aa4a h1:VjN8ttdfklC0dnAdKbZqGNESdERUxtE3l8a/4Grgarc=
+github.com/go-text/typesetting v0.0.0-20230616162802-9c17dd34aa4a/go.mod h1:evDBbvNR/KaVFZ2ZlDSOWWXIUKq0wCOEtzLxRM8SG3k=
+github.com/go-text/typesetting-utils v0.0.0-20230616150549-2a7df14b6a22 h1:LBQTFxP2MfsyEDqSKmUBZaDuDHN1vpqDyOZjcqS7MYI=
+github.com/go-text/typesetting-utils v0.0.0-20230616150549-2a7df14b6a22/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8=
-github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw=
+github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
+github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
-github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMHVoNcyXYq9otUupF7/h/2tmHlhrS2zw7ZVvUqc=
+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/go-cmp v0.5.6/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/gopherjs/gopherjs v0.0.0-20211219123610-ec9572f70e60/go.mod h1:cz9oNYuRUWGdHmLF2IodMLkAhcPtXeULvcBNagUrxTI=
+github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
+github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
+github.com/goxjs/gl v0.0.0-20210104184919-e3fafc6f8f2a/go.mod h1:dy/f2gjY09hwVfIyATps4G2ai7/hLwLkc5TrPqONuXY=
+github.com/goxjs/glfw v0.0.0-20191126052801-d2efb5f20838/go.mod h1:oS8P8gVOT4ywTcjV6wZlOU4GuVFQ8F5328KY3MJ79CY=
+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/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
-github.com/josephspurrier/goversioninfo v0.0.0-20200309025242-14b0ab84c6ca/go.mod h1:eJTEwMjXb7kZ633hO3Ln9mBUCOjX2+FlTljvpl9SYdE=
+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/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e h1:LvL4XsI70QxOGHed6yhQtAU34Kx3Qq2wwBzGFKY8zKk=
+github.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e/go.mod h1:kLgvv7o6UM+0QSf0QjAse3wReFDsb9qbZJdfexWlrQw=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
+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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/lucor/goinfo v0.0.0-20210802170112-c078a2b0f08b/go.mod h1:PRq09yoB+Q2OJReAmwzKivcYyremnibWGbK7WfftHzc=
-github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
-github.com/nickjwhite/gofpdf v1.12.7-0.20210817123627-3cbaeb9797ef h1:Pq7OiIQ0gWrNQr12kRIvAH7qEr3i6hfSfd0smfwGgC0=
-github.com/nickjwhite/gofpdf v1.12.7-0.20210817123627-3cbaeb9797ef/go.mod h1:HHhz41M4FT6ogJi7KMknlu/sEJd6halot657/rJwzVM=
+github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-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/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
+github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
+github.com/nickjwhite/gofpdf v1.12.7-0.20240307131705-b017c7c7e41b h1:Td9/25hvPktBd9Z4hFjBvrCHwtbVRyr6AoLtTLFXqpg=
+github.com/nickjwhite/gofpdf v1.12.7-0.20240307131705-b017c7c7e41b/go.mod h1:HHhz41M4FT6ogJi7KMknlu/sEJd6halot657/rJwzVM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+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/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
-github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/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/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/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
+github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
+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/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
-github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 h1:HunZiaEKNGVdhTRQOVpMmj5MQnGnv+e8uZNu3xFLgyM=
-github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4=
-github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 h1:m59mIOBO4kfcNCEzJNy71UkeF4XIx2EVmL9KLwDQdmM=
-github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU=
+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/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/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
+github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiYWEedbTT0qnSxrCjsVbb7yKY1KE=
+github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q=
+github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ=
+github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
+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/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA=
+github.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg=
github.com/wcharczuk/go-chart/v2 v2.1.0 h1:tY2slqVQ6bN+yHSnDYwZebLQFkphK4WNrVwnt7CJZ2I=
github.com/wcharczuk/go-chart/v2 v2.1.0/go.mod h1:yx7MvAVNcP/kN9lKXM/NTce4au4DFN99j6i1OwDclNA=
+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=
-github.com/yuin/goldmark v1.3.8 h1:Nw158Q8QN+CPgTmVRByhVwapp8Mm1e2blinhmx4wx5E=
-github.com/yuin/goldmark v1.3.8/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+github.com/yuin/goldmark v1.5.5 h1:IJznPe8wOzfIKETmMkd06F8nXkmlhaHqFRM9l1hAGsU=
+github.com/yuin/goldmark v1.5.5/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+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-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/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-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
+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/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs=
-golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
+golang.org/x/image v0.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo=
+golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
+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/mobile v0.0.0-20211207041440-4e6c2922fdee/go.mod h1:pe2sM7Uk+2Su1y7u/6Z8KJ24D7lepUjFZbhFOrmDfuQ=
+golang.org/x/mobile v0.0.0-20230531173138-3c911d8e3eda h1:O+EUvnBNPwI4eLthn8W5K+cS8zQZfgTABPLNm6Bna34=
+golang.org/x/mobile v0.0.0-20230531173138-3c911d8e3eda/go.mod h1:aAjjkJNdrh3PMckS4B10TGS2nag27cbKR1y2BpUxsiY=
+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/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/net v0.0.0-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/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+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/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-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-20190916202348-b4ddaad3f8a3/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-20210423082822-04245dca01da/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-20211023085530-d6a326fbbf70 h1:SeSEfdIxyvwGJliREIJhRPPXvW6sDlLT+UQ3B0hD0NA=
-golang.org/x/sys v0.0.0-20211023085530-d6a326fbbf70/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/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.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
+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/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+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/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/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/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 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-rescribe.xyz/integral v0.6.0 h1:CLF3sQ6th/OuG+/rp/lLR+AGOT4R7tG3IiUjSLKsriw=
-rescribe.xyz/integral v0.6.0/go.mod h1:gKJq4UaVn17RsMsUasEMcJDkTkwqeb6AzPIJtwcUipg=
-rescribe.xyz/pdf v0.1.3 h1:Fl4HHQPfkIUJs8WIkpjCm8yGu6Wd1TIDLZgXhVy8Pdk=
-rescribe.xyz/pdf v0.1.3/go.mod h1:fIia5YlYagNbBARPP2JXDoXXR5zd14Us5RkaKXUz7Nw=
-rescribe.xyz/preproc v0.4.2 h1:aX6rOf6ha3UNcHM0oHuY1MQi7ZwYj+46OxhTcptAI4E=
-rescribe.xyz/preproc v0.4.2/go.mod h1:LJe+rQ9cAxn/29cVK5l6X1hH1ZWRAI1Bs73yDGjvT4A=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/js/dom v0.0.0-20210725211120-f030747120f2 h1:oomkgU6VaQDsV6qZby2uz1Lap0eXmku8+2em3A/l700=
+honnef.co/go/js/dom v0.0.0-20210725211120-f030747120f2/go.mod h1:sUMDUKNB2ZcVjt92UnLy3cdGs+wDAcrPdV3JP6sVgA4=
+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=
+rescribe.xyz/integral v0.6.1 h1:0+4lajevAWO33sxnS33+URUbSalAh2Diti7ZWV/DbqU=
+rescribe.xyz/integral v0.6.1/go.mod h1:gKJq4UaVn17RsMsUasEMcJDkTkwqeb6AzPIJtwcUipg=
+rescribe.xyz/pdf v0.1.6 h1:Fpa/xGCwh9jZfKZ48xUw6Pdpz4lhYm/WsfGVmUmtBOc=
+rescribe.xyz/pdf v0.1.6/go.mod h1:fIia5YlYagNbBARPP2JXDoXXR5zd14Us5RkaKXUz7Nw=
+rescribe.xyz/preproc v0.4.3 h1:DySrMD7uqJyd1dAw9eYbaTCHPMPFTE3cVcy05BmkLN4=
+rescribe.xyz/preproc v0.4.3/go.mod h1:wY+4/ZMEtMb2ifew57+0ClfMNH01ctiiiyGeh0zcfUY=
rescribe.xyz/utils v0.1.3 h1:2rlHbUjAGXy/xgtmUb6Y7Kbpxl3qkwtWzkFUQ/cOaIA=
rescribe.xyz/utils v0.1.3/go.mod h1:4L2vClYUFklsXggN0CUyP/alcgzLNRT0dMpMfEiVbX8=
+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/internal/pipeline/put.go b/internal/pipeline/put.go
index 48ed9a9..fed04f8 100644
--- a/internal/pipeline/put.go
+++ b/internal/pipeline/put.go
@@ -135,7 +135,8 @@ func UploadImages(ctx context.Context, dir string, bookname string, conn Uploade
origbase := strings.TrimSuffix(origname, origsuffix)
origpath := filepath.Join(dir, origname)
- newname := fmt.Sprintf("%s_%04d%s", origbase, filenum, lsuffix)
+ safebase := strings.ReplaceAll(origbase, " ", "_")
+ newname := fmt.Sprintf("%s_%04d%s", safebase, filenum, lsuffix)
err = conn.Upload(conn.WIPStorageId(), filepath.Join(bookname, newname), origpath)
if err != nil {
return fmt.Errorf("Failed to upload %s: %v", origpath, err)