diff --git a/vendor/github.com/atomicgo/cursor/.gitignore b/vendor/github.com/atomicgo/cursor/.gitignore
new file mode 100644
index 0000000..99e2741
--- /dev/null
+++ b/vendor/github.com/atomicgo/cursor/.gitignore
@@ -0,0 +1,31 @@
+### Go template
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Dependency directories (remove the comment below to include it)
+vendor/
+
+### IntelliJ
+.idea
+*.iml
+out
+gen
+
+### VisualStudioCode
+.vscode
+*.code-workspace
+
+### macOS
+# General
+.DS_Store
+experimenting
diff --git a/vendor/github.com/atomicgo/cursor/.golangci.yml b/vendor/github.com/atomicgo/cursor/.golangci.yml
new file mode 100644
index 0000000..d18a485
--- /dev/null
+++ b/vendor/github.com/atomicgo/cursor/.golangci.yml
@@ -0,0 +1,71 @@
+linters-settings:
+ gocritic:
+ enabled-tags:
+ - diagnostic
+ - experimental
+ - opinionated
+ - performance
+ - style
+ disabled-checks:
+ - dupImport
+ - ifElseChain
+ - octalLiteral
+ - whyNoLint
+ - wrapperFunc
+ - exitAfterDefer
+ - hugeParam
+ - ptrToRefParam
+ - paramTypeCombine
+ - unnamedResult
+ misspell:
+ locale: US
+linters:
+ disable-all: true
+ enable:
+ - errcheck
+ - gosimple
+ - govet
+ - ineffassign
+ - staticcheck
+ - asciicheck
+ - bodyclose
+ - dupl
+ - durationcheck
+ - errorlint
+ - exhaustive
+ - gci
+ - gocognit
+ - gocritic
+ - godot
+ - godox
+ - goerr113
+ - gofmt
+ - goimports
+ - goprintffuncname
+ - misspell
+ - nilerr
+ - nlreturn
+ - noctx
+ - prealloc
+ - predeclared
+ - thelper
+ - unconvert
+ - unparam
+ - wastedassign
+ - wrapcheck
+issues:
+ # Excluding configuration per-path, per-linter, per-text and per-source
+ exclude-rules:
+ - path: _test\.go
+ linters:
+ - errcheck
+ - dupl
+ - gocritic
+ - wrapcheck
+ - goerr113
+ # https://github.com/go-critic/go-critic/issues/926
+ - linters:
+ - gocritic
+ text: "unnecessaryDefer:"
+service:
+ golangci-lint-version: 1.39.x # use the fixed version to not introduce new linters unexpectedly
diff --git a/vendor/github.com/atomicgo/cursor/CHANGELOG.md b/vendor/github.com/atomicgo/cursor/CHANGELOG.md
new file mode 100644
index 0000000..e69de29
diff --git a/vendor/github.com/atomicgo/cursor/LICENSE b/vendor/github.com/atomicgo/cursor/LICENSE
new file mode 100644
index 0000000..c78d7a5
--- /dev/null
+++ b/vendor/github.com/atomicgo/cursor/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 Marvin Wendt (MarvinJWendt)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/atomicgo/cursor/README.md b/vendor/github.com/atomicgo/cursor/README.md
new file mode 100644
index 0000000..16f6dcb
--- /dev/null
+++ b/vendor/github.com/atomicgo/cursor/README.md
@@ -0,0 +1,237 @@
+
AtomicGo | cursor
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+---
+
+
+Get The Module
+|
+Documentation
+|
+Contributing
+|
+Code of Conduct
+
+
+---
+
+
+
+
+
+## Description
+
+Package cursor contains cross-platform methods to move the terminal cursor in
+different directions. This package can be used to create interactive CLI tools
+and games, live charts, algorithm visualizations and other updatable output of
+any kind.
+
+Special thanks to github.com/k0kubun/go-ansi which this project is based on.
+
+## Install
+
+```console
+# Execute this command inside your project
+go get -u github.com/atomicgo/cursor
+```
+
+```go
+// Add this to your imports
+import "github.com/atomicgo/cursor"
+```
+
+## Usage
+
+#### func Bottom
+
+```go
+func Bottom()
+```
+Bottom moves the cursor to the bottom of the terminal. This is done by
+calculating how many lines were moved by Up and Down.
+
+#### func ClearLine
+
+```go
+func ClearLine()
+```
+ClearLine clears the current line and moves the cursor to it's start position.
+
+#### func ClearLinesDown
+
+```go
+func ClearLinesDown(n int)
+```
+ClearLinesDown clears n lines downwards from the current position and moves the
+cursor.
+
+#### func ClearLinesUp
+
+```go
+func ClearLinesUp(n int)
+```
+ClearLinesUp clears n lines upwards from the current position and moves the
+cursor.
+
+#### func Down
+
+```go
+func Down(n int)
+```
+Down moves the cursor n lines down relative to the current position.
+
+#### func DownAndClear
+
+```go
+func DownAndClear(n int)
+```
+DownAndClear moves the cursor down by n lines, then clears the line.
+
+#### func Hide
+
+```go
+func Hide()
+```
+Hide the cursor. Don't forget to show the cursor at least at the end of your
+application with Show. Otherwise the user might have a terminal with a
+permanently hidden cursor, until he reopens the terminal.
+
+#### func HorizontalAbsolute
+
+```go
+func HorizontalAbsolute(n int)
+```
+HorizontalAbsolute moves the cursor to n horizontally. The position n is
+absolute to the start of the line.
+
+#### func Left
+
+```go
+func Left(n int)
+```
+Left moves the cursor n characters to the left relative to the current position.
+
+#### func Move
+
+```go
+func Move(x, y int)
+```
+Move moves the cursor relative by x and y.
+
+#### func Right
+
+```go
+func Right(n int)
+```
+Right moves the cursor n characters to the right relative to the current
+position.
+
+#### func Show
+
+```go
+func Show()
+```
+Show the cursor if it was hidden previously. Don't forget to show the cursor at
+least at the end of your application. Otherwise the user might have a terminal
+with a permanently hidden cursor, until he reopens the terminal.
+
+#### func StartOfLine
+
+```go
+func StartOfLine()
+```
+StartOfLine moves the cursor to the start of the current line.
+
+#### func StartOfLineDown
+
+```go
+func StartOfLineDown(n int)
+```
+StartOfLineDown moves the cursor down by n lines, then moves to cursor to the
+start of the line.
+
+#### func StartOfLineUp
+
+```go
+func StartOfLineUp(n int)
+```
+StartOfLineUp moves the cursor up by n lines, then moves to cursor to the start
+of the line.
+
+#### func Up
+
+```go
+func Up(n int)
+```
+Up moves the cursor n lines up relative to the current position.
+
+#### func UpAndClear
+
+```go
+func UpAndClear(n int)
+```
+UpAndClear moves the cursor up by n lines, then clears the line.
+
+#### type Area
+
+```go
+type Area struct {
+}
+```
+
+Area displays content which can be updated on the fly. You can use this to
+create live output, charts, dropdowns, etc.
+
+#### func NewArea
+
+```go
+func NewArea() Area
+```
+NewArea returns a new Area.
+
+#### func (*Area) Clear
+
+```go
+func (area *Area) Clear()
+```
+Clear clears the content of the Area.
+
+#### func (*Area) Update
+
+```go
+func (area *Area) Update(content string)
+```
+Update overwrites the content of the Area.
+
+---
+
+> [AtomicGo.dev](https://atomicgo.dev) ·
+> with ❤️ by [@MarvinJWendt](https://github.com/MarvinJWendt) |
+> [MarvinJWendt.com](https://marvinjwendt.com)
diff --git a/vendor/github.com/atomicgo/cursor/area.go b/vendor/github.com/atomicgo/cursor/area.go
new file mode 100644
index 0000000..76d9916
--- /dev/null
+++ b/vendor/github.com/atomicgo/cursor/area.go
@@ -0,0 +1,45 @@
+package cursor
+
+import (
+ "fmt"
+ "runtime"
+ "strings"
+)
+
+// Area displays content which can be updated on the fly.
+// You can use this to create live output, charts, dropdowns, etc.
+type Area struct {
+ height int
+}
+
+// NewArea returns a new Area.
+func NewArea() Area {
+ return Area{}
+}
+
+// Clear clears the content of the Area.
+func (area *Area) Clear() {
+ Bottom()
+ if area.height > 0 {
+ ClearLinesUp(area.height)
+ }
+}
+
+// Update overwrites the content of the Area.
+func (area *Area) Update(content string) {
+ area.Clear()
+ lines := strings.Split(content, "\n")
+ if runtime.GOOS == "windows" {
+ for _, line := range lines {
+ fmt.Print(line)
+ StartOfLineDown(1)
+ }
+ } else {
+ for _, line := range lines {
+ fmt.Println(line)
+ }
+ }
+ height = 0
+
+ area.height = len(lines)
+}
diff --git a/vendor/github.com/atomicgo/cursor/cursor.go b/vendor/github.com/atomicgo/cursor/cursor.go
new file mode 100644
index 0000000..152d40c
--- /dev/null
+++ b/vendor/github.com/atomicgo/cursor/cursor.go
@@ -0,0 +1,59 @@
+// +build !windows
+
+package cursor
+
+import (
+ "fmt"
+)
+
+// Up moves the cursor n lines up relative to the current position.
+func Up(n int) {
+ fmt.Printf("\x1b[%dA", n)
+ height += n
+}
+
+// Down moves the cursor n lines down relative to the current position.
+func Down(n int) {
+ fmt.Printf("\x1b[%dB", n)
+ if height-n <= 0 {
+ height = 0
+ } else {
+ height -= n
+ }
+}
+
+// Right moves the cursor n characters to the right relative to the current position.
+func Right(n int) {
+ fmt.Printf("\x1b[%dC", n)
+}
+
+// Left moves the cursor n characters to the left relative to the current position.
+func Left(n int) {
+ fmt.Printf("\x1b[%dD", n)
+}
+
+// HorizontalAbsolute moves the cursor to n horizontally.
+// The position n is absolute to the start of the line.
+func HorizontalAbsolute(n int) {
+ n += 1 // Moves the line to the character after n
+ fmt.Printf("\x1b[%dG", n)
+}
+
+// Show the cursor if it was hidden previously.
+// Don't forget to show the cursor at least at the end of your application.
+// Otherwise the user might have a terminal with a permanently hidden cursor, until he reopens the terminal.
+func Show() {
+ fmt.Print("\x1b[?25h")
+}
+
+// Hide the cursor.
+// Don't forget to show the cursor at least at the end of your application with Show.
+// Otherwise the user might have a terminal with a permanently hidden cursor, until he reopens the terminal.
+func Hide() {
+ fmt.Print("\x1b[?25l")
+}
+
+// ClearLine clears the current line and moves the cursor to it's start position.
+func ClearLine() {
+ fmt.Print("\x1b[2K")
+}
diff --git a/vendor/github.com/atomicgo/cursor/cursor_windows.go b/vendor/github.com/atomicgo/cursor/cursor_windows.go
new file mode 100644
index 0000000..35a5f77
--- /dev/null
+++ b/vendor/github.com/atomicgo/cursor/cursor_windows.go
@@ -0,0 +1,105 @@
+package cursor
+
+import (
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+// Up moves the cursor n lines up relative to the current position.
+func Up(n int) {
+ move(0, -n)
+ height += n
+}
+
+// Down moves the cursor n lines down relative to the current position.
+func Down(n int) {
+ move(0, n)
+ if height-n <= 0 {
+ height = 0
+ } else {
+ height -= n
+ }
+}
+
+// Right moves the cursor n characters to the right relative to the current position.
+func Right(n int) {
+ move(n, 0)
+}
+
+// Left moves the cursor n characters to the left relative to the current position.
+func Left(n int) {
+ move(-n, 0)
+}
+
+func move(x int, y int) {
+ handle := syscall.Handle(os.Stdout.Fd())
+
+ var csbi consoleScreenBufferInfo
+ _, _, _ = procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+
+ var cursor coord
+ cursor.x = csbi.cursorPosition.x + short(x)
+ cursor.y = csbi.cursorPosition.y + short(y)
+
+ _, _, _ = procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursor))))
+}
+
+// HorizontalAbsolute moves the cursor to n horizontally.
+// The position n is absolute to the start of the line.
+func HorizontalAbsolute(n int) {
+ handle := syscall.Handle(os.Stdout.Fd())
+
+ var csbi consoleScreenBufferInfo
+ _, _, _ = procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+
+ var cursor coord
+ cursor.x = short(n)
+ cursor.y = csbi.cursorPosition.y
+
+ if csbi.size.x < cursor.x {
+ cursor.x = csbi.size.x
+ }
+
+ _, _, _ = procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursor))))
+}
+
+// Show the cursor if it was hidden previously.
+// Don't forget to show the cursor at least at the end of your application.
+// Otherwise the user might have a terminal with a permanently hidden cursor, until he reopens the terminal.
+func Show() {
+ handle := syscall.Handle(os.Stdout.Fd())
+
+ var cci consoleCursorInfo
+ _, _, _ = procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci)))
+ cci.visible = 1
+
+ _, _, _ = procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci)))
+}
+
+// Hide the cursor.
+// Don't forget to show the cursor at least at the end of your application with Show.
+// Otherwise the user might have a terminal with a permanently hidden cursor, until he reopens the terminal.
+func Hide() {
+ handle := syscall.Handle(os.Stdout.Fd())
+
+ var cci consoleCursorInfo
+ _, _, _ = procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci)))
+ cci.visible = 0
+
+ _, _, _ = procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci)))
+}
+
+// ClearLine clears the current line and moves the cursor to it's start position.
+func ClearLine() {
+ handle := syscall.Handle(os.Stdout.Fd())
+
+ var csbi consoleScreenBufferInfo
+ _, _, _ = procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+
+ var w uint32
+ var x short
+ cursor := csbi.cursorPosition
+ x = csbi.size.x
+ _, _, _ = procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(x), uintptr(*(*int32)(unsafe.Pointer(&cursor))), uintptr(unsafe.Pointer(&w)))
+}
diff --git a/vendor/github.com/atomicgo/cursor/doc.go b/vendor/github.com/atomicgo/cursor/doc.go
new file mode 100644
index 0000000..444326d
--- /dev/null
+++ b/vendor/github.com/atomicgo/cursor/doc.go
@@ -0,0 +1,7 @@
+/*
+Package cursor contains cross-platform methods to move the terminal cursor in different directions.
+This package can be used to create interactive CLI tools and games, live charts, algorithm visualizations and other updatable output of any kind.
+
+Special thanks to github.com/k0kubun/go-ansi which this project is based on.
+*/
+package cursor
diff --git a/vendor/github.com/atomicgo/cursor/go.mod b/vendor/github.com/atomicgo/cursor/go.mod
new file mode 100644
index 0000000..8d34575
--- /dev/null
+++ b/vendor/github.com/atomicgo/cursor/go.mod
@@ -0,0 +1,3 @@
+module github.com/atomicgo/cursor
+
+go 1.15
diff --git a/vendor/github.com/atomicgo/cursor/go.sum b/vendor/github.com/atomicgo/cursor/go.sum
new file mode 100644
index 0000000..e69de29
diff --git a/vendor/github.com/atomicgo/cursor/syscall_windows.go b/vendor/github.com/atomicgo/cursor/syscall_windows.go
new file mode 100644
index 0000000..d4bcdf7
--- /dev/null
+++ b/vendor/github.com/atomicgo/cursor/syscall_windows.go
@@ -0,0 +1,43 @@
+package cursor
+
+import (
+ "syscall"
+)
+
+var (
+ kernel32 = syscall.NewLazyDLL("kernel32.dll")
+ procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
+ procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo")
+ procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
+ procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo")
+ procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
+)
+
+type short int16
+type dword uint32
+type word uint16
+
+type coord struct {
+ x short
+ y short
+}
+
+type smallRect struct {
+ bottom short
+ left short
+ right short
+ top short
+}
+
+type consoleScreenBufferInfo struct {
+ size coord
+ cursorPosition coord
+ attributes word
+ window smallRect
+ maximumWindowSize coord
+}
+
+type consoleCursorInfo struct {
+ size dword
+ visible int32
+}
diff --git a/vendor/github.com/atomicgo/cursor/utils.go b/vendor/github.com/atomicgo/cursor/utils.go
new file mode 100644
index 0000000..819b05f
--- /dev/null
+++ b/vendor/github.com/atomicgo/cursor/utils.go
@@ -0,0 +1,73 @@
+package cursor
+
+var height int
+
+// Bottom moves the cursor to the bottom of the terminal.
+// This is done by calculating how many lines were moved by Up and Down.
+func Bottom() {
+ if height > 0 {
+ Down(height)
+ StartOfLine()
+ height = 0
+ }
+}
+
+// StartOfLine moves the cursor to the start of the current line.
+func StartOfLine() {
+ HorizontalAbsolute(0)
+}
+
+// StartOfLineDown moves the cursor down by n lines, then moves to cursor to the start of the line.
+func StartOfLineDown(n int) {
+ Down(n)
+ StartOfLine()
+}
+
+// StartOfLineUp moves the cursor up by n lines, then moves to cursor to the start of the line.
+func StartOfLineUp(n int) {
+ Up(n)
+ StartOfLine()
+}
+
+// UpAndClear moves the cursor up by n lines, then clears the line.
+func UpAndClear(n int) {
+ Up(n)
+ ClearLine()
+}
+
+// DownAndClear moves the cursor down by n lines, then clears the line.
+func DownAndClear(n int) {
+ Down(n)
+ ClearLine()
+}
+
+// Move moves the cursor relative by x and y.
+func Move(x, y int) {
+ if x > 0 {
+ Right(x)
+ } else if x < 0 {
+ x *= -1
+ Left(x)
+ }
+
+ if y > 0 {
+ Up(y)
+ } else if y < 0 {
+ y *= -1
+ Down(y)
+ }
+}
+
+// ClearLinesUp clears n lines upwards from the current position and moves the cursor.
+func ClearLinesUp(n int) {
+ for i := 0; i < n; i++ {
+ UpAndClear(1)
+ }
+}
+
+// ClearLinesDown clears n lines downwards from the current position and moves the cursor.
+func ClearLinesDown(n int) {
+ for i := 0; i < n; i++ {
+ DownAndClear(1)
+ }
+}
diff --git a/vendor/github.com/cpuguy83/go-md2man/v2/LICENSE.md b/vendor/github.com/cpuguy83/go-md2man/v2/LICENSE.md
new file mode 100644
index 0000000..1cade6c
--- /dev/null
+++ b/vendor/github.com/cpuguy83/go-md2man/v2/LICENSE.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Brian Goff
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go
new file mode 100644
index 0000000..b480056
--- /dev/null
+++ b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go
@@ -0,0 +1,14 @@
+package md2man
+
+import (
+ "github.com/russross/blackfriday/v2"
+)
+
+// Render converts a markdown document into a roff formatted document.
+func Render(doc []byte) []byte {
+ renderer := NewRoffRenderer()
+
+ return blackfriday.Run(doc,
+ []blackfriday.Option{blackfriday.WithRenderer(renderer),
+ blackfriday.WithExtensions(renderer.GetExtensions())}...)
+}
diff --git a/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go
new file mode 100644
index 0000000..0668a66
--- /dev/null
+++ b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go
@@ -0,0 +1,345 @@
+package md2man
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "strings"
+
+ "github.com/russross/blackfriday/v2"
+)
+
+// roffRenderer implements the blackfriday.Renderer interface for creating
+// roff format (manpages) from markdown text
+type roffRenderer struct {
+ extensions blackfriday.Extensions
+ listCounters []int
+ firstHeader bool
+ defineTerm bool
+ listDepth int
+}
+
+const (
+ titleHeader = ".TH "
+ topLevelHeader = "\n\n.SH "
+ secondLevelHdr = "\n.SH "
+ otherHeader = "\n.SS "
+ crTag = "\n"
+ emphTag = "\\fI"
+ emphCloseTag = "\\fP"
+ strongTag = "\\fB"
+ strongCloseTag = "\\fP"
+ breakTag = "\n.br\n"
+ paraTag = "\n.PP\n"
+ hruleTag = "\n.ti 0\n\\l'\\n(.lu'\n"
+ linkTag = "\n\\[la]"
+ linkCloseTag = "\\[ra]"
+ codespanTag = "\\fB\\fC"
+ codespanCloseTag = "\\fR"
+ codeTag = "\n.PP\n.RS\n\n.nf\n"
+ codeCloseTag = "\n.fi\n.RE\n"
+ quoteTag = "\n.PP\n.RS\n"
+ quoteCloseTag = "\n.RE\n"
+ listTag = "\n.RS\n"
+ listCloseTag = "\n.RE\n"
+ arglistTag = "\n.TP\n"
+ tableStart = "\n.TS\nallbox;\n"
+ tableEnd = ".TE\n"
+ tableCellStart = "T{\n"
+ tableCellEnd = "\nT}\n"
+)
+
+// NewRoffRenderer creates a new blackfriday Renderer for generating roff documents
+// from markdown
+func NewRoffRenderer() *roffRenderer { // nolint: golint
+ var extensions blackfriday.Extensions
+
+ extensions |= blackfriday.NoIntraEmphasis
+ extensions |= blackfriday.Tables
+ extensions |= blackfriday.FencedCode
+ extensions |= blackfriday.SpaceHeadings
+ extensions |= blackfriday.Footnotes
+ extensions |= blackfriday.Titleblock
+ extensions |= blackfriday.DefinitionLists
+ return &roffRenderer{
+ extensions: extensions,
+ }
+}
+
+// GetExtensions returns the list of extensions used by this renderer implementation
+func (r *roffRenderer) GetExtensions() blackfriday.Extensions {
+ return r.extensions
+}
+
+// RenderHeader handles outputting the header at document start
+func (r *roffRenderer) RenderHeader(w io.Writer, ast *blackfriday.Node) {
+ // disable hyphenation
+ out(w, ".nh\n")
+}
+
+// RenderFooter handles outputting the footer at the document end; the roff
+// renderer has no footer information
+func (r *roffRenderer) RenderFooter(w io.Writer, ast *blackfriday.Node) {
+}
+
+// RenderNode is called for each node in a markdown document; based on the node
+// type the equivalent roff output is sent to the writer
+func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering bool) blackfriday.WalkStatus {
+
+ var walkAction = blackfriday.GoToNext
+
+ switch node.Type {
+ case blackfriday.Text:
+ r.handleText(w, node, entering)
+ case blackfriday.Softbreak:
+ out(w, crTag)
+ case blackfriday.Hardbreak:
+ out(w, breakTag)
+ case blackfriday.Emph:
+ if entering {
+ out(w, emphTag)
+ } else {
+ out(w, emphCloseTag)
+ }
+ case blackfriday.Strong:
+ if entering {
+ out(w, strongTag)
+ } else {
+ out(w, strongCloseTag)
+ }
+ case blackfriday.Link:
+ if !entering {
+ out(w, linkTag+string(node.LinkData.Destination)+linkCloseTag)
+ }
+ case blackfriday.Image:
+ // ignore images
+ walkAction = blackfriday.SkipChildren
+ case blackfriday.Code:
+ out(w, codespanTag)
+ escapeSpecialChars(w, node.Literal)
+ out(w, codespanCloseTag)
+ case blackfriday.Document:
+ break
+ case blackfriday.Paragraph:
+ // roff .PP markers break lists
+ if r.listDepth > 0 {
+ return blackfriday.GoToNext
+ }
+ if entering {
+ out(w, paraTag)
+ } else {
+ out(w, crTag)
+ }
+ case blackfriday.BlockQuote:
+ if entering {
+ out(w, quoteTag)
+ } else {
+ out(w, quoteCloseTag)
+ }
+ case blackfriday.Heading:
+ r.handleHeading(w, node, entering)
+ case blackfriday.HorizontalRule:
+ out(w, hruleTag)
+ case blackfriday.List:
+ r.handleList(w, node, entering)
+ case blackfriday.Item:
+ r.handleItem(w, node, entering)
+ case blackfriday.CodeBlock:
+ out(w, codeTag)
+ escapeSpecialChars(w, node.Literal)
+ out(w, codeCloseTag)
+ case blackfriday.Table:
+ r.handleTable(w, node, entering)
+ case blackfriday.TableCell:
+ r.handleTableCell(w, node, entering)
+ case blackfriday.TableHead:
+ case blackfriday.TableBody:
+ case blackfriday.TableRow:
+ // no action as cell entries do all the nroff formatting
+ return blackfriday.GoToNext
+ default:
+ fmt.Fprintln(os.Stderr, "WARNING: go-md2man does not handle node type "+node.Type.String())
+ }
+ return walkAction
+}
+
+func (r *roffRenderer) handleText(w io.Writer, node *blackfriday.Node, entering bool) {
+ var (
+ start, end string
+ )
+ // handle special roff table cell text encapsulation
+ if node.Parent.Type == blackfriday.TableCell {
+ if len(node.Literal) > 30 {
+ start = tableCellStart
+ end = tableCellEnd
+ } else {
+ // end rows that aren't terminated by "tableCellEnd" with a cr if end of row
+ if node.Parent.Next == nil && !node.Parent.IsHeader {
+ end = crTag
+ }
+ }
+ }
+ out(w, start)
+ escapeSpecialChars(w, node.Literal)
+ out(w, end)
+}
+
+func (r *roffRenderer) handleHeading(w io.Writer, node *blackfriday.Node, entering bool) {
+ if entering {
+ switch node.Level {
+ case 1:
+ if !r.firstHeader {
+ out(w, titleHeader)
+ r.firstHeader = true
+ break
+ }
+ out(w, topLevelHeader)
+ case 2:
+ out(w, secondLevelHdr)
+ default:
+ out(w, otherHeader)
+ }
+ }
+}
+
+func (r *roffRenderer) handleList(w io.Writer, node *blackfriday.Node, entering bool) {
+ openTag := listTag
+ closeTag := listCloseTag
+ if node.ListFlags&blackfriday.ListTypeDefinition != 0 {
+ // tags for definition lists handled within Item node
+ openTag = ""
+ closeTag = ""
+ }
+ if entering {
+ r.listDepth++
+ if node.ListFlags&blackfriday.ListTypeOrdered != 0 {
+ r.listCounters = append(r.listCounters, 1)
+ }
+ out(w, openTag)
+ } else {
+ if node.ListFlags&blackfriday.ListTypeOrdered != 0 {
+ r.listCounters = r.listCounters[:len(r.listCounters)-1]
+ }
+ out(w, closeTag)
+ r.listDepth--
+ }
+}
+
+func (r *roffRenderer) handleItem(w io.Writer, node *blackfriday.Node, entering bool) {
+ if entering {
+ if node.ListFlags&blackfriday.ListTypeOrdered != 0 {
+ out(w, fmt.Sprintf(".IP \"%3d.\" 5\n", r.listCounters[len(r.listCounters)-1]))
+ r.listCounters[len(r.listCounters)-1]++
+ } else if node.ListFlags&blackfriday.ListTypeDefinition != 0 {
+ // state machine for handling terms and following definitions
+ // since blackfriday does not distinguish them properly, nor
+ // does it seperate them into separate lists as it should
+ if !r.defineTerm {
+ out(w, arglistTag)
+ r.defineTerm = true
+ } else {
+ r.defineTerm = false
+ }
+ } else {
+ out(w, ".IP \\(bu 2\n")
+ }
+ } else {
+ out(w, "\n")
+ }
+}
+
+func (r *roffRenderer) handleTable(w io.Writer, node *blackfriday.Node, entering bool) {
+ if entering {
+ out(w, tableStart)
+ //call walker to count cells (and rows?) so format section can be produced
+ columns := countColumns(node)
+ out(w, strings.Repeat("l ", columns)+"\n")
+ out(w, strings.Repeat("l ", columns)+".\n")
+ } else {
+ out(w, tableEnd)
+ }
+}
+
+func (r *roffRenderer) handleTableCell(w io.Writer, node *blackfriday.Node, entering bool) {
+ var (
+ start, end string
+ )
+ if node.IsHeader {
+ start = codespanTag
+ end = codespanCloseTag
+ }
+ if entering {
+ if node.Prev != nil && node.Prev.Type == blackfriday.TableCell {
+ out(w, "\t"+start)
+ } else {
+ out(w, start)
+ }
+ } else {
+ // need to carriage return if we are at the end of the header row
+ if node.IsHeader && node.Next == nil {
+ end = end + crTag
+ }
+ out(w, end)
+ }
+}
+
+// because roff format requires knowing the column count before outputting any table
+// data we need to walk a table tree and count the columns
+func countColumns(node *blackfriday.Node) int {
+ var columns int
+
+ node.Walk(func(node *blackfriday.Node, entering bool) blackfriday.WalkStatus {
+ switch node.Type {
+ case blackfriday.TableRow:
+ if !entering {
+ return blackfriday.Terminate
+ }
+ case blackfriday.TableCell:
+ if entering {
+ columns++
+ }
+ default:
+ }
+ return blackfriday.GoToNext
+ })
+ return columns
+}
+
+func out(w io.Writer, output string) {
+ io.WriteString(w, output) // nolint: errcheck
+}
+
+func needsBackslash(c byte) bool {
+ for _, r := range []byte("-_&\\~") {
+ if c == r {
+ return true
+ }
+ }
+ return false
+}
+
+func escapeSpecialChars(w io.Writer, text []byte) {
+ for i := 0; i < len(text); i++ {
+ // escape initial apostrophe or period
+ if len(text) >= 1 && (text[0] == '\'' || text[0] == '.') {
+ out(w, "\\&")
+ }
+
+ // directly copy normal characters
+ org := i
+
+ for i < len(text) && !needsBackslash(text[i]) {
+ i++
+ }
+ if i > org {
+ w.Write(text[org:i]) // nolint: errcheck
+ }
+
+ // escape a character
+ if i >= len(text) {
+ break
+ }
+
+ w.Write([]byte{'\\', text[i]}) // nolint: errcheck
+ }
+}
diff --git a/vendor/github.com/gookit/color/.gitignore b/vendor/github.com/gookit/color/.gitignore
new file mode 100644
index 0000000..5efa5e3
--- /dev/null
+++ b/vendor/github.com/gookit/color/.gitignore
@@ -0,0 +1,20 @@
+*.log
+*.swp
+.idea
+*.patch
+### Go template
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, build with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+.DS_Store
+app
+demo
diff --git a/vendor/github.com/gookit/color/LICENSE b/vendor/github.com/gookit/color/LICENSE
new file mode 100644
index 0000000..d839cdc
--- /dev/null
+++ b/vendor/github.com/gookit/color/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 inhere
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/vendor/github.com/gookit/color/README.md b/vendor/github.com/gookit/color/README.md
new file mode 100644
index 0000000..134181d
--- /dev/null
+++ b/vendor/github.com/gookit/color/README.md
@@ -0,0 +1,468 @@
+# CLI Color
+
+![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/gookit/color?style=flat-square)
+[![Actions Status](https://github.com/gookit/color/workflows/action-tests/badge.svg)](https://github.com/gookit/color/actions)
+[![Codacy Badge](https://api.codacy.com/project/badge/Grade/51b28c5f7ffe4cc2b0f12ecf25ed247f)](https://app.codacy.com/app/inhere/color)
+[![GoDoc](https://godoc.org/github.com/gookit/color?status.svg)](https://pkg.go.dev/github.com/gookit/color?tab=overview)
+[![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/gookit/color)](https://github.com/gookit/color)
+[![Build Status](https://travis-ci.org/gookit/color.svg?branch=master)](https://travis-ci.org/gookit/color)
+[![Coverage Status](https://coveralls.io/repos/github/gookit/color/badge.svg?branch=master)](https://coveralls.io/github/gookit/color?branch=master)
+[![Go Report Card](https://goreportcard.com/badge/github.com/gookit/color)](https://goreportcard.com/report/github.com/gookit/color)
+
+A command-line color library with true color support, universal API methods and Windows support.
+
+> **[中文说明](README.zh-CN.md)**
+
+Basic color preview:
+
+![basic-color](_examples/images/basic-color2.png)
+
+Now, 256 colors and RGB colors have also been supported to work in Windows CMD and PowerShell:
+
+![color-on-cmd-pwsh](_examples/images/color-on-cmd-pwsh.jpg)
+
+## Features
+
+ - Simple to use, zero dependencies
+ - Supports rich color output: 16-color (4-bit), 256-color (8-bit), true color (24-bit, RGB)
+ - 16-color output is the most commonly used and most widely supported, working on any Windows version
+ - Since `v1.2.4` **the 256-color (8-bit), true color (24-bit) support windows CMD and PowerShell**
+ - See [this gist](https://gist.github.com/XVilka/8346728) for information on true color support
+ - Generic API methods: `Print`, `Printf`, `Println`, `Sprint`, `Sprintf`
+ - Supports HTML tag-style color rendering, such as `message>`.
+ - In addition to using built-in tags, it also supports custom color attributes
+ - Custom color attributes support the use of 16 color names, 256 color values, rgb color values and hex color values
+ - Support working on Windows `cmd` and `powerShell` terminal
+ - Basic colors: `Bold`, `Black`, `White`, `Gray`, `Red`, `Green`, `Yellow`, `Blue`, `Magenta`, `Cyan`
+ - Additional styles: `Info`, `Note`, `Light`, `Error`, `Danger`, `Notice`, `Success`, `Comment`, `Primary`, `Warning`, `Question`, `Secondary`
+ - Support by set `NO_COLOR` for disable color or use `FORCE_COLOR` for force open color render.
+ - Support Rgb, 256, 16 color conversion
+
+## GoDoc
+
+ - [godoc for gopkg](https://pkg.go.dev/gopkg.in/gookit/color.v1)
+ - [godoc for github](https://pkg.go.dev/github.com/gookit/color)
+
+## Install
+
+```bash
+go get github.com/gookit/color
+```
+
+## Quick start
+
+```go
+package main
+
+import (
+ "fmt"
+
+ "github.com/gookit/color"
+)
+
+func main() {
+ // quick use package func
+ color.Redp("Simple to use color")
+ color.Redln("Simple to use color")
+ color.Greenp("Simple to use color\n")
+ color.Cyanln("Simple to use color")
+ color.Yellowln("Simple to use color")
+
+ // quick use like fmt.Print*
+ color.Red.Println("Simple to use color")
+ color.Green.Print("Simple to use color\n")
+ color.Cyan.Printf("Simple to use %s\n", "color")
+ color.Yellow.Printf("Simple to use %s\n", "color")
+
+ // use like func
+ red := color.FgRed.Render
+ green := color.FgGreen.Render
+ fmt.Printf("%s line %s library\n", red("Command"), green("color"))
+
+ // custom color
+ color.New(color.FgWhite, color.BgBlack).Println("custom color style")
+
+ // can also:
+ color.Style{color.FgCyan, color.OpBold}.Println("custom color style")
+
+ // internal theme/style:
+ color.Info.Tips("message")
+ color.Info.Prompt("message")
+ color.Info.Println("message")
+ color.Warn.Println("message")
+ color.Error.Println("message")
+
+ // use style tag
+ color.Print("he>llo>, wel>come>\n")
+ // Custom label attr: Supports the use of 16 color names, 256 color values, rgb color values and hex color values
+ color.Println("he>llo>, wel>come>")
+
+ // apply a style tag
+ color.Tag("info").Println("info style text")
+
+ // prompt message
+ color.Info.Prompt("prompt style message")
+ color.Warn.Prompt("prompt style message")
+
+ // tips message
+ color.Info.Tips("tips style message")
+ color.Warn.Tips("tips style message")
+}
+```
+
+Run demo: `go run ./_examples/demo.go`
+
+![colored-out](_examples/images/color-demo.jpg)
+
+## Basic/16 color
+
+Supported on any Windows version. Provide generic API methods: `Print`, `Printf`, `Println`, `Sprint`, `Sprintf`
+
+```go
+color.Bold.Println("bold message")
+color.Black.Println("bold message")
+color.White.Println("bold message")
+color.Gray.Println("bold message")
+color.Red.Println("yellow message")
+color.Blue.Println("yellow message")
+color.Cyan.Println("yellow message")
+color.Yellow.Println("yellow message")
+color.Magenta.Println("yellow message")
+
+// Only use foreground color
+color.FgCyan.Printf("Simple to use %s\n", "color")
+// Only use background color
+color.BgRed.Printf("Simple to use %s\n", "color")
+```
+
+Run demo: `go run ./_examples/color_16.go`
+
+![basic-color](_examples/images/basic-color.png)
+
+### Custom build color
+
+```go
+// Full custom: foreground, background, option
+myStyle := color.New(color.FgWhite, color.BgBlack, color.OpBold)
+myStyle.Println("custom color style")
+
+// can also:
+color.Style{color.FgCyan, color.OpBold}.Println("custom color style")
+```
+
+custom set console settings:
+
+```go
+// set console color
+color.Set(color.FgCyan)
+
+// print message
+fmt.Print("message")
+
+// reset console settings
+color.Reset()
+```
+
+### Additional styles
+
+provide generic API methods: `Print`, `Printf`, `Println`, `Sprint`, `Sprintf`
+
+print message use defined style:
+
+```go
+color.Info.Println("Info message")
+color.Note.Println("Note message")
+color.Notice.Println("Notice message")
+color.Error.Println("Error message")
+color.Danger.Println("Danger message")
+color.Warn.Println("Warn message")
+color.Debug.Println("Debug message")
+color.Primary.Println("Primary message")
+color.Question.Println("Question message")
+color.Secondary.Println("Secondary message")
+```
+
+Run demo: `go run ./_examples/theme_basic.go`
+
+![theme-basic](_examples/images/theme-basic.png)
+
+**Tips style**
+
+```go
+color.Info.Tips("Info tips message")
+color.Note.Tips("Note tips message")
+color.Notice.Tips("Notice tips message")
+color.Error.Tips("Error tips message")
+color.Danger.Tips("Danger tips message")
+color.Warn.Tips("Warn tips message")
+color.Debug.Tips("Debug tips message")
+color.Primary.Tips("Primary tips message")
+color.Question.Tips("Question tips message")
+color.Secondary.Tips("Secondary tips message")
+```
+
+Run demo: `go run ./_examples/theme_tips.go`
+
+![theme-tips](_examples/images/theme-tips.png)
+
+**Prompt Style**
+
+```go
+color.Info.Prompt("Info prompt message")
+color.Note.Prompt("Note prompt message")
+color.Notice.Prompt("Notice prompt message")
+color.Error.Prompt("Error prompt message")
+color.Danger.Prompt("Danger prompt message")
+color.Warn.Prompt("Warn prompt message")
+color.Debug.Prompt("Debug prompt message")
+color.Primary.Prompt("Primary prompt message")
+color.Question.Prompt("Question prompt message")
+color.Secondary.Prompt("Secondary prompt message")
+```
+
+Run demo: `go run ./_examples/theme_prompt.go`
+
+![theme-prompt](_examples/images/theme-prompt.png)
+
+**Block Style**
+
+```go
+color.Info.Block("Info block message")
+color.Note.Block("Note block message")
+color.Notice.Block("Notice block message")
+color.Error.Block("Error block message")
+color.Danger.Block("Danger block message")
+color.Warn.Block("Warn block message")
+color.Debug.Block("Debug block message")
+color.Primary.Block("Primary block message")
+color.Question.Block("Question block message")
+color.Secondary.Block("Secondary block message")
+```
+
+Run demo: `go run ./_examples/theme_block.go`
+
+![theme-block](_examples/images/theme-block.png)
+
+## 256-color usage
+
+> 256 colors support Windows CMD, PowerShell environment after `v1.2.4`
+
+### Set the foreground or background color
+
+- `color.C256(val uint8, isBg ...bool) Color256`
+
+```go
+c := color.C256(132) // fg color
+c.Println("message")
+c.Printf("format %s", "message")
+
+c := color.C256(132, true) // bg color
+c.Println("message")
+c.Printf("format %s", "message")
+```
+
+### 256-color style
+
+Can be used to set foreground and background colors at the same time.
+
+- `S256(fgAndBg ...uint8) *Style256`
+
+```go
+s := color.S256(32, 203)
+s.Println("message")
+s.Printf("format %s", "message")
+```
+
+with options:
+
+```go
+s := color.S256(32, 203)
+s.SetOpts(color.Opts{color.OpBold})
+
+s.Println("style with options")
+s.Printf("style with %s\n", "options")
+```
+
+Run demo: `go run ./_examples/color_256.go`
+
+![color-tags](_examples/images/color-256.png)
+
+## RGB/True color
+
+> RGB colors support Windows `CMD`, `PowerShell` environment after `v1.2.4`
+
+**Preview:**
+
+> Run demo: `Run demo: go run ./_examples/color_rgb.go`
+
+![color-rgb](_examples/images/color-rgb.png)
+
+example:
+
+```go
+color.RGB(30, 144, 255).Println("message. use RGB number")
+
+color.HEX("#1976D2").Println("blue-darken")
+color.HEX("#D50000", true).Println("red-accent. use HEX style")
+
+color.RGBStyleFromString("213,0,0").Println("red-accent. use RGB number")
+color.HEXStyle("eee", "D50000").Println("deep-purple color")
+```
+
+### Set the foreground or background color
+
+- `color.RGB(r, g, b uint8, isBg ...bool) RGBColor`
+
+```go
+c := color.RGB(30,144,255) // fg color
+c.Println("message")
+c.Printf("format %s", "message")
+
+c := color.RGB(30,144,255, true) // bg color
+c.Println("message")
+c.Printf("format %s", "message")
+```
+
+Create a style from an hexadecimal color string:
+
+- `color.HEX(hex string, isBg ...bool) RGBColor`
+
+```go
+c := color.HEX("ccc") // can also: "cccccc" "#cccccc"
+c.Println("message")
+c.Printf("format %s", "message")
+
+c = color.HEX("aabbcc", true) // as bg color
+c.Println("message")
+c.Printf("format %s", "message")
+```
+
+### RGB color style
+
+Can be used to set the foreground and background colors at the same time.
+
+- `color.NewRGBStyle(fg RGBColor, bg ...RGBColor) *RGBStyle`
+
+```go
+s := color.NewRGBStyle(RGB(20, 144, 234), RGB(234, 78, 23))
+s.Println("message")
+s.Printf("format %s", "message")
+```
+
+Create a style from an hexadecimal color string:
+
+- `color.HEXStyle(fg string, bg ...string) *RGBStyle`
+
+```go
+s := color.HEXStyle("11aa23", "eee")
+s.Println("message")
+s.Printf("format %s", "message")
+```
+
+with options:
+
+```go
+s := color.HEXStyle("11aa23", "eee")
+s.SetOpts(color.Opts{color.OpBold})
+
+s.Println("style with options")
+s.Printf("style with %s\n", "options")
+```
+
+## HTML-like tag usage
+
+**Supported** on Windows `cmd.exe` `PowerShell` .
+
+```go
+// use style tag
+color.Print("he>llo>, wel>come>")
+color.Println("hello>")
+color.Println("hello>")
+color.Println("hello>")
+
+// custom color attributes
+color.Print("hello, welcome>\n")
+
+// Custom label attr: Supports the use of 16 color names, 256 color values, rgb color values and hex color values
+color.Println("he>llo>, wel>come>")
+```
+
+- `color.Tag`
+
+```go
+// set a style tag
+color.Tag("info").Print("info style text")
+color.Tag("info").Printf("%s style text", "info")
+color.Tag("info").Println("info style text")
+```
+
+Run demo: `go run ./_examples/color_tag.go`
+
+![color-tags](_examples/images/color-tags.png)
+
+## Color convert
+
+Supports conversion between Rgb, 256, 16 colors, `Rgb <=> 256 <=> 16`
+
+```go
+basic := color.Red
+basic.Println("basic color")
+
+c256 := color.Red.C256()
+c256.Println("256 color")
+c256.C16().Println("basic color")
+
+rgb := color.Red.RGB()
+rgb.Println("rgb color")
+rgb.C256().Println("256 color")
+```
+
+## Func refer
+
+There are some useful functions reference
+
+- `Disable()` disable color render
+- `SetOutput(io.Writer)` custom set the colored text output writer
+- `ForceOpenColor()` force open color render
+- `Colors2code(colors ...Color) string` Convert colors to code. return like "32;45;3"
+- `ClearCode(str string) string` Use for clear color codes
+- `ClearTag(s string) string` clear all color html-tag for a string
+- `IsConsole(w io.Writer)` Determine whether w is one of stderr, stdout, stdin
+- `HexToRgb(hex string) (rgb []int)` Convert hex color string to RGB numbers
+- `RgbToHex(rgb []int) string` Convert RGB to hex code
+- More useful func please see https://pkg.go.dev/github.com/gookit/color
+
+## Project use
+
+Check out these projects, which use https://github.com/gookit/color :
+
+- https://github.com/Delta456/box-cli-maker Make Highly Customized Boxes for your CLI
+
+## Gookit packages
+
+ - [gookit/ini](https://github.com/gookit/ini) Go config management, use INI files
+ - [gookit/rux](https://github.com/gookit/rux) Simple and fast request router for golang HTTP
+ - [gookit/gcli](https://github.com/gookit/gcli) build CLI application, tool library, running CLI commands
+ - [gookit/slog](https://github.com/gookit/slog) Concise and extensible go log library
+ - [gookit/event](https://github.com/gookit/event) Lightweight event manager and dispatcher implements by Go
+ - [gookit/cache](https://github.com/gookit/cache) Generic cache use and cache manager for golang. support File, Memory, Redis, Memcached.
+ - [gookit/config](https://github.com/gookit/config) Go config management. support JSON, YAML, TOML, INI, HCL, ENV and Flags
+ - [gookit/color](https://github.com/gookit/color) A command-line color library with true color support, universal API methods and Windows support
+ - [gookit/filter](https://github.com/gookit/filter) Provide filtering, sanitizing, and conversion of golang data
+ - [gookit/validate](https://github.com/gookit/validate) Use for data validation and filtering. support Map, Struct, Form data
+ - [gookit/goutil](https://github.com/gookit/goutil) Some utils for the Go: string, array/slice, map, format, cli, env, filesystem, test and more
+ - More, please see https://github.com/gookit
+
+## See also
+
+ - [inhere/console](https://github.com/inhere/php-console)
+ - [xo/terminfo](https://github.com/xo/terminfo)
+ - [beego/bee](https://github.com/beego/bee)
+ - [issue9/term](https://github.com/issue9/term)
+ - [ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code)
+ - [Standard ANSI color map](https://conemu.github.io/en/AnsiEscapeCodes.html#Standard_ANSI_color_map)
+ - [Terminal Colors](https://gist.github.com/XVilka/8346728)
+
+## License
+
+[MIT](/LICENSE)
diff --git a/vendor/github.com/gookit/color/README.zh-CN.md b/vendor/github.com/gookit/color/README.zh-CN.md
new file mode 100644
index 0000000..dee1458
--- /dev/null
+++ b/vendor/github.com/gookit/color/README.zh-CN.md
@@ -0,0 +1,472 @@
+# CLI Color
+
+![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/gookit/color?style=flat-square)
+[![Actions Status](https://github.com/gookit/color/workflows/action-tests/badge.svg)](https://github.com/gookit/color/actions)
+[![Codacy Badge](https://api.codacy.com/project/badge/Grade/51b28c5f7ffe4cc2b0f12ecf25ed247f)](https://app.codacy.com/app/inhere/color)
+[![GoDoc](https://godoc.org/github.com/gookit/color?status.svg)](https://pkg.go.dev/github.com/gookit/color?tab=overview)
+[![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/gookit/color)](https://github.com/gookit/color)
+[![Build Status](https://travis-ci.org/gookit/color.svg?branch=master)](https://travis-ci.org/gookit/color)
+[![Coverage Status](https://coveralls.io/repos/github/gookit/color/badge.svg?branch=master)](https://coveralls.io/github/gookit/color?branch=master)
+[![Go Report Card](https://goreportcard.com/badge/github.com/gookit/color)](https://goreportcard.com/report/github.com/gookit/color)
+
+Golang下的命令行色彩使用库, 拥有丰富的色彩渲染输出,通用的API方法,兼容Windows系统
+
+> **[EN README](README.md)**
+
+基本颜色预览:
+
+![basic-color](_examples/images/basic-color2.png)
+
+现在,256色和RGB色彩也已经支持windows CMD和PowerShell中工作:
+
+![color-on-cmd-pwsh](_examples/images/color-on-cmd-pwsh.jpg)
+
+## 功能特色
+
+ - 使用简单方便
+ - 支持丰富的颜色输出, 16色(4bit),256色(8bit),RGB色彩(24bit, RGB)
+ - 16色(4bit)是最常用和支持最广的,支持Windows `cmd.exe`
+ - 自 `v1.2.4` 起 **256色(8bit),RGB色彩(24bit)均支持Windows CMD和PowerShell终端**
+ - 请查看 [this gist](https://gist.github.com/XVilka/8346728) 了解支持RGB色彩的终端
+ - 提供通用的API方法:`Print` `Printf` `Println` `Sprint` `Sprintf`
+ - 同时支持html标签式的颜色渲染,除了使用内置标签,同时支持自定义颜色属性
+ - 例如: `this an message>` 标签内部的文本将会渲染为绿色字体
+ - 自定义颜色属性: 支持使用16色彩名称,256色彩值,rgb色彩值以及hex色彩值
+ - 基础色彩: `Bold` `Black` `White` `Gray` `Red` `Green` `Yellow` `Blue` `Magenta` `Cyan`
+ - 扩展风格: `Info` `Note` `Light` `Error` `Danger` `Notice` `Success` `Comment` `Primary` `Warning` `Question` `Secondary`
+ - 支持通过设置环境变量 `NO_COLOR` 来禁用色彩,或者使用 `FORCE_COLOR` 来强制使用色彩渲染.
+ - 支持 Rgb, 256, 16 色彩之间的互相转换
+ - 支持Linux、Mac,同时兼容Windows系统环境
+
+## GoDoc
+
+ - [godoc for gopkg](https://pkg.go.dev/gopkg.in/gookit/color.v1)
+ - [godoc for github](https://pkg.go.dev/github.com/gookit/color)
+
+## 安装
+
+```bash
+go get github.com/gookit/color
+```
+
+## 快速开始
+
+如下,引入当前包就可以快速的使用
+
+```go
+package main
+
+import (
+ "fmt"
+
+ "github.com/gookit/color"
+)
+
+func main() {
+ // 简单快速的使用,跟 fmt.Print* 类似
+ color.Redp("Simple to use color")
+ color.Redln("Simple to use color")
+ color.Greenp("Simple to use color\n")
+ color.Cyanln("Simple to use color")
+ color.Yellowln("Simple to use color")
+
+ // 简单快速的使用,跟 fmt.Print* 类似
+ color.Red.Println("Simple to use color")
+ color.Green.Print("Simple to use color\n")
+ color.Cyan.Printf("Simple to use %s\n", "color")
+ color.Yellow.Printf("Simple to use %s\n", "color")
+
+ // use like func
+ red := color.FgRed.Render
+ green := color.FgGreen.Render
+ fmt.Printf("%s line %s library\n", red("Command"), green("color"))
+
+ // 自定义颜色
+ color.New(color.FgWhite, color.BgBlack).Println("custom color style")
+
+ // 也可以:
+ color.Style{color.FgCyan, color.OpBold}.Println("custom color style")
+
+ // internal style:
+ color.Info.Println("message")
+ color.Warn.Println("message")
+ color.Error.Println("message")
+
+ // 使用内置颜色标签
+ color.Print("he>llo>, wel>come>\n")
+ // 自定义标签: 支持使用16色彩名称,256色彩值,rgb色彩值以及hex色彩值
+ color.Println("he>llo>, wel>come>")
+
+ // apply a style tag
+ color.Tag("info").Println("info style text")
+
+ // prompt message
+ color.Info.Prompt("prompt style message")
+ color.Warn.Prompt("prompt style message")
+
+ // tips message
+ color.Info.Tips("tips style message")
+ color.Warn.Tips("tips style message")
+}
+```
+
+> 运行 demo: `go run ./_examples/demo.go`
+
+![colored-out](_examples/images/color-demo.jpg)
+
+## 基础颜色(16-color)
+
+提供通用的API方法:`Print` `Printf` `Println` `Sprint` `Sprintf`
+
+> 支持在windows `cmd.exe` `powerShell` 等终端使用
+
+```go
+color.Bold.Println("bold message")
+color.Black.Println("bold message")
+color.White.Println("bold message")
+color.Gray.Println("bold message")
+color.Red.Println("yellow message")
+color.Blue.Println("yellow message")
+color.Cyan.Println("yellow message")
+color.Yellow.Println("yellow message")
+color.Magenta.Println("yellow message")
+
+// Only use foreground color
+color.FgCyan.Printf("Simple to use %s\n", "color")
+// Only use background color
+color.BgRed.Printf("Simple to use %s\n", "color")
+```
+
+> 运行demo: `go run ./_examples/color_16.go`
+
+![basic-color](_examples/images/basic-color.png)
+
+### 构建风格
+
+```go
+// 仅设置前景色
+color.FgCyan.Printf("Simple to use %s\n", "color")
+// 仅设置背景色
+color.BgRed.Printf("Simple to use %s\n", "color")
+
+// 完全自定义: 前景色 背景色 选项
+style := color.New(color.FgWhite, color.BgBlack, color.OpBold)
+style.Println("custom color style")
+
+// 也可以:
+color.Style{color.FgCyan, color.OpBold}.Println("custom color style")
+```
+
+直接设置控制台属性:
+
+```go
+// 设置console颜色
+color.Set(color.FgCyan)
+
+// 输出信息
+fmt.Print("message")
+
+// 重置console颜色
+color.Reset()
+```
+
+> 当然,color已经内置丰富的色彩风格支持
+
+### 扩展风格方法
+
+提供通用的API方法:`Print` `Printf` `Println` `Sprint` `Sprintf`
+
+> 支持在windows `cmd.exe` `powerShell` 等终端使用
+
+基础使用:
+
+```go
+// print message
+color.Info.Println("Info message")
+color.Note.Println("Note message")
+color.Notice.Println("Notice message")
+color.Error.Println("Error message")
+color.Danger.Println("Danger message")
+color.Warn.Println("Warn message")
+color.Debug.Println("Debug message")
+color.Primary.Println("Primary message")
+color.Question.Println("Question message")
+color.Secondary.Println("Secondary message")
+```
+
+Run demo: `go run ./_examples/theme_basic.go`
+
+![theme-basic](_examples/images/theme-basic.png)
+
+**简约提示风格**
+
+```go
+color.Info.Tips("Info tips message")
+color.Note.Tips("Note tips message")
+color.Notice.Tips("Notice tips message")
+color.Error.Tips("Error tips message")
+color.Danger.Tips("Danger tips message")
+color.Warn.Tips("Warn tips message")
+color.Debug.Tips("Debug tips message")
+color.Primary.Tips("Primary tips message")
+color.Question.Tips("Question tips message")
+color.Secondary.Tips("Secondary tips message")
+```
+
+Run demo: `go run ./_examples/theme_tips.go`
+
+![theme-tips](_examples/images/theme-tips.png)
+
+**着重提示风格**
+
+```go
+color.Info.Prompt("Info prompt message")
+color.Note.Prompt("Note prompt message")
+color.Notice.Prompt("Notice prompt message")
+color.Error.Prompt("Error prompt message")
+color.Danger.Prompt("Danger prompt message")
+```
+
+Run demo: `go run ./_examples/theme_prompt.go`
+
+![theme-prompt](_examples/images/theme-prompt.png)
+
+**强调提示风格**
+
+```go
+color.Warn.Block("Warn block message")
+color.Debug.Block("Debug block message")
+color.Primary.Block("Primary block message")
+color.Question.Block("Question block message")
+color.Secondary.Block("Secondary block message")
+```
+
+Run demo: `go run ./_examples/theme_block.go`
+
+![theme-block](_examples/images/theme-block.png)
+
+## 256 色彩使用
+
+> 256色彩在 `v1.2.4` 后支持Windows CMD,PowerShell 环境
+
+### 使用前景或后景色
+
+ - `color.C256(val uint8, isBg ...bool) Color256`
+
+```go
+c := color.C256(132) // fg color
+c.Println("message")
+c.Printf("format %s", "message")
+
+c := color.C256(132, true) // bg color
+c.Println("message")
+c.Printf("format %s", "message")
+```
+
+### 使用256 色彩风格
+
+> 可同时设置前景和背景色
+
+- `color.S256(fgAndBg ...uint8) *Style256`
+
+```go
+s := color.S256(32, 203)
+s.Println("message")
+s.Printf("format %s", "message")
+```
+
+可以同时添加选项设置:
+
+```go
+s := color.S256(32, 203)
+s.SetOpts(color.Opts{color.OpBold})
+
+s.Println("style with options")
+s.Printf("style with %s\n", "options")
+```
+
+> 运行 demo: `go run ./_examples/color_256.go`
+
+![color-tags](_examples/images/color-256.png)
+
+## RGB/True色彩使用
+
+> RGB色彩在 `v1.2.4` 后支持 Windows `CMD`, `PowerShell` 环境
+
+**效果预览:**
+
+> 运行 demo: `Run demo: go run ./_examples/color_rgb.go`
+
+![color-rgb](_examples/images/color-rgb.png)
+
+代码示例:
+
+```go
+color.RGB(30, 144, 255).Println("message. use RGB number")
+
+color.HEX("#1976D2").Println("blue-darken")
+color.HEX("#D50000", true).Println("red-accent. use HEX style")
+
+color.RGBStyleFromString("213,0,0").Println("red-accent. use RGB number")
+color.HEXStyle("eee", "D50000").Println("deep-purple color")
+```
+
+### 使用前景或后景色
+
+- `color.RGB(r, g, b uint8, isBg ...bool) RGBColor`
+
+```go
+c := color.RGB(30,144,255) // fg color
+c.Println("message")
+c.Printf("format %s", "message")
+
+c := color.RGB(30,144,255, true) // bg color
+c.Println("message")
+c.Printf("format %s", "message")
+```
+
+- `color.HEX(hex string, isBg ...bool) RGBColor` 从16进制颜色创建
+
+```go
+c := color.HEX("ccc") // 也可以写为: "cccccc" "#cccccc"
+c.Println("message")
+c.Printf("format %s", "message")
+
+c = color.HEX("aabbcc", true) // as bg color
+c.Println("message")
+c.Printf("format %s", "message")
+```
+
+### 使用RGB风格
+
+> 可同时设置前景和背景色
+
+- `color.NewRGBStyle(fg RGBColor, bg ...RGBColor) *RGBStyle`
+
+```go
+s := color.NewRGBStyle(RGB(20, 144, 234), RGB(234, 78, 23))
+s.Println("message")
+s.Printf("format %s", "message")
+```
+
+- `color.HEXStyle(fg string, bg ...string) *RGBStyle` 从16进制颜色创建
+
+```go
+s := color.HEXStyle("11aa23", "eee")
+s.Println("message")
+s.Printf("format %s", "message")
+```
+
+- 可以同时添加选项设置:
+
+```go
+s := color.HEXStyle("11aa23", "eee")
+s.SetOpts(color.Opts{color.OpBold})
+
+s.Println("style with options")
+s.Printf("style with %s\n", "options")
+```
+
+## 使用颜色标签
+
+> **支持** 在windows `cmd.exe` `PowerShell` 使用
+
+使用内置的颜色标签,可以非常方便简单的构建自己需要的任何格式
+
+> 同时支持自定义颜色属性: 支持使用16色彩名称,256色彩值,rgb色彩值以及hex色彩值
+
+```go
+// 使用内置的 color tag
+color.Print("he>llo>, wel>come>")
+color.Println("hello>")
+color.Println("hello>")
+color.Println("hello>")
+
+// 自定义颜色属性
+color.Print("hello, welcome>\n")
+
+// 自定义颜色属性: 支持使用16色彩名称,256色彩值,rgb色彩值以及hex色彩值
+color.Println("he>llo>, wel>come>")
+```
+
+- 使用 `color.Tag`
+
+给后面输出的文本信息加上给定的颜色风格标签
+
+```go
+// set a style tag
+color.Tag("info").Print("info style text")
+color.Tag("info").Printf("%s style text", "info")
+color.Tag("info").Println("info style text")
+```
+
+> 运行 demo: `go run ./_examples/color_tag.go`
+
+![color-tags](_examples/images/color-tags.png)
+
+## 颜色转换
+
+支持 Rgb, 256, 16 色彩之间的互相转换 `Rgb <=> 256 <=> 16`
+
+```go
+basic := color.Red
+basic.Println("basic color")
+
+c256 := color.Red.C256()
+c256.Println("256 color")
+c256.C16().Println("basic color")
+
+rgb := color.Red.RGB()
+rgb.Println("rgb color")
+rgb.C256().Println("256 color")
+```
+
+## 方法参考
+
+一些有用的工具方法参考
+
+- `Disable()` disable color render
+- `SetOutput(io.Writer)` custom set the colored text output writer
+- `ForceOpenColor()` force open color render
+- `ClearCode(str string) string` Use for clear color codes
+- `Colors2code(colors ...Color) string` Convert colors to code. return like "32;45;3"
+- `ClearTag(s string) string` clear all color html-tag for a string
+- `IsConsole(w io.Writer)` Determine whether w is one of stderr, stdout, stdin
+- `HexToRgb(hex string) (rgb []int)` Convert hex color string to RGB numbers
+- `RgbToHex(rgb []int) string` Convert RGB to hex code
+- 更多请查看文档 https://pkg.go.dev/github.com/gookit/color
+
+## 使用color的项目
+
+看看这些使用了 https://github.com/gookit/color 的项目:
+
+- https://github.com/Delta456/box-cli-maker Make Highly Customized Boxes for your CLI
+
+## Gookit 工具包
+
+ - [gookit/ini](https://github.com/gookit/ini) INI配置读取管理,支持多文件加载,数据覆盖合并, 解析ENV变量, 解析变量引用
+ - [gookit/rux](https://github.com/gookit/rux) Simple and fast request router for golang HTTP
+ - [gookit/gcli](https://github.com/gookit/gcli) Go的命令行应用,工具库,运行CLI命令,支持命令行色彩,用户交互,进度显示,数据格式化显示
+ - [gookit/slog](https://github.com/gookit/slog) 简洁易扩展的go日志库
+ - [gookit/event](https://github.com/gookit/event) Go实现的轻量级的事件管理、调度程序库, 支持设置监听器的优先级, 支持对一组事件进行监听
+ - [gookit/cache](https://github.com/gookit/cache) 通用的缓存使用包装库,通过包装各种常用的驱动,来提供统一的使用API
+ - [gookit/config](https://github.com/gookit/config) Go应用配置管理,支持多种格式(JSON, YAML, TOML, INI, HCL, ENV, Flags),多文件加载,远程文件加载,数据合并
+ - [gookit/color](https://github.com/gookit/color) CLI 控制台颜色渲染工具库, 拥有简洁的使用API,支持16色,256色,RGB色彩渲染输出
+ - [gookit/filter](https://github.com/gookit/filter) 提供对Golang数据的过滤,净化,转换
+ - [gookit/validate](https://github.com/gookit/validate) Go通用的数据验证与过滤库,使用简单,内置大部分常用验证、过滤器
+ - [gookit/goutil](https://github.com/gookit/goutil) Go 的一些工具函数,格式化,特殊处理,常用信息获取等
+ - 更多请查看 https://github.com/gookit
+
+## 参考项目
+
+ - [inhere/console](https://github.com/inhere/php-console)
+ - [xo/terminfo](https://github.com/xo/terminfo)
+ - [beego/bee](https://github.com/beego/bee)
+ - [issue9/term](https://github.com/issue9/term)
+ - [ANSI转义序列](https://zh.wikipedia.org/wiki/ANSI转义序列)
+ - [Standard ANSI color map](https://conemu.github.io/en/AnsiEscapeCodes.html#Standard_ANSI_color_map)
+ - [Terminal Colors](https://gist.github.com/XVilka/8346728)
+
+## License
+
+MIT
diff --git a/vendor/github.com/gookit/color/color.go b/vendor/github.com/gookit/color/color.go
new file mode 100644
index 0000000..edb2a5d
--- /dev/null
+++ b/vendor/github.com/gookit/color/color.go
@@ -0,0 +1,238 @@
+/*
+Package color is Command line color library.
+Support rich color rendering output, universal API method, compatible with Windows system
+
+Source code and other details for the project are available at GitHub:
+
+ https://github.com/gookit/color
+
+More usage please see README and tests.
+*/
+package color
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "regexp"
+
+ "github.com/xo/terminfo"
+)
+
+// terminal color available level alias of the terminfo.ColorLevel*
+const (
+ LevelNo = terminfo.ColorLevelNone // not support color.
+ Level16 = terminfo.ColorLevelBasic // 3/4 bit color supported
+ Level256 = terminfo.ColorLevelHundreds // 8 bit color supported
+ LevelRgb = terminfo.ColorLevelMillions // (24 bit)true color supported
+)
+
+// color render templates
+// ESC 操作的表示:
+// "\033"(Octal 8进制) = "\x1b"(Hexadecimal 16进制) = 27 (10进制)
+const (
+ SettingTpl = "\x1b[%sm"
+ FullColorTpl = "\x1b[%sm%s\x1b[0m"
+)
+
+// ResetSet Close all properties.
+const ResetSet = "\x1b[0m"
+
+// CodeExpr regex to clear color codes eg "\033[1;36mText\x1b[0m"
+const CodeExpr = `\033\[[\d;?]+m`
+
+var (
+ // Enable switch color render and display
+ //
+ // NOTICE:
+ // if ENV: NO_COLOR is not empty, will disable color render.
+ Enable = os.Getenv("NO_COLOR") == ""
+ // RenderTag render HTML tag on call color.Xprint, color.PrintX
+ RenderTag = true
+ // debug mode for development.
+ //
+ // set env:
+ // COLOR_DEBUG_MODE=on
+ // or:
+ // COLOR_DEBUG_MODE=on go run ./_examples/envcheck.go
+ debugMode = os.Getenv("COLOR_DEBUG_MODE") == "on"
+ // inner errors record on detect color level
+ innerErrs []error
+ // output the default io.Writer message print
+ output io.Writer = os.Stdout
+ // mark current env, It's like in `cmd.exe`
+ // if not in windows, it's always is False.
+ isLikeInCmd bool
+ // the color support level for current terminal
+ // needVTP - need enable VTP, only for windows OS
+ colorLevel, needVTP = detectTermColorLevel()
+ // match color codes
+ codeRegex = regexp.MustCompile(CodeExpr)
+ // mark current env is support color.
+ // Always: isLikeInCmd != supportColor
+ // supportColor = IsSupportColor()
+)
+
+// TermColorLevel value on current ENV
+func TermColorLevel() terminfo.ColorLevel {
+ return colorLevel
+}
+
+// SupportColor on the current ENV
+func SupportColor() bool {
+ return colorLevel > terminfo.ColorLevelNone
+}
+
+// Support16Color on the current ENV
+// func Support16Color() bool {
+// return colorLevel > terminfo.ColorLevelNone
+// }
+
+// Support256Color on the current ENV
+func Support256Color() bool {
+ return colorLevel > terminfo.ColorLevelBasic
+}
+
+// SupportTrueColor on the current ENV
+func SupportTrueColor() bool {
+ return colorLevel > terminfo.ColorLevelHundreds
+}
+
+/*************************************************************
+ * global settings
+ *************************************************************/
+
+// Set set console color attributes
+func Set(colors ...Color) (int, error) {
+ code := Colors2code(colors...)
+ err := SetTerminal(code)
+ return 0, err
+}
+
+// Reset reset console color attributes
+func Reset() (int, error) {
+ err := ResetTerminal()
+ return 0, err
+}
+
+// Disable disable color output
+func Disable() bool {
+ oldVal := Enable
+ Enable = false
+ return oldVal
+}
+
+// NotRenderTag on call color.Xprint, color.PrintX
+func NotRenderTag() {
+ RenderTag = false
+}
+
+// SetOutput set default colored text output
+func SetOutput(w io.Writer) {
+ output = w
+}
+
+// ResetOutput reset output
+func ResetOutput() {
+ output = os.Stdout
+}
+
+// ResetOptions reset all package option setting
+func ResetOptions() {
+ RenderTag = true
+ Enable = true
+ output = os.Stdout
+}
+
+// ForceColor force open color render
+func ForceSetColorLevel(level terminfo.ColorLevel) terminfo.ColorLevel {
+ oldLevelVal := colorLevel
+ colorLevel = level
+ return oldLevelVal
+}
+
+// ForceColor force open color render
+func ForceColor() terminfo.ColorLevel {
+ return ForceOpenColor()
+}
+
+// ForceOpenColor force open color render
+func ForceOpenColor() terminfo.ColorLevel {
+ // TODO should set level to ?
+ return ForceSetColorLevel(terminfo.ColorLevelMillions)
+}
+
+// IsLikeInCmd check result
+// Deprecated
+func IsLikeInCmd() bool {
+ return isLikeInCmd
+}
+
+// InnerErrs info
+func InnerErrs() []error {
+ return innerErrs
+}
+
+/*************************************************************
+ * render color code
+ *************************************************************/
+
+// RenderCode render message by color code.
+// Usage:
+// msg := RenderCode("3;32;45", "some", "message")
+func RenderCode(code string, args ...interface{}) string {
+ var message string
+ if ln := len(args); ln == 0 {
+ return ""
+ }
+
+ message = fmt.Sprint(args...)
+ if len(code) == 0 {
+ return message
+ }
+
+ // disabled OR not support color
+ if !Enable || !SupportColor() {
+ return ClearCode(message)
+ }
+
+ return fmt.Sprintf(FullColorTpl, code, message)
+}
+
+// RenderWithSpaces Render code with spaces.
+// If the number of args is > 1, a space will be added between the args
+func RenderWithSpaces(code string, args ...interface{}) string {
+ message := formatArgsForPrintln(args)
+ if len(code) == 0 {
+ return message
+ }
+
+ // disabled OR not support color
+ if !Enable || !SupportColor() {
+ return ClearCode(message)
+ }
+
+ return fmt.Sprintf(FullColorTpl, code, message)
+}
+
+// RenderString render a string with color code.
+// Usage:
+// msg := RenderString("3;32;45", "a message")
+func RenderString(code string, str string) string {
+ if len(code) == 0 || str == "" {
+ return str
+ }
+
+ // disabled OR not support color
+ if !Enable || !SupportColor() {
+ return ClearCode(str)
+ }
+
+ return fmt.Sprintf(FullColorTpl, code, str)
+}
+
+// ClearCode clear color codes.
+// eg: "\033[36;1mText\x1b[0m" -> "Text"
+func ClearCode(str string) string {
+ return codeRegex.ReplaceAllString(str, "")
+}
diff --git a/vendor/github.com/gookit/color/color_16.go b/vendor/github.com/gookit/color/color_16.go
new file mode 100644
index 0000000..28e1048
--- /dev/null
+++ b/vendor/github.com/gookit/color/color_16.go
@@ -0,0 +1,440 @@
+package color
+
+import (
+ "fmt"
+ "strconv"
+)
+
+// Color Color16, 16 color value type
+// 3(2^3=8) OR 4(2^4=16) bite color.
+type Color uint8
+type Basic = Color // alias of Color
+
+// Opts basic color options. code: 0 - 9
+type Opts []Color
+
+// Add option value
+func (o *Opts) Add(ops ...Color) {
+ for _, op := range ops {
+ if uint8(op) < 10 {
+ *o = append(*o, op)
+ }
+ }
+}
+
+// IsValid options
+func (o Opts) IsValid() bool {
+ return len(o) > 0
+}
+
+// IsEmpty options
+func (o Opts) IsEmpty() bool {
+ return len(o) == 0
+}
+
+// String options to string. eg: "1;3"
+func (o Opts) String() string {
+ return Colors2code(o...)
+}
+
+/*************************************************************
+ * Basic 16 color definition
+ *************************************************************/
+
+// Base value for foreground/background color
+const (
+ FgBase uint8 = 30
+ BgBase uint8 = 40
+ // hi color base code
+ HiFgBase uint8 = 90
+ HiBgBase uint8 = 100
+)
+
+// Foreground colors. basic foreground colors 30 - 37
+const (
+ FgBlack Color = iota + 30
+ FgRed
+ FgGreen
+ FgYellow
+ FgBlue
+ FgMagenta // 品红
+ FgCyan // 青色
+ FgWhite
+ // FgDefault revert default FG
+ FgDefault Color = 39
+)
+
+// Extra foreground color 90 - 97(非标准)
+const (
+ FgDarkGray Color = iota + 90 // 亮黑(灰)
+ FgLightRed
+ FgLightGreen
+ FgLightYellow
+ FgLightBlue
+ FgLightMagenta
+ FgLightCyan
+ FgLightWhite
+ // FgGray is alias of FgDarkGray
+ FgGray Color = 90 // 亮黑(灰)
+)
+
+// Background colors. basic background colors 40 - 47
+const (
+ BgBlack Color = iota + 40
+ BgRed
+ BgGreen
+ BgYellow // BgBrown like yellow
+ BgBlue
+ BgMagenta
+ BgCyan
+ BgWhite
+ // BgDefault revert default BG
+ BgDefault Color = 49
+)
+
+// Extra background color 100 - 107(非标准)
+const (
+ BgDarkGray Color = iota + 100
+ BgLightRed
+ BgLightGreen
+ BgLightYellow
+ BgLightBlue
+ BgLightMagenta
+ BgLightCyan
+ BgLightWhite
+ // BgGray is alias of BgDarkGray
+ BgGray Color = 100
+)
+
+// Option settings
+const (
+ OpReset Color = iota // 0 重置所有设置
+ OpBold // 1 加粗
+ OpFuzzy // 2 模糊(不是所有的终端仿真器都支持)
+ OpItalic // 3 斜体(不是所有的终端仿真器都支持)
+ OpUnderscore // 4 下划线
+ OpBlink // 5 闪烁
+ OpFastBlink // 5 快速闪烁(未广泛支持)
+ OpReverse // 7 颠倒的 交换背景色与前景色
+ OpConcealed // 8 隐匿的
+ OpStrikethrough // 9 删除的,删除线(未广泛支持)
+)
+
+// There are basic and light foreground color aliases
+const (
+ Red = FgRed
+ Cyan = FgCyan
+ Gray = FgDarkGray // is light Black
+ Blue = FgBlue
+ Black = FgBlack
+ Green = FgGreen
+ White = FgWhite
+ Yellow = FgYellow
+ Magenta = FgMagenta
+
+ // special
+
+ Bold = OpBold
+ Normal = FgDefault
+
+ // extra light
+
+ LightRed = FgLightRed
+ LightCyan = FgLightCyan
+ LightBlue = FgLightBlue
+ LightGreen = FgLightGreen
+ LightWhite = FgLightWhite
+ LightYellow = FgLightYellow
+ LightMagenta = FgLightMagenta
+
+ HiRed = FgLightRed
+ HiCyan = FgLightCyan
+ HiBlue = FgLightBlue
+ HiGreen = FgLightGreen
+ HiWhite = FgLightWhite
+ HiYellow = FgLightYellow
+ HiMagenta = FgLightMagenta
+
+ BgHiRed = BgLightRed
+ BgHiCyan = BgLightCyan
+ BgHiBlue = BgLightBlue
+ BgHiGreen = BgLightGreen
+ BgHiWhite = BgLightWhite
+ BgHiYellow = BgLightYellow
+ BgHiMagenta = BgLightMagenta
+)
+
+// Bit4 an method for create Color
+func Bit4(code uint8) Color {
+ return Color(code)
+}
+
+/*************************************************************
+ * Color render methods
+ *************************************************************/
+
+// Name get color code name.
+func (c Color) Name() string {
+ name, ok := basic2nameMap[uint8(c)]
+ if ok {
+ return name
+ }
+ return "unknown"
+}
+
+// Text render a text message
+func (c Color) Text(message string) string {
+ return RenderString(c.String(), message)
+}
+
+// Render messages by color setting
+// Usage:
+// green := color.FgGreen.Render
+// fmt.Println(green("message"))
+func (c Color) Render(a ...interface{}) string {
+ return RenderCode(c.String(), a...)
+}
+
+// Renderln messages by color setting.
+// like Println, will add spaces for each argument
+// Usage:
+// green := color.FgGreen.Renderln
+// fmt.Println(green("message"))
+func (c Color) Renderln(a ...interface{}) string {
+ return RenderWithSpaces(c.String(), a...)
+}
+
+// Sprint render messages by color setting. is alias of the Render()
+func (c Color) Sprint(a ...interface{}) string {
+ return RenderCode(c.String(), a...)
+}
+
+// Sprintf format and render message.
+// Usage:
+// green := color.Green.Sprintf
+// colored := green("message")
+func (c Color) Sprintf(format string, args ...interface{}) string {
+ return RenderString(c.String(), fmt.Sprintf(format, args...))
+}
+
+// Print messages.
+// Usage:
+// color.Green.Print("message")
+// OR:
+// green := color.FgGreen.Print
+// green("message")
+func (c Color) Print(args ...interface{}) {
+ doPrintV2(c.Code(), fmt.Sprint(args...))
+}
+
+// Printf format and print messages.
+// Usage:
+// color.Cyan.Printf("string %s", "arg0")
+func (c Color) Printf(format string, a ...interface{}) {
+ doPrintV2(c.Code(), fmt.Sprintf(format, a...))
+}
+
+// Println messages with new line
+func (c Color) Println(a ...interface{}) {
+ doPrintlnV2(c.String(), a)
+}
+
+// Light current color. eg: 36(FgCyan) -> 96(FgLightCyan).
+// Usage:
+// lightCyan := Cyan.Light()
+// lightCyan.Print("message")
+func (c Color) Light() Color {
+ val := int(c)
+ if val >= 30 && val <= 47 {
+ return Color(uint8(c) + 60)
+ }
+
+ // don't change
+ return c
+}
+
+// Darken current color. eg. 96(FgLightCyan) -> 36(FgCyan)
+// Usage:
+// cyan := LightCyan.Darken()
+// cyan.Print("message")
+func (c Color) Darken() Color {
+ val := int(c)
+ if val >= 90 && val <= 107 {
+ return Color(uint8(c) - 60)
+ }
+
+ // don't change
+ return c
+}
+
+// C256 convert 16 color to 256-color code.
+func (c Color) C256() Color256 {
+ val := uint8(c)
+ if val < 10 { // is option code
+ return emptyC256 // empty
+ }
+
+ var isBg uint8
+ if val >= BgBase && val <= 47 { // is bg
+ isBg = AsBg
+ val = val - 10 // to fg code
+ } else if val >= HiBgBase && val <= 107 { // is hi bg
+ isBg = AsBg
+ val = val - 10 // to fg code
+ }
+
+ if c256, ok := basicTo256Map[val]; ok {
+ return Color256{c256, isBg}
+ }
+
+ // use raw value direct convert
+ return Color256{val}
+}
+
+// RGB convert 16 color to 256-color code.
+func (c Color) RGB() RGBColor {
+ val := uint8(c)
+ if val < 10 { // is option code
+ return emptyRGBColor
+ }
+
+ return HEX(Basic2hex(val))
+}
+
+// Code convert to code string. eg "35"
+func (c Color) Code() string {
+ // return fmt.Sprintf("%d", c)
+ return strconv.Itoa(int(c))
+}
+
+// String convert to code string. eg "35"
+func (c Color) String() string {
+ // return fmt.Sprintf("%d", c)
+ return strconv.Itoa(int(c))
+}
+
+// IsValid color value
+func (c Color) IsValid() bool {
+ return c < 107
+}
+
+/*************************************************************
+ * basic color maps
+ *************************************************************/
+
+// FgColors foreground colors map
+var FgColors = map[string]Color{
+ "black": FgBlack,
+ "red": FgRed,
+ "green": FgGreen,
+ "yellow": FgYellow,
+ "blue": FgBlue,
+ "magenta": FgMagenta,
+ "cyan": FgCyan,
+ "white": FgWhite,
+ "default": FgDefault,
+}
+
+// BgColors background colors map
+var BgColors = map[string]Color{
+ "black": BgBlack,
+ "red": BgRed,
+ "green": BgGreen,
+ "yellow": BgYellow,
+ "blue": BgBlue,
+ "magenta": BgMagenta,
+ "cyan": BgCyan,
+ "white": BgWhite,
+ "default": BgDefault,
+}
+
+// ExFgColors extra foreground colors map
+var ExFgColors = map[string]Color{
+ "darkGray": FgDarkGray,
+ "lightRed": FgLightRed,
+ "lightGreen": FgLightGreen,
+ "lightYellow": FgLightYellow,
+ "lightBlue": FgLightBlue,
+ "lightMagenta": FgLightMagenta,
+ "lightCyan": FgLightCyan,
+ "lightWhite": FgLightWhite,
+}
+
+// ExBgColors extra background colors map
+var ExBgColors = map[string]Color{
+ "darkGray": BgDarkGray,
+ "lightRed": BgLightRed,
+ "lightGreen": BgLightGreen,
+ "lightYellow": BgLightYellow,
+ "lightBlue": BgLightBlue,
+ "lightMagenta": BgLightMagenta,
+ "lightCyan": BgLightCyan,
+ "lightWhite": BgLightWhite,
+}
+
+// Options color options map
+// Deprecated
+// NOTICE: please use AllOptions instead.
+var Options = AllOptions
+
+// AllOptions color options map
+var AllOptions = map[string]Color{
+ "reset": OpReset,
+ "bold": OpBold,
+ "fuzzy": OpFuzzy,
+ "italic": OpItalic,
+ "underscore": OpUnderscore,
+ "blink": OpBlink,
+ "reverse": OpReverse,
+ "concealed": OpConcealed,
+}
+
+var (
+ // TODO basic name alias
+ // basicNameAlias = map[string]string{}
+
+ // basic color name to code
+ name2basicMap = initName2basicMap()
+ // basic2nameMap basic color code to name
+ basic2nameMap = map[uint8]string{
+ 30: "black",
+ 31: "red",
+ 32: "green",
+ 33: "yellow",
+ 34: "blue",
+ 35: "magenta",
+ 36: "cyan",
+ 37: "white",
+ // hi color code
+ 90: "lightBlack",
+ 91: "lightRed",
+ 92: "lightGreen",
+ 93: "lightYellow",
+ 94: "lightBlue",
+ 95: "lightMagenta",
+ 96: "lightCyan",
+ 97: "lightWhite",
+ // options
+ 0: "reset",
+ 1: "bold",
+ 2: "fuzzy",
+ 3: "italic",
+ 4: "underscore",
+ 5: "blink",
+ 7: "reverse",
+ 8: "concealed",
+ }
+)
+
+// Basic2nameMap data
+func Basic2nameMap() map[uint8]string {
+ return basic2nameMap
+}
+
+func initName2basicMap() map[string]uint8 {
+ n2b := make(map[string]uint8, len(basic2nameMap))
+ for u, s := range basic2nameMap {
+ n2b[s] = u
+ }
+ return n2b
+}
diff --git a/vendor/github.com/gookit/color/color_256.go b/vendor/github.com/gookit/color/color_256.go
new file mode 100644
index 0000000..efd6dca
--- /dev/null
+++ b/vendor/github.com/gookit/color/color_256.go
@@ -0,0 +1,308 @@
+package color
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+/*
+from wikipedia, 256 color:
+ ESC[ … 38;5; … m选择前景色
+ ESC[ … 48;5; … m选择背景色
+ 0- 7:标准颜色(同 ESC[30–37m)
+ 8- 15:高强度颜色(同 ESC[90–97m)
+ 16-231:6 × 6 × 6 立方(216色): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
+ 232-255:从黑到白的24阶灰度色
+*/
+
+// tpl for 8 bit 256 color(`2^8`)
+//
+// format:
+// ESC[ … 38;5; … m // 选择前景色
+// ESC[ … 48;5; … m // 选择背景色
+//
+// example:
+// fg "\x1b[38;5;242m"
+// bg "\x1b[48;5;208m"
+// both "\x1b[38;5;242;48;5;208m"
+//
+// links:
+// https://zh.wikipedia.org/wiki/ANSI%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97#8位
+const (
+ TplFg256 = "38;5;%d"
+ TplBg256 = "48;5;%d"
+ Fg256Pfx = "38;5;"
+ Bg256Pfx = "48;5;"
+)
+
+/*************************************************************
+ * 8bit(256) Color: Bit8Color Color256
+ *************************************************************/
+
+// Color256 256 color (8 bit), uint8 range at 0 - 255
+//
+// 颜色值使用10进制和16进制都可 0x98 = 152
+//
+// The color consists of two uint8:
+// 0: color value
+// 1: color type; Fg=0, Bg=1, >1: unset value
+//
+// example:
+// fg color: [152, 0]
+// bg color: [152, 1]
+//
+// NOTICE: now support 256 color on windows CMD, PowerShell
+// lint warn - Name starts with package name
+type Color256 [2]uint8
+type Bit8Color = Color256 // alias
+
+var emptyC256 = Color256{1: 99}
+
+// Bit8 create a color256
+func Bit8(val uint8, isBg ...bool) Color256 {
+ return C256(val, isBg...)
+}
+
+// C256 create a color256
+func C256(val uint8, isBg ...bool) Color256 {
+ bc := Color256{val}
+
+ // mark is bg color
+ if len(isBg) > 0 && isBg[0] {
+ bc[1] = AsBg
+ }
+
+ return bc
+}
+
+// Set terminal by 256 color code
+func (c Color256) Set() error {
+ return SetTerminal(c.String())
+}
+
+// Reset terminal. alias of the ResetTerminal()
+func (c Color256) Reset() error {
+ return ResetTerminal()
+}
+
+// Print print message
+func (c Color256) Print(a ...interface{}) {
+ doPrintV2(c.String(), fmt.Sprint(a...))
+}
+
+// Printf format and print message
+func (c Color256) Printf(format string, a ...interface{}) {
+ doPrintV2(c.String(), fmt.Sprintf(format, a...))
+}
+
+// Println print message with newline
+func (c Color256) Println(a ...interface{}) {
+ doPrintlnV2(c.String(), a)
+}
+
+// Sprint returns rendered message
+func (c Color256) Sprint(a ...interface{}) string {
+ return RenderCode(c.String(), a...)
+}
+
+// Sprintf returns format and rendered message
+func (c Color256) Sprintf(format string, a ...interface{}) string {
+ return RenderString(c.String(), fmt.Sprintf(format, a...))
+}
+
+// C16 convert color-256 to 16 color.
+func (c Color256) C16() Color {
+ return c.Basic()
+}
+
+// Basic convert color-256 to basic 16 color.
+func (c Color256) Basic() Color {
+ return Color(c[0]) // TODO
+}
+
+// RGB convert color-256 to RGB color.
+func (c Color256) RGB() RGBColor {
+ return RGBFromSlice(C256ToRgb(c[0]), c[1] == AsBg)
+}
+
+// RGBColor convert color-256 to RGB color.
+func (c Color256) RGBColor() RGBColor {
+ return c.RGB()
+}
+
+// Value return color value
+func (c Color256) Value() uint8 {
+ return c[0]
+}
+
+// Code convert to color code string. eg: "12"
+func (c Color256) Code() string {
+ return strconv.Itoa(int(c[0]))
+}
+
+// FullCode convert to color code string with prefix. eg: "38;5;12"
+func (c Color256) FullCode() string {
+ return c.String()
+}
+
+// String convert to color code string with prefix. eg: "38;5;12"
+func (c Color256) String() string {
+ if c[1] == AsFg { // 0 is Fg
+ // return fmt.Sprintf(TplFg256, c[0])
+ return Fg256Pfx + strconv.Itoa(int(c[0]))
+ }
+
+ if c[1] == AsBg { // 1 is Bg
+ // return fmt.Sprintf(TplBg256, c[0])
+ return Bg256Pfx + strconv.Itoa(int(c[0]))
+ }
+
+ return "" // empty
+}
+
+// IsFg color
+func (c Color256) IsFg() bool {
+ return c[1] == AsFg
+}
+
+// ToFg 256 color
+func (c Color256) ToFg() Color256 {
+ c[1] = AsFg
+ return c
+}
+
+// IsBg color
+func (c Color256) IsBg() bool {
+ return c[1] == AsBg
+}
+
+// ToBg 256 color
+func (c Color256) ToBg() Color256 {
+ c[1] = AsBg
+ return c
+}
+
+// IsEmpty value
+func (c Color256) IsEmpty() bool {
+ return c[1] > 1
+}
+
+/*************************************************************
+ * 8bit(256) Style
+ *************************************************************/
+
+// Style256 definition
+//
+// 前/背景色
+// 都是由两位uint8组成, 第一位是色彩值;
+// 第二位与 Bit8Color 不一样的是,在这里表示是否设置了值 0 未设置 !=0 已设置
+type Style256 struct {
+ // p Printer
+
+ // Name of the style
+ Name string
+ // color options of the style
+ opts Opts
+ // fg and bg color
+ fg, bg Color256
+}
+
+// S256 create a color256 style
+// Usage:
+// s := color.S256()
+// s := color.S256(132) // fg
+// s := color.S256(132, 203) // fg and bg
+func S256(fgAndBg ...uint8) *Style256 {
+ s := &Style256{}
+ vl := len(fgAndBg)
+ if vl > 0 { // with fg
+ s.fg = Color256{fgAndBg[0], 1}
+
+ if vl > 1 { // and with bg
+ s.bg = Color256{fgAndBg[1], 1}
+ }
+ }
+
+ return s
+}
+
+// Set fg and bg color value, can also with color options
+func (s *Style256) Set(fgVal, bgVal uint8, opts ...Color) *Style256 {
+ s.fg = Color256{fgVal, 1}
+ s.bg = Color256{bgVal, 1}
+ s.opts.Add(opts...)
+ return s
+}
+
+// SetBg set bg color value
+func (s *Style256) SetBg(bgVal uint8) *Style256 {
+ s.bg = Color256{bgVal, 1}
+ return s
+}
+
+// SetFg set fg color value
+func (s *Style256) SetFg(fgVal uint8) *Style256 {
+ s.fg = Color256{fgVal, 1}
+ return s
+}
+
+// SetOpts set options
+func (s *Style256) SetOpts(opts Opts) *Style256 {
+ s.opts = opts
+ return s
+}
+
+// AddOpts add options
+func (s *Style256) AddOpts(opts ...Color) *Style256 {
+ s.opts.Add(opts...)
+ return s
+}
+
+// Print message
+func (s *Style256) Print(a ...interface{}) {
+ doPrintV2(s.String(), fmt.Sprint(a...))
+}
+
+// Printf format and print message
+func (s *Style256) Printf(format string, a ...interface{}) {
+ doPrintV2(s.String(), fmt.Sprintf(format, a...))
+}
+
+// Println print message with newline
+func (s *Style256) Println(a ...interface{}) {
+ doPrintlnV2(s.String(), a)
+}
+
+// Sprint returns rendered message
+func (s *Style256) Sprint(a ...interface{}) string {
+ return RenderCode(s.Code(), a...)
+}
+
+// Sprintf returns format and rendered message
+func (s *Style256) Sprintf(format string, a ...interface{}) string {
+ return RenderString(s.Code(), fmt.Sprintf(format, a...))
+}
+
+// Code convert to color code string
+func (s *Style256) Code() string {
+ return s.String()
+}
+
+// String convert to color code string
+func (s *Style256) String() string {
+ var ss []string
+ if s.fg[1] > 0 {
+ ss = append(ss, fmt.Sprintf(TplFg256, s.fg[0]))
+ }
+
+ if s.bg[1] > 0 {
+ ss = append(ss, fmt.Sprintf(TplBg256, s.bg[0]))
+ }
+
+ if s.opts.IsValid() {
+ ss = append(ss, s.opts.String())
+ }
+
+ return strings.Join(ss, ";")
+}
diff --git a/vendor/github.com/gookit/color/color_rgb.go b/vendor/github.com/gookit/color/color_rgb.go
new file mode 100644
index 0000000..a7ede18
--- /dev/null
+++ b/vendor/github.com/gookit/color/color_rgb.go
@@ -0,0 +1,391 @@
+package color
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// 24 bit RGB color
+// RGB:
+// R 0-255 G 0-255 B 0-255
+// R 00-FF G 00-FF B 00-FF (16进制)
+//
+// Format:
+// ESC[ … 38;2;;; … m // Select RGB foreground color
+// ESC[ … 48;2;;; … m // Choose RGB background color
+//
+// links:
+// https://zh.wikipedia.org/wiki/ANSI%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97#24位
+//
+// example:
+// fg: \x1b[38;2;30;144;255mMESSAGE\x1b[0m
+// bg: \x1b[48;2;30;144;255mMESSAGE\x1b[0m
+// both: \x1b[38;2;233;90;203;48;2;30;144;255mMESSAGE\x1b[0m
+const (
+ TplFgRGB = "38;2;%d;%d;%d"
+ TplBgRGB = "48;2;%d;%d;%d"
+ FgRGBPfx = "38;2;"
+ BgRGBPfx = "48;2;"
+)
+
+// mark color is fg or bg.
+const (
+ AsFg uint8 = iota
+ AsBg
+)
+
+// values from https://github.com/go-terminfo/terminfo
+// var (
+// RgbaBlack = image_color.RGBA{0, 0, 0, 255}
+// Red = color.RGBA{205, 0, 0, 255}
+// Green = color.RGBA{0, 205, 0, 255}
+// Orange = color.RGBA{205, 205, 0, 255}
+// Blue = color.RGBA{0, 0, 238, 255}
+// Magenta = color.RGBA{205, 0, 205, 255}
+// Cyan = color.RGBA{0, 205, 205, 255}
+// LightGrey = color.RGBA{229, 229, 229, 255}
+//
+// DarkGrey = color.RGBA{127, 127, 127, 255}
+// LightRed = color.RGBA{255, 0, 0, 255}
+// LightGreen = color.RGBA{0, 255, 0, 255}
+// Yellow = color.RGBA{255, 255, 0, 255}
+// LightBlue = color.RGBA{92, 92, 255, 255}
+// LightMagenta = color.RGBA{255, 0, 255, 255}
+// LightCyan = color.RGBA{0, 255, 255, 255}
+// White = color.RGBA{255, 255, 255, 255}
+// )
+
+/*************************************************************
+ * RGB Color(Bit24Color, TrueColor)
+ *************************************************************/
+
+// RGBColor definition.
+//
+// The first to third digits represent the color value.
+// The last digit represents the foreground(0), background(1), >1 is unset value
+//
+// Usage:
+// // 0, 1, 2 is R,G,B.
+// // 3rd: Fg=0, Bg=1, >1: unset value
+// RGBColor{30,144,255, 0}
+// RGBColor{30,144,255, 1}
+//
+// NOTICE: now support RGB color on windows CMD, PowerShell
+type RGBColor [4]uint8
+
+// create a empty RGBColor
+var emptyRGBColor = RGBColor{3: 99}
+
+// RGB color create.
+// Usage:
+// c := RGB(30,144,255)
+// c := RGB(30,144,255, true)
+// c.Print("message")
+func RGB(r, g, b uint8, isBg ...bool) RGBColor {
+ rgb := RGBColor{r, g, b}
+ if len(isBg) > 0 && isBg[0] {
+ rgb[3] = AsBg
+ }
+
+ return rgb
+}
+
+// Rgb alias of the RGB()
+func Rgb(r, g, b uint8, isBg ...bool) RGBColor { return RGB(r, g, b, isBg...) }
+
+// Bit24 alias of the RGB()
+func Bit24(r, g, b uint8, isBg ...bool) RGBColor { return RGB(r, g, b, isBg...) }
+
+// RGBFromSlice quick RGBColor from slice
+func RGBFromSlice(rgb []uint8, isBg ...bool) RGBColor {
+ return RGB(rgb[0], rgb[1], rgb[2], isBg...)
+}
+
+// HEX create RGB color from a HEX color string.
+// Usage:
+// c := HEX("ccc") // rgb: [204 204 204]
+// c := HEX("aabbcc") // rgb: [170 187 204]
+// c := HEX("#aabbcc")
+// c := HEX("0xaabbcc")
+// c.Print("message")
+func HEX(hex string, isBg ...bool) RGBColor {
+ if rgb := HexToRgb(hex); len(rgb) > 0 {
+ return RGB(uint8(rgb[0]), uint8(rgb[1]), uint8(rgb[2]), isBg...)
+ }
+
+ // mark is empty
+ return emptyRGBColor
+}
+
+// Hex alias of the HEX()
+func Hex(hex string, isBg ...bool) RGBColor { return HEX(hex, isBg...) }
+
+// RGBFromString create RGB color from a string.
+// Usage:
+// c := RGBFromString("170,187,204")
+// c.Print("message")
+func RGBFromString(rgb string, isBg ...bool) RGBColor {
+ ss := stringToArr(rgb, ",")
+ if len(ss) != 3 {
+ return emptyRGBColor
+ }
+
+ var ar [3]int
+ for i, val := range ss {
+ iv, err := strconv.Atoi(val)
+ if err != nil {
+ return emptyRGBColor
+ }
+
+ ar[i] = iv
+ }
+
+ return RGB(uint8(ar[0]), uint8(ar[1]), uint8(ar[2]), isBg...)
+}
+
+// Set terminal by rgb/true color code
+func (c RGBColor) Set() error {
+ return SetTerminal(c.String())
+}
+
+// Reset terminal. alias of the ResetTerminal()
+func (c RGBColor) Reset() error {
+ return ResetTerminal()
+}
+
+// Print print message
+func (c RGBColor) Print(a ...interface{}) {
+ doPrintV2(c.String(), fmt.Sprint(a...))
+}
+
+// Printf format and print message
+func (c RGBColor) Printf(format string, a ...interface{}) {
+ doPrintV2(c.String(), fmt.Sprintf(format, a...))
+}
+
+// Println print message with newline
+func (c RGBColor) Println(a ...interface{}) {
+ doPrintlnV2(c.String(), a)
+}
+
+// Sprint returns rendered message
+func (c RGBColor) Sprint(a ...interface{}) string {
+ return RenderCode(c.String(), a...)
+}
+
+// Sprintf returns format and rendered message
+func (c RGBColor) Sprintf(format string, a ...interface{}) string {
+ return RenderString(c.String(), fmt.Sprintf(format, a...))
+}
+
+// Values to RGB values
+func (c RGBColor) Values() []int {
+ return []int{int(c[0]), int(c[1]), int(c[2])}
+}
+
+// Code to color code string without prefix. eg: "204;123;56"
+func (c RGBColor) Code() string {
+ return fmt.Sprintf("%d;%d;%d", c[0], c[1], c[2])
+}
+
+// Hex color rgb to hex string. as in "ff0080".
+func (c RGBColor) Hex() string {
+ return fmt.Sprintf("%02x%02x%02x", c[0], c[1], c[2])
+}
+
+// FullCode to color code string with prefix
+func (c RGBColor) FullCode() string {
+ return c.String()
+}
+
+// String to color code string with prefix. eg: "38;2;204;123;56"
+func (c RGBColor) String() string {
+ if c[3] == AsFg {
+ return fmt.Sprintf(TplFgRGB, c[0], c[1], c[2])
+ }
+
+ if c[3] == AsBg {
+ return fmt.Sprintf(TplBgRGB, c[0], c[1], c[2])
+ }
+
+ // c[3] > 1 is empty
+ return ""
+}
+
+// IsEmpty value
+func (c RGBColor) IsEmpty() bool {
+ return c[3] > AsBg
+}
+
+// IsValid value
+// func (c RGBColor) IsValid() bool {
+// return c[3] <= AsBg
+// }
+
+// C256 returns the closest approximate 256 (8 bit) color
+func (c RGBColor) C256() Color256 {
+ return C256(RgbTo256(c[0], c[1], c[2]), c[3] == AsBg)
+}
+
+// Basic returns the closest approximate 16 (4 bit) color
+func (c RGBColor) Basic() Color {
+ // return Color(RgbToAnsi(c[0], c[1], c[2], c[3] == AsBg))
+ return Color(Rgb2basic(c[0], c[1], c[2], c[3] == AsBg))
+}
+
+// Color returns the closest approximate 16 (4 bit) color
+func (c RGBColor) Color() Color { return c.Basic() }
+
+// C16 returns the closest approximate 16 (4 bit) color
+func (c RGBColor) C16() Color { return c.Basic() }
+
+/*************************************************************
+ * RGB Style
+ *************************************************************/
+
+// RGBStyle definition.
+//
+// Foreground/Background color
+// All are composed of 4 digits uint8, the first three digits are the color value;
+// The last bit is different from RGBColor, here it indicates whether the value is set.
+// - 1 Has been set
+// - ^1 Not set
+type RGBStyle struct {
+ // Name of the style
+ Name string
+ // color options of the style
+ opts Opts
+ // fg and bg color
+ fg, bg RGBColor
+}
+
+// NewRGBStyle create a RGBStyle.
+func NewRGBStyle(fg RGBColor, bg ...RGBColor) *RGBStyle {
+ s := &RGBStyle{}
+ if len(bg) > 0 {
+ s.SetBg(bg[0])
+ }
+
+ return s.SetFg(fg)
+}
+
+// HEXStyle create a RGBStyle from HEX color string.
+// Usage:
+// s := HEXStyle("aabbcc", "eee")
+// s.Print("message")
+func HEXStyle(fg string, bg ...string) *RGBStyle {
+ s := &RGBStyle{}
+ if len(bg) > 0 {
+ s.SetBg(HEX(bg[0]))
+ }
+
+ if len(fg) > 0 {
+ s.SetFg(HEX(fg))
+ }
+
+ return s
+}
+
+// RGBStyleFromString create a RGBStyle from color value string.
+// Usage:
+// s := RGBStyleFromString("170,187,204", "70,87,4")
+// s.Print("message")
+func RGBStyleFromString(fg string, bg ...string) *RGBStyle {
+ s := &RGBStyle{}
+ if len(bg) > 0 {
+ s.SetBg(RGBFromString(bg[0]))
+ }
+
+ return s.SetFg(RGBFromString(fg))
+}
+
+// Set fg and bg color, can also with color options
+func (s *RGBStyle) Set(fg, bg RGBColor, opts ...Color) *RGBStyle {
+ return s.SetFg(fg).SetBg(bg).SetOpts(opts)
+}
+
+// SetFg set fg color
+func (s *RGBStyle) SetFg(fg RGBColor) *RGBStyle {
+ fg[3] = 1 // add fixed value, mark is valid
+ s.fg = fg
+ return s
+}
+
+// SetBg set bg color
+func (s *RGBStyle) SetBg(bg RGBColor) *RGBStyle {
+ bg[3] = 1 // add fixed value, mark is valid
+ s.bg = bg
+ return s
+}
+
+// SetOpts set color options
+func (s *RGBStyle) SetOpts(opts Opts) *RGBStyle {
+ s.opts = opts
+ return s
+}
+
+// AddOpts add options
+func (s *RGBStyle) AddOpts(opts ...Color) *RGBStyle {
+ s.opts.Add(opts...)
+ return s
+}
+
+// Print print message
+func (s *RGBStyle) Print(a ...interface{}) {
+ doPrintV2(s.String(), fmt.Sprint(a...))
+}
+
+// Printf format and print message
+func (s *RGBStyle) Printf(format string, a ...interface{}) {
+ doPrintV2(s.String(), fmt.Sprintf(format, a...))
+}
+
+// Println print message with newline
+func (s *RGBStyle) Println(a ...interface{}) {
+ doPrintlnV2(s.String(), a)
+}
+
+// Sprint returns rendered message
+func (s *RGBStyle) Sprint(a ...interface{}) string {
+ return RenderCode(s.String(), a...)
+}
+
+// Sprintf returns format and rendered message
+func (s *RGBStyle) Sprintf(format string, a ...interface{}) string {
+ return RenderString(s.String(), fmt.Sprintf(format, a...))
+}
+
+// Code convert to color code string
+func (s *RGBStyle) Code() string {
+ return s.String()
+}
+
+// FullCode convert to color code string
+func (s *RGBStyle) FullCode() string {
+ return s.String()
+}
+
+// String convert to color code string
+func (s *RGBStyle) String() string {
+ var ss []string
+ // last value ensure is enable.
+ if s.fg[3] == 1 {
+ ss = append(ss, fmt.Sprintf(TplFgRGB, s.fg[0], s.fg[1], s.fg[2]))
+ }
+
+ if s.bg[3] == 1 {
+ ss = append(ss, fmt.Sprintf(TplBgRGB, s.bg[0], s.bg[1], s.bg[2]))
+ }
+
+ if s.opts.IsValid() {
+ ss = append(ss, s.opts.String())
+ }
+
+ return strings.Join(ss, ";")
+}
+
+// IsEmpty style
+func (s *RGBStyle) IsEmpty() bool {
+ return s.fg[3] != 1 && s.bg[3] != 1
+}
diff --git a/vendor/github.com/gookit/color/color_tag.go b/vendor/github.com/gookit/color/color_tag.go
new file mode 100644
index 0000000..051ba84
--- /dev/null
+++ b/vendor/github.com/gookit/color/color_tag.go
@@ -0,0 +1,427 @@
+package color
+
+import (
+ "fmt"
+ "regexp"
+ "strings"
+)
+
+// output colored text like use html tag. (not support windows cmd)
+const (
+ // MatchExpr regex to match color tags
+ //
+ // Notice: golang 不支持反向引用. 即不支持使用 \1 引用第一个匹配 ([a-z=;]+)
+ // MatchExpr = `<([a-z=;]+)>(.*?)<\/\1>`
+ // 所以调整一下 统一使用 `>` 来结束标签,例如 "some text>"
+ //
+ // allow custom attrs, eg: "content>"
+ // (?s:...) s - 让 "." 匹配换行
+ MatchExpr = `<([0-9a-zA-Z_=,;]+)>(?s:(.*?))<\/>`
+
+ // AttrExpr regex to match custom color attributes
+ // eg: "content>"
+ AttrExpr = `(fg|bg|op)[\s]*=[\s]*([0-9a-zA-Z,]+);?`
+
+ // StripExpr regex used for removing color tags
+ // StripExpr = `<[\/]?[a-zA-Z=;]+>`
+ // 随着上面的做一些调整
+ StripExpr = `<[\/]?[0-9a-zA-Z_=,;]*>`
+)
+
+var (
+ attrRegex = regexp.MustCompile(AttrExpr)
+ matchRegex = regexp.MustCompile(MatchExpr)
+ stripRegex = regexp.MustCompile(StripExpr)
+)
+
+/*************************************************************
+ * internal defined color tags
+ *************************************************************/
+
+// There are internal defined color tags
+// Usage: content text>
+// @notice 加 0 在前面是为了防止之前的影响到现在的设置
+var colorTags = map[string]string{
+ // basic tags
+ "red": "0;31",
+ "red1": "1;31", // with bold
+ "redB": "1;31",
+ "red_b": "1;31",
+ "blue": "0;34",
+ "blue1": "1;34", // with bold
+ "blueB": "1;34",
+ "blue_b": "1;34",
+ "cyan": "0;36",
+ "cyan1": "1;36", // with bold
+ "cyanB": "1;36",
+ "cyan_b": "1;36",
+ "green": "0;32",
+ "green1": "1;32", // with bold
+ "greenB": "1;32",
+ "green_b": "1;32",
+ "black": "0;30",
+ "white": "1;37",
+ "default": "0;39", // no color
+ "normal": "0;39", // no color
+ "brown": "0;33", // #A52A2A
+ "yellow": "0;33",
+ "ylw0": "0;33",
+ "yellowB": "1;33", // with bold
+ "ylw1": "1;33",
+ "ylwB": "1;33",
+ "magenta": "0;35",
+ "mga": "0;35", // short name
+ "magentaB": "1;35", // with bold
+ "mgb": "1;35",
+ "mgaB": "1;35",
+
+ // light/hi tags
+
+ "gray": "0;90",
+ "darkGray": "0;90",
+ "dark_gray": "0;90",
+ "lightYellow": "0;93",
+ "light_yellow": "0;93",
+ "hiYellow": "0;93",
+ "hi_yellow": "0;93",
+ "hiYellowB": "1;93", // with bold
+ "hi_yellow_b": "1;93",
+ "lightMagenta": "0;95",
+ "light_magenta": "0;95",
+ "hiMagenta": "0;95",
+ "hi_magenta": "0;95",
+ "lightMagentaB": "1;95", // with bold
+ "hiMagentaB": "1;95", // with bold
+ "hi_magenta_b": "1;95",
+ "lightRed": "0;91",
+ "light_red": "0;91",
+ "hiRed": "0;91",
+ "hi_red": "0;91",
+ "lightRedB": "1;91", // with bold
+ "light_red_b": "1;91",
+ "hi_red_b": "1;91",
+ "lightGreen": "0;92",
+ "light_green": "0;92",
+ "hiGreen": "0;92",
+ "hi_green": "0;92",
+ "lightGreenB": "1;92",
+ "light_green_b": "1;92",
+ "hi_green_b": "1;92",
+ "lightBlue": "0;94",
+ "light_blue": "0;94",
+ "hiBlue": "0;94",
+ "hi_blue": "0;94",
+ "lightBlueB": "1;94",
+ "light_blue_b": "1;94",
+ "hi_blue_b": "1;94",
+ "lightCyan": "0;96",
+ "light_cyan": "0;96",
+ "hiCyan": "0;96",
+ "hi_cyan": "0;96",
+ "lightCyanB": "1;96",
+ "light_cyan_b": "1;96",
+ "hi_cyan_b": "1;96",
+ "lightWhite": "0;97;40",
+ "light_white": "0;97;40",
+
+ // option
+ "bold": "1",
+ "b": "1",
+ "underscore": "4",
+ "us": "4", // short name for 'underscore'
+ "reverse": "7",
+
+ // alert tags, like bootstrap's alert
+ "suc": "1;32", // same "green" and "bold"
+ "success": "1;32",
+ "info": "0;32", // same "green",
+ "comment": "0;33", // same "brown"
+ "note": "36;1",
+ "notice": "36;4",
+ "warn": "0;1;33",
+ "warning": "0;30;43",
+ "primary": "0;34",
+ "danger": "1;31", // same "red" but add bold
+ "err": "97;41",
+ "error": "97;41", // fg light white; bg red
+}
+
+/*************************************************************
+ * parse color tags
+ *************************************************************/
+
+var (
+ tagParser = TagParser{}
+ rxNumStr = regexp.MustCompile("^[0-9]{1,3}$")
+ rxHexCode = regexp.MustCompile("^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$")
+)
+
+// TagParser struct
+type TagParser struct {
+ disable bool
+}
+
+// NewTagParser create
+func NewTagParser() *TagParser {
+ return &TagParser{}
+}
+
+// func (tp *TagParser) Disable() *TagParser {
+// tp.disable = true
+// return tp
+// }
+
+// ParseByEnv parse given string. will check package setting.
+func (tp *TagParser) ParseByEnv(str string) string {
+ // disable handler TAG
+ if !RenderTag {
+ return str
+ }
+
+ // disable OR not support color
+ if !Enable || !SupportColor() {
+ return ClearTag(str)
+ }
+
+ return tp.Parse(str)
+}
+
+// Parse parse given string, replace color tag and return rendered string
+func (tp *TagParser) Parse(str string) string {
+ // not contains color tag
+ if !strings.Contains(str, ">") {
+ return str
+ }
+
+ // find color tags by regex. str eg: "content>"
+ matched := matchRegex.FindAllStringSubmatch(str, -1)
+
+ // item: 0 full text 1 tag name 2 tag content
+ for _, item := range matched {
+ full, tag, content := item[0], item[1], item[2]
+
+ // use defined tag name: "content>" -> tag: "info"
+ if !strings.ContainsRune(tag, '=') {
+ code := colorTags[tag]
+ if len(code) > 0 {
+ now := RenderString(code, content)
+ // old := WrapTag(content, tag) is equals to var 'full'
+ str = strings.Replace(str, full, now, 1)
+ }
+ continue
+ }
+
+ // custom color in tag
+ // - basic: "fg=white;bg=blue;op=bold"
+ if code := ParseCodeFromAttr(tag); len(code) > 0 {
+ now := RenderString(code, content)
+ str = strings.Replace(str, full, now, 1)
+ }
+ }
+
+ return str
+}
+
+// func (tp *TagParser) ParseAttr(attr string) (code string) {
+// return
+// }
+
+// ReplaceTag parse string, replace color tag and return rendered string
+func ReplaceTag(str string) string {
+ return tagParser.ParseByEnv(str)
+}
+
+// ParseCodeFromAttr parse color attributes.
+//
+// attr format:
+// // VALUE please see var: FgColors, BgColors, AllOptions
+// "fg=VALUE;bg=VALUE;op=VALUE"
+// 16 color:
+// "fg=yellow"
+// "bg=red"
+// "op=bold,underscore" option is allow multi value
+// "fg=white;bg=blue;op=bold"
+// "fg=white;op=bold,underscore"
+// 256 color:
+// "fg=167"
+// "fg=167;bg=23"
+// "fg=167;bg=23;op=bold"
+// true color:
+// // hex
+// "fg=fc1cac"
+// "fg=fc1cac;bg=c2c3c4"
+// // r,g,b
+// "fg=23,45,214"
+// "fg=23,45,214;bg=109,99,88"
+func ParseCodeFromAttr(attr string) (code string) {
+ if !strings.ContainsRune(attr, '=') {
+ return
+ }
+
+ attr = strings.Trim(attr, ";=,")
+ if len(attr) == 0 {
+ return
+ }
+
+ var codes []string
+ matched := attrRegex.FindAllStringSubmatch(attr, -1)
+
+ for _, item := range matched {
+ pos, val := item[1], item[2]
+ switch pos {
+ case "fg":
+ if c, ok := FgColors[val]; ok { // basic
+ codes = append(codes, c.String())
+ } else if c, ok := ExFgColors[val]; ok { // extra
+ codes = append(codes, c.String())
+ } else if code := rgbHex256toCode(val, false); code != "" {
+ codes = append(codes, code)
+ }
+ case "bg":
+ if c, ok := BgColors[val]; ok { // basic bg
+ codes = append(codes, c.String())
+ } else if c, ok := ExBgColors[val]; ok { // extra bg
+ codes = append(codes, c.String())
+ } else if code := rgbHex256toCode(val, true); code != "" {
+ codes = append(codes, code)
+ }
+ case "op": // options allow multi value
+ if strings.Contains(val, ",") {
+ ns := strings.Split(val, ",")
+ for _, n := range ns {
+ if c, ok := AllOptions[n]; ok {
+ codes = append(codes, c.String())
+ }
+ }
+ } else if c, ok := AllOptions[val]; ok {
+ codes = append(codes, c.String())
+ }
+ }
+ }
+
+ return strings.Join(codes, ";")
+}
+
+func rgbHex256toCode(val string, isBg bool) (code string) {
+ if len(val) == 6 && rxHexCode.MatchString(val) { // hex: "fc1cac"
+ code = HEX(val, isBg).String()
+ } else if strings.ContainsRune(val, ',') { // rgb: "231,178,161"
+ code = strings.Replace(val, ",", ";", -1)
+ if isBg {
+ code = BgRGBPfx + code
+ } else {
+ code = FgRGBPfx + code
+ }
+ } else if len(val) < 4 && rxNumStr.MatchString(val) { // 256 code
+ if isBg {
+ code = Bg256Pfx + val
+ } else {
+ code = Fg256Pfx + val
+ }
+ }
+ return
+}
+
+// ClearTag clear all tag for a string
+func ClearTag(s string) string {
+ if !strings.Contains(s, ">") {
+ return s
+ }
+
+ return stripRegex.ReplaceAllString(s, "")
+}
+
+/*************************************************************
+ * helper methods
+ *************************************************************/
+
+// GetTagCode get color code by tag name
+func GetTagCode(name string) string {
+ return colorTags[name]
+}
+
+// ApplyTag for messages
+func ApplyTag(tag string, a ...interface{}) string {
+ return RenderCode(GetTagCode(tag), a...)
+}
+
+// WrapTag wrap a tag for a string "content>"
+func WrapTag(s string, tag string) string {
+ if s == "" || tag == "" {
+ return s
+ }
+
+ return fmt.Sprintf("<%s>%s>", tag, s)
+}
+
+// GetColorTags get all internal color tags
+func GetColorTags() map[string]string {
+ return colorTags
+}
+
+// IsDefinedTag is defined tag name
+func IsDefinedTag(name string) bool {
+ _, ok := colorTags[name]
+ return ok
+}
+
+/*************************************************************
+ * Tag extra
+ *************************************************************/
+
+// Tag value is a defined style name
+// Usage:
+// Tag("info").Println("message")
+type Tag string
+
+// Print messages
+func (tg Tag) Print(a ...interface{}) {
+ name := string(tg)
+ str := fmt.Sprint(a...)
+
+ if stl := GetStyle(name); !stl.IsEmpty() {
+ stl.Print(str)
+ } else {
+ doPrintV2(GetTagCode(name), str)
+ }
+}
+
+// Printf format and print messages
+func (tg Tag) Printf(format string, a ...interface{}) {
+ name := string(tg)
+ str := fmt.Sprintf(format, a...)
+
+ if stl := GetStyle(name); !stl.IsEmpty() {
+ stl.Print(str)
+ } else {
+ doPrintV2(GetTagCode(name), str)
+ }
+}
+
+// Println messages line
+func (tg Tag) Println(a ...interface{}) {
+ name := string(tg)
+ if stl := GetStyle(name); !stl.IsEmpty() {
+ stl.Println(a...)
+ } else {
+ doPrintlnV2(GetTagCode(name), a)
+ }
+}
+
+// Sprint render messages
+func (tg Tag) Sprint(a ...interface{}) string {
+ name := string(tg)
+ // if stl := GetStyle(name); !stl.IsEmpty() {
+ // return stl.Render(args...)
+ // }
+
+ return RenderCode(GetTagCode(name), a...)
+}
+
+// Sprintf format and render messages
+func (tg Tag) Sprintf(format string, a ...interface{}) string {
+ tag := string(tg)
+ str := fmt.Sprintf(format, a...)
+
+ return RenderString(GetTagCode(tag), str)
+}
diff --git a/vendor/github.com/gookit/color/convert.go b/vendor/github.com/gookit/color/convert.go
new file mode 100644
index 0000000..d641fb7
--- /dev/null
+++ b/vendor/github.com/gookit/color/convert.go
@@ -0,0 +1,593 @@
+package color
+
+import (
+ "fmt"
+ "math"
+ "strconv"
+ "strings"
+)
+
+var (
+ // ---------- basic(16) <=> 256 color convert ----------
+ basicTo256Map = map[uint8]uint8{
+ 30: 0, // black 000000
+ 31: 160, // red c51e14
+ 32: 34, // green 1dc121
+ 33: 184, // yellow c7c329
+ 34: 20, // blue 0a2fc4
+ 35: 170, // magenta c839c5
+ 36: 44, // cyan 20c5c6
+ 37: 188, // white c7c7c7
+ 90: 59, // lightBlack 686868
+ 91: 203, // lightRed fd6f6b
+ 92: 83, // lightGreen 67f86f
+ 93: 227, // lightYellow fffa72
+ 94: 69, // lightBlue 6a76fb
+ 95: 213, // lightMagenta fd7cfc
+ 96: 87, // lightCyan 68fdfe
+ 97: 15, // lightWhite ffffff
+ }
+
+ // ---------- basic(16) <=> RGB color convert ----------
+ // refer from Hyper app
+ basic2hexMap = map[uint8]string{
+ 30: "000000", // black
+ 31: "c51e14", // red
+ 32: "1dc121", // green
+ 33: "c7c329", // yellow
+ 34: "0a2fc4", // blue
+ 35: "c839c5", // magenta
+ 36: "20c5c6", // cyan
+ 37: "c7c7c7", // white
+ 90: "686868", // lightBlack/darkGray
+ 91: "fd6f6b", // lightRed
+ 92: "67f86f", // lightGreen
+ 93: "fffa72", // lightYellow
+ 94: "6a76fb", // lightBlue
+ 95: "fd7cfc", // lightMagenta
+ 96: "68fdfe", // lightCyan
+ 97: "ffffff", // lightWhite
+ }
+ // will convert data from basic2hexMap
+ hex2basicMap = initHex2basicMap()
+
+ // ---------- 256 <=> RGB color convert ----------
+ // adapted from https://gist.github.com/MicahElliott/719710
+
+ c256ToHexMap = init256ToHexMap()
+
+ // rgb to 256 color look-up table
+ // RGB hex => 256 code
+ hexTo256Table = map[string]uint8{
+ // Primary 3-bit (8 colors). Unique representation!
+ "000000": 0,
+ "800000": 1,
+ "008000": 2,
+ "808000": 3,
+ "000080": 4,
+ "800080": 5,
+ "008080": 6,
+ "c0c0c0": 7,
+
+ // Equivalent "bright" versions of original 8 colors.
+ "808080": 8,
+ "ff0000": 9,
+ "00ff00": 10,
+ "ffff00": 11,
+ "0000ff": 12,
+ "ff00ff": 13,
+ "00ffff": 14,
+ "ffffff": 15,
+
+ // values commented out below are duplicates from the prior sections
+
+ // Strictly ascending.
+ // "000000": 16,
+ "000001": 16, // up: avoid key conflicts, value + 1
+ "00005f": 17,
+ "000087": 18,
+ "0000af": 19,
+ "0000d7": 20,
+ // "0000ff": 21,
+ "0000fe": 21, // up: avoid key conflicts, value - 1
+ "005f00": 22,
+ "005f5f": 23,
+ "005f87": 24,
+ "005faf": 25,
+ "005fd7": 26,
+ "005fff": 27,
+ "008700": 28,
+ "00875f": 29,
+ "008787": 30,
+ "0087af": 31,
+ "0087d7": 32,
+ "0087ff": 33,
+ "00af00": 34,
+ "00af5f": 35,
+ "00af87": 36,
+ "00afaf": 37,
+ "00afd7": 38,
+ "00afff": 39,
+ "00d700": 40,
+ "00d75f": 41,
+ "00d787": 42,
+ "00d7af": 43,
+ "00d7d7": 44,
+ "00d7ff": 45,
+ // "00ff00": 46,
+ "00ff01": 46, // up: avoid key conflicts, value + 1
+ "00ff5f": 47,
+ "00ff87": 48,
+ "00ffaf": 49,
+ "00ffd7": 50,
+ // "00ffff": 51,
+ "00fffe": 51, // up: avoid key conflicts, value - 1
+ "5f0000": 52,
+ "5f005f": 53,
+ "5f0087": 54,
+ "5f00af": 55,
+ "5f00d7": 56,
+ "5f00ff": 57,
+ "5f5f00": 58,
+ "5f5f5f": 59,
+ "5f5f87": 60,
+ "5f5faf": 61,
+ "5f5fd7": 62,
+ "5f5fff": 63,
+ "5f8700": 64,
+ "5f875f": 65,
+ "5f8787": 66,
+ "5f87af": 67,
+ "5f87d7": 68,
+ "5f87ff": 69,
+ "5faf00": 70,
+ "5faf5f": 71,
+ "5faf87": 72,
+ "5fafaf": 73,
+ "5fafd7": 74,
+ "5fafff": 75,
+ "5fd700": 76,
+ "5fd75f": 77,
+ "5fd787": 78,
+ "5fd7af": 79,
+ "5fd7d7": 80,
+ "5fd7ff": 81,
+ "5fff00": 82,
+ "5fff5f": 83,
+ "5fff87": 84,
+ "5fffaf": 85,
+ "5fffd7": 86,
+ "5fffff": 87,
+ "870000": 88,
+ "87005f": 89,
+ "870087": 90,
+ "8700af": 91,
+ "8700d7": 92,
+ "8700ff": 93,
+ "875f00": 94,
+ "875f5f": 95,
+ "875f87": 96,
+ "875faf": 97,
+ "875fd7": 98,
+ "875fff": 99,
+ "878700": 100,
+ "87875f": 101,
+ "878787": 102,
+ "8787af": 103,
+ "8787d7": 104,
+ "8787ff": 105,
+ "87af00": 106,
+ "87af5f": 107,
+ "87af87": 108,
+ "87afaf": 109,
+ "87afd7": 110,
+ "87afff": 111,
+ "87d700": 112,
+ "87d75f": 113,
+ "87d787": 114,
+ "87d7af": 115,
+ "87d7d7": 116,
+ "87d7ff": 117,
+ "87ff00": 118,
+ "87ff5f": 119,
+ "87ff87": 120,
+ "87ffaf": 121,
+ "87ffd7": 122,
+ "87ffff": 123,
+ "af0000": 124,
+ "af005f": 125,
+ "af0087": 126,
+ "af00af": 127,
+ "af00d7": 128,
+ "af00ff": 129,
+ "af5f00": 130,
+ "af5f5f": 131,
+ "af5f87": 132,
+ "af5faf": 133,
+ "af5fd7": 134,
+ "af5fff": 135,
+ "af8700": 136,
+ "af875f": 137,
+ "af8787": 138,
+ "af87af": 139,
+ "af87d7": 140,
+ "af87ff": 141,
+ "afaf00": 142,
+ "afaf5f": 143,
+ "afaf87": 144,
+ "afafaf": 145,
+ "afafd7": 146,
+ "afafff": 147,
+ "afd700": 148,
+ "afd75f": 149,
+ "afd787": 150,
+ "afd7af": 151,
+ "afd7d7": 152,
+ "afd7ff": 153,
+ "afff00": 154,
+ "afff5f": 155,
+ "afff87": 156,
+ "afffaf": 157,
+ "afffd7": 158,
+ "afffff": 159,
+ "d70000": 160,
+ "d7005f": 161,
+ "d70087": 162,
+ "d700af": 163,
+ "d700d7": 164,
+ "d700ff": 165,
+ "d75f00": 166,
+ "d75f5f": 167,
+ "d75f87": 168,
+ "d75faf": 169,
+ "d75fd7": 170,
+ "d75fff": 171,
+ "d78700": 172,
+ "d7875f": 173,
+ "d78787": 174,
+ "d787af": 175,
+ "d787d7": 176,
+ "d787ff": 177,
+ "d7af00": 178,
+ "d7af5f": 179,
+ "d7af87": 180,
+ "d7afaf": 181,
+ "d7afd7": 182,
+ "d7afff": 183,
+ "d7d700": 184,
+ "d7d75f": 185,
+ "d7d787": 186,
+ "d7d7af": 187,
+ "d7d7d7": 188,
+ "d7d7ff": 189,
+ "d7ff00": 190,
+ "d7ff5f": 191,
+ "d7ff87": 192,
+ "d7ffaf": 193,
+ "d7ffd7": 194,
+ "d7ffff": 195,
+ // "ff0000": 196,
+ "ff0001": 196, // up: avoid key conflicts, value + 1
+ "ff005f": 197,
+ "ff0087": 198,
+ "ff00af": 199,
+ "ff00d7": 200,
+ // "ff00ff": 201,
+ "ff00fe": 201, // up: avoid key conflicts, value - 1
+ "ff5f00": 202,
+ "ff5f5f": 203,
+ "ff5f87": 204,
+ "ff5faf": 205,
+ "ff5fd7": 206,
+ "ff5fff": 207,
+ "ff8700": 208,
+ "ff875f": 209,
+ "ff8787": 210,
+ "ff87af": 211,
+ "ff87d7": 212,
+ "ff87ff": 213,
+ "ffaf00": 214,
+ "ffaf5f": 215,
+ "ffaf87": 216,
+ "ffafaf": 217,
+ "ffafd7": 218,
+ "ffafff": 219,
+ "ffd700": 220,
+ "ffd75f": 221,
+ "ffd787": 222,
+ "ffd7af": 223,
+ "ffd7d7": 224,
+ "ffd7ff": 225,
+ // "ffff00": 226,
+ "ffff01": 226, // up: avoid key conflicts, value + 1
+ "ffff5f": 227,
+ "ffff87": 228,
+ "ffffaf": 229,
+ "ffffd7": 230,
+ // "ffffff": 231,
+ "fffffe": 231, // up: avoid key conflicts, value - 1
+
+ // Gray-scale range.
+ "080808": 232,
+ "121212": 233,
+ "1c1c1c": 234,
+ "262626": 235,
+ "303030": 236,
+ "3a3a3a": 237,
+ "444444": 238,
+ "4e4e4e": 239,
+ "585858": 240,
+ "626262": 241,
+ "6c6c6c": 242,
+ "767676": 243,
+ // "808080": 244,
+ "808081": 244, // up: avoid key conflicts, value + 1
+ "8a8a8a": 245,
+ "949494": 246,
+ "9e9e9e": 247,
+ "a8a8a8": 248,
+ "b2b2b2": 249,
+ "bcbcbc": 250,
+ "c6c6c6": 251,
+ "d0d0d0": 252,
+ "dadada": 253,
+ "e4e4e4": 254,
+ "eeeeee": 255,
+ }
+
+ incs = []uint8{0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff}
+)
+
+func initHex2basicMap() map[string]uint8 {
+ h2b := make(map[string]uint8, len(basic2hexMap))
+ // ini data map
+ for u, s := range basic2hexMap {
+ h2b[s] = u
+ }
+ return h2b
+}
+
+func init256ToHexMap() map[uint8]string {
+ c256toh := make(map[uint8]string, len(hexTo256Table))
+ // ini data map
+ for hex, c256 := range hexTo256Table {
+ c256toh[c256] = hex
+ }
+ return c256toh
+}
+
+// RgbTo256Table mapping data
+func RgbTo256Table() map[string]uint8 {
+ return hexTo256Table
+}
+
+// Colors2code convert colors to code. return like "32;45;3"
+func Colors2code(colors ...Color) string {
+ if len(colors) == 0 {
+ return ""
+ }
+
+ var codes []string
+ for _, color := range colors {
+ codes = append(codes, color.String())
+ }
+
+ return strings.Join(codes, ";")
+}
+
+/*************************************************************
+ * HEX code <=> RGB/True color code
+ *************************************************************/
+
+// Hex2rgb alias of the HexToRgb()
+func Hex2rgb(hex string) []int { return HexToRgb(hex) }
+
+// HexToRGB alias of the HexToRgb()
+func HexToRGB(hex string) []int { return HexToRgb(hex) }
+
+// HexToRgb convert hex color string to RGB numbers
+//
+// Usage:
+// rgb := HexToRgb("ccc") // rgb: [204 204 204]
+// rgb := HexToRgb("aabbcc") // rgb: [170 187 204]
+// rgb := HexToRgb("#aabbcc") // rgb: [170 187 204]
+// rgb := HexToRgb("0xad99c0") // rgb: [170 187 204]
+func HexToRgb(hex string) (rgb []int) {
+ hex = strings.TrimSpace(hex)
+ if hex == "" {
+ return
+ }
+
+ // like from css. eg "#ccc" "#ad99c0"
+ if hex[0] == '#' {
+ hex = hex[1:]
+ }
+
+ hex = strings.ToLower(hex)
+ switch len(hex) {
+ case 3: // "ccc"
+ hex = string([]byte{hex[0], hex[0], hex[1], hex[1], hex[2], hex[2]})
+ case 8: // "0xad99c0"
+ hex = strings.TrimPrefix(hex, "0x")
+ }
+
+ // recheck
+ if len(hex) != 6 {
+ return
+ }
+
+ // convert string to int64
+ if i64, err := strconv.ParseInt(hex, 16, 32); err == nil {
+ color := int(i64)
+ // parse int
+ rgb = make([]int, 3)
+ rgb[0] = color >> 16
+ rgb[1] = (color & 0x00FF00) >> 8
+ rgb[2] = color & 0x0000FF
+ }
+ return
+}
+
+// Rgb2hex alias of the RgbToHex()
+func Rgb2hex(rgb []int) string { return RgbToHex(rgb) }
+
+// RgbToHex convert RGB-code to hex-code
+//
+// Usage:
+// hex := RgbToHex([]int{170, 187, 204}) // hex: "aabbcc"
+func RgbToHex(rgb []int) string {
+ hexNodes := make([]string, len(rgb))
+
+ for _, v := range rgb {
+ hexNodes = append(hexNodes, strconv.FormatInt(int64(v), 16))
+ }
+ return strings.Join(hexNodes, "")
+}
+
+/*************************************************************
+ * 4bit(16) color <=> RGB/True color
+ *************************************************************/
+
+// Basic2hex convert basic color to hex string.
+func Basic2hex(val uint8) string {
+ return basic2hexMap[val]
+}
+
+// Hex2basic convert hex string to basic color code.
+func Hex2basic(hex string) uint8 {
+ return hex2basicMap[hex]
+}
+
+// Rgb2basic alias of the RgbToAnsi()
+func Rgb2basic(r, g, b uint8, isBg bool) uint8 {
+ // is basic color, direct use static map data.
+ hex := RgbToHex([]int{int(r), int(g), int(b)})
+ if val, ok := hex2basicMap[hex]; ok {
+ if isBg {
+ return val + 10
+ }
+ return val
+ }
+
+ return RgbToAnsi(r, g, b, isBg)
+}
+
+// Rgb2ansi alias of the RgbToAnsi()
+func Rgb2ansi(r, g, b uint8, isBg bool) uint8 {
+ return RgbToAnsi(r, g, b, isBg)
+}
+
+// RgbToAnsi convert RGB-code to 16-code
+// refer https://github.com/radareorg/radare2/blob/master/libr/cons/rgb.c#L249-L271
+func RgbToAnsi(r, g, b uint8, isBg bool) uint8 {
+ var bright, c, k uint8
+ base := compareVal(isBg, BgBase, FgBase)
+
+ // eco bright-specific
+ if r == 0x80 && g == 0x80 && b == 0x80 { // 0x80=128
+ bright = 53
+ } else if r == 0xff || g == 0xff || b == 0xff { // 0xff=255
+ bright = 60
+ } // else bright = 0
+
+ if r == g && g == b {
+ // 0x7f=127
+ // r = (r > 0x7f) ? 1 : 0;
+ r = compareVal(r > 0x7f, 1, 0)
+ g = compareVal(g > 0x7f, 1, 0)
+ b = compareVal(b > 0x7f, 1, 0)
+ } else {
+ k = (r + g + b) / 3
+
+ // r = (r >= k) ? 1 : 0;
+ r = compareVal(r >= k, 1, 0)
+ g = compareVal(g >= k, 1, 0)
+ b = compareVal(b >= k, 1, 0)
+ }
+
+ // c = (r ? 1 : 0) + (g ? (b ? 6 : 2) : (b ? 4 : 0))
+ c = compareVal(r > 0, 1, 0)
+
+ if g > 0 {
+ c += compareVal(b > 0, 6, 2)
+ } else {
+ c += compareVal(b > 0, 4, 0)
+ }
+ return base + bright + c
+}
+
+/*************************************************************
+ * 8bit(256) color <=> RGB/True color
+ *************************************************************/
+
+// Rgb2short convert RGB-code to 256-code
+func Rgb2short(r, g, b uint8) uint8 {
+ return RgbTo256(r, g, b)
+}
+
+// RgbTo256 convert RGB-code to 256-code
+func RgbTo256(r, g, b uint8) uint8 {
+ res := make([]uint8, 3)
+ for partI, part := range [3]uint8{r, g, b} {
+ i := 0
+ for i < len(incs)-1 {
+ s, b := incs[i], incs[i+1] // smaller, bigger
+ if s <= part && part <= b {
+ s1 := math.Abs(float64(s) - float64(part))
+ b1 := math.Abs(float64(b) - float64(part))
+ var closest uint8
+ if s1 < b1 {
+ closest = s
+ } else {
+ closest = b
+ }
+ res[partI] = closest
+ break
+ }
+ i++
+ }
+ }
+ hex := fmt.Sprintf("%02x%02x%02x", res[0], res[1], res[2])
+ equiv := hexTo256Table[hex]
+ return equiv
+}
+
+// C256ToRgb convert an 256 color code to RGB numbers
+func C256ToRgb(val uint8) (rgb []uint8) {
+ hex := c256ToHexMap[val]
+ // convert to rgb code
+ rgbInts := Hex2rgb(hex)
+
+ return []uint8{
+ uint8(rgbInts[0]),
+ uint8(rgbInts[1]),
+ uint8(rgbInts[2]),
+ }
+}
+
+// C256ToRgbV1 convert an 256 color code to RGB numbers
+// refer https://github.com/torvalds/linux/commit/cec5b2a97a11ade56a701e83044d0a2a984c67b4
+func C256ToRgbV1(val uint8) (rgb []uint8) {
+ var r, g, b uint8
+ if val < 8 { // Standard colours.
+ // r = val&1 ? 0xaa : 0x00;
+ r = compareVal(val&1 == 1, 0xaa, 0x00)
+ g = compareVal(val&2 == 2, 0xaa, 0x00)
+ b = compareVal(val&4 == 4, 0xaa, 0x00)
+ } else if val < 16 {
+ // r = val & 1 ? 0xff : 0x55;
+ r = compareVal(val&1 == 1, 0xff, 0x55)
+ g = compareVal(val&2 == 2, 0xff, 0x55)
+ b = compareVal(val&4 == 4, 0xff, 0x55)
+ } else if val < 232 { /* 6x6x6 colour cube. */
+ r = (val - 16) / 36 * 85 / 2
+ g = (val - 16) / 6 % 6 * 85 / 2
+ b = (val - 16) % 6 * 85 / 2
+ } else { /* Grayscale ramp. */
+ nv := uint8(int(val)*10 - 2312)
+ // set value
+ r, g, b = nv, nv, nv
+ }
+
+ return []uint8{r, g, b}
+}
diff --git a/vendor/github.com/gookit/color/detect_env.go b/vendor/github.com/gookit/color/detect_env.go
new file mode 100644
index 0000000..f5dde8f
--- /dev/null
+++ b/vendor/github.com/gookit/color/detect_env.go
@@ -0,0 +1,281 @@
+package color
+
+import (
+ "io"
+ "io/ioutil"
+ "os"
+ "runtime"
+ "strconv"
+ "strings"
+ "syscall"
+
+ "github.com/xo/terminfo"
+)
+
+/*************************************************************
+ * helper methods for detect color supports
+ *************************************************************/
+
+// DetectColorLevel for current env
+//
+// NOTICE: The method will detect terminal info each times,
+// if only want get current color level, please direct call SupportColor() or TermColorLevel()
+func DetectColorLevel() terminfo.ColorLevel {
+ level, _ := detectTermColorLevel()
+ return level
+}
+
+// detect terminal color support level
+//
+// refer https://github.com/Delta456/box-cli-maker
+func detectTermColorLevel() (level terminfo.ColorLevel, needVTP bool) {
+ // on windows WSL:
+ // - runtime.GOOS == "Linux"
+ // - support true-color
+ // env:
+ // WSL_DISTRO_NAME=Debian
+ if val := os.Getenv("WSL_DISTRO_NAME"); val != "" {
+ // detect WSL as it has True Color support
+ if detectWSL() {
+ debugf("True Color support on WSL environment")
+ return terminfo.ColorLevelMillions, false
+ }
+ }
+
+ isWin := runtime.GOOS == "windows"
+ termVal := os.Getenv("TERM")
+
+ // on TERM=screen: not support true-color
+ if termVal != "screen" {
+ // On JetBrains Terminal
+ // - support true-color
+ // env:
+ // TERMINAL_EMULATOR=JetBrains-JediTerm
+ val := os.Getenv("TERMINAL_EMULATOR")
+ if val == "JetBrains-JediTerm" {
+ debugf("True Color support on JetBrains-JediTerm, is win: %v", isWin)
+ return terminfo.ColorLevelMillions, isWin
+ }
+ }
+
+ // level, err = terminfo.ColorLevelFromEnv()
+ level = detectColorLevelFromEnv(termVal, isWin)
+ debugf("color level by detectColorLevelFromEnv: %s", level.String())
+
+ // fallback: simple detect by TERM value string.
+ if level == terminfo.ColorLevelNone {
+ debugf("level none - fallback check special term color support")
+ // on Windows: enable VTP as it has True Color support
+ level, needVTP = detectSpecialTermColor(termVal)
+ }
+ return
+}
+
+// detectColorFromEnv returns the color level COLORTERM, FORCE_COLOR,
+// TERM_PROGRAM, or determined from the TERM environment variable.
+//
+// refer the terminfo.ColorLevelFromEnv()
+// https://en.wikipedia.org/wiki/Terminfo
+func detectColorLevelFromEnv(termVal string, isWin bool) terminfo.ColorLevel {
+ // check for overriding environment variables
+ colorTerm, termProg, forceColor := os.Getenv("COLORTERM"), os.Getenv("TERM_PROGRAM"), os.Getenv("FORCE_COLOR")
+ switch {
+ case strings.Contains(colorTerm, "truecolor") || strings.Contains(colorTerm, "24bit"):
+ if termVal == "screen" { // on TERM=screen: not support true-color
+ return terminfo.ColorLevelHundreds
+ }
+ return terminfo.ColorLevelMillions
+ case colorTerm != "" || forceColor != "":
+ return terminfo.ColorLevelBasic
+ case termProg == "Apple_Terminal":
+ return terminfo.ColorLevelHundreds
+ case termProg == "Terminus" || termProg == "Hyper":
+ if termVal == "screen" { // on TERM=screen: not support true-color
+ return terminfo.ColorLevelHundreds
+ }
+ return terminfo.ColorLevelMillions
+ case termProg == "iTerm.app":
+ if termVal == "screen" { // on TERM=screen: not support true-color
+ return terminfo.ColorLevelHundreds
+ }
+
+ // check iTerm version
+ ver := os.Getenv("TERM_PROGRAM_VERSION")
+ if ver != "" {
+ i, err := strconv.Atoi(strings.Split(ver, ".")[0])
+ if err != nil {
+ saveInternalError(terminfo.ErrInvalidTermProgramVersion)
+ // return terminfo.ColorLevelNone
+ return terminfo.ColorLevelHundreds
+ }
+ if i == 3 {
+ return terminfo.ColorLevelMillions
+ }
+ }
+ return terminfo.ColorLevelHundreds
+ }
+
+ // otherwise determine from TERM's max_colors capability
+ if !isWin && termVal != "" {
+ debugf("TERM=%s - check color level by load terminfo file", termVal)
+ ti, err := terminfo.Load(termVal)
+ if err != nil {
+ saveInternalError(err)
+ return terminfo.ColorLevelNone
+ }
+
+ debugf("the loaded term info file is: %s", ti.File)
+ v, ok := ti.Nums[terminfo.MaxColors]
+ switch {
+ case !ok || v <= 16:
+ return terminfo.ColorLevelNone
+ case ok && v >= 256:
+ return terminfo.ColorLevelHundreds
+ }
+ return terminfo.ColorLevelBasic
+ }
+
+ // no TERM env value. default return none level
+ return terminfo.ColorLevelNone
+ // return terminfo.ColorLevelBasic
+}
+
+var detectedWSL bool
+var wslContents string
+
+// https://github.com/Microsoft/WSL/issues/423#issuecomment-221627364
+func detectWSL() bool {
+ if !detectedWSL {
+ b := make([]byte, 1024)
+ // `cat /proc/version`
+ // on mac:
+ // !not the file!
+ // on linux(debian,ubuntu,alpine):
+ // Linux version 4.19.121-linuxkit (root@18b3f92ade35) (gcc version 9.2.0 (Alpine 9.2.0)) #1 SMP Thu Jan 21 15:36:34 UTC 2021
+ // on win git bash, conEmu:
+ // MINGW64_NT-10.0-19042 version 3.1.7-340.x86_64 (@WIN-N0G619FD3UK) (gcc version 9.3.0 (GCC) ) 2020-10-23 13:08 UTC
+ // on WSL:
+ // Linux version 4.4.0-19041-Microsoft (Microsoft@Microsoft.com) (gcc version 5.4.0 (GCC) ) #488-Microsoft Mon Sep 01 13:43:00 PST 2020
+ f, err := os.Open("/proc/version")
+ if err == nil {
+ _, _ = f.Read(b) // ignore error
+ if err = f.Close(); err != nil {
+ saveInternalError(err)
+ }
+
+ wslContents = string(b)
+ }
+ detectedWSL = true
+ }
+ return strings.Contains(wslContents, "Microsoft")
+}
+
+// refer
+// https://github.com/Delta456/box-cli-maker/blob/7b5a1ad8a016ce181e7d8b05e24b54ff60b4b38a/detect_unix.go#L27-L45
+// detect WSL as it has True Color support
+func isWSL() bool {
+ // on windows WSL:
+ // - runtime.GOOS == "Linux"
+ // - support true-color
+ // WSL_DISTRO_NAME=Debian
+ if val := os.Getenv("WSL_DISTRO_NAME"); val == "" {
+ return false
+ }
+
+ // `cat /proc/sys/kernel/osrelease`
+ // on mac:
+ // !not the file!
+ // on linux:
+ // 4.19.121-linuxkit
+ // on WSL Output:
+ // 4.4.0-19041-Microsoft
+ wsl, err := ioutil.ReadFile("/proc/sys/kernel/osrelease")
+ if err != nil {
+ saveInternalError(err)
+ return false
+ }
+
+ // it gives "Microsoft" for WSL and "microsoft" for WSL 2
+ // it support True-color
+ content := strings.ToLower(string(wsl))
+ return strings.Contains(content, "microsoft")
+}
+
+/*************************************************************
+ * helper methods for check env
+ *************************************************************/
+
+// IsWindows OS env
+func IsWindows() bool {
+ return runtime.GOOS == "windows"
+}
+
+// IsConsole Determine whether w is one of stderr, stdout, stdin
+func IsConsole(w io.Writer) bool {
+ o, ok := w.(*os.File)
+ if !ok {
+ return false
+ }
+
+ fd := o.Fd()
+
+ // fix: cannot use 'o == os.Stdout' to compare
+ return fd == uintptr(syscall.Stdout) || fd == uintptr(syscall.Stdin) || fd == uintptr(syscall.Stderr)
+}
+
+// IsMSys msys(MINGW64) environment, does not necessarily support color
+func IsMSys() bool {
+ // like "MSYSTEM=MINGW64"
+ if len(os.Getenv("MSYSTEM")) > 0 {
+ return true
+ }
+
+ return false
+}
+
+// IsSupportColor check current console is support color.
+//
+// NOTICE: The method will detect terminal info each times,
+// if only want get current color level, please direct call SupportColor() or TermColorLevel()
+func IsSupportColor() bool {
+ return IsSupport16Color()
+}
+
+// IsSupportColor check current console is support color.
+//
+// NOTICE: The method will detect terminal info each times,
+// if only want get current color level, please direct call SupportColor() or TermColorLevel()
+func IsSupport16Color() bool {
+ level, _ := detectTermColorLevel()
+ return level > terminfo.ColorLevelNone
+}
+
+// IsSupport256Color render check
+//
+// NOTICE: The method will detect terminal info each times,
+// if only want get current color level, please direct call SupportColor() or TermColorLevel()
+func IsSupport256Color() bool {
+ level, _ := detectTermColorLevel()
+ return level > terminfo.ColorLevelBasic
+}
+
+// IsSupportRGBColor check. alias of the IsSupportTrueColor()
+//
+// NOTICE: The method will detect terminal info each times,
+// if only want get current color level, please direct call SupportColor() or TermColorLevel()
+func IsSupportRGBColor() bool {
+ return IsSupportTrueColor()
+}
+
+// IsSupportTrueColor render check.
+//
+// NOTICE: The method will detect terminal info each times,
+// if only want get current color level, please direct call SupportColor() or TermColorLevel()
+//
+// ENV:
+// "COLORTERM=truecolor"
+// "COLORTERM=24bit"
+func IsSupportTrueColor() bool {
+ level, _ := detectTermColorLevel()
+ return level > terminfo.ColorLevelHundreds
+}
diff --git a/vendor/github.com/gookit/color/detect_nonwin.go b/vendor/github.com/gookit/color/detect_nonwin.go
new file mode 100644
index 0000000..75c7202
--- /dev/null
+++ b/vendor/github.com/gookit/color/detect_nonwin.go
@@ -0,0 +1,48 @@
+// +build !windows
+
+// The method in the file has no effect
+// Only for compatibility with non-Windows systems
+
+package color
+
+import (
+ "strings"
+ "syscall"
+
+ "github.com/xo/terminfo"
+)
+
+// detect special term color support
+func detectSpecialTermColor(termVal string) (terminfo.ColorLevel, bool) {
+ if termVal == "" {
+ return terminfo.ColorLevelNone, false
+ }
+
+ debugf("terminfo check fail - fallback detect color by check TERM value")
+
+ // on TERM=screen:
+ // - support 256, not support true-color. test on macOS
+ if termVal == "screen" {
+ return terminfo.ColorLevelHundreds, false
+ }
+
+ if strings.Contains(termVal, "256color") {
+ return terminfo.ColorLevelHundreds, false
+ }
+
+ if strings.Contains(termVal, "xterm") {
+ return terminfo.ColorLevelHundreds, false
+ // return terminfo.ColorLevelBasic, false
+ }
+
+ // return terminfo.ColorLevelNone, nil
+ return terminfo.ColorLevelBasic, false
+}
+
+// IsTerminal returns true if the given file descriptor is a terminal.
+//
+// Usage:
+// IsTerminal(os.Stdout.Fd())
+func IsTerminal(fd uintptr) bool {
+ return fd == uintptr(syscall.Stdout) || fd == uintptr(syscall.Stdin) || fd == uintptr(syscall.Stderr)
+}
diff --git a/vendor/github.com/gookit/color/detect_windows.go b/vendor/github.com/gookit/color/detect_windows.go
new file mode 100644
index 0000000..7707d9c
--- /dev/null
+++ b/vendor/github.com/gookit/color/detect_windows.go
@@ -0,0 +1,243 @@
+// +build windows
+
+// Display color on windows
+// refer:
+// golang.org/x/sys/windows
+// golang.org/x/crypto/ssh/terminal
+// https://docs.microsoft.com/en-us/windows/console
+package color
+
+import (
+ "os"
+ "syscall"
+ "unsafe"
+
+ "github.com/xo/terminfo"
+ "golang.org/x/sys/windows"
+)
+
+// related docs
+// https://docs.microsoft.com/zh-cn/windows/console/console-virtual-terminal-sequences
+// https://docs.microsoft.com/zh-cn/windows/console/console-virtual-terminal-sequences#samples
+var (
+ // isMSys bool
+ kernel32 *syscall.LazyDLL
+
+ procGetConsoleMode *syscall.LazyProc
+ procSetConsoleMode *syscall.LazyProc
+)
+
+func init() {
+ if !SupportColor() {
+ isLikeInCmd = true
+ return
+ }
+
+ // if disabled.
+ if !Enable {
+ return
+ }
+
+ // if at windows's ConEmu, Cmder, putty ... terminals not need VTP
+
+ // -------- try force enable colors on windows terminal -------
+ tryEnableVTP(needVTP)
+
+ // fetch console screen buffer info
+ // err := getConsoleScreenBufferInfo(uintptr(syscall.Stdout), &defScreenInfo)
+}
+
+// try force enable colors on windows terminal
+func tryEnableVTP(enable bool) bool {
+ if !enable {
+ return false
+ }
+
+ debugf("True-Color by enable VirtualTerminalProcessing on windows")
+
+ initKernel32Proc()
+
+ // enable colors on windows terminal
+ if tryEnableOnCONOUT() {
+ return true
+ }
+
+ return tryEnableOnStdout()
+}
+
+func initKernel32Proc() {
+ if kernel32 != nil {
+ return
+ }
+
+ // load related windows dll
+ // https://docs.microsoft.com/en-us/windows/console/setconsolemode
+ kernel32 = syscall.NewLazyDLL("kernel32.dll")
+
+ procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
+ procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
+}
+
+func tryEnableOnCONOUT() bool {
+ outHandle, err := syscall.Open("CONOUT$", syscall.O_RDWR, 0)
+ if err != nil {
+ saveInternalError(err)
+ return false
+ }
+
+ err = EnableVirtualTerminalProcessing(outHandle, true)
+ if err != nil {
+ saveInternalError(err)
+ return false
+ }
+
+ return true
+}
+
+func tryEnableOnStdout() bool {
+ // try direct open syscall.Stdout
+ err := EnableVirtualTerminalProcessing(syscall.Stdout, true)
+ if err != nil {
+ saveInternalError(err)
+ return false
+ }
+
+ return true
+}
+
+// Get the Windows Version and Build Number
+var (
+ winVersion, _, buildNumber = windows.RtlGetNtVersionNumbers()
+)
+
+// refer
+// https://github.com/Delta456/box-cli-maker/blob/7b5a1ad8a016ce181e7d8b05e24b54ff60b4b38a/detect_windows.go#L30-L57
+// https://github.com/gookit/color/issues/25#issuecomment-738727917
+// detects the Color Level Supported on windows: cmd, powerShell
+func detectSpecialTermColor(termVal string) (tl terminfo.ColorLevel, needVTP bool) {
+ if os.Getenv("ConEmuANSI") == "ON" {
+ debugf("support True Color by ConEmuANSI=ON")
+ // ConEmuANSI is "ON" for generic ANSI support
+ // but True Color option is enabled by default
+ // I am just assuming that people wouldn't have disabled it
+ // Even if it is not enabled then ConEmu will auto round off
+ // accordingly
+ return terminfo.ColorLevelMillions, false
+ }
+
+ // Before Windows 10 Build Number 10586, console never supported ANSI Colors
+ if buildNumber < 10586 || winVersion < 10 {
+ // Detect if using ANSICON on older systems
+ if os.Getenv("ANSICON") != "" {
+ conVersion := os.Getenv("ANSICON_VER")
+ // 8 bit Colors were only supported after v1.81 release
+ if conVersion >= "181" {
+ return terminfo.ColorLevelHundreds, false
+ }
+ return terminfo.ColorLevelBasic, false
+ }
+
+ return terminfo.ColorLevelNone, false
+ }
+
+ // True Color is not available before build 14931 so fallback to 8 bit color.
+ if buildNumber < 14931 {
+ return terminfo.ColorLevelHundreds, true
+ }
+
+ // Windows 10 build 14931 is the first release that supports 16m/TrueColor
+ debugf("support True Color on windows version is >= build 14931")
+ return terminfo.ColorLevelMillions, true
+}
+
+/*************************************************************
+ * render full color code on windows(8,16,24bit color)
+ *************************************************************/
+
+// docs https://docs.microsoft.com/zh-cn/windows/console/getconsolemode#parameters
+const (
+ // equals to docs page's ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
+ EnableVirtualTerminalProcessingMode uint32 = 0x4
+)
+
+// EnableVirtualTerminalProcessing Enable virtual terminal processing
+//
+// ref from github.com/konsorten/go-windows-terminal-sequences
+// doc https://docs.microsoft.com/zh-cn/windows/console/console-virtual-terminal-sequences#samples
+//
+// Usage:
+// err := EnableVirtualTerminalProcessing(syscall.Stdout, true)
+// // support print color text
+// err = EnableVirtualTerminalProcessing(syscall.Stdout, false)
+func EnableVirtualTerminalProcessing(stream syscall.Handle, enable bool) error {
+ var mode uint32
+ // Check if it is currently in the terminal
+ // err := syscall.GetConsoleMode(syscall.Stdout, &mode)
+ err := syscall.GetConsoleMode(stream, &mode)
+ if err != nil {
+ // fmt.Println("EnableVirtualTerminalProcessing", err)
+ return err
+ }
+
+ if enable {
+ mode |= EnableVirtualTerminalProcessingMode
+ } else {
+ mode &^= EnableVirtualTerminalProcessingMode
+ }
+
+ ret, _, err := procSetConsoleMode.Call(uintptr(stream), uintptr(mode))
+ if ret == 0 {
+ return err
+ }
+
+ return nil
+}
+
+// renderColorCodeOnCmd enable cmd color render.
+// func renderColorCodeOnCmd(fn func()) {
+// err := EnableVirtualTerminalProcessing(syscall.Stdout, true)
+// // if is not in terminal, will clear color tag.
+// if err != nil {
+// // panic(err)
+// fn()
+// return
+// }
+//
+// // force open color render
+// old := ForceOpenColor()
+// fn()
+// // revert color setting
+// supportColor = old
+//
+// err = EnableVirtualTerminalProcessing(syscall.Stdout, false)
+// if err != nil {
+// panic(err)
+// }
+// }
+
+/*************************************************************
+ * render simple color code on windows
+ *************************************************************/
+
+// IsTty returns true if the given file descriptor is a terminal.
+func IsTty(fd uintptr) bool {
+ initKernel32Proc()
+
+ var st uint32
+ r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
+ return r != 0 && e == 0
+}
+
+// IsTerminal returns true if the given file descriptor is a terminal.
+//
+// Usage:
+// fd := os.Stdout.Fd()
+// fd := uintptr(syscall.Stdout) // for windows
+// IsTerminal(fd)
+func IsTerminal(fd uintptr) bool {
+ initKernel32Proc()
+
+ var st uint32
+ r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
+ return r != 0 && e == 0
+}
diff --git a/vendor/github.com/gookit/color/go.mod b/vendor/github.com/gookit/color/go.mod
new file mode 100644
index 0000000..cd94efc
--- /dev/null
+++ b/vendor/github.com/gookit/color/go.mod
@@ -0,0 +1,9 @@
+module github.com/gookit/color
+
+go 1.12
+
+require (
+ github.com/stretchr/testify v1.6.1
+ github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778
+ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44
+)
diff --git a/vendor/github.com/gookit/color/go.sum b/vendor/github.com/gookit/color/go.sum
new file mode 100644
index 0000000..2d67cba
--- /dev/null
+++ b/vendor/github.com/gookit/color/go.sum
@@ -0,0 +1,15 @@
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
+github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/BESIg2ze4Pgfh/aI8c=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/vendor/github.com/gookit/color/printer.go b/vendor/github.com/gookit/color/printer.go
new file mode 100644
index 0000000..326aabc
--- /dev/null
+++ b/vendor/github.com/gookit/color/printer.go
@@ -0,0 +1,122 @@
+package color
+
+import "fmt"
+
+/*************************************************************
+ * colored message Printer
+ *************************************************************/
+
+// PrinterFace interface
+type PrinterFace interface {
+ fmt.Stringer
+ Sprint(a ...interface{}) string
+ Sprintf(format string, a ...interface{}) string
+ Print(a ...interface{})
+ Printf(format string, a ...interface{})
+ Println(a ...interface{})
+}
+
+// Printer a generic color message printer.
+//
+// Usage:
+// p := &Printer{Code: "32;45;3"}
+// p.Print("message")
+type Printer struct {
+ // NoColor disable color.
+ NoColor bool
+ // Code color code string. eg "32;45;3"
+ Code string
+}
+
+// NewPrinter instance
+func NewPrinter(colorCode string) *Printer {
+ return &Printer{Code: colorCode}
+}
+
+// String returns color code string. eg: "32;45;3"
+func (p *Printer) String() string {
+ // panic("implement me")
+ return p.Code
+}
+
+// Sprint returns rendering colored messages
+func (p *Printer) Sprint(a ...interface{}) string {
+ return RenderCode(p.String(), a...)
+}
+
+// Sprintf returns format and rendering colored messages
+func (p *Printer) Sprintf(format string, a ...interface{}) string {
+ return RenderString(p.String(), fmt.Sprintf(format, a...))
+}
+
+// Print rendering colored messages
+func (p *Printer) Print(a ...interface{}) {
+ doPrintV2(p.String(), fmt.Sprint(a...))
+}
+
+// Printf format and rendering colored messages
+func (p *Printer) Printf(format string, a ...interface{}) {
+ doPrintV2(p.String(), fmt.Sprintf(format, a...))
+}
+
+// Println rendering colored messages with newline
+func (p *Printer) Println(a ...interface{}) {
+ doPrintlnV2(p.Code, a)
+}
+
+// IsEmpty color code
+func (p *Printer) IsEmpty() bool {
+ return p.Code == ""
+}
+
+/*************************************************************
+ * SimplePrinter struct
+ *************************************************************/
+
+// SimplePrinter use for quick use color print on inject to struct
+type SimplePrinter struct{}
+
+// Print message
+func (s *SimplePrinter) Print(v ...interface{}) {
+ Print(v...)
+}
+
+// Printf message
+func (s *SimplePrinter) Printf(format string, v ...interface{}) {
+ Printf(format, v...)
+}
+
+// Println message
+func (s *SimplePrinter) Println(v ...interface{}) {
+ Println(v...)
+}
+
+// Infof message
+func (s *SimplePrinter) Infof(format string, a ...interface{}) {
+ Info.Printf(format, a...)
+}
+
+// Infoln message
+func (s *SimplePrinter) Infoln(a ...interface{}) {
+ Info.Println(a...)
+}
+
+// Warnf message
+func (s *SimplePrinter) Warnf(format string, a ...interface{}) {
+ Warn.Printf(format, a...)
+}
+
+// Warnln message
+func (s *SimplePrinter) Warnln(a ...interface{}) {
+ Warn.Println(a...)
+}
+
+// Errorf message
+func (s *SimplePrinter) Errorf(format string, a ...interface{}) {
+ Error.Printf(format, a...)
+}
+
+// Errorln message
+func (s *SimplePrinter) Errorln(a ...interface{}) {
+ Error.Println(a...)
+}
diff --git a/vendor/github.com/gookit/color/quickstart.go b/vendor/github.com/gookit/color/quickstart.go
new file mode 100644
index 0000000..3cc3b77
--- /dev/null
+++ b/vendor/github.com/gookit/color/quickstart.go
@@ -0,0 +1,109 @@
+package color
+
+/*************************************************************
+ * quick use color print message
+ *************************************************************/
+
+// Redp print message with Red color
+func Redp(a ...interface{}) {
+ Red.Print(a...)
+}
+
+// Redln print message line with Red color
+func Redln(a ...interface{}) {
+ Red.Println(a...)
+}
+
+// Bluep print message with Blue color
+func Bluep(a ...interface{}) {
+ Blue.Print(a...)
+}
+
+// Blueln print message line with Blue color
+func Blueln(a ...interface{}) {
+ Blue.Println(a...)
+}
+
+// Cyanp print message with Cyan color
+func Cyanp(a ...interface{}) {
+ Cyan.Print(a...)
+}
+
+// Cyanln print message line with Cyan color
+func Cyanln(a ...interface{}) {
+ Cyan.Println(a...)
+}
+
+// Grayp print message with Gray color
+func Grayp(a ...interface{}) {
+ Gray.Print(a...)
+}
+
+// Grayln print message line with Gray color
+func Grayln(a ...interface{}) {
+ Gray.Println(a...)
+}
+
+// Greenp print message with Green color
+func Greenp(a ...interface{}) {
+ Green.Print(a...)
+}
+
+// Greenln print message line with Green color
+func Greenln(a ...interface{}) {
+ Green.Println(a...)
+}
+
+// Yellowp print message with Yellow color
+func Yellowp(a ...interface{}) {
+ Yellow.Print(a...)
+}
+
+// Yellowln print message line with Yellow color
+func Yellowln(a ...interface{}) {
+ Yellow.Println(a...)
+}
+
+// Magentap print message with Magenta color
+func Magentap(a ...interface{}) {
+ Magenta.Print(a...)
+}
+
+// Magentaln print message line with Magenta color
+func Magentaln(a ...interface{}) {
+ Magenta.Println(a...)
+}
+
+/*************************************************************
+ * quick use style print message
+ *************************************************************/
+
+// Infof print message with Info style
+func Infof(format string, a ...interface{}) {
+ Info.Printf(format, a...)
+}
+
+// Infoln print message with Info style
+func Infoln(a ...interface{}) {
+ Info.Println(a...)
+}
+
+// Errorf print message with Error style
+func Errorf(format string, a ...interface{}) {
+ Error.Printf(format, a...)
+}
+
+// Errorln print message with Error style
+func Errorln(a ...interface{}) {
+ Error.Println(a...)
+}
+
+// Warnf print message with Warn style
+func Warnf(format string, a ...interface{}) {
+ Warn.Printf(format, a...)
+}
+
+// Warnln print message with Warn style
+func Warnln(a ...interface{}) {
+ Warn.Println(a...)
+}
diff --git a/vendor/github.com/gookit/color/style.go b/vendor/github.com/gookit/color/style.go
new file mode 100644
index 0000000..fad76fb
--- /dev/null
+++ b/vendor/github.com/gookit/color/style.go
@@ -0,0 +1,315 @@
+package color
+
+import (
+ "fmt"
+ "strings"
+)
+
+/*************************************************************
+ * 16 color Style
+ *************************************************************/
+
+// Style a 16 color style. can add: fg color, bg color, color options
+//
+// Example:
+// color.Style{color.FgGreen}.Print("message")
+type Style []Color
+
+// New create a custom style
+//
+// Usage:
+// color.New(color.FgGreen).Print("message")
+// equals to:
+// color.Style{color.FgGreen}.Print("message")
+func New(colors ...Color) Style {
+ return colors
+}
+
+// Save to global styles map
+func (s Style) Save(name string) {
+ AddStyle(name, s)
+}
+
+// Add to global styles map
+func (s *Style) Add(cs ...Color) {
+ *s = append(*s, cs...)
+}
+
+// Render render text
+// Usage:
+// color.New(color.FgGreen).Render("text")
+// color.New(color.FgGreen, color.BgBlack, color.OpBold).Render("text")
+func (s Style) Render(a ...interface{}) string {
+ return RenderCode(s.String(), a...)
+}
+
+// Renderln render text line.
+// like Println, will add spaces for each argument
+// Usage:
+// color.New(color.FgGreen).Renderln("text", "more")
+// color.New(color.FgGreen, color.BgBlack, color.OpBold).Render("text", "more")
+func (s Style) Renderln(a ...interface{}) string {
+ return RenderWithSpaces(s.String(), a...)
+}
+
+// Sprint is alias of the 'Render'
+func (s Style) Sprint(a ...interface{}) string {
+ return RenderCode(s.String(), a...)
+}
+
+// Sprintf format and render message.
+func (s Style) Sprintf(format string, a ...interface{}) string {
+ return RenderString(s.String(), fmt.Sprintf(format, a...))
+}
+
+// Print render and Print text
+func (s Style) Print(a ...interface{}) {
+ doPrintV2(s.String(), fmt.Sprint(a...))
+}
+
+// Printf render and print text
+func (s Style) Printf(format string, a ...interface{}) {
+ doPrintV2(s.Code(), fmt.Sprintf(format, a...))
+}
+
+// Println render and print text line
+func (s Style) Println(a ...interface{}) {
+ doPrintlnV2(s.String(), a)
+}
+
+// Code convert to code string. returns like "32;45;3"
+func (s Style) Code() string {
+ return s.String()
+}
+
+// String convert to code string. returns like "32;45;3"
+func (s Style) String() string {
+ return Colors2code(s...)
+}
+
+// IsEmpty style
+func (s Style) IsEmpty() bool {
+ return len(s) == 0
+}
+
+/*************************************************************
+ * Theme(extended Style)
+ *************************************************************/
+
+// Theme definition. extends from Style
+type Theme struct {
+ // Name theme name
+ Name string
+ // Style for the theme
+ Style
+}
+
+// NewTheme instance
+func NewTheme(name string, style Style) *Theme {
+ return &Theme{name, style}
+}
+
+// Save to themes map
+func (t *Theme) Save() {
+ AddTheme(t.Name, t.Style)
+}
+
+// Tips use name as title, only apply style for name
+func (t *Theme) Tips(format string, a ...interface{}) {
+ // only apply style for name
+ t.Print(strings.ToUpper(t.Name) + ": ")
+ Printf(format+"\n", a...)
+}
+
+// Prompt use name as title, and apply style for message
+func (t *Theme) Prompt(format string, a ...interface{}) {
+ title := strings.ToUpper(t.Name) + ":"
+ t.Println(title, fmt.Sprintf(format, a...))
+}
+
+// Block like Prompt, but will wrap a empty line
+func (t *Theme) Block(format string, a ...interface{}) {
+ title := strings.ToUpper(t.Name) + ":\n"
+
+ t.Println(title, fmt.Sprintf(format, a...))
+}
+
+/*************************************************************
+ * Theme: internal themes
+ *************************************************************/
+
+// internal themes(like bootstrap style)
+// Usage:
+// color.Info.Print("message")
+// color.Info.Printf("a %s message", "test")
+// color.Warn.Println("message")
+// color.Error.Println("message")
+var (
+ // Info color style
+ Info = &Theme{"info", Style{OpReset, FgGreen}}
+ // Note color style
+ Note = &Theme{"note", Style{OpBold, FgLightCyan}}
+ // Warn color style
+ Warn = &Theme{"warning", Style{OpBold, FgYellow}}
+ // Light color style
+ Light = &Theme{"light", Style{FgLightWhite, BgBlack}}
+ // Error color style
+ Error = &Theme{"error", Style{FgLightWhite, BgRed}}
+ // Danger color style
+ Danger = &Theme{"danger", Style{OpBold, FgRed}}
+ // Debug color style
+ Debug = &Theme{"debug", Style{OpReset, FgCyan}}
+ // Notice color style
+ Notice = &Theme{"notice", Style{OpBold, FgCyan}}
+ // Comment color style
+ Comment = &Theme{"comment", Style{OpReset, FgYellow}}
+ // Success color style
+ Success = &Theme{"success", Style{OpBold, FgGreen}}
+ // Primary color style
+ Primary = &Theme{"primary", Style{OpReset, FgBlue}}
+ // Question color style
+ Question = &Theme{"question", Style{OpReset, FgMagenta}}
+ // Secondary color style
+ Secondary = &Theme{"secondary", Style{FgDarkGray}}
+)
+
+// Themes internal defined themes.
+// Usage:
+// color.Themes["info"].Println("message")
+var Themes = map[string]*Theme{
+ "info": Info,
+ "note": Note,
+ "light": Light,
+ "error": Error,
+
+ "debug": Debug,
+ "danger": Danger,
+ "notice": Notice,
+ "success": Success,
+ "comment": Comment,
+ "primary": Primary,
+ "warning": Warn,
+
+ "question": Question,
+ "secondary": Secondary,
+}
+
+// AddTheme add a theme and style
+func AddTheme(name string, style Style) {
+ Themes[name] = NewTheme(name, style)
+ Styles[name] = style
+}
+
+// GetTheme get defined theme by name
+func GetTheme(name string) *Theme {
+ return Themes[name]
+}
+
+/*************************************************************
+ * internal styles
+ *************************************************************/
+
+// Styles internal defined styles, like bootstrap styles.
+// Usage:
+// color.Styles["info"].Println("message")
+var Styles = map[string]Style{
+ "info": {OpReset, FgGreen},
+ "note": {OpBold, FgLightCyan},
+ "light": {FgLightWhite, BgRed},
+ "error": {FgLightWhite, BgRed},
+
+ "danger": {OpBold, FgRed},
+ "notice": {OpBold, FgCyan},
+ "success": {OpBold, FgGreen},
+ "comment": {OpReset, FgMagenta},
+ "primary": {OpReset, FgBlue},
+ "warning": {OpBold, FgYellow},
+
+ "question": {OpReset, FgMagenta},
+ "secondary": {FgDarkGray},
+}
+
+// some style name alias
+var styleAliases = map[string]string{
+ "err": "error",
+ "suc": "success",
+ "warn": "warning",
+}
+
+// AddStyle add a style
+func AddStyle(name string, s Style) {
+ Styles[name] = s
+}
+
+// GetStyle get defined style by name
+func GetStyle(name string) Style {
+ if s, ok := Styles[name]; ok {
+ return s
+ }
+
+ if realName, ok := styleAliases[name]; ok {
+ return Styles[realName]
+ }
+
+ // empty style
+ return New()
+}
+
+/*************************************************************
+ * color scheme
+ *************************************************************/
+
+// Scheme struct
+type Scheme struct {
+ Name string
+ Styles map[string]Style
+}
+
+// NewScheme create new Scheme
+func NewScheme(name string, styles map[string]Style) *Scheme {
+ return &Scheme{Name: name, Styles: styles}
+}
+
+// NewDefaultScheme create an defuault color Scheme
+func NewDefaultScheme(name string) *Scheme {
+ return NewScheme(name, map[string]Style{
+ "info": {OpReset, FgGreen},
+ "warn": {OpBold, FgYellow},
+ "error": {FgLightWhite, BgRed},
+ })
+}
+
+// Style get by name
+func (s *Scheme) Style(name string) Style {
+ return s.Styles[name]
+}
+
+// Infof message print
+func (s *Scheme) Infof(format string, a ...interface{}) {
+ s.Styles["info"].Printf(format, a...)
+}
+
+// Infoln message print
+func (s *Scheme) Infoln(v ...interface{}) {
+ s.Styles["info"].Println(v...)
+}
+
+// Warnf message print
+func (s *Scheme) Warnf(format string, a ...interface{}) {
+ s.Styles["warn"].Printf(format, a...)
+}
+
+// Warnln message print
+func (s *Scheme) Warnln(v ...interface{}) {
+ s.Styles["warn"].Println(v...)
+}
+
+// Errorf message print
+func (s *Scheme) Errorf(format string, a ...interface{}) {
+ s.Styles["error"].Printf(format, a...)
+}
+
+// Errorln message print
+func (s *Scheme) Errorln(v ...interface{}) {
+ s.Styles["error"].Println(v...)
+}
diff --git a/vendor/github.com/gookit/color/utils.go b/vendor/github.com/gookit/color/utils.go
new file mode 100644
index 0000000..dedf9f2
--- /dev/null
+++ b/vendor/github.com/gookit/color/utils.go
@@ -0,0 +1,206 @@
+package color
+
+import (
+ "fmt"
+ "io"
+ "log"
+ "strings"
+)
+
+// SetTerminal by given code.
+func SetTerminal(code string) error {
+ if !Enable || !SupportColor() {
+ return nil
+ }
+
+ _, err := fmt.Fprintf(output, SettingTpl, code)
+ return err
+}
+
+// ResetTerminal terminal setting.
+func ResetTerminal() error {
+ if !Enable || !SupportColor() {
+ return nil
+ }
+
+ _, err := fmt.Fprint(output, ResetSet)
+ return err
+}
+
+/*************************************************************
+ * print methods(will auto parse color tags)
+ *************************************************************/
+
+// Print render color tag and print messages
+func Print(a ...interface{}) {
+ Fprint(output, a...)
+}
+
+// Printf format and print messages
+func Printf(format string, a ...interface{}) {
+ Fprintf(output, format, a...)
+}
+
+// Println messages with new line
+func Println(a ...interface{}) {
+ Fprintln(output, a...)
+}
+
+// Fprint print rendered messages to writer
+// Notice: will ignore print error
+func Fprint(w io.Writer, a ...interface{}) {
+ _, err := fmt.Fprint(w, Render(a...))
+ saveInternalError(err)
+
+ // if isLikeInCmd {
+ // renderColorCodeOnCmd(func() {
+ // _, _ = fmt.Fprint(w, Render(a...))
+ // })
+ // } else {
+ // _, _ = fmt.Fprint(w, Render(a...))
+ // }
+}
+
+// Fprintf print format and rendered messages to writer.
+// Notice: will ignore print error
+func Fprintf(w io.Writer, format string, a ...interface{}) {
+ str := fmt.Sprintf(format, a...)
+ _, err := fmt.Fprint(w, ReplaceTag(str))
+ saveInternalError(err)
+}
+
+// Fprintln print rendered messages line to writer
+// Notice: will ignore print error
+func Fprintln(w io.Writer, a ...interface{}) {
+ str := formatArgsForPrintln(a)
+ _, err := fmt.Fprintln(w, ReplaceTag(str))
+ saveInternalError(err)
+}
+
+// Lprint passes colored messages to a log.Logger for printing.
+// Notice: should be goroutine safe
+func Lprint(l *log.Logger, a ...interface{}) {
+ l.Print(Render(a...))
+}
+
+// Render parse color tags, return rendered string.
+// Usage:
+// text := Render("hello> world>!")
+// fmt.Println(text)
+func Render(a ...interface{}) string {
+ if len(a) == 0 {
+ return ""
+ }
+
+ return ReplaceTag(fmt.Sprint(a...))
+}
+
+// Sprint parse color tags, return rendered string
+func Sprint(a ...interface{}) string {
+ if len(a) == 0 {
+ return ""
+ }
+
+ return ReplaceTag(fmt.Sprint(a...))
+}
+
+// Sprintf format and return rendered string
+func Sprintf(format string, a ...interface{}) string {
+ return ReplaceTag(fmt.Sprintf(format, a...))
+}
+
+// String alias of the ReplaceTag
+func String(s string) string {
+ return ReplaceTag(s)
+}
+
+// Text alias of the ReplaceTag
+func Text(s string) string {
+ return ReplaceTag(s)
+}
+
+/*************************************************************
+ * helper methods for print
+ *************************************************************/
+
+// new implementation, support render full color code on pwsh.exe, cmd.exe
+func doPrintV2(code, str string) {
+ _, err := fmt.Fprint(output, RenderString(code, str))
+ saveInternalError(err)
+
+ // if isLikeInCmd {
+ // renderColorCodeOnCmd(func() {
+ // _, _ = fmt.Fprint(output, RenderString(code, str))
+ // })
+ // } else {
+ // _, _ = fmt.Fprint(output, RenderString(code, str))
+ // }
+}
+
+// new implementation, support render full color code on pwsh.exe, cmd.exe
+func doPrintlnV2(code string, args []interface{}) {
+ str := formatArgsForPrintln(args)
+ _, err := fmt.Fprintln(output, RenderString(code, str))
+ saveInternalError(err)
+}
+
+// if use Println, will add spaces for each arg
+func formatArgsForPrintln(args []interface{}) (message string) {
+ if ln := len(args); ln == 0 {
+ message = ""
+ } else if ln == 1 {
+ message = fmt.Sprint(args[0])
+ } else {
+ message = fmt.Sprintln(args...)
+ // clear last "\n"
+ message = message[:len(message)-1]
+ }
+ return
+}
+
+/*************************************************************
+ * helper methods
+ *************************************************************/
+
+// is on debug mode
+// func isDebugMode() bool {
+// return debugMode == "on"
+// }
+
+func debugf(f string, v ...interface{}) {
+ if debugMode {
+ fmt.Print("COLOR_DEBUG: ")
+ fmt.Printf(f, v...)
+ fmt.Println()
+ }
+}
+
+// equals: return ok ? val1 : val2
+func compareVal(ok bool, val1, val2 uint8) uint8 {
+ if ok {
+ return val1
+ }
+ return val2
+}
+
+func saveInternalError(err error) {
+ if err != nil {
+ debugf("inner error: %s", err.Error())
+ innerErrs = append(innerErrs, err)
+ }
+}
+
+func stringToArr(str, sep string) (arr []string) {
+ str = strings.TrimSpace(str)
+ if str == "" {
+ return
+ }
+
+ ss := strings.Split(str, sep)
+ for _, val := range ss {
+ if val = strings.TrimSpace(val); val != "" {
+ arr = append(arr, val)
+ }
+ }
+ return
+}
diff --git a/vendor/github.com/mattn/go-runewidth/.travis.yml b/vendor/github.com/mattn/go-runewidth/.travis.yml
new file mode 100644
index 0000000..6a21813
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/.travis.yml
@@ -0,0 +1,16 @@
+language: go
+sudo: false
+go:
+ - 1.13.x
+ - tip
+
+before_install:
+ - go get -t -v ./...
+
+script:
+ - go generate
+ - git diff --cached --exit-code
+ - ./go.test.sh
+
+after_success:
+ - bash <(curl -s https://codecov.io/bash)
diff --git a/vendor/github.com/mattn/go-runewidth/LICENSE b/vendor/github.com/mattn/go-runewidth/LICENSE
new file mode 100644
index 0000000..91b5cef
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Yasuhiro Matsumoto
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/mattn/go-runewidth/README.md b/vendor/github.com/mattn/go-runewidth/README.md
new file mode 100644
index 0000000..aa56ab9
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/README.md
@@ -0,0 +1,27 @@
+go-runewidth
+============
+
+[![Build Status](https://travis-ci.org/mattn/go-runewidth.png?branch=master)](https://travis-ci.org/mattn/go-runewidth)
+[![Codecov](https://codecov.io/gh/mattn/go-runewidth/branch/master/graph/badge.svg)](https://codecov.io/gh/mattn/go-runewidth)
+[![GoDoc](https://godoc.org/github.com/mattn/go-runewidth?status.svg)](http://godoc.org/github.com/mattn/go-runewidth)
+[![Go Report Card](https://goreportcard.com/badge/github.com/mattn/go-runewidth)](https://goreportcard.com/report/github.com/mattn/go-runewidth)
+
+Provides functions to get fixed width of the character or string.
+
+Usage
+-----
+
+```go
+runewidth.StringWidth("つのだ☆HIRO") == 12
+```
+
+
+Author
+------
+
+Yasuhiro Matsumoto
+
+License
+-------
+
+under the MIT License: http://mattn.mit-license.org/2013
diff --git a/vendor/github.com/mattn/go-runewidth/go.mod b/vendor/github.com/mattn/go-runewidth/go.mod
new file mode 100644
index 0000000..62dba1b
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/go.mod
@@ -0,0 +1,5 @@
+module github.com/mattn/go-runewidth
+
+go 1.9
+
+require github.com/rivo/uniseg v0.2.0
diff --git a/vendor/github.com/mattn/go-runewidth/go.sum b/vendor/github.com/mattn/go-runewidth/go.sum
new file mode 100644
index 0000000..03f902d
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/go.sum
@@ -0,0 +1,2 @@
+github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
diff --git a/vendor/github.com/mattn/go-runewidth/go.test.sh b/vendor/github.com/mattn/go-runewidth/go.test.sh
new file mode 100644
index 0000000..012162b
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/go.test.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+set -e
+echo "" > coverage.txt
+
+for d in $(go list ./... | grep -v vendor); do
+ go test -race -coverprofile=profile.out -covermode=atomic "$d"
+ if [ -f profile.out ]; then
+ cat profile.out >> coverage.txt
+ rm profile.out
+ fi
+done
diff --git a/vendor/github.com/mattn/go-runewidth/runewidth.go b/vendor/github.com/mattn/go-runewidth/runewidth.go
new file mode 100644
index 0000000..3d7fa56
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/runewidth.go
@@ -0,0 +1,273 @@
+package runewidth
+
+import (
+ "os"
+
+ "github.com/rivo/uniseg"
+)
+
+//go:generate go run script/generate.go
+
+var (
+ // EastAsianWidth will be set true if the current locale is CJK
+ EastAsianWidth bool
+
+ // StrictEmojiNeutral should be set false if handle broken fonts
+ StrictEmojiNeutral bool = true
+
+ // DefaultCondition is a condition in current locale
+ DefaultCondition = &Condition{
+ EastAsianWidth: false,
+ StrictEmojiNeutral: true,
+ }
+)
+
+func init() {
+ handleEnv()
+}
+
+func handleEnv() {
+ env := os.Getenv("RUNEWIDTH_EASTASIAN")
+ if env == "" {
+ EastAsianWidth = IsEastAsian()
+ } else {
+ EastAsianWidth = env == "1"
+ }
+ // update DefaultCondition
+ DefaultCondition.EastAsianWidth = EastAsianWidth
+}
+
+type interval struct {
+ first rune
+ last rune
+}
+
+type table []interval
+
+func inTables(r rune, ts ...table) bool {
+ for _, t := range ts {
+ if inTable(r, t) {
+ return true
+ }
+ }
+ return false
+}
+
+func inTable(r rune, t table) bool {
+ if r < t[0].first {
+ return false
+ }
+
+ bot := 0
+ top := len(t) - 1
+ for top >= bot {
+ mid := (bot + top) >> 1
+
+ switch {
+ case t[mid].last < r:
+ bot = mid + 1
+ case t[mid].first > r:
+ top = mid - 1
+ default:
+ return true
+ }
+ }
+
+ return false
+}
+
+var private = table{
+ {0x00E000, 0x00F8FF}, {0x0F0000, 0x0FFFFD}, {0x100000, 0x10FFFD},
+}
+
+var nonprint = table{
+ {0x0000, 0x001F}, {0x007F, 0x009F}, {0x00AD, 0x00AD},
+ {0x070F, 0x070F}, {0x180B, 0x180E}, {0x200B, 0x200F},
+ {0x2028, 0x202E}, {0x206A, 0x206F}, {0xD800, 0xDFFF},
+ {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, {0xFFFE, 0xFFFF},
+}
+
+// Condition have flag EastAsianWidth whether the current locale is CJK or not.
+type Condition struct {
+ EastAsianWidth bool
+ StrictEmojiNeutral bool
+}
+
+// NewCondition return new instance of Condition which is current locale.
+func NewCondition() *Condition {
+ return &Condition{
+ EastAsianWidth: EastAsianWidth,
+ StrictEmojiNeutral: StrictEmojiNeutral,
+ }
+}
+
+// RuneWidth returns the number of cells in r.
+// See http://www.unicode.org/reports/tr11/
+func (c *Condition) RuneWidth(r rune) int {
+ // optimized version, verified by TestRuneWidthChecksums()
+ if !c.EastAsianWidth {
+ switch {
+ case r < 0x20 || r > 0x10FFFF:
+ return 0
+ case (r >= 0x7F && r <= 0x9F) || r == 0xAD: // nonprint
+ return 0
+ case r < 0x300:
+ return 1
+ case inTable(r, narrow):
+ return 1
+ case inTables(r, nonprint, combining):
+ return 0
+ case inTable(r, doublewidth):
+ return 2
+ default:
+ return 1
+ }
+ } else {
+ switch {
+ case r < 0 || r > 0x10FFFF || inTables(r, nonprint, combining):
+ return 0
+ case inTable(r, narrow):
+ return 1
+ case inTables(r, ambiguous, doublewidth):
+ return 2
+ case !c.StrictEmojiNeutral && inTables(r, ambiguous, emoji, narrow):
+ return 2
+ default:
+ return 1
+ }
+ }
+}
+
+// StringWidth return width as you can see
+func (c *Condition) StringWidth(s string) (width int) {
+ g := uniseg.NewGraphemes(s)
+ for g.Next() {
+ var chWidth int
+ for _, r := range g.Runes() {
+ chWidth = c.RuneWidth(r)
+ if chWidth > 0 {
+ break // Our best guess at this point is to use the width of the first non-zero-width rune.
+ }
+ }
+ width += chWidth
+ }
+ return
+}
+
+// Truncate return string truncated with w cells
+func (c *Condition) Truncate(s string, w int, tail string) string {
+ if c.StringWidth(s) <= w {
+ return s
+ }
+ w -= c.StringWidth(tail)
+ var width int
+ pos := len(s)
+ g := uniseg.NewGraphemes(s)
+ for g.Next() {
+ var chWidth int
+ for _, r := range g.Runes() {
+ chWidth = c.RuneWidth(r)
+ if chWidth > 0 {
+ break // See StringWidth() for details.
+ }
+ }
+ if width+chWidth > w {
+ pos, _ = g.Positions()
+ break
+ }
+ width += chWidth
+ }
+ return s[:pos] + tail
+}
+
+// Wrap return string wrapped with w cells
+func (c *Condition) Wrap(s string, w int) string {
+ width := 0
+ out := ""
+ for _, r := range []rune(s) {
+ cw := c.RuneWidth(r)
+ if r == '\n' {
+ out += string(r)
+ width = 0
+ continue
+ } else if width+cw > w {
+ out += "\n"
+ width = 0
+ out += string(r)
+ width += cw
+ continue
+ }
+ out += string(r)
+ width += cw
+ }
+ return out
+}
+
+// FillLeft return string filled in left by spaces in w cells
+func (c *Condition) FillLeft(s string, w int) string {
+ width := c.StringWidth(s)
+ count := w - width
+ if count > 0 {
+ b := make([]byte, count)
+ for i := range b {
+ b[i] = ' '
+ }
+ return string(b) + s
+ }
+ return s
+}
+
+// FillRight return string filled in left by spaces in w cells
+func (c *Condition) FillRight(s string, w int) string {
+ width := c.StringWidth(s)
+ count := w - width
+ if count > 0 {
+ b := make([]byte, count)
+ for i := range b {
+ b[i] = ' '
+ }
+ return s + string(b)
+ }
+ return s
+}
+
+// RuneWidth returns the number of cells in r.
+// See http://www.unicode.org/reports/tr11/
+func RuneWidth(r rune) int {
+ return DefaultCondition.RuneWidth(r)
+}
+
+// IsAmbiguousWidth returns whether is ambiguous width or not.
+func IsAmbiguousWidth(r rune) bool {
+ return inTables(r, private, ambiguous)
+}
+
+// IsNeutralWidth returns whether is neutral width or not.
+func IsNeutralWidth(r rune) bool {
+ return inTable(r, neutral)
+}
+
+// StringWidth return width as you can see
+func StringWidth(s string) (width int) {
+ return DefaultCondition.StringWidth(s)
+}
+
+// Truncate return string truncated with w cells
+func Truncate(s string, w int, tail string) string {
+ return DefaultCondition.Truncate(s, w, tail)
+}
+
+// Wrap return string wrapped with w cells
+func Wrap(s string, w int) string {
+ return DefaultCondition.Wrap(s, w)
+}
+
+// FillLeft return string filled in left by spaces in w cells
+func FillLeft(s string, w int) string {
+ return DefaultCondition.FillLeft(s, w)
+}
+
+// FillRight return string filled in left by spaces in w cells
+func FillRight(s string, w int) string {
+ return DefaultCondition.FillRight(s, w)
+}
diff --git a/vendor/github.com/mattn/go-runewidth/runewidth_appengine.go b/vendor/github.com/mattn/go-runewidth/runewidth_appengine.go
new file mode 100644
index 0000000..7d99f6e
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/runewidth_appengine.go
@@ -0,0 +1,8 @@
+// +build appengine
+
+package runewidth
+
+// IsEastAsian return true if the current locale is CJK
+func IsEastAsian() bool {
+ return false
+}
diff --git a/vendor/github.com/mattn/go-runewidth/runewidth_js.go b/vendor/github.com/mattn/go-runewidth/runewidth_js.go
new file mode 100644
index 0000000..c5fdf40
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/runewidth_js.go
@@ -0,0 +1,9 @@
+// +build js
+// +build !appengine
+
+package runewidth
+
+func IsEastAsian() bool {
+ // TODO: Implement this for the web. Detect east asian in a compatible way, and return true.
+ return false
+}
diff --git a/vendor/github.com/mattn/go-runewidth/runewidth_posix.go b/vendor/github.com/mattn/go-runewidth/runewidth_posix.go
new file mode 100644
index 0000000..480ad74
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/runewidth_posix.go
@@ -0,0 +1,82 @@
+// +build !windows
+// +build !js
+// +build !appengine
+
+package runewidth
+
+import (
+ "os"
+ "regexp"
+ "strings"
+)
+
+var reLoc = regexp.MustCompile(`^[a-z][a-z][a-z]?(?:_[A-Z][A-Z])?\.(.+)`)
+
+var mblenTable = map[string]int{
+ "utf-8": 6,
+ "utf8": 6,
+ "jis": 8,
+ "eucjp": 3,
+ "euckr": 2,
+ "euccn": 2,
+ "sjis": 2,
+ "cp932": 2,
+ "cp51932": 2,
+ "cp936": 2,
+ "cp949": 2,
+ "cp950": 2,
+ "big5": 2,
+ "gbk": 2,
+ "gb2312": 2,
+}
+
+func isEastAsian(locale string) bool {
+ charset := strings.ToLower(locale)
+ r := reLoc.FindStringSubmatch(locale)
+ if len(r) == 2 {
+ charset = strings.ToLower(r[1])
+ }
+
+ if strings.HasSuffix(charset, "@cjk_narrow") {
+ return false
+ }
+
+ for pos, b := range []byte(charset) {
+ if b == '@' {
+ charset = charset[:pos]
+ break
+ }
+ }
+ max := 1
+ if m, ok := mblenTable[charset]; ok {
+ max = m
+ }
+ if max > 1 && (charset[0] != 'u' ||
+ strings.HasPrefix(locale, "ja") ||
+ strings.HasPrefix(locale, "ko") ||
+ strings.HasPrefix(locale, "zh")) {
+ return true
+ }
+ return false
+}
+
+// IsEastAsian return true if the current locale is CJK
+func IsEastAsian() bool {
+ locale := os.Getenv("LC_ALL")
+ if locale == "" {
+ locale = os.Getenv("LC_CTYPE")
+ }
+ if locale == "" {
+ locale = os.Getenv("LANG")
+ }
+
+ // ignore C locale
+ if locale == "POSIX" || locale == "C" {
+ return false
+ }
+ if len(locale) > 1 && locale[0] == 'C' && (locale[1] == '.' || locale[1] == '-') {
+ return false
+ }
+
+ return isEastAsian(locale)
+}
diff --git a/vendor/github.com/mattn/go-runewidth/runewidth_table.go b/vendor/github.com/mattn/go-runewidth/runewidth_table.go
new file mode 100644
index 0000000..e5d890c
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/runewidth_table.go
@@ -0,0 +1,439 @@
+// Code generated by script/generate.go. DO NOT EDIT.
+
+package runewidth
+
+var combining = table{
+ {0x0300, 0x036F}, {0x0483, 0x0489}, {0x07EB, 0x07F3},
+ {0x0C00, 0x0C00}, {0x0C04, 0x0C04}, {0x0D00, 0x0D01},
+ {0x135D, 0x135F}, {0x1A7F, 0x1A7F}, {0x1AB0, 0x1AC0},
+ {0x1B6B, 0x1B73}, {0x1DC0, 0x1DF9}, {0x1DFB, 0x1DFF},
+ {0x20D0, 0x20F0}, {0x2CEF, 0x2CF1}, {0x2DE0, 0x2DFF},
+ {0x3099, 0x309A}, {0xA66F, 0xA672}, {0xA674, 0xA67D},
+ {0xA69E, 0xA69F}, {0xA6F0, 0xA6F1}, {0xA8E0, 0xA8F1},
+ {0xFE20, 0xFE2F}, {0x101FD, 0x101FD}, {0x10376, 0x1037A},
+ {0x10EAB, 0x10EAC}, {0x10F46, 0x10F50}, {0x11300, 0x11301},
+ {0x1133B, 0x1133C}, {0x11366, 0x1136C}, {0x11370, 0x11374},
+ {0x16AF0, 0x16AF4}, {0x1D165, 0x1D169}, {0x1D16D, 0x1D172},
+ {0x1D17B, 0x1D182}, {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD},
+ {0x1D242, 0x1D244}, {0x1E000, 0x1E006}, {0x1E008, 0x1E018},
+ {0x1E01B, 0x1E021}, {0x1E023, 0x1E024}, {0x1E026, 0x1E02A},
+ {0x1E8D0, 0x1E8D6},
+}
+
+var doublewidth = table{
+ {0x1100, 0x115F}, {0x231A, 0x231B}, {0x2329, 0x232A},
+ {0x23E9, 0x23EC}, {0x23F0, 0x23F0}, {0x23F3, 0x23F3},
+ {0x25FD, 0x25FE}, {0x2614, 0x2615}, {0x2648, 0x2653},
+ {0x267F, 0x267F}, {0x2693, 0x2693}, {0x26A1, 0x26A1},
+ {0x26AA, 0x26AB}, {0x26BD, 0x26BE}, {0x26C4, 0x26C5},
+ {0x26CE, 0x26CE}, {0x26D4, 0x26D4}, {0x26EA, 0x26EA},
+ {0x26F2, 0x26F3}, {0x26F5, 0x26F5}, {0x26FA, 0x26FA},
+ {0x26FD, 0x26FD}, {0x2705, 0x2705}, {0x270A, 0x270B},
+ {0x2728, 0x2728}, {0x274C, 0x274C}, {0x274E, 0x274E},
+ {0x2753, 0x2755}, {0x2757, 0x2757}, {0x2795, 0x2797},
+ {0x27B0, 0x27B0}, {0x27BF, 0x27BF}, {0x2B1B, 0x2B1C},
+ {0x2B50, 0x2B50}, {0x2B55, 0x2B55}, {0x2E80, 0x2E99},
+ {0x2E9B, 0x2EF3}, {0x2F00, 0x2FD5}, {0x2FF0, 0x2FFB},
+ {0x3000, 0x303E}, {0x3041, 0x3096}, {0x3099, 0x30FF},
+ {0x3105, 0x312F}, {0x3131, 0x318E}, {0x3190, 0x31E3},
+ {0x31F0, 0x321E}, {0x3220, 0x3247}, {0x3250, 0x4DBF},
+ {0x4E00, 0xA48C}, {0xA490, 0xA4C6}, {0xA960, 0xA97C},
+ {0xAC00, 0xD7A3}, {0xF900, 0xFAFF}, {0xFE10, 0xFE19},
+ {0xFE30, 0xFE52}, {0xFE54, 0xFE66}, {0xFE68, 0xFE6B},
+ {0xFF01, 0xFF60}, {0xFFE0, 0xFFE6}, {0x16FE0, 0x16FE4},
+ {0x16FF0, 0x16FF1}, {0x17000, 0x187F7}, {0x18800, 0x18CD5},
+ {0x18D00, 0x18D08}, {0x1B000, 0x1B11E}, {0x1B150, 0x1B152},
+ {0x1B164, 0x1B167}, {0x1B170, 0x1B2FB}, {0x1F004, 0x1F004},
+ {0x1F0CF, 0x1F0CF}, {0x1F18E, 0x1F18E}, {0x1F191, 0x1F19A},
+ {0x1F200, 0x1F202}, {0x1F210, 0x1F23B}, {0x1F240, 0x1F248},
+ {0x1F250, 0x1F251}, {0x1F260, 0x1F265}, {0x1F300, 0x1F320},
+ {0x1F32D, 0x1F335}, {0x1F337, 0x1F37C}, {0x1F37E, 0x1F393},
+ {0x1F3A0, 0x1F3CA}, {0x1F3CF, 0x1F3D3}, {0x1F3E0, 0x1F3F0},
+ {0x1F3F4, 0x1F3F4}, {0x1F3F8, 0x1F43E}, {0x1F440, 0x1F440},
+ {0x1F442, 0x1F4FC}, {0x1F4FF, 0x1F53D}, {0x1F54B, 0x1F54E},
+ {0x1F550, 0x1F567}, {0x1F57A, 0x1F57A}, {0x1F595, 0x1F596},
+ {0x1F5A4, 0x1F5A4}, {0x1F5FB, 0x1F64F}, {0x1F680, 0x1F6C5},
+ {0x1F6CC, 0x1F6CC}, {0x1F6D0, 0x1F6D2}, {0x1F6D5, 0x1F6D7},
+ {0x1F6EB, 0x1F6EC}, {0x1F6F4, 0x1F6FC}, {0x1F7E0, 0x1F7EB},
+ {0x1F90C, 0x1F93A}, {0x1F93C, 0x1F945}, {0x1F947, 0x1F978},
+ {0x1F97A, 0x1F9CB}, {0x1F9CD, 0x1F9FF}, {0x1FA70, 0x1FA74},
+ {0x1FA78, 0x1FA7A}, {0x1FA80, 0x1FA86}, {0x1FA90, 0x1FAA8},
+ {0x1FAB0, 0x1FAB6}, {0x1FAC0, 0x1FAC2}, {0x1FAD0, 0x1FAD6},
+ {0x20000, 0x2FFFD}, {0x30000, 0x3FFFD},
+}
+
+var ambiguous = table{
+ {0x00A1, 0x00A1}, {0x00A4, 0x00A4}, {0x00A7, 0x00A8},
+ {0x00AA, 0x00AA}, {0x00AD, 0x00AE}, {0x00B0, 0x00B4},
+ {0x00B6, 0x00BA}, {0x00BC, 0x00BF}, {0x00C6, 0x00C6},
+ {0x00D0, 0x00D0}, {0x00D7, 0x00D8}, {0x00DE, 0x00E1},
+ {0x00E6, 0x00E6}, {0x00E8, 0x00EA}, {0x00EC, 0x00ED},
+ {0x00F0, 0x00F0}, {0x00F2, 0x00F3}, {0x00F7, 0x00FA},
+ {0x00FC, 0x00FC}, {0x00FE, 0x00FE}, {0x0101, 0x0101},
+ {0x0111, 0x0111}, {0x0113, 0x0113}, {0x011B, 0x011B},
+ {0x0126, 0x0127}, {0x012B, 0x012B}, {0x0131, 0x0133},
+ {0x0138, 0x0138}, {0x013F, 0x0142}, {0x0144, 0x0144},
+ {0x0148, 0x014B}, {0x014D, 0x014D}, {0x0152, 0x0153},
+ {0x0166, 0x0167}, {0x016B, 0x016B}, {0x01CE, 0x01CE},
+ {0x01D0, 0x01D0}, {0x01D2, 0x01D2}, {0x01D4, 0x01D4},
+ {0x01D6, 0x01D6}, {0x01D8, 0x01D8}, {0x01DA, 0x01DA},
+ {0x01DC, 0x01DC}, {0x0251, 0x0251}, {0x0261, 0x0261},
+ {0x02C4, 0x02C4}, {0x02C7, 0x02C7}, {0x02C9, 0x02CB},
+ {0x02CD, 0x02CD}, {0x02D0, 0x02D0}, {0x02D8, 0x02DB},
+ {0x02DD, 0x02DD}, {0x02DF, 0x02DF}, {0x0300, 0x036F},
+ {0x0391, 0x03A1}, {0x03A3, 0x03A9}, {0x03B1, 0x03C1},
+ {0x03C3, 0x03C9}, {0x0401, 0x0401}, {0x0410, 0x044F},
+ {0x0451, 0x0451}, {0x2010, 0x2010}, {0x2013, 0x2016},
+ {0x2018, 0x2019}, {0x201C, 0x201D}, {0x2020, 0x2022},
+ {0x2024, 0x2027}, {0x2030, 0x2030}, {0x2032, 0x2033},
+ {0x2035, 0x2035}, {0x203B, 0x203B}, {0x203E, 0x203E},
+ {0x2074, 0x2074}, {0x207F, 0x207F}, {0x2081, 0x2084},
+ {0x20AC, 0x20AC}, {0x2103, 0x2103}, {0x2105, 0x2105},
+ {0x2109, 0x2109}, {0x2113, 0x2113}, {0x2116, 0x2116},
+ {0x2121, 0x2122}, {0x2126, 0x2126}, {0x212B, 0x212B},
+ {0x2153, 0x2154}, {0x215B, 0x215E}, {0x2160, 0x216B},
+ {0x2170, 0x2179}, {0x2189, 0x2189}, {0x2190, 0x2199},
+ {0x21B8, 0x21B9}, {0x21D2, 0x21D2}, {0x21D4, 0x21D4},
+ {0x21E7, 0x21E7}, {0x2200, 0x2200}, {0x2202, 0x2203},
+ {0x2207, 0x2208}, {0x220B, 0x220B}, {0x220F, 0x220F},
+ {0x2211, 0x2211}, {0x2215, 0x2215}, {0x221A, 0x221A},
+ {0x221D, 0x2220}, {0x2223, 0x2223}, {0x2225, 0x2225},
+ {0x2227, 0x222C}, {0x222E, 0x222E}, {0x2234, 0x2237},
+ {0x223C, 0x223D}, {0x2248, 0x2248}, {0x224C, 0x224C},
+ {0x2252, 0x2252}, {0x2260, 0x2261}, {0x2264, 0x2267},
+ {0x226A, 0x226B}, {0x226E, 0x226F}, {0x2282, 0x2283},
+ {0x2286, 0x2287}, {0x2295, 0x2295}, {0x2299, 0x2299},
+ {0x22A5, 0x22A5}, {0x22BF, 0x22BF}, {0x2312, 0x2312},
+ {0x2460, 0x24E9}, {0x24EB, 0x254B}, {0x2550, 0x2573},
+ {0x2580, 0x258F}, {0x2592, 0x2595}, {0x25A0, 0x25A1},
+ {0x25A3, 0x25A9}, {0x25B2, 0x25B3}, {0x25B6, 0x25B7},
+ {0x25BC, 0x25BD}, {0x25C0, 0x25C1}, {0x25C6, 0x25C8},
+ {0x25CB, 0x25CB}, {0x25CE, 0x25D1}, {0x25E2, 0x25E5},
+ {0x25EF, 0x25EF}, {0x2605, 0x2606}, {0x2609, 0x2609},
+ {0x260E, 0x260F}, {0x261C, 0x261C}, {0x261E, 0x261E},
+ {0x2640, 0x2640}, {0x2642, 0x2642}, {0x2660, 0x2661},
+ {0x2663, 0x2665}, {0x2667, 0x266A}, {0x266C, 0x266D},
+ {0x266F, 0x266F}, {0x269E, 0x269F}, {0x26BF, 0x26BF},
+ {0x26C6, 0x26CD}, {0x26CF, 0x26D3}, {0x26D5, 0x26E1},
+ {0x26E3, 0x26E3}, {0x26E8, 0x26E9}, {0x26EB, 0x26F1},
+ {0x26F4, 0x26F4}, {0x26F6, 0x26F9}, {0x26FB, 0x26FC},
+ {0x26FE, 0x26FF}, {0x273D, 0x273D}, {0x2776, 0x277F},
+ {0x2B56, 0x2B59}, {0x3248, 0x324F}, {0xE000, 0xF8FF},
+ {0xFE00, 0xFE0F}, {0xFFFD, 0xFFFD}, {0x1F100, 0x1F10A},
+ {0x1F110, 0x1F12D}, {0x1F130, 0x1F169}, {0x1F170, 0x1F18D},
+ {0x1F18F, 0x1F190}, {0x1F19B, 0x1F1AC}, {0xE0100, 0xE01EF},
+ {0xF0000, 0xFFFFD}, {0x100000, 0x10FFFD},
+}
+var narrow = table{
+ {0x0020, 0x007E}, {0x00A2, 0x00A3}, {0x00A5, 0x00A6},
+ {0x00AC, 0x00AC}, {0x00AF, 0x00AF}, {0x27E6, 0x27ED},
+ {0x2985, 0x2986},
+}
+
+var neutral = table{
+ {0x0000, 0x001F}, {0x007F, 0x00A0}, {0x00A9, 0x00A9},
+ {0x00AB, 0x00AB}, {0x00B5, 0x00B5}, {0x00BB, 0x00BB},
+ {0x00C0, 0x00C5}, {0x00C7, 0x00CF}, {0x00D1, 0x00D6},
+ {0x00D9, 0x00DD}, {0x00E2, 0x00E5}, {0x00E7, 0x00E7},
+ {0x00EB, 0x00EB}, {0x00EE, 0x00EF}, {0x00F1, 0x00F1},
+ {0x00F4, 0x00F6}, {0x00FB, 0x00FB}, {0x00FD, 0x00FD},
+ {0x00FF, 0x0100}, {0x0102, 0x0110}, {0x0112, 0x0112},
+ {0x0114, 0x011A}, {0x011C, 0x0125}, {0x0128, 0x012A},
+ {0x012C, 0x0130}, {0x0134, 0x0137}, {0x0139, 0x013E},
+ {0x0143, 0x0143}, {0x0145, 0x0147}, {0x014C, 0x014C},
+ {0x014E, 0x0151}, {0x0154, 0x0165}, {0x0168, 0x016A},
+ {0x016C, 0x01CD}, {0x01CF, 0x01CF}, {0x01D1, 0x01D1},
+ {0x01D3, 0x01D3}, {0x01D5, 0x01D5}, {0x01D7, 0x01D7},
+ {0x01D9, 0x01D9}, {0x01DB, 0x01DB}, {0x01DD, 0x0250},
+ {0x0252, 0x0260}, {0x0262, 0x02C3}, {0x02C5, 0x02C6},
+ {0x02C8, 0x02C8}, {0x02CC, 0x02CC}, {0x02CE, 0x02CF},
+ {0x02D1, 0x02D7}, {0x02DC, 0x02DC}, {0x02DE, 0x02DE},
+ {0x02E0, 0x02FF}, {0x0370, 0x0377}, {0x037A, 0x037F},
+ {0x0384, 0x038A}, {0x038C, 0x038C}, {0x038E, 0x0390},
+ {0x03AA, 0x03B0}, {0x03C2, 0x03C2}, {0x03CA, 0x0400},
+ {0x0402, 0x040F}, {0x0450, 0x0450}, {0x0452, 0x052F},
+ {0x0531, 0x0556}, {0x0559, 0x058A}, {0x058D, 0x058F},
+ {0x0591, 0x05C7}, {0x05D0, 0x05EA}, {0x05EF, 0x05F4},
+ {0x0600, 0x061C}, {0x061E, 0x070D}, {0x070F, 0x074A},
+ {0x074D, 0x07B1}, {0x07C0, 0x07FA}, {0x07FD, 0x082D},
+ {0x0830, 0x083E}, {0x0840, 0x085B}, {0x085E, 0x085E},
+ {0x0860, 0x086A}, {0x08A0, 0x08B4}, {0x08B6, 0x08C7},
+ {0x08D3, 0x0983}, {0x0985, 0x098C}, {0x098F, 0x0990},
+ {0x0993, 0x09A8}, {0x09AA, 0x09B0}, {0x09B2, 0x09B2},
+ {0x09B6, 0x09B9}, {0x09BC, 0x09C4}, {0x09C7, 0x09C8},
+ {0x09CB, 0x09CE}, {0x09D7, 0x09D7}, {0x09DC, 0x09DD},
+ {0x09DF, 0x09E3}, {0x09E6, 0x09FE}, {0x0A01, 0x0A03},
+ {0x0A05, 0x0A0A}, {0x0A0F, 0x0A10}, {0x0A13, 0x0A28},
+ {0x0A2A, 0x0A30}, {0x0A32, 0x0A33}, {0x0A35, 0x0A36},
+ {0x0A38, 0x0A39}, {0x0A3C, 0x0A3C}, {0x0A3E, 0x0A42},
+ {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A51, 0x0A51},
+ {0x0A59, 0x0A5C}, {0x0A5E, 0x0A5E}, {0x0A66, 0x0A76},
+ {0x0A81, 0x0A83}, {0x0A85, 0x0A8D}, {0x0A8F, 0x0A91},
+ {0x0A93, 0x0AA8}, {0x0AAA, 0x0AB0}, {0x0AB2, 0x0AB3},
+ {0x0AB5, 0x0AB9}, {0x0ABC, 0x0AC5}, {0x0AC7, 0x0AC9},
+ {0x0ACB, 0x0ACD}, {0x0AD0, 0x0AD0}, {0x0AE0, 0x0AE3},
+ {0x0AE6, 0x0AF1}, {0x0AF9, 0x0AFF}, {0x0B01, 0x0B03},
+ {0x0B05, 0x0B0C}, {0x0B0F, 0x0B10}, {0x0B13, 0x0B28},
+ {0x0B2A, 0x0B30}, {0x0B32, 0x0B33}, {0x0B35, 0x0B39},
+ {0x0B3C, 0x0B44}, {0x0B47, 0x0B48}, {0x0B4B, 0x0B4D},
+ {0x0B55, 0x0B57}, {0x0B5C, 0x0B5D}, {0x0B5F, 0x0B63},
+ {0x0B66, 0x0B77}, {0x0B82, 0x0B83}, {0x0B85, 0x0B8A},
+ {0x0B8E, 0x0B90}, {0x0B92, 0x0B95}, {0x0B99, 0x0B9A},
+ {0x0B9C, 0x0B9C}, {0x0B9E, 0x0B9F}, {0x0BA3, 0x0BA4},
+ {0x0BA8, 0x0BAA}, {0x0BAE, 0x0BB9}, {0x0BBE, 0x0BC2},
+ {0x0BC6, 0x0BC8}, {0x0BCA, 0x0BCD}, {0x0BD0, 0x0BD0},
+ {0x0BD7, 0x0BD7}, {0x0BE6, 0x0BFA}, {0x0C00, 0x0C0C},
+ {0x0C0E, 0x0C10}, {0x0C12, 0x0C28}, {0x0C2A, 0x0C39},
+ {0x0C3D, 0x0C44}, {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D},
+ {0x0C55, 0x0C56}, {0x0C58, 0x0C5A}, {0x0C60, 0x0C63},
+ {0x0C66, 0x0C6F}, {0x0C77, 0x0C8C}, {0x0C8E, 0x0C90},
+ {0x0C92, 0x0CA8}, {0x0CAA, 0x0CB3}, {0x0CB5, 0x0CB9},
+ {0x0CBC, 0x0CC4}, {0x0CC6, 0x0CC8}, {0x0CCA, 0x0CCD},
+ {0x0CD5, 0x0CD6}, {0x0CDE, 0x0CDE}, {0x0CE0, 0x0CE3},
+ {0x0CE6, 0x0CEF}, {0x0CF1, 0x0CF2}, {0x0D00, 0x0D0C},
+ {0x0D0E, 0x0D10}, {0x0D12, 0x0D44}, {0x0D46, 0x0D48},
+ {0x0D4A, 0x0D4F}, {0x0D54, 0x0D63}, {0x0D66, 0x0D7F},
+ {0x0D81, 0x0D83}, {0x0D85, 0x0D96}, {0x0D9A, 0x0DB1},
+ {0x0DB3, 0x0DBB}, {0x0DBD, 0x0DBD}, {0x0DC0, 0x0DC6},
+ {0x0DCA, 0x0DCA}, {0x0DCF, 0x0DD4}, {0x0DD6, 0x0DD6},
+ {0x0DD8, 0x0DDF}, {0x0DE6, 0x0DEF}, {0x0DF2, 0x0DF4},
+ {0x0E01, 0x0E3A}, {0x0E3F, 0x0E5B}, {0x0E81, 0x0E82},
+ {0x0E84, 0x0E84}, {0x0E86, 0x0E8A}, {0x0E8C, 0x0EA3},
+ {0x0EA5, 0x0EA5}, {0x0EA7, 0x0EBD}, {0x0EC0, 0x0EC4},
+ {0x0EC6, 0x0EC6}, {0x0EC8, 0x0ECD}, {0x0ED0, 0x0ED9},
+ {0x0EDC, 0x0EDF}, {0x0F00, 0x0F47}, {0x0F49, 0x0F6C},
+ {0x0F71, 0x0F97}, {0x0F99, 0x0FBC}, {0x0FBE, 0x0FCC},
+ {0x0FCE, 0x0FDA}, {0x1000, 0x10C5}, {0x10C7, 0x10C7},
+ {0x10CD, 0x10CD}, {0x10D0, 0x10FF}, {0x1160, 0x1248},
+ {0x124A, 0x124D}, {0x1250, 0x1256}, {0x1258, 0x1258},
+ {0x125A, 0x125D}, {0x1260, 0x1288}, {0x128A, 0x128D},
+ {0x1290, 0x12B0}, {0x12B2, 0x12B5}, {0x12B8, 0x12BE},
+ {0x12C0, 0x12C0}, {0x12C2, 0x12C5}, {0x12C8, 0x12D6},
+ {0x12D8, 0x1310}, {0x1312, 0x1315}, {0x1318, 0x135A},
+ {0x135D, 0x137C}, {0x1380, 0x1399}, {0x13A0, 0x13F5},
+ {0x13F8, 0x13FD}, {0x1400, 0x169C}, {0x16A0, 0x16F8},
+ {0x1700, 0x170C}, {0x170E, 0x1714}, {0x1720, 0x1736},
+ {0x1740, 0x1753}, {0x1760, 0x176C}, {0x176E, 0x1770},
+ {0x1772, 0x1773}, {0x1780, 0x17DD}, {0x17E0, 0x17E9},
+ {0x17F0, 0x17F9}, {0x1800, 0x180E}, {0x1810, 0x1819},
+ {0x1820, 0x1878}, {0x1880, 0x18AA}, {0x18B0, 0x18F5},
+ {0x1900, 0x191E}, {0x1920, 0x192B}, {0x1930, 0x193B},
+ {0x1940, 0x1940}, {0x1944, 0x196D}, {0x1970, 0x1974},
+ {0x1980, 0x19AB}, {0x19B0, 0x19C9}, {0x19D0, 0x19DA},
+ {0x19DE, 0x1A1B}, {0x1A1E, 0x1A5E}, {0x1A60, 0x1A7C},
+ {0x1A7F, 0x1A89}, {0x1A90, 0x1A99}, {0x1AA0, 0x1AAD},
+ {0x1AB0, 0x1AC0}, {0x1B00, 0x1B4B}, {0x1B50, 0x1B7C},
+ {0x1B80, 0x1BF3}, {0x1BFC, 0x1C37}, {0x1C3B, 0x1C49},
+ {0x1C4D, 0x1C88}, {0x1C90, 0x1CBA}, {0x1CBD, 0x1CC7},
+ {0x1CD0, 0x1CFA}, {0x1D00, 0x1DF9}, {0x1DFB, 0x1F15},
+ {0x1F18, 0x1F1D}, {0x1F20, 0x1F45}, {0x1F48, 0x1F4D},
+ {0x1F50, 0x1F57}, {0x1F59, 0x1F59}, {0x1F5B, 0x1F5B},
+ {0x1F5D, 0x1F5D}, {0x1F5F, 0x1F7D}, {0x1F80, 0x1FB4},
+ {0x1FB6, 0x1FC4}, {0x1FC6, 0x1FD3}, {0x1FD6, 0x1FDB},
+ {0x1FDD, 0x1FEF}, {0x1FF2, 0x1FF4}, {0x1FF6, 0x1FFE},
+ {0x2000, 0x200F}, {0x2011, 0x2012}, {0x2017, 0x2017},
+ {0x201A, 0x201B}, {0x201E, 0x201F}, {0x2023, 0x2023},
+ {0x2028, 0x202F}, {0x2031, 0x2031}, {0x2034, 0x2034},
+ {0x2036, 0x203A}, {0x203C, 0x203D}, {0x203F, 0x2064},
+ {0x2066, 0x2071}, {0x2075, 0x207E}, {0x2080, 0x2080},
+ {0x2085, 0x208E}, {0x2090, 0x209C}, {0x20A0, 0x20A8},
+ {0x20AA, 0x20AB}, {0x20AD, 0x20BF}, {0x20D0, 0x20F0},
+ {0x2100, 0x2102}, {0x2104, 0x2104}, {0x2106, 0x2108},
+ {0x210A, 0x2112}, {0x2114, 0x2115}, {0x2117, 0x2120},
+ {0x2123, 0x2125}, {0x2127, 0x212A}, {0x212C, 0x2152},
+ {0x2155, 0x215A}, {0x215F, 0x215F}, {0x216C, 0x216F},
+ {0x217A, 0x2188}, {0x218A, 0x218B}, {0x219A, 0x21B7},
+ {0x21BA, 0x21D1}, {0x21D3, 0x21D3}, {0x21D5, 0x21E6},
+ {0x21E8, 0x21FF}, {0x2201, 0x2201}, {0x2204, 0x2206},
+ {0x2209, 0x220A}, {0x220C, 0x220E}, {0x2210, 0x2210},
+ {0x2212, 0x2214}, {0x2216, 0x2219}, {0x221B, 0x221C},
+ {0x2221, 0x2222}, {0x2224, 0x2224}, {0x2226, 0x2226},
+ {0x222D, 0x222D}, {0x222F, 0x2233}, {0x2238, 0x223B},
+ {0x223E, 0x2247}, {0x2249, 0x224B}, {0x224D, 0x2251},
+ {0x2253, 0x225F}, {0x2262, 0x2263}, {0x2268, 0x2269},
+ {0x226C, 0x226D}, {0x2270, 0x2281}, {0x2284, 0x2285},
+ {0x2288, 0x2294}, {0x2296, 0x2298}, {0x229A, 0x22A4},
+ {0x22A6, 0x22BE}, {0x22C0, 0x2311}, {0x2313, 0x2319},
+ {0x231C, 0x2328}, {0x232B, 0x23E8}, {0x23ED, 0x23EF},
+ {0x23F1, 0x23F2}, {0x23F4, 0x2426}, {0x2440, 0x244A},
+ {0x24EA, 0x24EA}, {0x254C, 0x254F}, {0x2574, 0x257F},
+ {0x2590, 0x2591}, {0x2596, 0x259F}, {0x25A2, 0x25A2},
+ {0x25AA, 0x25B1}, {0x25B4, 0x25B5}, {0x25B8, 0x25BB},
+ {0x25BE, 0x25BF}, {0x25C2, 0x25C5}, {0x25C9, 0x25CA},
+ {0x25CC, 0x25CD}, {0x25D2, 0x25E1}, {0x25E6, 0x25EE},
+ {0x25F0, 0x25FC}, {0x25FF, 0x2604}, {0x2607, 0x2608},
+ {0x260A, 0x260D}, {0x2610, 0x2613}, {0x2616, 0x261B},
+ {0x261D, 0x261D}, {0x261F, 0x263F}, {0x2641, 0x2641},
+ {0x2643, 0x2647}, {0x2654, 0x265F}, {0x2662, 0x2662},
+ {0x2666, 0x2666}, {0x266B, 0x266B}, {0x266E, 0x266E},
+ {0x2670, 0x267E}, {0x2680, 0x2692}, {0x2694, 0x269D},
+ {0x26A0, 0x26A0}, {0x26A2, 0x26A9}, {0x26AC, 0x26BC},
+ {0x26C0, 0x26C3}, {0x26E2, 0x26E2}, {0x26E4, 0x26E7},
+ {0x2700, 0x2704}, {0x2706, 0x2709}, {0x270C, 0x2727},
+ {0x2729, 0x273C}, {0x273E, 0x274B}, {0x274D, 0x274D},
+ {0x274F, 0x2752}, {0x2756, 0x2756}, {0x2758, 0x2775},
+ {0x2780, 0x2794}, {0x2798, 0x27AF}, {0x27B1, 0x27BE},
+ {0x27C0, 0x27E5}, {0x27EE, 0x2984}, {0x2987, 0x2B1A},
+ {0x2B1D, 0x2B4F}, {0x2B51, 0x2B54}, {0x2B5A, 0x2B73},
+ {0x2B76, 0x2B95}, {0x2B97, 0x2C2E}, {0x2C30, 0x2C5E},
+ {0x2C60, 0x2CF3}, {0x2CF9, 0x2D25}, {0x2D27, 0x2D27},
+ {0x2D2D, 0x2D2D}, {0x2D30, 0x2D67}, {0x2D6F, 0x2D70},
+ {0x2D7F, 0x2D96}, {0x2DA0, 0x2DA6}, {0x2DA8, 0x2DAE},
+ {0x2DB0, 0x2DB6}, {0x2DB8, 0x2DBE}, {0x2DC0, 0x2DC6},
+ {0x2DC8, 0x2DCE}, {0x2DD0, 0x2DD6}, {0x2DD8, 0x2DDE},
+ {0x2DE0, 0x2E52}, {0x303F, 0x303F}, {0x4DC0, 0x4DFF},
+ {0xA4D0, 0xA62B}, {0xA640, 0xA6F7}, {0xA700, 0xA7BF},
+ {0xA7C2, 0xA7CA}, {0xA7F5, 0xA82C}, {0xA830, 0xA839},
+ {0xA840, 0xA877}, {0xA880, 0xA8C5}, {0xA8CE, 0xA8D9},
+ {0xA8E0, 0xA953}, {0xA95F, 0xA95F}, {0xA980, 0xA9CD},
+ {0xA9CF, 0xA9D9}, {0xA9DE, 0xA9FE}, {0xAA00, 0xAA36},
+ {0xAA40, 0xAA4D}, {0xAA50, 0xAA59}, {0xAA5C, 0xAAC2},
+ {0xAADB, 0xAAF6}, {0xAB01, 0xAB06}, {0xAB09, 0xAB0E},
+ {0xAB11, 0xAB16}, {0xAB20, 0xAB26}, {0xAB28, 0xAB2E},
+ {0xAB30, 0xAB6B}, {0xAB70, 0xABED}, {0xABF0, 0xABF9},
+ {0xD7B0, 0xD7C6}, {0xD7CB, 0xD7FB}, {0xD800, 0xDFFF},
+ {0xFB00, 0xFB06}, {0xFB13, 0xFB17}, {0xFB1D, 0xFB36},
+ {0xFB38, 0xFB3C}, {0xFB3E, 0xFB3E}, {0xFB40, 0xFB41},
+ {0xFB43, 0xFB44}, {0xFB46, 0xFBC1}, {0xFBD3, 0xFD3F},
+ {0xFD50, 0xFD8F}, {0xFD92, 0xFDC7}, {0xFDF0, 0xFDFD},
+ {0xFE20, 0xFE2F}, {0xFE70, 0xFE74}, {0xFE76, 0xFEFC},
+ {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFC}, {0x10000, 0x1000B},
+ {0x1000D, 0x10026}, {0x10028, 0x1003A}, {0x1003C, 0x1003D},
+ {0x1003F, 0x1004D}, {0x10050, 0x1005D}, {0x10080, 0x100FA},
+ {0x10100, 0x10102}, {0x10107, 0x10133}, {0x10137, 0x1018E},
+ {0x10190, 0x1019C}, {0x101A0, 0x101A0}, {0x101D0, 0x101FD},
+ {0x10280, 0x1029C}, {0x102A0, 0x102D0}, {0x102E0, 0x102FB},
+ {0x10300, 0x10323}, {0x1032D, 0x1034A}, {0x10350, 0x1037A},
+ {0x10380, 0x1039D}, {0x1039F, 0x103C3}, {0x103C8, 0x103D5},
+ {0x10400, 0x1049D}, {0x104A0, 0x104A9}, {0x104B0, 0x104D3},
+ {0x104D8, 0x104FB}, {0x10500, 0x10527}, {0x10530, 0x10563},
+ {0x1056F, 0x1056F}, {0x10600, 0x10736}, {0x10740, 0x10755},
+ {0x10760, 0x10767}, {0x10800, 0x10805}, {0x10808, 0x10808},
+ {0x1080A, 0x10835}, {0x10837, 0x10838}, {0x1083C, 0x1083C},
+ {0x1083F, 0x10855}, {0x10857, 0x1089E}, {0x108A7, 0x108AF},
+ {0x108E0, 0x108F2}, {0x108F4, 0x108F5}, {0x108FB, 0x1091B},
+ {0x1091F, 0x10939}, {0x1093F, 0x1093F}, {0x10980, 0x109B7},
+ {0x109BC, 0x109CF}, {0x109D2, 0x10A03}, {0x10A05, 0x10A06},
+ {0x10A0C, 0x10A13}, {0x10A15, 0x10A17}, {0x10A19, 0x10A35},
+ {0x10A38, 0x10A3A}, {0x10A3F, 0x10A48}, {0x10A50, 0x10A58},
+ {0x10A60, 0x10A9F}, {0x10AC0, 0x10AE6}, {0x10AEB, 0x10AF6},
+ {0x10B00, 0x10B35}, {0x10B39, 0x10B55}, {0x10B58, 0x10B72},
+ {0x10B78, 0x10B91}, {0x10B99, 0x10B9C}, {0x10BA9, 0x10BAF},
+ {0x10C00, 0x10C48}, {0x10C80, 0x10CB2}, {0x10CC0, 0x10CF2},
+ {0x10CFA, 0x10D27}, {0x10D30, 0x10D39}, {0x10E60, 0x10E7E},
+ {0x10E80, 0x10EA9}, {0x10EAB, 0x10EAD}, {0x10EB0, 0x10EB1},
+ {0x10F00, 0x10F27}, {0x10F30, 0x10F59}, {0x10FB0, 0x10FCB},
+ {0x10FE0, 0x10FF6}, {0x11000, 0x1104D}, {0x11052, 0x1106F},
+ {0x1107F, 0x110C1}, {0x110CD, 0x110CD}, {0x110D0, 0x110E8},
+ {0x110F0, 0x110F9}, {0x11100, 0x11134}, {0x11136, 0x11147},
+ {0x11150, 0x11176}, {0x11180, 0x111DF}, {0x111E1, 0x111F4},
+ {0x11200, 0x11211}, {0x11213, 0x1123E}, {0x11280, 0x11286},
+ {0x11288, 0x11288}, {0x1128A, 0x1128D}, {0x1128F, 0x1129D},
+ {0x1129F, 0x112A9}, {0x112B0, 0x112EA}, {0x112F0, 0x112F9},
+ {0x11300, 0x11303}, {0x11305, 0x1130C}, {0x1130F, 0x11310},
+ {0x11313, 0x11328}, {0x1132A, 0x11330}, {0x11332, 0x11333},
+ {0x11335, 0x11339}, {0x1133B, 0x11344}, {0x11347, 0x11348},
+ {0x1134B, 0x1134D}, {0x11350, 0x11350}, {0x11357, 0x11357},
+ {0x1135D, 0x11363}, {0x11366, 0x1136C}, {0x11370, 0x11374},
+ {0x11400, 0x1145B}, {0x1145D, 0x11461}, {0x11480, 0x114C7},
+ {0x114D0, 0x114D9}, {0x11580, 0x115B5}, {0x115B8, 0x115DD},
+ {0x11600, 0x11644}, {0x11650, 0x11659}, {0x11660, 0x1166C},
+ {0x11680, 0x116B8}, {0x116C0, 0x116C9}, {0x11700, 0x1171A},
+ {0x1171D, 0x1172B}, {0x11730, 0x1173F}, {0x11800, 0x1183B},
+ {0x118A0, 0x118F2}, {0x118FF, 0x11906}, {0x11909, 0x11909},
+ {0x1190C, 0x11913}, {0x11915, 0x11916}, {0x11918, 0x11935},
+ {0x11937, 0x11938}, {0x1193B, 0x11946}, {0x11950, 0x11959},
+ {0x119A0, 0x119A7}, {0x119AA, 0x119D7}, {0x119DA, 0x119E4},
+ {0x11A00, 0x11A47}, {0x11A50, 0x11AA2}, {0x11AC0, 0x11AF8},
+ {0x11C00, 0x11C08}, {0x11C0A, 0x11C36}, {0x11C38, 0x11C45},
+ {0x11C50, 0x11C6C}, {0x11C70, 0x11C8F}, {0x11C92, 0x11CA7},
+ {0x11CA9, 0x11CB6}, {0x11D00, 0x11D06}, {0x11D08, 0x11D09},
+ {0x11D0B, 0x11D36}, {0x11D3A, 0x11D3A}, {0x11D3C, 0x11D3D},
+ {0x11D3F, 0x11D47}, {0x11D50, 0x11D59}, {0x11D60, 0x11D65},
+ {0x11D67, 0x11D68}, {0x11D6A, 0x11D8E}, {0x11D90, 0x11D91},
+ {0x11D93, 0x11D98}, {0x11DA0, 0x11DA9}, {0x11EE0, 0x11EF8},
+ {0x11FB0, 0x11FB0}, {0x11FC0, 0x11FF1}, {0x11FFF, 0x12399},
+ {0x12400, 0x1246E}, {0x12470, 0x12474}, {0x12480, 0x12543},
+ {0x13000, 0x1342E}, {0x13430, 0x13438}, {0x14400, 0x14646},
+ {0x16800, 0x16A38}, {0x16A40, 0x16A5E}, {0x16A60, 0x16A69},
+ {0x16A6E, 0x16A6F}, {0x16AD0, 0x16AED}, {0x16AF0, 0x16AF5},
+ {0x16B00, 0x16B45}, {0x16B50, 0x16B59}, {0x16B5B, 0x16B61},
+ {0x16B63, 0x16B77}, {0x16B7D, 0x16B8F}, {0x16E40, 0x16E9A},
+ {0x16F00, 0x16F4A}, {0x16F4F, 0x16F87}, {0x16F8F, 0x16F9F},
+ {0x1BC00, 0x1BC6A}, {0x1BC70, 0x1BC7C}, {0x1BC80, 0x1BC88},
+ {0x1BC90, 0x1BC99}, {0x1BC9C, 0x1BCA3}, {0x1D000, 0x1D0F5},
+ {0x1D100, 0x1D126}, {0x1D129, 0x1D1E8}, {0x1D200, 0x1D245},
+ {0x1D2E0, 0x1D2F3}, {0x1D300, 0x1D356}, {0x1D360, 0x1D378},
+ {0x1D400, 0x1D454}, {0x1D456, 0x1D49C}, {0x1D49E, 0x1D49F},
+ {0x1D4A2, 0x1D4A2}, {0x1D4A5, 0x1D4A6}, {0x1D4A9, 0x1D4AC},
+ {0x1D4AE, 0x1D4B9}, {0x1D4BB, 0x1D4BB}, {0x1D4BD, 0x1D4C3},
+ {0x1D4C5, 0x1D505}, {0x1D507, 0x1D50A}, {0x1D50D, 0x1D514},
+ {0x1D516, 0x1D51C}, {0x1D51E, 0x1D539}, {0x1D53B, 0x1D53E},
+ {0x1D540, 0x1D544}, {0x1D546, 0x1D546}, {0x1D54A, 0x1D550},
+ {0x1D552, 0x1D6A5}, {0x1D6A8, 0x1D7CB}, {0x1D7CE, 0x1DA8B},
+ {0x1DA9B, 0x1DA9F}, {0x1DAA1, 0x1DAAF}, {0x1E000, 0x1E006},
+ {0x1E008, 0x1E018}, {0x1E01B, 0x1E021}, {0x1E023, 0x1E024},
+ {0x1E026, 0x1E02A}, {0x1E100, 0x1E12C}, {0x1E130, 0x1E13D},
+ {0x1E140, 0x1E149}, {0x1E14E, 0x1E14F}, {0x1E2C0, 0x1E2F9},
+ {0x1E2FF, 0x1E2FF}, {0x1E800, 0x1E8C4}, {0x1E8C7, 0x1E8D6},
+ {0x1E900, 0x1E94B}, {0x1E950, 0x1E959}, {0x1E95E, 0x1E95F},
+ {0x1EC71, 0x1ECB4}, {0x1ED01, 0x1ED3D}, {0x1EE00, 0x1EE03},
+ {0x1EE05, 0x1EE1F}, {0x1EE21, 0x1EE22}, {0x1EE24, 0x1EE24},
+ {0x1EE27, 0x1EE27}, {0x1EE29, 0x1EE32}, {0x1EE34, 0x1EE37},
+ {0x1EE39, 0x1EE39}, {0x1EE3B, 0x1EE3B}, {0x1EE42, 0x1EE42},
+ {0x1EE47, 0x1EE47}, {0x1EE49, 0x1EE49}, {0x1EE4B, 0x1EE4B},
+ {0x1EE4D, 0x1EE4F}, {0x1EE51, 0x1EE52}, {0x1EE54, 0x1EE54},
+ {0x1EE57, 0x1EE57}, {0x1EE59, 0x1EE59}, {0x1EE5B, 0x1EE5B},
+ {0x1EE5D, 0x1EE5D}, {0x1EE5F, 0x1EE5F}, {0x1EE61, 0x1EE62},
+ {0x1EE64, 0x1EE64}, {0x1EE67, 0x1EE6A}, {0x1EE6C, 0x1EE72},
+ {0x1EE74, 0x1EE77}, {0x1EE79, 0x1EE7C}, {0x1EE7E, 0x1EE7E},
+ {0x1EE80, 0x1EE89}, {0x1EE8B, 0x1EE9B}, {0x1EEA1, 0x1EEA3},
+ {0x1EEA5, 0x1EEA9}, {0x1EEAB, 0x1EEBB}, {0x1EEF0, 0x1EEF1},
+ {0x1F000, 0x1F003}, {0x1F005, 0x1F02B}, {0x1F030, 0x1F093},
+ {0x1F0A0, 0x1F0AE}, {0x1F0B1, 0x1F0BF}, {0x1F0C1, 0x1F0CE},
+ {0x1F0D1, 0x1F0F5}, {0x1F10B, 0x1F10F}, {0x1F12E, 0x1F12F},
+ {0x1F16A, 0x1F16F}, {0x1F1AD, 0x1F1AD}, {0x1F1E6, 0x1F1FF},
+ {0x1F321, 0x1F32C}, {0x1F336, 0x1F336}, {0x1F37D, 0x1F37D},
+ {0x1F394, 0x1F39F}, {0x1F3CB, 0x1F3CE}, {0x1F3D4, 0x1F3DF},
+ {0x1F3F1, 0x1F3F3}, {0x1F3F5, 0x1F3F7}, {0x1F43F, 0x1F43F},
+ {0x1F441, 0x1F441}, {0x1F4FD, 0x1F4FE}, {0x1F53E, 0x1F54A},
+ {0x1F54F, 0x1F54F}, {0x1F568, 0x1F579}, {0x1F57B, 0x1F594},
+ {0x1F597, 0x1F5A3}, {0x1F5A5, 0x1F5FA}, {0x1F650, 0x1F67F},
+ {0x1F6C6, 0x1F6CB}, {0x1F6CD, 0x1F6CF}, {0x1F6D3, 0x1F6D4},
+ {0x1F6E0, 0x1F6EA}, {0x1F6F0, 0x1F6F3}, {0x1F700, 0x1F773},
+ {0x1F780, 0x1F7D8}, {0x1F800, 0x1F80B}, {0x1F810, 0x1F847},
+ {0x1F850, 0x1F859}, {0x1F860, 0x1F887}, {0x1F890, 0x1F8AD},
+ {0x1F8B0, 0x1F8B1}, {0x1F900, 0x1F90B}, {0x1F93B, 0x1F93B},
+ {0x1F946, 0x1F946}, {0x1FA00, 0x1FA53}, {0x1FA60, 0x1FA6D},
+ {0x1FB00, 0x1FB92}, {0x1FB94, 0x1FBCA}, {0x1FBF0, 0x1FBF9},
+ {0xE0001, 0xE0001}, {0xE0020, 0xE007F},
+}
+
+var emoji = table{
+ {0x203C, 0x203C}, {0x2049, 0x2049}, {0x2122, 0x2122},
+ {0x2139, 0x2139}, {0x2194, 0x2199}, {0x21A9, 0x21AA},
+ {0x231A, 0x231B}, {0x2328, 0x2328}, {0x2388, 0x2388},
+ {0x23CF, 0x23CF}, {0x23E9, 0x23F3}, {0x23F8, 0x23FA},
+ {0x24C2, 0x24C2}, {0x25AA, 0x25AB}, {0x25B6, 0x25B6},
+ {0x25C0, 0x25C0}, {0x25FB, 0x25FE}, {0x2600, 0x2605},
+ {0x2607, 0x2612}, {0x2614, 0x2685}, {0x2690, 0x2705},
+ {0x2708, 0x2712}, {0x2714, 0x2714}, {0x2716, 0x2716},
+ {0x271D, 0x271D}, {0x2721, 0x2721}, {0x2728, 0x2728},
+ {0x2733, 0x2734}, {0x2744, 0x2744}, {0x2747, 0x2747},
+ {0x274C, 0x274C}, {0x274E, 0x274E}, {0x2753, 0x2755},
+ {0x2757, 0x2757}, {0x2763, 0x2767}, {0x2795, 0x2797},
+ {0x27A1, 0x27A1}, {0x27B0, 0x27B0}, {0x27BF, 0x27BF},
+ {0x2934, 0x2935}, {0x2B05, 0x2B07}, {0x2B1B, 0x2B1C},
+ {0x2B50, 0x2B50}, {0x2B55, 0x2B55}, {0x3030, 0x3030},
+ {0x303D, 0x303D}, {0x3297, 0x3297}, {0x3299, 0x3299},
+ {0x1F000, 0x1F0FF}, {0x1F10D, 0x1F10F}, {0x1F12F, 0x1F12F},
+ {0x1F16C, 0x1F171}, {0x1F17E, 0x1F17F}, {0x1F18E, 0x1F18E},
+ {0x1F191, 0x1F19A}, {0x1F1AD, 0x1F1E5}, {0x1F201, 0x1F20F},
+ {0x1F21A, 0x1F21A}, {0x1F22F, 0x1F22F}, {0x1F232, 0x1F23A},
+ {0x1F23C, 0x1F23F}, {0x1F249, 0x1F3FA}, {0x1F400, 0x1F53D},
+ {0x1F546, 0x1F64F}, {0x1F680, 0x1F6FF}, {0x1F774, 0x1F77F},
+ {0x1F7D5, 0x1F7FF}, {0x1F80C, 0x1F80F}, {0x1F848, 0x1F84F},
+ {0x1F85A, 0x1F85F}, {0x1F888, 0x1F88F}, {0x1F8AE, 0x1F8FF},
+ {0x1F90C, 0x1F93A}, {0x1F93C, 0x1F945}, {0x1F947, 0x1FAFF},
+ {0x1FC00, 0x1FFFD},
+}
diff --git a/vendor/github.com/mattn/go-runewidth/runewidth_windows.go b/vendor/github.com/mattn/go-runewidth/runewidth_windows.go
new file mode 100644
index 0000000..d6a6177
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/runewidth_windows.go
@@ -0,0 +1,28 @@
+// +build windows
+// +build !appengine
+
+package runewidth
+
+import (
+ "syscall"
+)
+
+var (
+ kernel32 = syscall.NewLazyDLL("kernel32")
+ procGetConsoleOutputCP = kernel32.NewProc("GetConsoleOutputCP")
+)
+
+// IsEastAsian return true if the current locale is CJK
+func IsEastAsian() bool {
+ r1, _, _ := procGetConsoleOutputCP.Call()
+ if r1 == 0 {
+ return false
+ }
+
+ switch int(r1) {
+ case 932, 51932, 936, 949, 950:
+ return true
+ }
+
+ return false
+}
diff --git a/vendor/github.com/pterm/pterm/.gitignore b/vendor/github.com/pterm/pterm/.gitignore
new file mode 100644
index 0000000..6d04504
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/.gitignore
@@ -0,0 +1,21 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Dependency directories (remove the comment below to include it)
+vendor/
+
+# This is where we test stuff
+/experimenting/
+
+/.history
+/.vscode
diff --git a/vendor/github.com/pterm/pterm/.golangci.yml b/vendor/github.com/pterm/pterm/.golangci.yml
new file mode 100644
index 0000000..4b48b03
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/.golangci.yml
@@ -0,0 +1,92 @@
+linters-settings:
+ gocritic:
+ enabled-tags:
+ - diagnostic
+ - experimental
+ - opinionated
+ - performance
+ - style
+ disabled-checks:
+ - dupImport
+ - ifElseChain
+ - octalLiteral
+ - whyNoLint
+ - wrapperFunc
+ - exitAfterDefer
+ - hugeParam
+ - ptrToRefParam
+ - paramTypeCombine
+ - unnamedResult
+ # maligned:
+ # suggest-new: true
+ misspell:
+ locale: US
+linters:
+ disable-all: true
+ enable:
+ - gocritic
+ - gosec
+ - govet
+ - ineffassign
+ - interfacer
+ - unconvert
+ - gosimple
+ - godox
+ - whitespace
+ - staticcheck
+ # - bodyclose
+ # - maligned
+ # - godot
+ # - deadcode
+ # - depguard
+ # - dogsled
+ # - dupl
+ # - errcheck
+ # - exhaustive
+ # - funlen
+ # - gochecknoinits
+ # - goconst
+ # - gocyclo
+ # - gofmt
+ # - goimports
+ # - golint
+ # - gomnd
+ # - goprintffuncname
+ # - lll
+ # - misspell
+ # - nakedret
+ # - noctx
+ # - nolintlint
+ # - rowserrcheck
+ # - scopelint
+ # - structcheck
+ # - stylecheck
+ # - typecheck
+ # - unparam
+ # - unused
+ # - varcheck
+ # - whitespace
+ # - asciicheck
+ # - gochecknoglobals
+ # - gocognit
+ # - goerr113
+ # - nestif
+ # - prealloc
+ # - testpackage
+ # - wsl
+issues:
+ # Excluding configuration per-path, per-linter, per-text and per-source
+ exclude-rules:
+ - path: _test\.go
+ linters:
+ - gocyclo
+ - errcheck
+ - dupl
+ - gosec
+ - gocritic
+ # https://github.com/go-critic/go-critic/issues/926
+ - linters:
+ - gocritic
+ text: "unnecessaryDefer:"
+service:
+ golangci-lint-version: 1.31.x # use the fixed version to not introduce new linters unexpectedly
\ No newline at end of file
diff --git a/vendor/github.com/pterm/pterm/CHANGELOG.md b/vendor/github.com/pterm/pterm/CHANGELOG.md
new file mode 100644
index 0000000..4d2eba6
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/CHANGELOG.md
@@ -0,0 +1,1003 @@
+
+## [Unreleased]
+
+### Code Refactoring
+- fix linting
+- regenerate snapshots
+
+
+
+## [v0.12.34] - 2022-01-16
+### Bug Fixes
+- **progressbar:** refresh progressbars on every PTerm print ([#302](https://github.com/pterm/pterm/issues/302))
+
+### Test
+- removed `AreaPrinter` test output
+- **table:** changed mock reader from `os.Stdin` to `outBuf`
+
+
+
+## [v0.12.33] - 2021-10-24
+### Features
+- add `PrintOnErrorf` for every `TextPrinter` ([#279](https://github.com/pterm/pterm/issues/279))
+- **coverage:** add unit test
+- **progressbar:** made updating the progressbar title easier. ([#267](https://github.com/pterm/pterm/issues/267))
+- **table:** increase test coverage
+- **table:** revamp to follow practice
+- **table:** add support for right data alignment
+
+### Bug Fixes
+- **idea:** revert unwanted config changes
+- **linter:** do linter recommendation to delete fallthrough
+
+
+
+## [v0.12.32] - 2021-10-15
+### Features
+- added `AreaPrinter.Clear()`
+
+### Bug Fixes
+- progressbar method name
+- **header:** fixed length calculation for Chinese strings
+
+### Code Refactoring
+- change bitSize size
+
+
+
+## [v0.12.31] - 2021-09-21
+### Features
+- **prefix:** added `LineNumberOffset` to `PrefixPrinter`
+
+
+
+## [v0.12.30] - 2021-08-16
+### Bug Fixes
+- **style:** resetting to previous color also resets attributes
+
+### Code Refactoring
+- adapt new testza function name
+
+
+
+## [v0.12.29] - 2021-07-19
+### Features
+- **putils:** add `PrintAverageExecutionTime`
+
+### Test
+- fix rgb error test
+- fix internal test import cycle
+- move tests into own package
+
+### Code Refactoring
+- replace `testify` with `testza`
+
+
+
+## [v0.12.28] - 2021-07-17
+### Features
+- **spinner:** add option to show a timer
+
+### Bug Fixes
+- **bar chart:** fix panic when rendering empty horizontal bar chart
+
+### Test
+- **spinner:** try to fix RawOutput text
+- **spinner:** add raw output test
+
+### Code Refactoring
+- **spinner:** better raw output logic
+- **spinner:** refactor
+
+
+
+## [v0.12.27] - 2021-07-05
+### Bug Fixes
+- **style:** fix multiline style coloring
+
+### Test
+- **style:** fix multiline style coloring
+- **style:** fix multiline style coloring
+
+
+
+## [v0.12.26] - 2021-07-01
+### Bug Fixes
+- **spinner:** Override previous text in `UpdateText`
+
+
+
+## [v0.12.25] - 2021-07-01
+### Features
+- **table:** add `Boxed` option
+
+### Test
+- add tests for boxed `TablePrinter`
+
+
+
+## [v0.12.24] - 2021-06-13
+### Features
+- **boxprinter:** replace line breaks in title with space
+- **boxprinter:** add title center position to `BoxPrinter`
+- **boxprinter:** add title & title position to `BoxPrinter`
+- **boxprinter:** add title & title position to `BoxPrinter`
+- **putils:** add `TableDataFromSeparatedValues`
+- **putils:** add `TableDataFromTSV`
+- **putils:** add `TableDataFromCSV`
+- **putils:** add function to convert TSV to `TableData`
+- **putils:** add function to convert CSV to `TableData`
+
+### Test
+- add test for putils `TableData` generation
+- **boxprinter:** add tests for title center position to `BoxPrinter`
+- **boxprinter:** add tests for title & title position
+
+### Code Refactoring
+- **boxprinter:** prefix title positions with `Title`
+- **putils:** add `rowSeparator` to `TableFromSeparatedValues`
+
+
+
+## [v0.12.23] - 2021-06-07
+### Features
+- Add util functions to create tables from slices of structs ([#217](https://github.com/pterm/pterm/issues/217))
+
+### Bug Fixes
+- **headerprinter:** don't panic if content width > terminal width
+
+### Test
+- **prefix:** `pterm.Error` default no line number shown
+
+### Code Refactoring
+- **prefix:** `pterm.Error` default no line number shown
+
+
+
+## [v0.12.22] - 2021-05-30
+### Features
+- make spinner update faster
+
+### Performance Improvements
+- improve performance of `SpinnerPrinter`
+
+
+
+## [v0.12.21] - 2021-05-30
+### Features
+- print lines above active spinners
+- **putils:** add `DownloadFileWithProgressbar`
+
+### Test
+- clear active spinners after tests complete
+
+### Code Refactoring
+- **putils:** change internal variable name
+
+
+
+## [v0.12.20] - 2021-05-29
+### Features
+- force color output by default
+
+
+
+## [v0.12.19] - 2021-05-29
+### Features
+- add `PrintOnError` for all printers and interface
+- **putils:** add `putils` package ([#206](https://github.com/pterm/pterm/issues/206))
+
+### Bug Fixes
+- **header:** fix multiline header
+
+### Test
+- add tests for all printers for `PrintOnError`
+
+### Code Refactoring
+- make `PrintOnError` return `*TextPrinter`
+- **area:** better height calculation
+
+
+
+## [v0.12.18] - 2021-05-22
+### Features
+- add `AreaPrinter`
+- **area:** add `Center` option
+- **area:** add `Fullscreen` option
+- **area:** add `GetContent` function
+- **area:** add `AreaPrinter`
+
+### Test
+- **area:** fix tests for `AreaPrinter`
+- **area:** add `AreaPrinter` tests
+
+### Code Refactoring
+- fix linting errors
+
+
+
+## [v0.12.17] - 2021-05-14
+### Bug Fixes
+- fix `pterm.Fatal.Printfln` not panicking
+- **prefix:** fix `pterm.Fatal.Printfln` not panicking and had output in debug mode
+
+### Test
+- **prefix:** add tests for `Sprintfln` and `Printfln` function when in debug mode
+
+
+
+## [v0.12.16] - 2021-05-13
+### Code Refactoring
+- **prefix:** make `PrintOnError` accept multiple inputs
+
+
+
+## [v0.12.15] - 2021-05-13
+### Features
+- add raw output mode for `BarChart`
+- add disable styling boolean option
+- **bigtext:** add raw output mode
+- **centerprinter:** add raw output mode
+- **headerprinter:** add raw output mode
+- **panelprinter:** add raw output mode
+- **paragraph:** add raw output mode
+- **prefix:** add `PrintIfError`
+- **prefix:** add raw output mode
+- **progressbar:** add raw output mode
+- **spinner:** add raw output mode
+
+### Bug Fixes
+- **prefix:** fix `PrintOnError`
+
+### Test
+- add tests with `RawOutput` enabled
+- add interface tests for `Color` and `RGB`
+- added tests for `DisableStyling` and `EnableStyling`
+
+### Code Refactoring
+- correct behaviour of Enable-/DisableStyling
+- fix variable names
+
+
+
+## [v0.12.14] - 2021-05-09
+### Features
+- **basic-text:** add `Sprintfln` and `Printfln` function
+- **boxprinter:** add `Sprintfln` and `Printfln` function
+- **centerprinter:** add `Sprintfln` and `Printfln` function
+- **color:** add `Sprintfln` and `Printfln` function
+- **header:** add `Sprintfln` and `Printfln` function
+- **paragraph:** add `Sprintfln` and `Printfln` function
+- **prefix:** add `Sprintfln` and `Printfln` function
+- **print:** add `Sprintfln` and `Printfln` function
+- **printer-interface:** add `Sprintfln` and `Printfln` to the interface
+- **rgb:** add `Sprintfln` and `Printfln` function
+- **section:** add `Sprintfln` and `Printfln` function
+
+### Bug Fixes
+- **header:** fix inline color in `Header`
+
+### Test
+- add tests for `Sprintfln` and `Printfln` function
+
+### Code Refactoring
+- refactor `Sprintfln` and `Printfln` func. for better performance
+
+### Reverts
+- ci: change color scheme for rendered examples
+
+
+
+## [v0.12.13] - 2021-04-10
+### Bug Fixes
+- **bigtext:** fix height of some characters [#180](https://github.com/pterm/pterm/issues/180)
+- **color:** make color implement `TextPrinter`
+
+### Test
+- add interface tests
+
+### Code Refactoring
+- **examples:** center the intro of `demo`
+- **examples:** add note to box printer
+
+
+
+## [v0.12.12] - 2021-03-01
+### Features
+- **prefixprinter:** Add option to show line number of caller
+
+### Code Refactoring
+- **examples:** Update `PrefixPrinter` example
+
+
+
+## [v0.12.11] - 2021-02-26
+### Code Refactoring
+- refactor print logic of `BoxPrinter`
+- refactor print logic of `CenterPrinter`
+
+
+
+## [v0.12.10] - 2021-02-26
+### Bug Fixes
+- correct `pterm.Println()` behaviour to fit to `fmt.Println()`
+
+
+
+## [v0.12.9] - 2021-02-23
+### Bug Fixes
+- correct `pterm.Println()` behaviour to fit to `fmt.Println()`
+- change terminal package import path to updated version
+
+
+
+## [v0.12.8] - 2020-12-11
+### Features
+- **boxprinter:** add `WithHorizontalString` to `BoxPrinter`
+- **boxprinter:** add `BoxPrinter`
+- **panel:** add optional border for `Panel`
+- **panelprinter:** add theme support to `PanelPrinter`
+- **theme:** add `BoxStyle` and `BoxTextStyle`
+- **theme:** add optional theme for border in `Panel`
+
+### Bug Fixes
+- revert change horizontal string change
+
+### Test
+- **boxprinter:** add test
+- **boxprinter:** test multiple lines in one box
+- **boxprinter:** add tests for `BoxPrinter`
+- **panelprinter:** add tests for adding box printer
+- **panelprinter:** add tests for optional border for `Panel`
+- **theme:** add tests for `BoxStyle` and `BoxTextStyle`
+
+### Code Refactoring
+- remove analytics
+- **boxprinter:** change from `RenderablePrinter` to `TextPrinter`
+- **boxprinter:** return theme when style is nil
+- **boxprinter:** change `DefaultBox` top and bottom padding to 0
+- **boxprinter:** fix spacing between boxes and in boxes
+- **boxprinter:** refactor code
+- **panelprinter:** optional border for `Panel`
+- **panelprinter:** add `BoxPrinter` to surround panels with a fully custom box
+
+
+
+## [v0.12.7] - 2020-11-24
+### Features
+- add values to chart
+- add horizontal `BarChartPrinter`
+- add `BarChartPrinter`
+- add `BarChartPrinter`
+- add `BarChartPrinter`
+- **theme:** add theme support to `BarChart`
+
+### Bug Fixes
+- center bars over colored labels in `BarChart`
+
+### Test
+- add tests to `BarChartPrinter`
+
+
+
+## [v0.12.6] - 2020-11-17
+### Bug Fixes
+- disabling output works as expected now ([#149](https://github.com/pterm/pterm/issues/149))
+
+
+
+## [v0.12.5] - 2020-11-17
+### Bug Fixes
+- fix `PrefixPrinter` with multiple trailing newline endings.
+
+
+
+## [v0.12.4] - 2020-11-17
+### Bug Fixes
+- fix `Printf` of `PrefixPrinter`
+
+
+
+## [v0.12.3] - 2020-11-12
+### Test
+- reduce tests
+- different test logic for rgb printing
+- add better test names for `RGB` tests
+
+
+
+## [v0.12.2] - 2020-11-05
+### Features
+- color each line separately when using multi line input
+
+### Bug Fixes
+- fix internal `GetStringMaxWidth` max width
+
+### Test
+- **basictext:** proxy print functions to DevNull
+- **progressbar:** proxy print functions to DevNull
+
+### Code Refactoring
+- use `pterm.Sprint` to print
+
+
+
+## [v0.12.1] - 2020-11-04
+### Bug Fixes
+- **panel:** Fix output when input is colored
+
+### Performance Improvements
+- **header:** calculate margin faster
+
+
+
+## [v0.12.0] - 2020-11-04
+### Features
+- **panel:** add an option to make a padding beneath `panel`
+- **panel:** add an option to make columns the same length
+
+### Bug Fixes
+- **panel:** add invalid check for `padding` in `panel`
+
+### Test
+- **bulletlist:** `BulletListItem` remove `Render` and `Srender`
+- **bulletlist:** change `BulletList` to `BulletListPrinter`
+- **panel:** add invalid check for `padding` in `panel`
+- **panel:** add test for `WithBottomPadding`
+- **panel:** add test for `WithSameColumnWidth` & multiple `panel`
+- **panel:** add test for `WithSameColumnWidth`
+- **progressbar:** change `Progressbar` to `ProgressbarPrinter`
+- **progressbar:** change directory name `progressbar_test` to `progressbar_printer_test`
+- **spinner:** change directory name `spinner_test` to `spinner_printer_test`
+- **spinner:** change `Spinner` to `SpinnerPrinter`
+- **table:** change `Table` to `TablePrinter`
+- **tree:** change `Tree` to `TreePrinter`
+
+### Code Refactoring
+- make all printer names end with `Printer` ([#134](https://github.com/pterm/pterm/issues/134))
+- **bulletlist:** remove `DefaultBulletListItem`
+- **bulletlist:** `BulletListItem` remove `Render` and `Srender`
+- **bulletlist:** `BulletListItem` is no renderable anymore
+- **bulletlist:** change `BulletList` to `BulletListPrinter`
+- **progressbar:** change `ActiveProgressbars` to `ActiveProgressbarPrinters`
+- **progressbar:** change directory name `progressbar` to `progressbar_printer`
+- **progressbar:** change `Progressbar` to `ProgressbarPrinter`
+- **spinner:** change `Spinner` to `SpinnerPrinter`
+- **spinner:** change directory name `spinner` to `spinner_printer`
+- **table:** change `Table` to `TablePrinter`
+- **tree:** change `Tree` to `TreePrinter`
+
+### BREAKING CHANGE
+
+Removed `DefaultBulletListItem`.
+
+Change names of printers which didn't end with `Printer`. Every printer name ends with `Printer` now to fit into the new naming convention.
+
+change `ActiveProgressbars` to `ActiveProgressbarPrinters`
+
+`BulletListItem` is no renderable anymore, removed `Render` and `Srender`
+
+`BulletListItem` is no renderable anymore, removed `Render` and `Srender`
+
+`BulletListItem` is no renderable anymore
+
+change `Tree` to `TreePrinter` to unify the naming scheme
+
+change `Tree` to `TreePrinter` to unify the naming scheme
+
+change `Table` to `TablePrinter` to unify the naming scheme
+
+change `Table` to `TablePrinter` to unify the naming scheme
+
+change `Spinner` to `SpinnerPrinter` to unify the naming scheme
+
+change `Spinner` to `SpinnerPrinter` to unify the naming scheme
+
+change `Progressbar` to `ProgressbarPrinter` to unify the naming scheme
+
+change `Progressbar` to `ProgressbarPrinter` to unify the naming scheme
+
+change `BulletList` to `BulletListPrinter` to unify the naming scheme
+
+change `BulletList` to `BulletListPrinter` to unify the naming scheme
+
+
+
+## [v0.11.0] - 2020-11-03
+### Features
+- add `PanelPrinter`
+
+### Bug Fixes
+- **centerprinter:** make centerprinter func return pointer
+
+### BREAKING CHANGE
+
+make centerprinter func `WithCenterEachLineSeparately` return a pointer of centerprinter
+
+
+
+## [v0.10.1] - 2020-11-02
+### Features
+- add `CenterPrinter`
+
+
+
+## [v0.10.0] - 2020-11-01
+### Features
+- make printers return errors
+- add `DisableOutput()` and `EnableOutput()` ([#108](https://github.com/pterm/pterm/issues/108))
+
+### Code Refactoring
+- ignore errors where no errors can occur
+- **theme:** change `ListTextStyle` to `BulletListTextStyle` ([#104](https://github.com/pterm/pterm/issues/104))
+- **theme:** change `ProgressbarBarStyle` to `FgCyan` ([#106](https://github.com/pterm/pterm/issues/106))
+- **theme:** change white to default color in `Theme` ([#103](https://github.com/pterm/pterm/issues/103))
+
+### BREAKING CHANGE
+
+Interface of `RenderablePrinter` and `LivePrinter` changed.
+
+The global variable `DisableOutput` was renamed to `Output`.
+
+
+
+## [v0.9.3] - 2020-10-31
+### Features
+- add a levelList converter for TreeListPrinter
+- add `TreeListPrinter` as a renderable printer
+- add `TreeListPrinter` as a renderable printer
+- **theme:** add theme support for `Tree`
+
+### Test
+- **tree:** add `Tree` tests
+
+### Code Refactoring
+- clean up `Tree`
+- **theme:** change `TreeTextStyle` to `FgDefault`
+- **tree:** add Indent to control the spacing between levels and changed docs(examples)
+- **tree:** add more spacing between levels
+- **tree:** refactor `Tree` code and write tests for `Tree`
+- **tree:** refactor `Tree` code
+- **tree:** refactor `Tree` code
+- **tree:** refactor `Tree` code
+- **tree:** refactor `Tree` code and write tests for `Tree`
+
+
+
+## [v0.9.2] - 2020-10-29
+### Features
+- add option to disable and enable colors
+
+
+
+## [v0.9.1] - 2020-10-27
+### Code Refactoring
+- make the prefix of `Info` smaller again
+
+
+
+## [v0.9.0] - 2020-10-27
+### Features
+- add `Debug` `PrefixPrinter`
+- add support for enabling and disabling debug messages
+
+### Bug Fixes
+- progressbar disappears when done and something is printed after
+
+### Test
+- add debugger tests to `PrefixPrinter`
+- add progressbar tests
+
+### Code Refactoring
+- remove `UpdateDelay` from `Progressbar`
+- change `NewList` to `NewBulletList`
+- change `NewList` to `NewBulletList`
+- deprecate `UpdateDelay` in `Progressbar`
+
+### BREAKING CHANGE
+
+Removed `UpdateDelay` from `Progressbar`. It's no longer used. The Progressbar automatically updates on every change to the current value.
+
+Changed `NewList` to `NewBulletList`.
+
+
+
+## [v0.8.1] - 2020-10-26
+### Features
+- add fade from one RGB over several RGBs to another RGB
+
+### Code Refactoring
+- refactor doc
+- refactor code
+
+
+
+## [v0.8.0] - 2020-10-24
+### Features
+- add `BigTextPrinter` ([#75](https://github.com/pterm/pterm/issues/75))
+- use level of section printer
+- add `BulletListPrinter` ([#67](https://github.com/pterm/pterm/issues/67))
+
+### Test
+- test that `%s` won't fail to print
+
+### Code Refactoring
+- make `BigTextPrinter` release ready
+- change `LineCharacter` to `BarCharacter` ([#70](https://github.com/pterm/pterm/issues/70))
+
+### BREAKING CHANGE
+
+Changed `LineCharacter` to `BarCharacter`.
+
+
+
+## [v0.7.0] - 2020-10-20
+### Features
+- **progressbar:** add RemoveWhenDone
+
+### Bug Fixes
+- make theme accept pointer styles
+- make Spinner accept pointer Style
+- make WithMessageStyle accept Style pointer
+- add nil check to SectionPrinter Style
+- section printer Style to pointer
+
+### Test
+- add tests color and style
+- add tests to root print functions
+- add tests to progressbar
+- add tests to terminal
+- add tests to theme
+- fix internal percentage test
+- add tests to Spinner
+- add tests for TablePrinter
+- special tests for special statements
+- complete PrefixPrinter tests
+- add PrefixPrinter tests
+- rename HeaderPrinter tests
+- complete HeaderPrinter tests
+- add ParagraphPrinter tests
+- add HeaderPrinter tests
+- make unit test system check different types
+- add SectionPrinter tests
+- implement test utils
+- add rgb tests
+
+### Code Refactoring
+- use log output
+- remove obsolete if
+- fit progressbar to new percentage calculation method
+- make fatal panic
+- rename parameters
+- don't show empty line when removing a progressbar
+
+
+
+## [v0.6.1] - 2020-10-20
+### Bug Fixes
+- fix RGB methods
+
+
+
+## [v0.6.0] - 2020-10-19
+### Features
+- add BasicTextPrinter
+- add theme support to section and table printer
+- add theme support to spinner
+- add theme support to headers
+- add template support for progressbars
+- add default theme
+
+### Test
+- **benchmark:** fix spinner benchmark
+
+### Code Refactoring
+- make printers accept pointers to styles
+- remove emojis to comply with cross-platform policy
+- change LivePrinter interface to pointer output
+- change TextPrinter interface to pointer output
+
+### BREAKING CHANGE
+
+All printers only accept pointers as any `Style` attribute.
+
+LivePrinter now requires to return a pointer.
+
+TextPrinter now requires to return a pointer.
+
+
+
+## [v0.5.1] - 2020-10-14
+### Features
+- add ability to disable output ([#44](https://github.com/pterm/pterm/issues/44))
+- add `Srender` to `RenderPrinter` interface
+- add csv table support ([#42](https://github.com/pterm/pterm/issues/42))
+- add HEX to RGB converter in `RGB` ([#41](https://github.com/pterm/pterm/issues/41))
+- add theme to generated animations
+- add color fade example ([#38](https://github.com/pterm/pterm/issues/38))
+- implement `TextPrinter` into `RGB`
+- implement color fade to `Progressbar` ([#37](https://github.com/pterm/pterm/issues/37))
+- add color fade function and `RBG` ([#34](https://github.com/pterm/pterm/issues/34))
+- change `Section` style
+
+### Code Refactoring
+- declare function name as `WithCSVReader`
+
+
+
+## [v0.5.0] - 2020-10-08
+### Features
+- implement `LivePrinter` in `Spinner`
+- add `BottomPadding` to `SectionPrinter`
+- add `RenderPrinter` interface
+- implement `LivePrinter` in `Progressbar`
+- add `LivePrinter` interface
+- add `TablePrinter` ([#27](https://github.com/pterm/pterm/issues/27))
+- add `ParagraphPrinter` ([#24](https://github.com/pterm/pterm/issues/24))
+
+### Test
+- add `Print` equals `Sprint` tests for `GenericPrinter`
+- add `Spinner` benchmarks
+
+### Code Refactoring
+- rename spinner_printer.go to spinner.go
+- rename `GenericPrinter` to `TextPrinter`
+
+### BREAKING CHANGE
+
+The `GenericPrinter` is now called `TextPrinter`.
+
+
+
+## [v0.4.1] - 2020-10-07
+
+
+## [v0.4.0] - 2020-10-07
+### Features
+- add `Add` to `Style`
+- add options shorthands to `SectionPrinter`
+
+### Test
+- ignore writer close errors in stdout capture
+
+### Code Refactoring
+- use `Style` instead of colors
+- refactor function parameters to fit expectation
+- rename `RemoveColors` to `RemoveColorFromString`
+
+### BREAKING CHANGE
+
+use `Style` instead of colors
+
+Refactor function parameters to fit expectation.
+Affects: `WithStyle(colors -> style)`, `WithScope(string, colors -> scope)`
+
+rename `RemoveColors` to `RemoveColorFromString`
+
+
+
+## [v0.3.2] - 2020-10-06
+### Features
+- add `SectionPrinter`
+
+### Bug Fixes
+- fix `Sprintf` function of `HeaderPrinter`
+
+### Test
+- add tests for `HeaderPrinter` and `SectionPrinter`
+
+
+
+## [v0.3.1] - 2020-10-06
+### Features
+- add `BarFiller` to `Progressbar`
+
+### Test
+- fix import cycle
+- change to inbuilt `SetDefaultOutput` option
+- add more benchmarks
+- add benchmarks
+- add tests to `GenericPrinter` and default print methods
+
+### Code Refactoring
+- set default `BarFiller` to space
+- move tests directly into `pterm` module
+
+
+
+## [v0.3.0] - 2020-10-05
+### Bug Fixes
+- fix `WithXYZ(b ...bool)` to detect booleans correctly
+
+### Code Refactoring
+- remove `Version` constant
+- change `WithXXX(b bool)` to `WithXXX(b ...bool)`
+- change `SetXXX` to `WithXXX`
+- change `Header` to `DefaultHeader`
+
+### BREAKING CHANGE
+
+remove `Version` constant
+
+rename `SetXXX` to `WithXXX`
+
+rename `Header` to `DefaultHeader`
+
+
+
+## [v0.2.4] - 2020-10-04
+### Bug Fixes
+- `Printf` works again
+
+
+
+## [v0.2.3] - 2020-10-04
+### Features
+- automatically print above `Progressbar`
+
+### Code Refactoring
+- remove goroutine from `Progressbar`
+
+
+
+## [v0.2.2] - 2020-10-04
+### Features
+- add `Fatal` printer
+
+
+
+## [v0.2.1] - 2020-10-04
+### Features
+- make progressbar configurable
+- add percentage helper
+- add `RemoveColors`
+- add `Progressbar` ([#5](https://github.com/pterm/pterm/issues/5))
+- add `Progressbar`
+- add fatal to `PrefixPrinter` ([#4](https://github.com/pterm/pterm/issues/4))
+- **progressbar:** fade percentage color according to value
+
+### Code Refactoring
+- bump version to "v0.2.1"
+
+
+
+## [v0.2.0] - 2020-09-30
+### Features
+- change style of `Description` printer
+- add color in color support
+- add `RemoveWhenDone` to `Spinner`
+- add multiline support to `PrefixPrinter`
+- add `UpdateText` to spinner
+
+### Bug Fixes
+- spinners spin evenly when multiple spinners are started
+
+### Performance Improvements
+- improve spinner performance
+
+### Code Refactoring
+- bump version to "v0.2.0"
+- change `WithXXX` to `SetXXX`
+- removed `Println` aliases
+
+### BREAKING CHANGE
+
+every `WithXXX` is renamed to `SetXXX`
+
+remove `GetFormattedMessage` from `PrefixPrinter`
+
+removed `Println` aliases
+
+
+
+## [v0.1.0] - 2020-09-28
+### Features
+- add spinners
+- shorten printer names and add builder methods to printers
+- add `Printo` to override printed text
+- add `FullWidth` to `HeaderPrinter`
+- add terminal size detection
+
+### Code Refactoring
+- bump version to "v0.1.0"
+- consistent example code for `Printo`
+- better comments for `Printo`
+- simplify `HeaderPrinter`
+
+### BREAKING CHANGE
+
+printer names changed
+
+removed `Header` and put it's content directly into `HeaderPrinter`
+
+
+
+## [v0.0.1] - 2020-09-21
+### Features
+- add aliases to default printers
+- add header example
+- integrate ci
+- add `HeaderPrinter`
+- add exported version variable
+- add example `override-default-printer`
+- change prefix text color to `LightWhite`
+
+### Bug Fixes
+- header should now work in CI
+
+### Code Refactoring
+- bump version to "v0.0.1"
+- refactor project
+- add comments to functions
+
+
+
+## v0.0.0 - 2020-09-18
+### Features
+- add changelog template
+- configs
+- initial commit
+
+
+[Unreleased]: https://github.com/pterm/pterm/compare/v0.12.34...HEAD
+[v0.12.34]: https://github.com/pterm/pterm/compare/v0.12.33...v0.12.34
+[v0.12.33]: https://github.com/pterm/pterm/compare/v0.12.32...v0.12.33
+[v0.12.32]: https://github.com/pterm/pterm/compare/v0.12.31...v0.12.32
+[v0.12.31]: https://github.com/pterm/pterm/compare/v0.12.30...v0.12.31
+[v0.12.30]: https://github.com/pterm/pterm/compare/v0.12.29...v0.12.30
+[v0.12.29]: https://github.com/pterm/pterm/compare/v0.12.28...v0.12.29
+[v0.12.28]: https://github.com/pterm/pterm/compare/v0.12.27...v0.12.28
+[v0.12.27]: https://github.com/pterm/pterm/compare/v0.12.26...v0.12.27
+[v0.12.26]: https://github.com/pterm/pterm/compare/v0.12.25...v0.12.26
+[v0.12.25]: https://github.com/pterm/pterm/compare/v0.12.24...v0.12.25
+[v0.12.24]: https://github.com/pterm/pterm/compare/v0.12.23...v0.12.24
+[v0.12.23]: https://github.com/pterm/pterm/compare/v0.12.22...v0.12.23
+[v0.12.22]: https://github.com/pterm/pterm/compare/v0.12.21...v0.12.22
+[v0.12.21]: https://github.com/pterm/pterm/compare/v0.12.20...v0.12.21
+[v0.12.20]: https://github.com/pterm/pterm/compare/v0.12.19...v0.12.20
+[v0.12.19]: https://github.com/pterm/pterm/compare/v0.12.18...v0.12.19
+[v0.12.18]: https://github.com/pterm/pterm/compare/v0.12.17...v0.12.18
+[v0.12.17]: https://github.com/pterm/pterm/compare/v0.12.16...v0.12.17
+[v0.12.16]: https://github.com/pterm/pterm/compare/v0.12.15...v0.12.16
+[v0.12.15]: https://github.com/pterm/pterm/compare/v0.12.14...v0.12.15
+[v0.12.14]: https://github.com/pterm/pterm/compare/v0.12.13...v0.12.14
+[v0.12.13]: https://github.com/pterm/pterm/compare/v0.12.12...v0.12.13
+[v0.12.12]: https://github.com/pterm/pterm/compare/v0.12.11...v0.12.12
+[v0.12.11]: https://github.com/pterm/pterm/compare/v0.12.10...v0.12.11
+[v0.12.10]: https://github.com/pterm/pterm/compare/v0.12.9...v0.12.10
+[v0.12.9]: https://github.com/pterm/pterm/compare/v0.12.8...v0.12.9
+[v0.12.8]: https://github.com/pterm/pterm/compare/v0.12.7...v0.12.8
+[v0.12.7]: https://github.com/pterm/pterm/compare/v0.12.6...v0.12.7
+[v0.12.6]: https://github.com/pterm/pterm/compare/v0.12.5...v0.12.6
+[v0.12.5]: https://github.com/pterm/pterm/compare/v0.12.4...v0.12.5
+[v0.12.4]: https://github.com/pterm/pterm/compare/v0.12.3...v0.12.4
+[v0.12.3]: https://github.com/pterm/pterm/compare/v0.12.2...v0.12.3
+[v0.12.2]: https://github.com/pterm/pterm/compare/v0.12.1...v0.12.2
+[v0.12.1]: https://github.com/pterm/pterm/compare/v0.12.0...v0.12.1
+[v0.12.0]: https://github.com/pterm/pterm/compare/v0.11.0...v0.12.0
+[v0.11.0]: https://github.com/pterm/pterm/compare/v0.10.1...v0.11.0
+[v0.10.1]: https://github.com/pterm/pterm/compare/v0.10.0...v0.10.1
+[v0.10.0]: https://github.com/pterm/pterm/compare/v0.9.3...v0.10.0
+[v0.9.3]: https://github.com/pterm/pterm/compare/v0.9.2...v0.9.3
+[v0.9.2]: https://github.com/pterm/pterm/compare/v0.9.1...v0.9.2
+[v0.9.1]: https://github.com/pterm/pterm/compare/v0.9.0...v0.9.1
+[v0.9.0]: https://github.com/pterm/pterm/compare/v0.8.1...v0.9.0
+[v0.8.1]: https://github.com/pterm/pterm/compare/v0.8.0...v0.8.1
+[v0.8.0]: https://github.com/pterm/pterm/compare/v0.7.0...v0.8.0
+[v0.7.0]: https://github.com/pterm/pterm/compare/v0.6.1...v0.7.0
+[v0.6.1]: https://github.com/pterm/pterm/compare/v0.6.0...v0.6.1
+[v0.6.0]: https://github.com/pterm/pterm/compare/v0.5.1...v0.6.0
+[v0.5.1]: https://github.com/pterm/pterm/compare/v0.5.0...v0.5.1
+[v0.5.0]: https://github.com/pterm/pterm/compare/v0.4.1...v0.5.0
+[v0.4.1]: https://github.com/pterm/pterm/compare/v0.4.0...v0.4.1
+[v0.4.0]: https://github.com/pterm/pterm/compare/v0.3.2...v0.4.0
+[v0.3.2]: https://github.com/pterm/pterm/compare/v0.3.1...v0.3.2
+[v0.3.1]: https://github.com/pterm/pterm/compare/v0.3.0...v0.3.1
+[v0.3.0]: https://github.com/pterm/pterm/compare/v0.2.4...v0.3.0
+[v0.2.4]: https://github.com/pterm/pterm/compare/v0.2.3...v0.2.4
+[v0.2.3]: https://github.com/pterm/pterm/compare/v0.2.2...v0.2.3
+[v0.2.2]: https://github.com/pterm/pterm/compare/v0.2.1...v0.2.2
+[v0.2.1]: https://github.com/pterm/pterm/compare/v0.2.0...v0.2.1
+[v0.2.0]: https://github.com/pterm/pterm/compare/v0.1.0...v0.2.0
+[v0.1.0]: https://github.com/pterm/pterm/compare/v0.0.1...v0.1.0
+[v0.0.1]: https://github.com/pterm/pterm/compare/v0.0.0...v0.0.1
diff --git a/vendor/github.com/pterm/pterm/CODE_OF_CONDUCT.md b/vendor/github.com/pterm/pterm/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..066ceae
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/CODE_OF_CONDUCT.md
@@ -0,0 +1,76 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, sex characteristics, gender identity and expression,
+level of experience, education, socio-economic status, nationality, personal
+appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at pterm@marvinjwendt.com. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see
+https://www.contributor-covenant.org/faq
diff --git a/vendor/github.com/pterm/pterm/CONTRIBUTING.md b/vendor/github.com/pterm/pterm/CONTRIBUTING.md
new file mode 100644
index 0000000..73d392d
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/CONTRIBUTING.md
@@ -0,0 +1,217 @@
+# Contributing to PTerm
+
+> This document explains how to participate in the development of PTerm.\
+If your goal is to report a bug instead of programming PTerm, you can do so [here](https://github.com/pterm/pterm/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
+
+## Creating a new printer
+
+> In this chapter we will show you how to create a new printer.
+
+### `TextPrinter` Template
+```go
+package pterm
+
+type TemplatePrinter struct{
+ // TODO: Add printer settings here
+}
+
+// Sprint formats using the default formats for its operands and returns the resulting string.
+// Spaces are added between operands when neither is a string.
+func (p TemplatePrinter) Sprint(a ...interface{}) string {
+ panic("write printer code here")
+}
+
+// Sprintln formats using the default formats for its operands and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func (p TemplatePrinter) Sprintln(a ...interface{}) string {
+ return Sprintln(p.Sprint(a...))
+}
+
+// Sprintf formats according to a format specifier and returns the resulting string.
+func (p TemplatePrinter) Sprintf(format string, a ...interface{}) string {
+ return p.Sprint(Sprintf(format, a...))
+}
+
+// Print formats using the default formats for its operands and writes to standard output.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+func (p TemplatePrinter) Print(a ...interface{}) *TextPrinter {
+ Print(p.Sprint(a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Println formats using the default formats for its operands and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func (p TemplatePrinter) Println(a ...interface{}) *TextPrinter {
+ Println(p.Sprint(a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
+func (p TemplatePrinter) Printf(format string, a ...interface{}) *TextPrinter {
+ Print(p.Sprintf(format, a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+```
+
+### `RenderablePrinter` Template
+
+```go
+package pterm
+
+type TemplatePrinter struct{
+ // TODO: Add printer settings here
+}
+
+// Srender renders the Template as a string.
+func (p TemplatePrinter) Srender() (string, error) {
+ var ret string
+
+ return ret, nil
+}
+
+// Render prints the Template to the terminal.
+func (p TemplatePrinter) Render() error {
+ s, err := p.Srender()
+ if err != nil {
+ return err
+ }
+ Println(s)
+
+ return nil
+}
+```
+
+### `LivePrinter` Template
+
+```go
+// Start the TemplatePrinter.
+package pterm
+import "github.com/pterm/pterm"
+
+type TemplatePrinter struct{
+
+}
+
+
+func (s TemplatePrinter) Start(text...interface{}) (*TemplatePrinter, error) { // TODO: Replace Template with actual printer.
+ // TODO: start logic
+ return &s, nil
+}
+
+// Stop terminates the TemplatePrinter immediately.
+// The TemplatePrinter will not resolve into anything.
+func (s *TemplatePrinter) Stop() error {
+ // TODO: stop logic
+ return nil
+}
+
+// GenericStart runs Start, but returns a LivePrinter.
+// This is used for the interface LivePrinter.
+// You most likely want to use Start instead of this in your program.
+func (s *TemplatePrinter) GenericStart() (*LivePrinter, error) {
+ _, err := s.Start()
+ lp := LivePrinter(s)
+ return &lp, err
+}
+
+// GenericStop runs Stop, but returns a LivePrinter.
+// This is used for the interface LivePrinter.
+// You most likely want to use Stop instead of this in your program.
+func (s *TemplatePrinter) GenericStop() (*LivePrinter, error) {
+ err := s.Stop()
+ lp := LivePrinter(s)
+ return &lp, err
+}
+```
+
+## Writing Tests
+
+> Each method of PTerm must be tested.
+
+### Required tests for every printer
+
+#### Nil Check
+
+> This ensures that a printer without set values will not produce errors.
+
+```go
+func TestTemplatePrinterNilPrint(t *testing.T) { // TODO: Replace "Template" with actual printer name.
+ p := TemplatePrinter{} // TODO: Replace "Template" with actual printer name.
+ p.Println("Hello, World!")
+}
+```
+
+#### `WithXxx()` Methods
+
+> Each method, which starts with `With` can be tested by checking if it actually creates a new printer and sets the value.
+
+Example from `SectionPrinter`:
+
+```go
+func TestSectionPrinter_WithStyle(t *testing.T) {
+ p := SectionPrinter{}
+ s := NewStyle(FgRed, BgRed, Bold)
+ p2 := p.WithStyle(s)
+
+ assert.Equal(t, s, p2.Style)
+ assert.Empty(t, p.Style)
+}
+
+func TestSectionPrinter_WithTopPadding(t *testing.T) {
+ p := SectionPrinter{}
+ p2 := p.WithTopPadding(1337)
+
+ assert.Equal(t, 1337, p2.TopPadding)
+ assert.Empty(t, p.TopPadding)
+}
+```
+
+### `TextPrinter` Tests Template
+
+```go
+func TestTemplatePrinterPrintMethods(t *testing.T) { // TODO: Replace "Template" with actual printer name.
+ p := DefaultTemplate // TODO: Replace "Template" with actual printer name.
+
+ t.Run("Print", func(t *testing.T) {
+ testPrintContains(t, func(w io.Writer, a interface{}) {
+ p.Print(a)
+ })
+ })
+
+ t.Run("Printf", func(t *testing.T) {
+ testPrintfContains(t, func(w io.Writer, format string, a interface{}) {
+ p.Printf(format, a)
+ })
+ })
+
+ t.Run("Println", func(t *testing.T) {
+ testPrintlnContains(t, func(w io.Writer, a interface{}) {
+ p.Println(a)
+ })
+ })
+
+ t.Run("Sprint", func(t *testing.T) {
+ testSprintContains(t, func(a interface{}) string {
+ return p.Sprint(a)
+ })
+ })
+
+ t.Run("Sprintf", func(t *testing.T) {
+ testSprintfContains(t, func(format string, a interface{}) string {
+ return p.Sprintf(format, a)
+ })
+ })
+
+ t.Run("Sprintln", func(t *testing.T) {
+ testSprintlnContains(t, func(a interface{}) string {
+ return p.Sprintln(a)
+ })
+ })
+}
+```
diff --git a/vendor/github.com/pterm/pterm/LICENSE b/vendor/github.com/pterm/pterm/LICENSE
new file mode 100644
index 0000000..63f8a64
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 pterm
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/pterm/pterm/README.md b/vendor/github.com/pterm/pterm/README.md
new file mode 100644
index 0000000..b0b4922
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/README.md
@@ -0,0 +1,1827 @@
+
+
+💻 PTerm | Pretty Terminal Printer
+A golang module to print pretty text
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Show Demo Code
+
+
+
+
+
+
+---
+
+
+PTerm.sh
+|
+Installation
+|
+Quick Start
+|
+Documentation
+|
+Examples
+|
+Q&A
+
+
+---
+
+## 📦 Installation
+
+To make PTerm available in your project, you can run the following command.\
+Make sure to run this command inside your project, when you're using go modules 😉
+
+```sh
+go get github.com/pterm/pterm
+```
+
+If you want to create a CLI tool, make sure to check out our [cli-template](https://github.com/pterm/cli-template),
+which features automatic website generation, automatic deployments, a custom CI-System and much more!
+
+## 🥅 Goal of PTerm
+
+PTerm is designed to create a **platform independent way to create beautiful terminal output**. Most modules that want to improve the terminal output do not guarantee platform independence - PTerm does. PTerm follows the **most common methods for displaying color in a terminal**. With PTerm, it is possible to create beautiful output **even in low-level environments**.
+
+### • 🪀 Easy to use
+
+Our first priority is to keep PTerm as easy to use as possible. With many [examples](#-examples) for each individual component, getting started with PTerm is extremely easy. All components are similar in design and implement interfaces to simplify mixing individual components together.
+
+### • 🤹♀️ Cross-Platform
+
+We take special precautions to ensure that PTerm works on as many operating systems and terminals as possible. Whether it's `Windows CMD`, `macOS iTerm2` or in the backend (for example inside a `GitHub Action` or other CI systems), PTerm **guarantees** beautiful output!\
+\
+*PTerm is actively tested on `Windows`, `Linux (Debian & Ubuntu)` and `macOS`.*
+
+### • ⭐ Main Features
+
+|Feature|Example|Docs|-|Feature|Example|Docs
+|---|---|---|---|---|---|---|
+|Bar Charts|[Example](#barchart)|[Docs](https://pterm.sh/#/docs/printer/barchart)|-|RGB|[Example](#print-color-rgb)|[Docs](https://pterm.sh/#/docs/printer/rgb)|
+|BigText|[Example](#bigtext)|[Docs](https://pterm.sh/#/docs/printer/bigtext)|-|Sections|[Example](#section)|[Docs](https://pterm.sh/#/docs/printer/section)|
+|Boxed|[Example](#box)|[Docs](https://pterm.sh/#/docs/printer/box)|-|Spinners|[Example](#spinner)|[Docs](https://pterm.sh/#/docs/printer/spinner)|
+|Bullet Lists|[Example](#bulletlist)|[Docs](https://pterm.sh/#/docs/printer/bulletlist)|-|Trees|[Example](#tree)|[Docs](https://pterm.sh/#/docs/printer/tree)|
+|Centered|[Example](#center)|[Docs](https://pterm.sh/#/docs/printer/center)|-|Theming|[Example](#theme)|[Docs](https://pterm.sh/#/docs/customizing/theming)|
+|Colors|[Example](#print-with-color)|[Docs](https://pterm.sh/#/docs/printer/color)|-|Tables|[Example](#table)|[Docs](https://pterm.sh/#/docs/printer/table)|
+|Headers|[Example](#header)|[Docs](https://pterm.sh/#/docs/printer/header)|-|Styles|[Example](#style)|[Docs](https://pterm.sh/#/docs/printer/style)|
+|Panels|[Example](#panel)|[Docs](https://pterm.sh/#/docs/printer/panel)|-|Area|[Example](#area)|[Docs](https://pterm.sh/#/docs/printer/area)|
+|Paragraphs|[Example](#paragraph)|[Docs](https://pterm.sh/#/docs/printer/paragraph)|-|||
+|Prefixes|[Example](#prefix)|[Docs](https://pterm.sh/#/docs/printer/prefix)|-|||
+|Progress Bars|[Example](#progressbar)|[Docs](https://pterm.sh/#/docs/printer/progressbar)|-|||
+
+### • 🧪 Well tested
+
+> PTerm has a 100% test coverage, which means that every line of code inside PTerm gets tested automatically
+
+We test PTerm continuously. However, since a human cannot test everything all the time, we have our own test system with which we currently run **`28740`**
+automated tests to ensure that PTerm has no bugs.
+
+### • ✨ Consistent Colors
+
+PTerm uses the [ANSI color scheme](https://en.wikipedia.org/wiki/ANSI_escape_code#3/4_bit) which is widely used by terminals to ensure consistent colors in different terminal themes.
+If that's not enough, PTerm can be used to access the full RGB color scheme (16 million colors) in terminals that support `TrueColor`.
+
+![ANSI Colors](https://user-images.githubusercontent.com/31022056/96002009-f10c3a80-0e38-11eb-8d90-f3150150599c.png)
+
+### • 📚 Component system
+
+PTerm consists of many components, called `Printers`, which can be used individually or together to generate pretty console output.
+
+### • 🛠 Configurable
+
+PTerm can be used by without any configuration. However, you can easily configure each component with little code, so everyone has the freedom to design their own terminal output.
+
+## ✏ Documentation
+
+To view the official documentation of the latest release, you can go to the automatically generated page of [pkg.go.dev](https://pkg.go.dev/github.com/pterm/pterm#section-documentation) This documentation is very technical and includes every method that can be used in PTerm.
+
+**For an easy start we recommend that you take a look at the [examples section](#-examples).** Here you can see pretty much every feature of PTerm with its source code. The animations of the examples are automatically updated as soon as something changes in PTerm.
+
+Have fun exploring this project 🚀
+
+## 💖 Contributing
+
+If you have found a bug or want to suggest a feature, you can do so [here](https://github.com/pterm/pterm/issues) by opening a new issue.
+
+If you want to contribute to the development of PTerm, you are very welcome to do so. Our contribution guidelines can be found [here](CONTRIBUTING.md).
+
+## 💕 Support
+
+
+If you want to support me in further developing my open source projects, you can give me a little tip 😄
+
+Your financial support enables me to focus more on my projects. Thank you very much!
+
+
+
+
+
+
+### 🦸♂️ Supporters
+
+|-|User|💸|
+|---|---|---|
+|![Jens Lauterbach](https://avatars.githubusercontent.com/u/1292368?s=25)|[@jenslauterbach](https://github.com/jenslauterbach)|25$|
+
+## 🧪 Examples
+
+You can find all the examples, with their source code, here: [`./_examples`](./_examples)
+
+
+### area
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/area/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "time"
+
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ pterm.Info.Println("The previous text will stay in place, while the area updates.")
+ pterm.Print("\n\n") // Add two new lines as spacer.
+
+ area, _ := pterm.DefaultArea.WithCenter().Start() // Start the Area printer, with the Center option.
+ for i := 0; i < 10; i++ {
+ str, _ := pterm.DefaultBigText.WithLetters(pterm.NewLettersFromString(time.Now().Format("15:04:05"))).Srender() // Save current time in str.
+ area.Update(str) // Update Area contents.
+ time.Sleep(time.Second)
+ }
+ area.Stop()
+}
+
+```
+
+
+
+### barchart
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/barchart/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ positiveBars := pterm.Bars{
+ pterm.Bar{
+ Label: "Bar 1",
+ Value: 5,
+ },
+ pterm.Bar{
+ Label: "Bar 2",
+ Value: 3,
+ },
+ pterm.Bar{
+ Label: "Longer Label",
+ Value: 7,
+ },
+ }
+
+ pterm.Info.Println("Chart example with positive only values (bars use 100% of chart area)")
+ _ = pterm.DefaultBarChart.WithBars(positiveBars).Render()
+ _ = pterm.DefaultBarChart.WithHorizontal().WithBars(positiveBars).Render()
+}
+
+```
+
+
+
+### barchart-mixed-values
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/barchart-mixed-values/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ mixedBars := pterm.Bars{
+ pterm.Bar{
+ Label: "Bar 1",
+ Value: 2,
+ },
+ pterm.Bar{
+ Label: "Bar 2",
+ Value: -3,
+ },
+ pterm.Bar{
+ Label: "Bar 3",
+ Value: -2,
+ },
+ pterm.Bar{
+ Label: "Bar 4",
+ Value: 5,
+ },
+ pterm.Bar{
+ Label: "Longer Label",
+ Value: 7,
+ },
+ }
+
+ pterm.DefaultSection.Println("Chart example with mixed values (note screen space usage in case when ABSOLUTE values of negative and positive parts are differ too much)")
+ _ = pterm.DefaultBarChart.WithBars(mixedBars).WithShowValue().Render()
+ _ = pterm.DefaultBarChart.WithHorizontal().WithBars(mixedBars).WithShowValue().Render()
+}
+
+```
+
+
+
+### barchart-negative-values
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/barchart-negative-values/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ negativeBars := pterm.Bars{
+ pterm.Bar{
+ Label: "Bar 1",
+ Value: -5,
+ },
+ pterm.Bar{
+ Label: "Bar 2",
+ Value: -3,
+ },
+ pterm.Bar{
+ Label: "Longer Label",
+ Value: -7,
+ },
+ }
+
+ pterm.Info.Println("Chart example with negative only values (bars use 100% of chart area)")
+ _ = pterm.DefaultBarChart.WithBars(negativeBars).WithShowValue().Render()
+ _ = pterm.DefaultBarChart.WithHorizontal().WithBars(negativeBars).WithShowValue().Render()
+}
+
+```
+
+
+
+### bigtext
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/bigtext/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Print a large text with the LetterStyle from the standard theme.
+ // Useful for title screens.
+ pterm.DefaultBigText.WithLetters(pterm.NewLettersFromString("PTerm")).Render()
+
+ // Print a large text with differently colored letters.
+ pterm.DefaultBigText.WithLetters(
+ pterm.NewLettersFromStringWithStyle("P", pterm.NewStyle(pterm.FgCyan)),
+ pterm.NewLettersFromStringWithStyle("Term", pterm.NewStyle(pterm.FgLightMagenta))).
+ Render()
+}
+
+```
+
+
+
+### box
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/box/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ pterm.Info.Println("This might not be rendered correctly on GitHub,\nbut it will work in a real terminal.\nThis is because GitHub does not use a monospaced font by default for SVGs.")
+
+ panel1 := pterm.DefaultBox.Sprint("Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit,\nsed do eiusmod tempor incididunt\nut labore et dolore\nmagna aliqua.")
+ panel2 := pterm.DefaultBox.WithTitle("title").Sprint("Ut enim ad minim veniam,\nquis nostrud exercitation\nullamco laboris\nnisi ut aliquip\nex ea commodo\nconsequat.")
+ panel3 := pterm.DefaultBox.WithTitle("bottom center title").WithTitleBottomCenter().Sprint("Duis aute irure\ndolor in reprehenderit\nin voluptate velit esse cillum\ndolore eu fugiat\nnulla pariatur.")
+
+ panels, _ := pterm.DefaultPanel.WithPanels(pterm.Panels{
+ {{Data: panel1}, {Data: panel2}},
+ {{Data: panel3}},
+ }).Srender()
+
+ pterm.DefaultBox.WithTitle("Lorem Ipsum").WithTitleBottomRight().WithRightPadding(0).WithBottomPadding(0).Println(panels)
+}
+
+```
+
+
+
+### bulletlist
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/bulletlist/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Print a list with different levels.
+ // Useful to generate lists automatically from data.
+ pterm.DefaultBulletList.WithItems([]pterm.BulletListItem{
+ {Level: 0, Text: "Level 0"},
+ {Level: 1, Text: "Level 1"},
+ {Level: 2, Text: "Level 2"},
+ }).Render()
+
+ // Convert a text to a list and print it.
+ pterm.NewBulletListFromString(`0
+ 1
+ 2
+ 3`, " ").Render()
+}
+
+```
+
+
+
+### bulletlist-custom
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/bulletlist-custom/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Print a customized list with different styles and levels.
+ pterm.DefaultBulletList.WithItems([]pterm.BulletListItem{
+ {Level: 0, Text: "Blue", TextStyle: pterm.NewStyle(pterm.FgBlue), BulletStyle: pterm.NewStyle(pterm.FgRed)},
+ {Level: 1, Text: "Green", TextStyle: pterm.NewStyle(pterm.FgGreen), Bullet: "-", BulletStyle: pterm.NewStyle(pterm.FgLightWhite)},
+ {Level: 2, Text: "Cyan", TextStyle: pterm.NewStyle(pterm.FgCyan), Bullet: ">", BulletStyle: pterm.NewStyle(pterm.FgYellow)},
+ }).Render()
+}
+
+```
+
+
+
+### center
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/center/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ pterm.DefaultCenter.Println("This text is centered!\nIt centeres the whole block by default.\nIn that way you can do stuff like this:")
+
+ // Generate BigLetters
+ s, _ := pterm.DefaultBigText.WithLetters(pterm.NewLettersFromString("PTerm")).Srender()
+ pterm.DefaultCenter.Println(s) // Print BigLetters with the default CenterPrinter
+
+ pterm.DefaultCenter.WithCenterEachLineSeparately().Println("This text is centered!\nBut each line is\ncentered\nseparately")
+}
+
+```
+
+
+
+### demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "math/rand"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/pterm/pterm"
+)
+
+// Change this to time.Millisecond*200 to speed up the demo.
+// Useful when debugging.
+const second = time.Second
+
+var pseudoProgramList = strings.Split("pseudo-excel pseudo-photoshop pseudo-chrome pseudo-outlook pseudo-explorer "+
+ "pseudo-dops pseudo-git pseudo-vsc pseudo-intellij pseudo-minecraft pseudo-scoop pseudo-chocolatey", " ")
+
+func main() {
+ introScreen()
+ clear()
+ pseudoApplicationHeader()
+ time.Sleep(second)
+ installingPseudoList()
+ time.Sleep(second * 2)
+ pterm.DefaultSection.WithLevel(2).Println("Program Install Report")
+ installedProgramsSize()
+ time.Sleep(second * 4)
+ pterm.DefaultSection.Println("Tree Printer")
+ installedTree()
+ time.Sleep(second * 4)
+ pterm.DefaultSection.Println("TrueColor Support")
+ fadeText()
+ time.Sleep(second)
+ pterm.DefaultSection.Println("Bullet List Printer")
+ listPrinter()
+}
+
+func installedTree() {
+ leveledList := pterm.LeveledList{
+ pterm.LeveledListItem{Level: 0, Text: "C:"},
+ pterm.LeveledListItem{Level: 1, Text: "Go"},
+ pterm.LeveledListItem{Level: 1, Text: "Windows"},
+ pterm.LeveledListItem{Level: 1, Text: "Programs"},
+ }
+ for _, s := range pseudoProgramList {
+ if s != "pseudo-minecraft" {
+ leveledList = append(leveledList, pterm.LeveledListItem{Level: 2, Text: s})
+ }
+ if s == "pseudo-chrome" {
+ leveledList = append(leveledList, pterm.LeveledListItem{Level: 3, Text: "pseudo-Tabs"})
+ leveledList = append(leveledList, pterm.LeveledListItem{Level: 3, Text: "pseudo-Extensions"})
+ leveledList = append(leveledList, pterm.LeveledListItem{Level: 4, Text: "Refined GitHub"})
+ leveledList = append(leveledList, pterm.LeveledListItem{Level: 4, Text: "GitHub Dark Theme"})
+ leveledList = append(leveledList, pterm.LeveledListItem{Level: 3, Text: "pseudo-Bookmarks"})
+ leveledList = append(leveledList, pterm.LeveledListItem{Level: 4, Text: "PTerm"})
+ }
+ }
+
+ pterm.DefaultTree.WithRoot(pterm.NewTreeFromLeveledList(leveledList)).Render()
+}
+
+func installingPseudoList() {
+ pterm.DefaultSection.Println("Installing pseudo programs")
+
+ p, _ := pterm.DefaultProgressbar.WithTotal(len(pseudoProgramList)).WithTitle("Installing stuff").Start()
+ for i := 0; i < p.Total; i++ {
+ p.UpdateTitle("Installing " + pseudoProgramList[i])
+ if pseudoProgramList[i] == "pseudo-minecraft" {
+ pterm.Warning.Println("Could not install pseudo-minecraft\nThe company policy forbids games.")
+ } else {
+ pterm.Success.Println("Installing " + pseudoProgramList[i])
+ p.Increment()
+ }
+ time.Sleep(second / 2)
+ }
+ p.Stop()
+}
+
+func listPrinter() {
+ pterm.NewBulletListFromString(`Good bye
+ Have a nice day!`, " ").Render()
+}
+
+func fadeText() {
+ from := pterm.NewRGB(0, 255, 255) // This RGB value is used as the gradients start point.
+ to := pterm.NewRGB(255, 0, 255) // This RGB value is used as the gradients first point.
+
+ str := "If your terminal has TrueColor support, you can use RGB colors!\nYou can even fade them :)"
+ strs := strings.Split(str, "")
+ var fadeInfo string // String which will be used to print info.
+ // For loop over the range of the string length.
+ for i := 0; i < len(str); i++ {
+ // Append faded letter to info string.
+ fadeInfo += from.Fade(0, float32(len(str)), float32(i), to).Sprint(strs[i])
+ }
+ pterm.Info.Println(fadeInfo)
+}
+
+func installedProgramsSize() {
+ d := pterm.TableData{{"Program Name", "Status", "Size"}}
+ for _, s := range pseudoProgramList {
+ if s != "pseudo-minecraft" {
+ d = append(d, []string{s, pterm.LightGreen("pass"), strconv.Itoa(randomInt(7, 200)) + "mb"})
+ } else {
+ d = append(d, []string{pterm.LightRed(s), pterm.LightRed("fail"), "0mb"})
+ }
+ }
+ pterm.DefaultTable.WithHasHeader().WithData(d).Render()
+}
+
+func pseudoApplicationHeader() *pterm.TextPrinter {
+ return pterm.DefaultHeader.WithBackgroundStyle(pterm.NewStyle(pterm.BgLightBlue)).WithMargin(10).Println(
+ "Pseudo Application created with PTerm")
+}
+
+func introScreen() {
+ ptermLogo, _ := pterm.DefaultBigText.WithLetters(
+ pterm.NewLettersFromStringWithStyle("P", pterm.NewStyle(pterm.FgLightCyan)),
+ pterm.NewLettersFromStringWithStyle("Term", pterm.NewStyle(pterm.FgLightMagenta))).
+ Srender()
+
+ pterm.DefaultCenter.Print(ptermLogo)
+
+ pterm.DefaultCenter.Print(pterm.DefaultHeader.WithFullWidth().WithBackgroundStyle(pterm.NewStyle(pterm.BgLightBlue)).WithMargin(10).Sprint("PTDP - PTerm Demo Program"))
+
+ pterm.Info.Println("This animation was generated with the latest version of PTerm!" +
+ "\nPTerm works on nearly every terminal and operating system." +
+ "\nIt's super easy to use!" +
+ "\nIf you want, you can customize everything :)" +
+ "\nYou can see the code of this demo in the " + pterm.LightMagenta("./_examples/demo") + " directory." +
+ "\n" +
+ "\nThis demo was updated at: " + pterm.Green(time.Now().Format("02 Jan 2006 - 15:04:05 MST")))
+ pterm.Println()
+ introSpinner, _ := pterm.DefaultSpinner.WithShowTimer(false).WithRemoveWhenDone(true).Start("Waiting for 15 seconds...")
+ time.Sleep(second)
+ for i := 14; i > 0; i-- {
+ if i > 1 {
+ introSpinner.UpdateText("Waiting for " + strconv.Itoa(i) + " seconds...")
+ } else {
+ introSpinner.UpdateText("Waiting for " + strconv.Itoa(i) + " second...")
+ }
+ time.Sleep(second)
+ }
+ introSpinner.Stop()
+}
+
+func clear() {
+ print("\033[H\033[2J")
+}
+
+func randomInt(min, max int) int {
+ rand.Seed(time.Now().UnixNano())
+ return rand.Intn(max-min+1) + min
+}
+
+```
+
+
+
+### disable-color
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/disable-color/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "math/rand"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/pterm/pterm"
+)
+
+// Change this to time.Millisecond*200 to speed up the demo.
+// Useful when debugging.
+const second = time.Second
+
+var pseudoProgramList = strings.Split("pseudo-excel pseudo-photoshop pseudo-chrome pseudo-outlook pseudo-explorer "+
+ "pseudo-dops pseudo-git pseudo-vsc pseudo-intellij pseudo-minecraft pseudo-scoop pseudo-chocolatey", " ")
+
+func main() {
+ pterm.DisableColor()
+ introScreen()
+ clear()
+ pseudoApplicationHeader()
+ time.Sleep(second)
+ installingPseudoList()
+ time.Sleep(second * 2)
+ pterm.DefaultSection.WithLevel(2).Println("Program Install Report")
+ installedProgramsSize()
+ time.Sleep(second * 4)
+ pterm.DefaultSection.Println("Tree Printer")
+ installedTree()
+ time.Sleep(second * 4)
+ pterm.DefaultSection.Println("TrueColor Support")
+ fadeText()
+ time.Sleep(second)
+ pterm.DefaultSection.Println("Bullet List Printer")
+ listPrinter()
+}
+
+func installedTree() {
+ leveledList := pterm.LeveledList{
+ pterm.LeveledListItem{Level: 0, Text: "C:"},
+ pterm.LeveledListItem{Level: 1, Text: "Go"},
+ pterm.LeveledListItem{Level: 1, Text: "Windows"},
+ pterm.LeveledListItem{Level: 1, Text: "Programs"},
+ }
+ for _, s := range pseudoProgramList {
+ if s != "pseudo-minecraft" {
+ leveledList = append(leveledList, pterm.LeveledListItem{Level: 2, Text: s})
+ }
+ if s == "pseudo-chrome" {
+ leveledList = append(leveledList, pterm.LeveledListItem{Level: 3, Text: "pseudo-Tabs"})
+ leveledList = append(leveledList, pterm.LeveledListItem{Level: 3, Text: "pseudo-Extensions"})
+ leveledList = append(leveledList, pterm.LeveledListItem{Level: 4, Text: "Refined GitHub"})
+ leveledList = append(leveledList, pterm.LeveledListItem{Level: 4, Text: "GitHub Dark Theme"})
+ leveledList = append(leveledList, pterm.LeveledListItem{Level: 3, Text: "pseudo-Bookmarks"})
+ leveledList = append(leveledList, pterm.LeveledListItem{Level: 4, Text: "PTerm"})
+ }
+ }
+
+ pterm.DefaultTree.WithRoot(pterm.NewTreeFromLeveledList(leveledList)).Render()
+}
+
+func installingPseudoList() {
+ pterm.DefaultSection.Println("Installing pseudo programs")
+
+ p, _ := pterm.DefaultProgressbar.WithTotal(len(pseudoProgramList)).WithTitle("Installing stuff").Start()
+ for i := 0; i < p.Total; i++ {
+ p.UpdateTitle("Installing " + pseudoProgramList[i])
+ if pseudoProgramList[i] == "pseudo-minecraft" {
+ pterm.Warning.Println("Could not install pseudo-minecraft\nThe company policy forbids games.")
+ } else {
+ pterm.Success.Println("Installing " + pseudoProgramList[i])
+ p.Increment()
+ }
+ time.Sleep(second / 2)
+ }
+ p.Stop()
+}
+
+func listPrinter() {
+ pterm.NewBulletListFromString(`Good bye
+ Have a nice day!`, " ").Render()
+}
+
+func fadeText() {
+ from := pterm.NewRGB(0, 255, 255) // This RGB value is used as the gradients start point.
+ to := pterm.NewRGB(255, 0, 255) // This RGB value is used as the gradients first point.
+
+ str := "If your terminal has TrueColor support, you can use RGB colors!\nYou can even fade them :)"
+ strs := strings.Split(str, "")
+ var fadeInfo string // String which will be used to print info.
+ // For loop over the range of the string length.
+ for i := 0; i < len(str); i++ {
+ // Append faded letter to info string.
+ fadeInfo += from.Fade(0, float32(len(str)), float32(i), to).Sprint(strs[i])
+ }
+ pterm.Info.Println(fadeInfo)
+}
+
+func installedProgramsSize() {
+ d := pterm.TableData{{"Program Name", "Status", "Size"}}
+ for _, s := range pseudoProgramList {
+ if s != "pseudo-minecraft" {
+ d = append(d, []string{s, pterm.LightGreen("pass"), strconv.Itoa(randomInt(7, 200)) + "mb"})
+ } else {
+ d = append(d, []string{pterm.LightRed(s), pterm.LightRed("fail"), "0mb"})
+ }
+ }
+ pterm.DefaultTable.WithHasHeader().WithData(d).Render()
+}
+
+func pseudoApplicationHeader() *pterm.TextPrinter {
+ return pterm.DefaultHeader.WithBackgroundStyle(pterm.NewStyle(pterm.BgLightBlue)).WithMargin(10).Println(
+ "Pseudo Application created with PTerm")
+}
+
+func introScreen() {
+ pterm.DefaultBigText.WithLetters(
+ pterm.NewLettersFromStringWithStyle("P", pterm.NewStyle(pterm.FgLightCyan)),
+ pterm.NewLettersFromStringWithStyle("Term", pterm.NewStyle(pterm.FgLightMagenta))).
+ Render()
+
+ pterm.DefaultHeader.WithBackgroundStyle(pterm.NewStyle(pterm.BgLightBlue)).WithMargin(10).Println(
+ "PTDP - PTerm Demo Program")
+
+ pterm.Info.Println("This animation was generated with the latest version of PTerm!" +
+ "\nPTerm works on nearly every terminal and operating system." +
+ "\nIt's super easy to use!" +
+ "\nIf you want, you can customize everything :)" +
+ "\nYou can see the code of this demo in the " + pterm.LightMagenta("./_examples/demo") + " directory." +
+ "\n" +
+ "\nThis demo was updated at: " + pterm.Green(time.Now().Format("02 Jan 2006 - 15:04:05 MST")))
+ pterm.Println()
+ introSpinner, _ := pterm.DefaultSpinner.WithRemoveWhenDone(true).Start("Waiting for 15 seconds...")
+ time.Sleep(second)
+ for i := 14; i > 0; i-- {
+ if i > 1 {
+ introSpinner.UpdateText("Waiting for " + strconv.Itoa(i) + " seconds...")
+ } else {
+ introSpinner.UpdateText("Waiting for " + strconv.Itoa(i) + " second...")
+ }
+ time.Sleep(second)
+ }
+ introSpinner.Stop()
+}
+
+func clear() {
+ print("\033[H\033[2J")
+}
+
+func randomInt(min, max int) int {
+ rand.Seed(time.Now().UnixNano())
+ return rand.Intn(max-min+1) + min
+}
+
+```
+
+
+
+### disable-output
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/disable-output/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ for i := 0; i < 15; i++ {
+ switch i {
+ case 5:
+ pterm.Info.Println("Disabled Output!")
+ pterm.DisableOutput()
+ case 10:
+ pterm.EnableOutput()
+ pterm.Info.Println("Enabled Output!")
+ }
+
+ pterm.Printf("Printing something... [%d/%d]\n", i, 15)
+ }
+}
+
+```
+
+
+
+### disable-styling
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/disable-styling/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "math/rand"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/pterm/pterm"
+)
+
+// Change this to time.Millisecond*200 to speed up the demo.
+// Useful when debugging.
+const second = time.Second
+
+var pseudoProgramList = strings.Split("pseudo-excel pseudo-photoshop pseudo-chrome pseudo-outlook pseudo-explorer "+
+ "pseudo-dops pseudo-git pseudo-vsc pseudo-intellij pseudo-minecraft pseudo-scoop pseudo-chocolatey", " ")
+
+func main() {
+ pterm.DisableStyling()
+ introScreen()
+ clear()
+ pseudoApplicationHeader()
+ time.Sleep(second)
+ installingPseudoList()
+ time.Sleep(second * 2)
+ pterm.DefaultSection.WithLevel(2).Println("Program Install Report")
+ installedProgramsSize()
+ time.Sleep(second * 4)
+ pterm.DefaultSection.Println("Tree Printer")
+ installedTree()
+ time.Sleep(second * 4)
+ pterm.DefaultSection.Println("TrueColor Support")
+ fadeText()
+ time.Sleep(second)
+ pterm.DefaultSection.Println("Bullet List Printer")
+ listPrinter()
+}
+
+func installedTree() {
+ leveledList := pterm.LeveledList{
+ pterm.LeveledListItem{Level: 0, Text: "C:"},
+ pterm.LeveledListItem{Level: 1, Text: "Go"},
+ pterm.LeveledListItem{Level: 1, Text: "Windows"},
+ pterm.LeveledListItem{Level: 1, Text: "Programs"},
+ }
+ for _, s := range pseudoProgramList {
+ if s != "pseudo-minecraft" {
+ leveledList = append(leveledList, pterm.LeveledListItem{Level: 2, Text: s})
+ }
+ if s == "pseudo-chrome" {
+ leveledList = append(leveledList, pterm.LeveledListItem{Level: 3, Text: "pseudo-Tabs"})
+ leveledList = append(leveledList, pterm.LeveledListItem{Level: 3, Text: "pseudo-Extensions"})
+ leveledList = append(leveledList, pterm.LeveledListItem{Level: 4, Text: "Refined GitHub"})
+ leveledList = append(leveledList, pterm.LeveledListItem{Level: 4, Text: "GitHub Dark Theme"})
+ leveledList = append(leveledList, pterm.LeveledListItem{Level: 3, Text: "pseudo-Bookmarks"})
+ leveledList = append(leveledList, pterm.LeveledListItem{Level: 4, Text: "PTerm"})
+ }
+ }
+
+ pterm.DefaultTree.WithRoot(pterm.NewTreeFromLeveledList(leveledList)).Render()
+}
+
+func installingPseudoList() {
+ pterm.DefaultSection.Println("Installing pseudo programs")
+
+ p, _ := pterm.DefaultProgressbar.WithTotal(len(pseudoProgramList)).WithTitle("Installing stuff").Start()
+ for i := 0; i < p.Total; i++ {
+ p.UpdateTitle("Installing " + pseudoProgramList[i])
+ if pseudoProgramList[i] == "pseudo-minecraft" {
+ pterm.Warning.Println("Could not install pseudo-minecraft\nThe company policy forbids games.")
+ } else {
+ pterm.Success.Println("Installing " + pseudoProgramList[i])
+ p.Increment()
+ }
+ time.Sleep(second / 2)
+ }
+ p.Stop()
+}
+
+func listPrinter() {
+ pterm.NewBulletListFromString(`Good bye
+ Have a nice day!`, " ").Render()
+}
+
+func fadeText() {
+ from := pterm.NewRGB(0, 255, 255) // This RGB value is used as the gradients start point.
+ to := pterm.NewRGB(255, 0, 255) // This RGB value is used as the gradients first point.
+
+ str := "If your terminal has TrueColor support, you can use RGB colors!\nYou can even fade them :)"
+ strs := strings.Split(str, "")
+ var fadeInfo string // String which will be used to print info.
+ // For loop over the range of the string length.
+ for i := 0; i < len(str); i++ {
+ // Append faded letter to info string.
+ fadeInfo += from.Fade(0, float32(len(str)), float32(i), to).Sprint(strs[i])
+ }
+ pterm.Info.Println(fadeInfo)
+}
+
+func installedProgramsSize() {
+ d := pterm.TableData{{"Program Name", "Status", "Size"}}
+ for _, s := range pseudoProgramList {
+ if s != "pseudo-minecraft" {
+ d = append(d, []string{s, pterm.LightGreen("pass"), strconv.Itoa(randomInt(7, 200)) + "mb"})
+ } else {
+ d = append(d, []string{pterm.LightRed(s), pterm.LightRed("fail"), "0mb"})
+ }
+ }
+ pterm.DefaultTable.WithHasHeader().WithData(d).Render()
+}
+
+func pseudoApplicationHeader() *pterm.TextPrinter {
+ return pterm.DefaultHeader.WithBackgroundStyle(pterm.NewStyle(pterm.BgLightBlue)).WithMargin(10).Println(
+ "Pseudo Application created with PTerm")
+}
+
+func introScreen() {
+ pterm.DefaultBigText.WithLetters(
+ pterm.NewLettersFromStringWithStyle("P", pterm.NewStyle(pterm.FgLightCyan)),
+ pterm.NewLettersFromStringWithStyle("Term", pterm.NewStyle(pterm.FgLightMagenta))).
+ Render()
+
+ pterm.DefaultHeader.WithBackgroundStyle(pterm.NewStyle(pterm.BgLightBlue)).WithMargin(10).Println(
+ "PTDP - PTerm Demo Program")
+
+ pterm.Info.Println("This animation was generated with the latest version of PTerm!" +
+ "\nPTerm works on nearly every terminal and operating system." +
+ "\nIt's super easy to use!" +
+ "\nIf you want, you can customize everything :)" +
+ "\nYou can see the code of this demo in the " + pterm.LightMagenta("./_examples/demo") + " directory." +
+ "\n" +
+ "\nThis demo was updated at: " + pterm.Green(time.Now().Format("02 Jan 2006 - 15:04:05 MST")))
+ pterm.Println()
+ introSpinner, _ := pterm.DefaultSpinner.WithRemoveWhenDone(true).Start("Waiting for 15 seconds...")
+ time.Sleep(second)
+ for i := 14; i > 0; i-- {
+ if i > 1 {
+ introSpinner.UpdateText("Waiting for " + strconv.Itoa(i) + " seconds...")
+ } else {
+ introSpinner.UpdateText("Waiting for " + strconv.Itoa(i) + " second...")
+ }
+ time.Sleep(second)
+ }
+ introSpinner.Stop()
+}
+
+func clear() {
+ print("\033[H\033[2J")
+}
+
+func randomInt(min, max int) int {
+ rand.Seed(time.Now().UnixNano())
+ return rand.Intn(max-min+1) + min
+}
+
+```
+
+
+
+### header
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/header/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Print a default header.
+ pterm.DefaultHeader.Println("This is the default header!")
+ pterm.Println() // spacer
+ pterm.DefaultHeader.WithFullWidth().Println("This is a full-width header.")
+}
+
+```
+
+
+
+### header-custom
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/header-custom/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // All available options: https://pkg.go.dev/github.com/pterm/pterm#HeaderPrinter
+
+ // Build on top of DefaultHeader
+ pterm.DefaultHeader. // Use DefaultHeader as base
+ WithMargin(15).
+ WithBackgroundStyle(pterm.NewStyle(pterm.BgCyan)).
+ WithTextStyle(pterm.NewStyle(pterm.FgBlack)).
+ Println("This is a custom header!")
+ // Instead of printing the header you can set it to a variable.
+ // You can then reuse your custom header.
+
+ // Making a completely new HeaderPrinter
+ newHeader := pterm.HeaderPrinter{
+ TextStyle: pterm.NewStyle(pterm.FgBlack),
+ BackgroundStyle: pterm.NewStyle(pterm.BgRed),
+ Margin: 20,
+ }
+
+ // Print header.
+ newHeader.Println("This is a custom header!")
+}
+
+```
+
+
+
+### override-default-printers
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/override-default-printers/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Print default error.
+ pterm.Error.Println("This is the default Error")
+
+ // Customize default error.
+ pterm.Error.Prefix = pterm.Prefix{
+ Text: "OVERRIDE",
+ Style: pterm.NewStyle(pterm.BgCyan, pterm.FgRed),
+ }
+
+ // Print new default error.
+ pterm.Error.Println("This is the default Error after the prefix was overridden")
+}
+
+```
+
+
+
+### panel
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/panel/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Declare panels in a two dimensional grid system.
+ panels := pterm.Panels{
+ {{Data: "This is the first panel"}, {Data: pterm.DefaultHeader.Sprint("Hello, World!")}, {Data: "This\npanel\ncontains\nmultiple\nlines"}},
+ {{Data: pterm.Red("This is another\npanel line")}, {Data: "This is the second panel\nwith a new line"}},
+ }
+
+ // Print panels.
+ _ = pterm.DefaultPanel.WithPanels(panels).WithPadding(5).Render()
+}
+
+```
+
+
+
+### paragraph
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/paragraph/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Print long text with default paragraph printer.
+ pterm.DefaultParagraph.Println("This is the default paragraph printer. As you can see, no words are separated, " +
+ "but the text is split at the spaces. This is useful for continuous text of all kinds. You can manually change the line width if you want to." +
+ "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam")
+
+ // Print one line space.
+ pterm.Println()
+
+ // Print long text without paragraph printer.
+ pterm.Println("This text is written with the default Println() function. No intelligent splitting here." +
+ "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam")
+}
+
+```
+
+
+
+### paragraph-custom
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/paragraph-custom/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Print a paragraph with a custom maximal width.
+ pterm.DefaultParagraph.WithMaxWidth(60).Println("This is a custom paragraph printer. As you can see, no words are separated, " +
+ "but the text is split at the spaces. This is useful for continuous text of all kinds. You can manually change the line width if you want to." +
+ "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam")
+
+ // Print one line space.
+ pterm.Println()
+
+ // Print text without a paragraph printer.
+ pterm.Println("This text is written with the default Println() function. No intelligent splitting here." +
+ "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam")
+}
+
+```
+
+
+
+### prefix
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/prefix/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Enable debug messages.
+ pterm.EnableDebugMessages()
+
+ pterm.Debug.Println("Hello, World!") // Print Debug.
+ pterm.Info.Println("Hello, World!") // Print Info.
+ pterm.Success.Println("Hello, World!") // Print Success.
+ pterm.Warning.Println("Hello, World!") // Print Warning.
+ pterm.Error.Println("Errors show the filename and linenumber inside the terminal!") // Print Error.
+ pterm.Info.WithShowLineNumber().Println("Other PrefixPrinters can do that too!") // Print Error.
+ // Temporarily set Fatal to false, so that the CI won't crash.
+ pterm.Fatal.WithFatal(false).Println("Hello, World!") // Print Fatal.
+}
+
+```
+
+
+
+### print-basic-text
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/print-basic-text/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // A BasicText printer is used to print text, without special formatting.
+ // As it implements the TextPrinter interface, you can use it in combination with other printers.
+ pterm.DefaultBasicText.Println("Default basic text printer.")
+ pterm.DefaultBasicText.Println("Can be used in any" + pterm.LightMagenta(" TextPrinter ") + "context.")
+ pterm.DefaultBasicText.Println("For example to resolve progressbars and spinners.")
+ // If you just want to print text, you should use this instead:
+ // pterm.Println("Hello, World!")
+}
+
+```
+
+
+
+### print-color-fade
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/print-color-fade/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Print info.
+ pterm.Info.Println("RGB colors only work in Terminals which support TrueColor.")
+
+ from := pterm.NewRGB(0, 255, 255) // This RGB value is used as the gradients start point.
+ to := pterm.NewRGB(255, 0, 255) // This RGB value is used as the gradients end point.
+
+ // For loop over the range of the terminal height.
+ for i := 0; i < pterm.GetTerminalHeight()-2; i++ {
+ // Print string which is colored with the faded RGB value.
+ from.Fade(0, float32(pterm.GetTerminalHeight()-2), float32(i), to).Println("Hello, World!")
+ }
+}
+
+```
+
+
+
+### print-color-fade-multiple
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/print-color-fade-multiple/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "strings"
+
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ from := pterm.NewRGB(0, 255, 255) // This RGB value is used as the gradients start point.
+ to := pterm.NewRGB(255, 0, 255) // This RGB value is used as the gradients first point.
+ to2 := pterm.NewRGB(255, 0, 0) // This RGB value is used as the gradients second point.
+ to3 := pterm.NewRGB(0, 255, 0) // This RGB value is used as the gradients third point.
+ to4 := pterm.NewRGB(255, 255, 255) // This RGB value is used as the gradients end point.
+
+ str := "RGB colors only work in Terminals which support TrueColor."
+ strs := strings.Split(str, "")
+ var fadeInfo string // String which will be used to print info.
+ // For loop over the range of the string length.
+ for i := 0; i < len(str); i++ {
+ // Append faded letter to info string.
+ fadeInfo += from.Fade(0, float32(len(str)), float32(i), to).Sprint(strs[i])
+ }
+
+ // Print info.
+ pterm.Info.Println(fadeInfo)
+
+ // For loop over the range of the terminal height.
+ for i := 0; i < pterm.GetTerminalHeight()-2; i++ {
+ // Print string which is colored with the faded RGB value.
+ from.Fade(0, float32(pterm.GetTerminalHeight()-2), float32(i), to, to2, to3, to4).Println("Hello, World!")
+ }
+}
+
+```
+
+
+
+### print-color-rgb
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/print-color-rgb/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Print strings with a custom RGB color.
+ // NOTICE: This only works with terminals which support TrueColor.
+ pterm.NewRGB(178, 44, 199).Println("This text is printed with a custom RGB!")
+ pterm.NewRGB(15, 199, 209).Println("This text is printed with a custom RGB!")
+ pterm.NewRGB(201, 144, 30).Println("This text is printed with a custom RGB!")
+}
+
+```
+
+
+
+### print-with-color
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/print-with-color/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Print different colored words.
+ pterm.Println(pterm.Red("Hello, ") + pterm.Green("World") + pterm.Cyan("!"))
+ pterm.Println(pterm.Red("Even " + pterm.Cyan("nested ") + pterm.Green("colors ") + "are supported!"))
+
+ // Print strings with set color.
+ pterm.FgBlack.Println("FgBlack")
+ pterm.FgRed.Println("FgRed")
+ pterm.FgGreen.Println("FgGreen")
+ pterm.FgYellow.Println("FgYellow")
+ pterm.FgBlue.Println("FgBlue")
+ pterm.FgMagenta.Println("FgMagenta")
+ pterm.FgCyan.Println("FgCyan")
+ pterm.FgWhite.Println("FgWhite")
+ pterm.Println() // Print one line space.
+ pterm.FgLightRed.Println("FgLightRed")
+ pterm.FgLightGreen.Println("FgLightGreen")
+ pterm.FgLightYellow.Println("FgLightYellow")
+ pterm.FgLightBlue.Println("FgLightBlue")
+ pterm.FgLightMagenta.Println("FgLightMagenta")
+ pterm.FgLightCyan.Println("FgLightCyan")
+ pterm.FgLightWhite.Println("FgLightWhite")
+}
+
+```
+
+
+
+### progressbar
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/progressbar/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "strings"
+ "time"
+
+ "github.com/pterm/pterm"
+)
+
+// Slice of strings with placeholder text.
+var fakeInstallList = strings.Split("pseudo-excel pseudo-photoshop pseudo-chrome pseudo-outlook pseudo-explorer "+
+ "pseudo-dops pseudo-git pseudo-vsc pseudo-intellij pseudo-minecraft pseudo-scoop pseudo-chocolatey", " ")
+
+func main() {
+ // Create progressbar as fork from the default progressbar.
+ p, _ := pterm.DefaultProgressbar.WithTotal(len(fakeInstallList)).WithTitle("Downloading stuff").Start()
+
+ for i := 0; i < p.Total; i++ {
+ p.UpdateTitle("Downloading " + fakeInstallList[i]) // Update the title of the progressbar.
+ pterm.Success.Println("Downloading " + fakeInstallList[i]) // If a progressbar is running, each print will be printed above the progressbar.
+ p.Increment() // Increment the progressbar by one. Use Add(x int) to increment by a custom amount.
+ time.Sleep(time.Millisecond * 350) // Sleep 350 milliseconds.
+ }
+}
+
+```
+
+
+
+### section
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/section/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Print a section with level one.
+ pterm.DefaultSection.Println("This is a section!")
+ // Print placeholder.
+ pterm.Info.Println("And here is some text.\nThis text could be anything.\nBasically it's just a placeholder")
+
+ // Print a section with level two.
+ pterm.DefaultSection.WithLevel(2).Println("This is another section!")
+ // Print placeholder.
+ pterm.Info.Println("And this is\nmore placeholder text")
+}
+
+```
+
+
+
+### spinner
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/spinner/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "time"
+
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Create and start a fork of the default spinner.
+ spinnerSuccess, _ := pterm.DefaultSpinner.Start("Doing something important... (will succeed)")
+ time.Sleep(time.Second * 2) // Simulate 3 seconds of processing something.
+ spinnerSuccess.Success() // Resolve spinner with success message.
+
+ // Create and start a fork of the default spinner.
+ spinnerWarning, _ := pterm.DefaultSpinner.Start("Doing something important... (will warn)")
+ time.Sleep(time.Second * 2) // Simulate 3 seconds of processing something.
+ spinnerWarning.Warning() // Resolve spinner with warning message.
+
+ // Create and start a fork of the default spinner.
+ spinnerFail, _ := pterm.DefaultSpinner.Start("Doing something important... (will fail)")
+ time.Sleep(time.Second * 2) // Simulate 3 seconds of processing something.
+ spinnerFail.Fail() // Resolve spinner with error message.
+
+ // Create and start a fork of the default spinner.
+ spinnerLiveText, _ := pterm.DefaultSpinner.Start("Doing a lot of stuff...")
+ time.Sleep(time.Second) // Simulate 2 seconds of processing something.
+ spinnerLiveText.UpdateText("It's really much") // Update spinner text.
+ time.Sleep(time.Second) // Simulate 2 seconds of processing something.
+ spinnerLiveText.UpdateText("We're nearly done!") // Update spinner text.
+ time.Sleep(time.Second) // Simulate 2 seconds of processing something.
+ spinnerLiveText.Success("Finally!") // Resolve spinner with success message.
+}
+
+```
+
+
+
+### style
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/style/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Create styles as new variables
+ primary := pterm.NewStyle(pterm.FgLightCyan, pterm.BgGray, pterm.Bold)
+ secondary := pterm.NewStyle(pterm.FgLightGreen, pterm.BgWhite, pterm.Italic)
+
+ // Use created styles
+ primary.Println("Hello, World!")
+ secondary.Println("Hello, World!")
+}
+
+```
+
+
+
+### table
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/table/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Create a fork of the default table, fill it with data and print it.
+ // Data can also be generated and inserted later.
+ pterm.DefaultTable.WithHasHeader().WithData(pterm.TableData{
+ {"Firstname", "Lastname", "Email"},
+ {"Paul", "Dean", "nisi.dictum.augue@velitAliquam.co.uk"},
+ {"Callie", "Mckay", "egestas.nunc.sed@est.com"},
+ {"Libby", "Camacho", "aliquet.lobortis@semper.com"},
+ }).Render()
+
+ pterm.Println() // Blank line
+
+ // Create a table with right alignment.
+ pterm.DefaultTable.WithHasHeader().WithData(pterm.TableData{
+ {"Firstname", "Lastname", "Email"},
+ {"Paul", "Dean", "nisi.dictum.augue@velitAliquam.co.uk"},
+ {"Callie", "Mckay", "egestas.nunc.sed@est.com"},
+ {"Libby", "Camacho", "aliquet.lobortis@semper.com"},
+ }).WithRightAlignment().Render()
+}
+
+```
+
+
+
+### theme
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/theme/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+ "reflect"
+ "time"
+)
+
+func main() {
+ // Print info.
+ pterm.Info.Println("These are the default theme styles.\n" +
+ "You can modify them easily to your personal preference,\n" +
+ "or create new themes from scratch :)")
+
+ pterm.Println() // Print one line space.
+
+ // Print every value of the default theme with its own style.
+ v := reflect.ValueOf(pterm.ThemeDefault)
+ typeOfS := v.Type()
+
+ if typeOfS == reflect.TypeOf(pterm.Theme{}) {
+ for i := 0; i < v.NumField(); i++ {
+ field, ok := v.Field(i).Interface().(pterm.Style)
+ if ok {
+ field.Println(typeOfS.Field(i).Name)
+ }
+ time.Sleep(time.Millisecond * 250)
+ }
+ }
+}
+
+```
+
+
+
+### tree
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/tree/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // You can use a LeveledList here, for easy generation.
+ leveledList := pterm.LeveledList{
+ pterm.LeveledListItem{Level: 0, Text: "C:"},
+ pterm.LeveledListItem{Level: 1, Text: "Users"},
+ pterm.LeveledListItem{Level: 1, Text: "Windows"},
+ pterm.LeveledListItem{Level: 1, Text: "Programs"},
+ pterm.LeveledListItem{Level: 1, Text: "Programs(x86)"},
+ pterm.LeveledListItem{Level: 1, Text: "dev"},
+ pterm.LeveledListItem{Level: 0, Text: "D:"},
+ pterm.LeveledListItem{Level: 0, Text: "E:"},
+ pterm.LeveledListItem{Level: 1, Text: "Movies"},
+ pterm.LeveledListItem{Level: 1, Text: "Music"},
+ pterm.LeveledListItem{Level: 2, Text: "LinkinPark"},
+ pterm.LeveledListItem{Level: 1, Text: "Games"},
+ pterm.LeveledListItem{Level: 2, Text: "Shooter"},
+ pterm.LeveledListItem{Level: 3, Text: "CallOfDuty"},
+ pterm.LeveledListItem{Level: 3, Text: "CS:GO"},
+ pterm.LeveledListItem{Level: 3, Text: "Battlefield"},
+ pterm.LeveledListItem{Level: 4, Text: "Battlefield 1"},
+ pterm.LeveledListItem{Level: 4, Text: "Battlefield 2"},
+ pterm.LeveledListItem{Level: 0, Text: "F:"},
+ pterm.LeveledListItem{Level: 1, Text: "dev"},
+ pterm.LeveledListItem{Level: 2, Text: "dops"},
+ pterm.LeveledListItem{Level: 2, Text: "PTerm"},
+ }
+
+ // Generate tree from LeveledList.
+ root := pterm.NewTreeFromLeveledList(leveledList)
+
+ // Render TreePrinter
+ pterm.DefaultTree.WithRoot(root).Render()
+}
+
+```
+
+
+
+
+
+
+
+---
+
+> GitHub [@pterm](https://github.com/pterm) ·
+> Author [@MarvinJWendt](https://github.com/MarvinJWendt)
+> | [PTerm.sh](https://pterm.sh)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vendor/github.com/pterm/pterm/area_printer.go b/vendor/github.com/pterm/pterm/area_printer.go
new file mode 100644
index 0000000..d304103
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/area_printer.go
@@ -0,0 +1,130 @@
+package pterm
+
+import (
+ "strings"
+
+ "github.com/atomicgo/cursor"
+
+ "github.com/pterm/pterm/internal"
+)
+
+// DefaultArea is the default area printer.
+var DefaultArea = AreaPrinter{}
+
+// AreaPrinter prints an area which can be updated easily.
+// use this printer for live output like charts, algorithm visualizations, simulations and even games.
+type AreaPrinter struct {
+ RemoveWhenDone bool
+ Fullscreen bool
+ Center bool
+
+ content string
+ isActive bool
+
+ area *cursor.Area
+}
+
+// GetContent returns the current area content.
+func (p *AreaPrinter) GetContent() string {
+ return p.content
+}
+
+// WithRemoveWhenDone removes the AreaPrinter content after it is stopped.
+func (p AreaPrinter) WithRemoveWhenDone(b ...bool) *AreaPrinter {
+ p.RemoveWhenDone = internal.WithBoolean(b)
+ return &p
+}
+
+// WithFullscreen sets the AreaPrinter height the same height as the terminal, making it fullscreen.
+func (p AreaPrinter) WithFullscreen(b ...bool) *AreaPrinter {
+ p.Fullscreen = internal.WithBoolean(b)
+ return &p
+}
+
+// WithCenter centers the AreaPrinter content to the terminal.
+func (p AreaPrinter) WithCenter(b ...bool) *AreaPrinter {
+ p.Center = internal.WithBoolean(b)
+ return &p
+}
+
+// Update overwrites the content of the AreaPrinter.
+// Can be used live.
+func (p *AreaPrinter) Update(text ...interface{}) {
+ if p.area == nil {
+ newArea := cursor.NewArea()
+ p.area = &newArea
+ }
+ str := Sprint(text...)
+ p.content = str
+
+ if p.Center {
+ str = DefaultCenter.Sprint(str)
+ }
+
+ if p.Fullscreen {
+ str = strings.TrimRight(str, "\n")
+ height := GetTerminalHeight()
+ contentHeight := strings.Count(str, "\n")
+
+ topPadding := 0
+ bottomPadding := height - contentHeight - 2
+
+ if p.Center {
+ topPadding = (bottomPadding / 2) + 1
+ bottomPadding /= 2
+ }
+
+ if height > contentHeight {
+ str = strings.Repeat("\n", topPadding) + str
+ str += strings.Repeat("\n", bottomPadding)
+ }
+ }
+ p.area.Update(str)
+}
+
+// Start the AreaPrinter.
+func (p *AreaPrinter) Start(text ...interface{}) (*AreaPrinter, error) {
+ p.isActive = true
+ str := Sprint(text...)
+ newArea := cursor.NewArea()
+ p.area = &newArea
+
+ p.Update(str)
+
+ return p, nil
+}
+
+// Stop terminates the AreaPrinter immediately.
+// The AreaPrinter will not resolve into anything.
+func (p *AreaPrinter) Stop() error {
+ p.isActive = false
+ if p.RemoveWhenDone {
+ p.Clear()
+ }
+ return nil
+}
+
+// GenericStart runs Start, but returns a LivePrinter.
+// This is used for the interface LivePrinter.
+// You most likely want to use Start instead of this in your program.
+func (p *AreaPrinter) GenericStart() (*LivePrinter, error) {
+ _, _ = p.Start()
+ lp := LivePrinter(p)
+ return &lp, nil
+}
+
+// GenericStop runs Stop, but returns a LivePrinter.
+// This is used for the interface LivePrinter.
+// You most likely want to use Stop instead of this in your program.
+func (p *AreaPrinter) GenericStop() (*LivePrinter, error) {
+ _ = p.Stop()
+ lp := LivePrinter(p)
+ return &lp, nil
+}
+
+// Wrapper function that clears the content of the Area.
+// Moves the cursor to the bottom of the terminal, clears n lines upwards from
+// the current position and moves the cursor again.
+func (p *AreaPrinter) Clear() {
+ p.area.Clear()
+}
diff --git a/vendor/github.com/pterm/pterm/atoms.go b/vendor/github.com/pterm/pterm/atoms.go
new file mode 100644
index 0000000..d241092
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/atoms.go
@@ -0,0 +1,36 @@
+package pterm
+
+// Bars is used to display multiple Bar.
+type Bars []Bar
+
+// Bar is used in bar charts.
+type Bar struct {
+ Label string
+ Value int
+ Style *Style
+ LabelStyle *Style
+}
+
+// WithLabel returns a new Bar with a specific option.
+func (p Bar) WithLabel(s string) *Bar {
+ p.Label = s
+ return &p
+}
+
+// WithLabelStyle returns a new Bar with a specific option.
+func (p Bar) WithLabelStyle(style *Style) *Bar {
+ p.LabelStyle = style
+ return &p
+}
+
+// WithValue returns a new Bar with a specific option.
+func (p Bar) WithValue(value int) *Bar {
+ p.Value = value
+ return &p
+}
+
+// WithStyle returns a new Bar with a specific option.
+func (p Bar) WithStyle(style *Style) *Bar {
+ p.Style = style
+ return &p
+}
diff --git a/vendor/github.com/pterm/pterm/barchart.go b/vendor/github.com/pterm/pterm/barchart.go
new file mode 100644
index 0000000..b610098
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/barchart.go
@@ -0,0 +1,416 @@
+package pterm
+
+import (
+ "strconv"
+ "strings"
+
+ "github.com/mattn/go-runewidth"
+
+ "github.com/pterm/pterm/internal"
+)
+
+// BarChartPrinter is used to print bar charts.
+type BarChartPrinter struct {
+ Bars Bars
+ Horizontal bool
+ ShowValue bool
+ // Height sets the maximum height of a vertical bar chart.
+ // The default is calculated to fit into the terminal.
+ // Ignored if Horizontal is set to true.
+ Height int
+ // Width sets the maximum width of a horizontal bar chart.
+ // The default is calculated to fit into the terminal.
+ // Ignored if Horizontal is set to false.
+ Width int
+ VerticalBarCharacter string
+ HorizontalBarCharacter string
+}
+
+var (
+ // DefaultBarChart is the default BarChartPrinter.
+ DefaultBarChart = BarChartPrinter{
+ Horizontal: false,
+ VerticalBarCharacter: "██",
+ HorizontalBarCharacter: "█",
+ // keep in sync with RecalculateTerminalSize()
+ Height: GetTerminalHeight() * 2 / 3,
+ Width: GetTerminalWidth() * 2 / 3,
+ }
+)
+
+// WithBars returns a new BarChartPrinter with a specific option.
+func (p BarChartPrinter) WithBars(bars Bars) *BarChartPrinter {
+ p.Bars = bars
+ return &p
+}
+
+// WithVerticalBarCharacter returns a new BarChartPrinter with a specific option.
+func (p BarChartPrinter) WithVerticalBarCharacter(char string) *BarChartPrinter {
+ p.VerticalBarCharacter = char
+ return &p
+}
+
+// WithHorizontalBarCharacter returns a new BarChartPrinter with a specific option.
+func (p BarChartPrinter) WithHorizontalBarCharacter(char string) *BarChartPrinter {
+ p.HorizontalBarCharacter = char
+ return &p
+}
+
+// WithHorizontal returns a new BarChartPrinter with a specific option.
+func (p BarChartPrinter) WithHorizontal(b ...bool) *BarChartPrinter {
+ b2 := internal.WithBoolean(b)
+ p.Horizontal = b2
+ return &p
+}
+
+// WithHeight returns a new BarChartPrinter with a specific option.
+func (p BarChartPrinter) WithHeight(value int) *BarChartPrinter {
+ p.Height = value
+ return &p
+}
+
+// WithWidth returns a new BarChartPrinter with a specific option.
+func (p BarChartPrinter) WithWidth(value int) *BarChartPrinter {
+ p.Width = value
+ return &p
+}
+
+// WithShowValue returns a new BarChartPrinter with a specific option.
+func (p BarChartPrinter) WithShowValue(b ...bool) *BarChartPrinter {
+ p.ShowValue = internal.WithBoolean(b)
+ return &p
+}
+
+func (p BarChartPrinter) getRawOutput() string {
+ var ret string
+
+ for _, bar := range p.Bars {
+ ret += Sprintfln("%s: %d", bar.Label, bar.Value)
+ }
+
+ return ret
+}
+
+// Srender renders the BarChart as a string.
+func (p BarChartPrinter) Srender() (string, error) {
+ maxAbsValue := func(value1 int, value2 int) int {
+ min := value1
+ max := value2
+
+ if value1 > value2 {
+ min = value2
+ max = value1
+ }
+
+ maxAbs := max
+
+ if min < 0 && -min > max { // This is to avoid something like "int(math.Abs(float64(minBarValue)))"
+ maxAbs = -min // (--) == (+)
+ }
+
+ return maxAbs
+ }
+
+ abs := func(value int) int {
+ if value < 0 {
+ return -value
+ }
+
+ return value
+ }
+ // =================================== VERTICAL BARS RENDERER ======================================================
+
+ type renderParams struct {
+ repeatCount int
+ bar Bar
+ positiveChartPartHeight int
+ negativeChartPartHeight int
+ positiveChartPartWidth int
+ negativeChartPartWidth int
+ indent string
+ showValue bool
+ moveUp bool
+ moveRight bool
+ }
+
+ renderPositiveVerticalBar := func(renderedBarRef *string, rParams renderParams) {
+ if rParams.showValue {
+ *renderedBarRef += Sprint(rParams.indent + strconv.Itoa(rParams.bar.Value) + rParams.indent + "\n")
+ }
+
+ for i := rParams.positiveChartPartHeight; i > 0; i-- {
+ if i > rParams.repeatCount {
+ *renderedBarRef += rParams.indent + " " + rParams.indent + " \n"
+ } else {
+ *renderedBarRef += rParams.indent + rParams.bar.Style.Sprint(p.VerticalBarCharacter) + rParams.indent + " \n"
+ }
+ }
+
+ // Used when we draw diagram with both POSITIVE and NEGATIVE values.
+ // In such case we separately draw top and bottom half of chart.
+ // And we need MOVE UP positive part to top part of chart,
+ // technically by adding empty pillars with height == height of chart's bottom part.
+ if rParams.moveUp {
+ for i := 0; i <= rParams.negativeChartPartHeight; i++ {
+ *renderedBarRef += rParams.indent + " " + rParams.indent + " \n"
+ }
+ }
+ }
+
+ renderNegativeVerticalBar := func(renderedBarRef *string, rParams renderParams) {
+ for i := 0; i > -rParams.negativeChartPartHeight; i-- {
+ if i > rParams.repeatCount {
+ *renderedBarRef += rParams.indent + rParams.bar.Style.Sprint(p.VerticalBarCharacter) + rParams.indent + " \n"
+ } else {
+ *renderedBarRef += rParams.indent + " " + rParams.indent + " \n"
+ }
+ }
+
+ if rParams.showValue {
+ *renderedBarRef += Sprint(rParams.indent + strconv.Itoa(rParams.bar.Value) + rParams.indent + "\n")
+ }
+ }
+
+ // =================================== HORIZONTAL BARS RENDERER ====================================================
+ renderPositiveHorizontalBar := func(renderedBarRef *string, rParams renderParams) {
+ if rParams.moveRight {
+ for i := 0; i < rParams.negativeChartPartWidth; i++ {
+ *renderedBarRef += " "
+ }
+ }
+
+ for i := 0; i < rParams.positiveChartPartWidth; i++ {
+ if i < rParams.repeatCount {
+ *renderedBarRef += rParams.bar.Style.Sprint(p.HorizontalBarCharacter)
+ } else {
+ *renderedBarRef += " "
+ }
+ }
+
+ if rParams.showValue {
+ // For positive horizontal bars we add one more space before adding value,
+ // so they will be well aligned with negative values, which have "-" sign before them
+ *renderedBarRef += " "
+
+ *renderedBarRef += " " + strconv.Itoa(rParams.bar.Value)
+ }
+ }
+
+ renderNegativeHorizontalBar := func(renderedBarRef *string, rParams renderParams) {
+ for i := -rParams.negativeChartPartWidth; i < 0; i++ {
+ if i < rParams.repeatCount {
+ *renderedBarRef += " "
+ } else {
+ *renderedBarRef += rParams.bar.Style.Sprint(p.HorizontalBarCharacter)
+ }
+ }
+
+ // In order to print values well-aligned (in case when we have both - positive and negative part of chart),
+ // we should insert an indent with width == width of positive chart part
+ if rParams.positiveChartPartWidth > 0 {
+ for i := 0; i < rParams.positiveChartPartWidth; i++ {
+ *renderedBarRef += " "
+ }
+ }
+
+ if rParams.showValue {
+ /*
+ This is in order to achieve this effect:
+ 0
+ -15
+ 0
+ -19
+
+ INSTEAD OF THIS:
+
+ 0
+ -15
+ 0
+ -19
+ */
+ if rParams.repeatCount == 0 {
+ *renderedBarRef += " "
+ }
+
+ *renderedBarRef += " " + strconv.Itoa(rParams.bar.Value)
+ }
+ }
+ // =================================================================================================================
+
+ if RawOutput {
+ return p.getRawOutput(), nil
+ }
+ for i, bar := range p.Bars {
+ if bar.Style == nil {
+ p.Bars[i].Style = &ThemeDefault.BarStyle
+ }
+
+ if bar.LabelStyle == nil {
+ p.Bars[i].LabelStyle = &ThemeDefault.BarLabelStyle
+ }
+
+ p.Bars[i].Label = p.Bars[i].LabelStyle.Sprint(bar.Label)
+ }
+
+ var ret string
+
+ var maxLabelHeight int
+ var maxBarValue int
+ var minBarValue int
+ var maxAbsBarValue int
+ var rParams renderParams
+
+ for _, bar := range p.Bars {
+ if bar.Value > maxBarValue {
+ maxBarValue = bar.Value
+ }
+ if bar.Value < minBarValue {
+ minBarValue = bar.Value
+ }
+ labelHeight := len(strings.Split(bar.Label, "\n"))
+ if labelHeight > maxLabelHeight {
+ maxLabelHeight = labelHeight
+ }
+ }
+
+ maxAbsBarValue = maxAbsValue(maxBarValue, minBarValue)
+
+ if p.Horizontal {
+ panels := Panels{[]Panel{{}, {}}}
+
+ rParams.showValue = p.ShowValue
+ rParams.positiveChartPartWidth = p.Width
+ rParams.negativeChartPartWidth = p.Width
+
+ // If chart will consist of two parts - positive and negative - we should recalculate max bars WIDTH in LEFT and RIGHT parts
+ if minBarValue < 0 && maxBarValue > 0 {
+ rParams.positiveChartPartWidth = abs(internal.MapRangeToRange(-float32(maxAbsBarValue), float32(maxAbsBarValue), -float32(p.Width)/2, float32(p.Width)/2, float32(maxBarValue)))
+ rParams.negativeChartPartWidth = abs(internal.MapRangeToRange(-float32(maxAbsBarValue), float32(maxAbsBarValue), -float32(p.Width)/2, float32(p.Width)/2, float32(minBarValue)))
+ }
+
+ for _, bar := range p.Bars {
+ rParams.bar = bar
+ panels[0][0].Data += "\n" + bar.Label
+ panels[0][1].Data += "\n"
+
+ if minBarValue >= 0 {
+ // As we don't have negative values, draw only positive (right) part of the chart:
+ rParams.repeatCount = internal.MapRangeToRange(0, float32(maxAbsBarValue), 0, float32(p.Width), float32(bar.Value))
+ rParams.moveRight = false
+
+ renderPositiveHorizontalBar(&panels[0][1].Data, rParams)
+ } else if maxBarValue <= 0 {
+ // As we have only negative values, draw only negative (left) part of the chart:
+ rParams.repeatCount = internal.MapRangeToRange(-float32(maxAbsBarValue), 0, -float32(p.Width), 0, float32(bar.Value))
+ rParams.positiveChartPartWidth = 0
+
+ renderNegativeHorizontalBar(&panels[0][1].Data, rParams)
+ } else {
+ // We have positive and negative values, so draw both (left+right) parts of the chart:
+ rParams.repeatCount = internal.MapRangeToRange(-float32(maxAbsBarValue), float32(maxAbsBarValue), -float32(p.Width)/2, float32(p.Width)/2, float32(bar.Value))
+
+ if bar.Value >= 0 {
+ rParams.moveRight = true
+
+ renderPositiveHorizontalBar(&panels[0][1].Data, rParams)
+ }
+
+ if bar.Value < 0 {
+ renderNegativeHorizontalBar(&panels[0][1].Data, rParams)
+ }
+ }
+ }
+ ret, _ = DefaultPanel.WithPanels(panels).Srender()
+ return ret, nil
+ } else {
+ renderedBars := make([]string, len(p.Bars))
+
+ rParams.showValue = p.ShowValue
+ rParams.positiveChartPartHeight = p.Height
+ rParams.negativeChartPartHeight = p.Height
+
+ // If chart will consist of two parts - positive and negative - we should recalculate max bars height in top and bottom parts
+ if minBarValue < 0 && maxBarValue > 0 {
+ rParams.positiveChartPartHeight = abs(internal.MapRangeToRange(-float32(maxAbsBarValue), float32(maxAbsBarValue), -float32(p.Height)/2, float32(p.Height)/2, float32(maxBarValue)))
+ rParams.negativeChartPartHeight = abs(internal.MapRangeToRange(-float32(maxAbsBarValue), float32(maxAbsBarValue), -float32(p.Height)/2, float32(p.Height)/2, float32(minBarValue)))
+ }
+
+ for i, bar := range p.Bars {
+ var renderedBar string
+ rParams.bar = bar
+ rParams.indent = strings.Repeat(" ", internal.GetStringMaxWidth(RemoveColorFromString(bar.Label))/2)
+
+ if minBarValue >= 0 {
+ // As we don't have negative values, draw only positive (top) part of the chart:
+ rParams.repeatCount = internal.MapRangeToRange(0, float32(maxAbsBarValue), 0, float32(p.Height), float32(bar.Value))
+ rParams.moveUp = false // Don't MOVE UP as we have ONLY positive part of chart.
+
+ renderPositiveVerticalBar(&renderedBar, rParams)
+ } else if maxBarValue <= 0 {
+ // As we have only negative values, draw only negative (bottom) part of the chart:
+ rParams.repeatCount = internal.MapRangeToRange(-float32(maxAbsBarValue), 0, -float32(p.Height), 0, float32(bar.Value))
+
+ renderNegativeVerticalBar(&renderedBar, rParams)
+ } else {
+ // We have positive and negative values, so draw both (top+bottom) parts of the chart:
+ rParams.repeatCount = internal.MapRangeToRange(-float32(maxAbsBarValue), float32(maxAbsBarValue), -float32(p.Height)/2, float32(p.Height)/2, float32(bar.Value))
+
+ if bar.Value >= 0 {
+ rParams.moveUp = true // MOVE UP positive part, because we have both positive and negative parts of chart.
+
+ renderPositiveVerticalBar(&renderedBar, rParams)
+ }
+
+ if bar.Value < 0 {
+ renderNegativeVerticalBar(&renderedBar, rParams)
+ }
+ }
+
+ labelHeight := len(strings.Split(bar.Label, "\n"))
+ renderedBars[i] = renderedBar + bar.Label + strings.Repeat("\n", maxLabelHeight-labelHeight) + " "
+ }
+
+ var maxBarHeight int
+
+ for _, bar := range renderedBars {
+ totalBarHeight := len(strings.Split(bar, "\n"))
+ if totalBarHeight > maxBarHeight {
+ maxBarHeight = totalBarHeight
+ }
+ }
+
+ for i, bar := range renderedBars {
+ totalBarHeight := len(strings.Split(bar, "\n"))
+ if totalBarHeight < maxBarHeight {
+ renderedBars[i] = strings.Repeat("\n", maxBarHeight-totalBarHeight) + renderedBars[i]
+ }
+ }
+
+ for i := 0; i <= maxBarHeight; i++ {
+ for _, barString := range renderedBars {
+ var barLine string
+ letterLines := strings.Split(barString, "\n")
+ maxBarWidth := internal.GetStringMaxWidth(RemoveColorFromString(barString))
+ if len(letterLines) > i {
+ barLine = letterLines[i]
+ }
+ letterLineLength := runewidth.StringWidth(RemoveColorFromString(barLine))
+ if letterLineLength < maxBarWidth {
+ barLine += strings.Repeat(" ", maxBarWidth-letterLineLength)
+ }
+ ret += barLine
+ }
+ ret += "\n"
+ }
+ }
+
+ return ret, nil
+}
+
+// Render prints the Template to the terminal.
+func (p BarChartPrinter) Render() error {
+ s, _ := p.Srender()
+ Println(s)
+
+ return nil
+}
diff --git a/vendor/github.com/pterm/pterm/basic_text_printer.go b/vendor/github.com/pterm/pterm/basic_text_printer.go
new file mode 100644
index 0000000..0a4b578
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/basic_text_printer.go
@@ -0,0 +1,114 @@
+package pterm
+
+import "fmt"
+
+var (
+ // DefaultBasicText returns a default BasicTextPrinter, which can be used to print text as is.
+ // No default style is present for BasicTextPrinter.
+ DefaultBasicText = BasicTextPrinter{}
+)
+
+// BasicTextPrinter is the printer used to print the input as-is or as specified by user formatting.
+type BasicTextPrinter struct {
+ Style *Style
+}
+
+// WithStyle adds a style to the printer.
+func (p BasicTextPrinter) WithStyle(style *Style) *BasicTextPrinter {
+ p.Style = style
+ return &p
+}
+
+// Sprint formats using the default formats for its operands and returns the resulting string.
+// Spaces are added between operands when neither is a string.
+func (p BasicTextPrinter) Sprint(a ...interface{}) string {
+ if p.Style == nil {
+ p.Style = NewStyle()
+ }
+ return p.Style.Sprint(a...)
+}
+
+// Sprintln formats using the default formats for its operands and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func (p BasicTextPrinter) Sprintln(a ...interface{}) string {
+ str := fmt.Sprintln(a...)
+ return Sprintln(p.Sprint(str))
+}
+
+// Sprintf formats according to a format specifier and returns the resulting string.
+func (p BasicTextPrinter) Sprintf(format string, a ...interface{}) string {
+ return p.Sprint(Sprintf(format, a...))
+}
+
+// Sprintfln formats according to a format specifier and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func (p BasicTextPrinter) Sprintfln(format string, a ...interface{}) string {
+ return p.Sprintf(format, a...) + "\n"
+}
+
+// Print formats using the default formats for its operands and writes to standard output.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+func (p *BasicTextPrinter) Print(a ...interface{}) *TextPrinter {
+ Print(p.Sprint(a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Println formats using the default formats for its operands and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func (p *BasicTextPrinter) Println(a ...interface{}) *TextPrinter {
+ Print(p.Sprintln(a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
+func (p *BasicTextPrinter) Printf(format string, a ...interface{}) *TextPrinter {
+ Print(p.Sprintf(format, a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Printfln formats according to a format specifier and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func (p *BasicTextPrinter) Printfln(format string, a ...interface{}) *TextPrinter {
+ Print(p.Sprintfln(format, a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// PrintOnError prints every error which is not nil.
+// If every error is nil, nothing will be printed.
+// This can be used for simple error checking.
+func (p *BasicTextPrinter) PrintOnError(a ...interface{}) *TextPrinter {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ p.Println(err)
+ }
+ }
+ }
+
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// PrintOnErrorf wraps every error which is not nil and prints it.
+// If every error is nil, nothing will be printed.
+// This can be used for simple error checking.
+func (p *BasicTextPrinter) PrintOnErrorf(format string, a ...interface{}) *TextPrinter {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ p.Println(fmt.Errorf(format, err))
+ }
+ }
+ }
+
+ tp := TextPrinter(p)
+ return &tp
+}
diff --git a/vendor/github.com/pterm/pterm/bigtext_printer.go b/vendor/github.com/pterm/pterm/bigtext_printer.go
new file mode 100644
index 0000000..a42dfcf
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/bigtext_printer.go
@@ -0,0 +1,549 @@
+package pterm
+
+import (
+ "strings"
+
+ "github.com/mattn/go-runewidth"
+
+ "github.com/pterm/pterm/internal"
+)
+
+// Letters is a slice of Letter.
+type Letters []Letter
+
+// NewLettersFromString creates a Letters object from a string, which is prefilled with the LetterStyle from ThemeDefault.
+// You can override the ThemeDefault LetterStyle if you want to.
+func NewLettersFromString(text string) Letters {
+ return NewLettersFromStringWithStyle(text, &ThemeDefault.LetterStyle)
+}
+
+// NewLettersFromStringWithStyle creates a Letters object from a string and applies a Style to it.
+func NewLettersFromStringWithStyle(text string, style *Style) Letters {
+ s := strings.Split(text, "")
+ l := Letters{}
+
+ for _, s2 := range s {
+ l = append(l, Letter{
+ String: s2,
+ Style: style,
+ })
+ }
+
+ return l
+}
+
+// Letter is an object, which holds a string and a specific Style for it.
+type Letter struct {
+ String string
+ Style *Style
+}
+
+// WithStyle returns a new Letter with a specific Style.
+func (l Letter) WithStyle(style *Style) *Letter {
+ l.Style = style
+ return &l
+}
+
+// WithString returns a new Letter with a specific String.
+func (l Letter) WithString(s string) *Letter {
+ l.String = s
+ return &l
+}
+
+// BigTextPrinter renders big text.
+// You can use this as title screen for your application.
+type BigTextPrinter struct {
+ // BigCharacters holds the map from a normal character to it's big version.
+ BigCharacters map[string]string
+ Letters Letters
+}
+
+// WithBigCharacters returns a new BigTextPrinter with specific BigCharacters.
+func (p BigTextPrinter) WithBigCharacters(chars map[string]string) *BigTextPrinter {
+ p.BigCharacters = chars
+ return &p
+}
+
+// WithLetters returns a new BigTextPrinter with specific Letters
+func (p BigTextPrinter) WithLetters(letters ...Letters) *BigTextPrinter {
+ l := Letters{}
+ for _, letter := range letters {
+ l = append(l, letter...)
+ }
+ p.Letters = l
+ return &p
+}
+
+// Srender renders the BigText as a string.
+func (p BigTextPrinter) Srender() (string, error) {
+ var ret string
+
+ if RawOutput {
+ for _, letter := range p.Letters {
+ ret += letter.String
+ }
+ return ret, nil
+ }
+
+ var bigLetters Letters
+ for _, l := range p.Letters {
+ if val, ok := p.BigCharacters[l.String]; ok {
+ bigLetters = append(bigLetters, Letter{
+ String: val,
+ Style: l.Style,
+ })
+ }
+ }
+
+ var maxHeight int
+
+ for _, l := range bigLetters {
+ h := strings.Count(l.String, "\n")
+ if h > maxHeight {
+ maxHeight = h
+ }
+ }
+
+ for i := 0; i <= maxHeight; i++ {
+ for _, letter := range bigLetters {
+ var letterLine string
+ letterLines := strings.Split(letter.String, "\n")
+ maxLetterWidth := internal.GetStringMaxWidth(letter.String)
+ if len(letterLines) > i {
+ letterLine = letterLines[i]
+ }
+ letterLineLength := runewidth.StringWidth(letterLine)
+ if letterLineLength < maxLetterWidth {
+ letterLine += strings.Repeat(" ", maxLetterWidth-letterLineLength)
+ }
+ ret += letter.Style.Sprint(letterLine)
+ }
+ ret += "\n"
+ }
+
+ return ret, nil
+}
+
+// Render prints the BigText to the terminal.
+func (p BigTextPrinter) Render() error {
+ s, _ := p.Srender()
+ Println(s)
+
+ return nil
+}
+
+// DefaultBigText contains default values for BigTextPrinter.
+var DefaultBigText = BigTextPrinter{
+ BigCharacters: map[string]string{
+ "a": ` █████
+██ ██
+███████
+██ ██
+██ ██ `,
+ "A": ` █████
+██ ██
+███████
+██ ██
+██ ██ `,
+ "b": `██████
+██ ██
+██████
+██ ██
+██████`,
+ "B": `██████
+██ ██
+██████
+██ ██
+██████`,
+ "c": ` ██████
+██
+██
+██
+ ██████`,
+ "C": ` ██████
+██
+██
+██
+ ██████`,
+ "d": `██████
+██ ██
+██ ██
+██ ██
+██████ `,
+ "D": `██████
+██ ██
+██ ██
+██ ██
+██████ `,
+ "e": `███████
+██
+█████
+██
+███████`,
+ "E": `███████
+██
+█████
+██
+███████`,
+ "f": `███████
+██
+█████
+██
+██ `,
+ "F": `███████
+██
+█████
+██
+██ `,
+ "g": ` ██████
+██
+██ ███
+██ ██
+ ██████ `,
+ "G": ` ██████
+██
+██ ███
+██ ██
+ ██████ `,
+ "h": `██ ██
+██ ██
+███████
+██ ██
+██ ██ `,
+ "H": `██ ██
+██ ██
+███████
+██ ██
+██ ██ `,
+ "i": `██
+██
+██
+██
+██`,
+ "I": `██
+██
+██
+██
+██`,
+ "j": ` ██
+ ██
+ ██
+██ ██
+ █████ `,
+ "J": ` ██
+ ██
+ ██
+██ ██
+ █████ `,
+ "k": `██ ██
+██ ██
+█████
+██ ██
+██ ██`,
+ "K": `██ ██
+██ ██
+█████
+██ ██
+██ ██`,
+ "l": `██
+██
+██
+██
+███████ `,
+ "L": `██
+██
+██
+██
+███████ `,
+ "m": `███ ███
+████ ████
+██ ████ ██
+██ ██ ██
+██ ██`,
+ "M": `███ ███
+████ ████
+██ ████ ██
+██ ██ ██
+██ ██`,
+ "n": `███ ██
+████ ██
+██ ██ ██
+██ ██ ██
+██ ████`,
+ "N": `███ ██
+████ ██
+██ ██ ██
+██ ██ ██
+██ ████`,
+ "o": ` ██████
+██ ██
+██ ██
+██ ██
+ ██████ `,
+ "O": ` ██████
+██ ██
+██ ██
+██ ██
+ ██████ `,
+ "p": `██████
+██ ██
+██████
+██
+██ `,
+ "P": `██████
+██ ██
+██████
+██
+██ `,
+ "q": ` ██████
+██ ██
+██ ██
+██ ▄▄ ██
+ ██████
+ ▀▀ `,
+ "Q": ` ██████
+██ ██
+██ ██
+██ ▄▄ ██
+ ██████
+ ▀▀ `,
+ "r": `██████
+██ ██
+██████
+██ ██
+██ ██`,
+ "R": `██████
+██ ██
+██████
+██ ██
+██ ██`,
+ "s": `███████
+██
+███████
+ ██
+███████`,
+ "S": `███████
+██
+███████
+ ██
+███████`,
+ "t": `████████
+ ██
+ ██
+ ██
+ ██ `,
+ "T": `████████
+ ██
+ ██
+ ██
+ ██ `,
+ "u": `██ ██
+██ ██
+██ ██
+██ ██
+ ██████ `,
+ "U": `██ ██
+██ ██
+██ ██
+██ ██
+ ██████ `,
+ "v": `██ ██
+██ ██
+██ ██
+ ██ ██
+ ████ `,
+ "V": `██ ██
+██ ██
+██ ██
+ ██ ██
+ ████ `,
+ "w": `██ ██
+██ ██
+██ █ ██
+██ ███ ██
+ ███ ███ `,
+ "W": `██ ██
+██ ██
+██ █ ██
+██ ███ ██
+ ███ ███ `,
+ "x": `██ ██
+ ██ ██
+ ███
+ ██ ██
+██ ██ `,
+ "X": `██ ██
+ ██ ██
+ ███
+ ██ ██
+██ ██ `,
+ "y": `██ ██
+ ██ ██
+ ████
+ ██
+ ██ `,
+ "Y": `██ ██
+ ██ ██
+ ████
+ ██
+ ██ `,
+ "z": `███████
+ ███
+ ███
+ ███
+███████`,
+ "Z": `███████
+ ███
+ ███
+ ███
+███████`,
+ "0": ` ██████
+██ ████
+██ ██ ██
+████ ██
+ ██████ `,
+ "1": ` ██
+███
+ ██
+ ██
+ ██ `,
+ "2": `██████
+ ██
+ █████
+██
+███████ `,
+ "3": `██████
+ ██
+ █████
+ ██
+██████ `,
+ "4": `██ ██
+██ ██
+███████
+ ██
+ ██ `,
+ "5": `███████
+██
+███████
+ ██
+███████`,
+ "6": ` ██████
+██
+███████
+██ ██
+ ██████ `,
+ "7": `███████
+ ██
+ ██
+ ██
+ ██`,
+ "8": ` █████
+██ ██
+ █████
+██ ██
+ █████ `,
+ "9": ` █████
+██ ██
+ ██████
+ ██
+ █████ `,
+ " ": " ",
+ "!": `██
+██
+██
+
+██ `,
+ "$": `▄▄███▄▄·
+██
+███████
+ ██
+███████
+ ▀▀▀ `,
+ "%": `██ ██
+ ██
+ ██
+ ██
+██ ██`,
+ "/": ` ██
+ ██
+ ██
+ ██
+██ `,
+ "(": ` ██
+██
+██
+██
+ ██ `,
+ ")": `██
+ ██
+ ██
+ ██
+██ `,
+ "?": `██████
+ ██
+ ▄███
+ ▀▀
+ ██ `,
+ "[": `███
+██
+██
+██
+███`,
+ "]": `███
+ ██
+ ██
+ ██
+███ `,
+ ".": `
+
+
+
+██`,
+ ",": `
+
+
+
+▄█`,
+ "-": `
+
+█████
+
+
+ `,
+ "<": ` ██
+ ██
+██
+ ██
+ ██ `,
+ ">": `██
+ ██
+ ██
+ ██
+██ `,
+ "*": `
+▄ ██ ▄
+ ████
+▀ ██ ▀
+ `,
+ "#": ` ██ ██
+████████
+ ██ ██
+████████
+ ██ ██ `,
+ "_": `
+
+
+
+███████ `,
+ ":": `
+██
+
+
+██ `,
+ "°": ` ████
+██ ██
+ ████
+
+ `,
+ },
+}
diff --git a/vendor/github.com/pterm/pterm/box_printer.go b/vendor/github.com/pterm/pterm/box_printer.go
new file mode 100644
index 0000000..750896d
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/box_printer.go
@@ -0,0 +1,363 @@
+package pterm
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/mattn/go-runewidth"
+
+ "github.com/pterm/pterm/internal"
+)
+
+// BoxPrinter is able to render a box around printables.
+type BoxPrinter struct {
+ Title string
+ TitleTopLeft bool
+ TitleTopRight bool
+ TitleTopCenter bool
+ TitleBottomLeft bool
+ TitleBottomRight bool
+ TitleBottomCenter bool
+ TextStyle *Style
+ VerticalString string
+ BoxStyle *Style
+ HorizontalString string
+ TopRightCornerString string
+ TopLeftCornerString string
+ BottomLeftCornerString string
+ BottomRightCornerString string
+ TopPadding int
+ BottomPadding int
+ RightPadding int
+ LeftPadding int
+}
+
+// DefaultBox is the default BoxPrinter.
+var DefaultBox = BoxPrinter{
+ VerticalString: "|",
+ TopRightCornerString: "└",
+ TopLeftCornerString: "┘",
+ BottomLeftCornerString: "┐",
+ BottomRightCornerString: "┌",
+ HorizontalString: "─",
+ BoxStyle: &ThemeDefault.BoxStyle,
+ TextStyle: &ThemeDefault.BoxTextStyle,
+ RightPadding: 1,
+ LeftPadding: 1,
+ TopPadding: 0,
+ BottomPadding: 0,
+ TitleTopLeft: true,
+}
+
+// WithTitle returns a new box with a specific Title.
+func (p BoxPrinter) WithTitle(str string) *BoxPrinter {
+ p.Title = str
+ return &p
+}
+
+// WithTitleTopLeft returns a new box with a specific Title alignment.
+func (p BoxPrinter) WithTitleTopLeft(b ...bool) *BoxPrinter {
+ b2 := internal.WithBoolean(b)
+ p.TitleTopLeft = b2
+ p.TitleTopRight = false
+ p.TitleTopCenter = false
+ p.TitleBottomLeft = false
+ p.TitleBottomRight = false
+ p.TitleBottomCenter = false
+ return &p
+}
+
+// WithTitleTopRight returns a new box with a specific Title alignment.
+func (p BoxPrinter) WithTitleTopRight(b ...bool) *BoxPrinter {
+ b2 := internal.WithBoolean(b)
+ p.TitleTopLeft = false
+ p.TitleTopRight = b2
+ p.TitleTopCenter = false
+ p.TitleBottomLeft = false
+ p.TitleBottomRight = false
+ p.TitleBottomCenter = false
+ return &p
+}
+
+// WithTitleTopCenter returns a new box with a specific Title alignment.
+func (p BoxPrinter) WithTitleTopCenter(b ...bool) *BoxPrinter {
+ b2 := internal.WithBoolean(b)
+ p.TitleTopLeft = false
+ p.TitleTopRight = false
+ p.TitleTopCenter = b2
+ p.TitleBottomLeft = false
+ p.TitleBottomRight = false
+ p.TitleBottomCenter = false
+ return &p
+}
+
+// WithTitleBottomLeft returns a new box with a specific Title alignment.
+func (p BoxPrinter) WithTitleBottomLeft(b ...bool) *BoxPrinter {
+ b2 := internal.WithBoolean(b)
+ p.TitleTopLeft = false
+ p.TitleTopRight = false
+ p.TitleTopCenter = false
+ p.TitleBottomLeft = b2
+ p.TitleBottomRight = false
+ p.TitleBottomCenter = false
+ return &p
+}
+
+// WithTitleBottomRight returns a new box with a specific Title alignment.
+func (p BoxPrinter) WithTitleBottomRight(b ...bool) *BoxPrinter {
+ b2 := internal.WithBoolean(b)
+ p.TitleTopLeft = false
+ p.TitleTopRight = false
+ p.TitleTopCenter = false
+ p.TitleBottomLeft = false
+ p.TitleBottomRight = b2
+ p.TitleBottomCenter = false
+ return &p
+}
+
+// WithTitleBottomCenter returns a new box with a specific Title alignment.
+func (p BoxPrinter) WithTitleBottomCenter(b ...bool) *BoxPrinter {
+ b2 := internal.WithBoolean(b)
+ p.TitleTopLeft = false
+ p.TitleTopRight = false
+ p.TitleTopCenter = false
+ p.TitleBottomLeft = false
+ p.TitleBottomRight = false
+ p.TitleBottomCenter = b2
+ return &p
+}
+
+// WithBoxStyle returns a new box with a specific box Style.
+func (p BoxPrinter) WithBoxStyle(style *Style) *BoxPrinter {
+ p.BoxStyle = style
+ return &p
+}
+
+// WithTextStyle returns a new box with a specific text Style.
+func (p BoxPrinter) WithTextStyle(style *Style) *BoxPrinter {
+ p.TextStyle = style
+ return &p
+}
+
+// WithTopRightCornerString returns a new box with a specific TopRightCornerString.
+func (p BoxPrinter) WithTopRightCornerString(str string) *BoxPrinter {
+ p.TopRightCornerString = str
+ return &p
+}
+
+// WithTopLeftCornerString returns a new box with a specific TopLeftCornerString.
+func (p BoxPrinter) WithTopLeftCornerString(str string) *BoxPrinter {
+ p.TopLeftCornerString = str
+ return &p
+}
+
+// WithBottomRightCornerString returns a new box with a specific BottomRightCornerString.
+func (p BoxPrinter) WithBottomRightCornerString(str string) *BoxPrinter {
+ p.BottomRightCornerString = str
+ return &p
+}
+
+// WithBottomLeftCornerString returns a new box with a specific BottomLeftCornerString.
+func (p BoxPrinter) WithBottomLeftCornerString(str string) *BoxPrinter {
+ p.BottomLeftCornerString = str
+ return &p
+}
+
+// WithVerticalString returns a new box with a specific VerticalString.
+func (p BoxPrinter) WithVerticalString(str string) *BoxPrinter {
+ p.VerticalString = str
+ return &p
+}
+
+// WithHorizontalString returns a new box with a specific HorizontalString.
+func (p BoxPrinter) WithHorizontalString(str string) *BoxPrinter {
+ p.HorizontalString = str
+ return &p
+}
+
+// WithTopPadding returns a new box with a specific TopPadding.
+func (p BoxPrinter) WithTopPadding(padding int) *BoxPrinter {
+ if padding < 0 {
+ padding = 0
+ }
+ p.TopPadding = padding
+ return &p
+}
+
+// WithBottomPadding returns a new box with a specific BottomPadding.
+func (p BoxPrinter) WithBottomPadding(padding int) *BoxPrinter {
+ if padding < 0 {
+ padding = 0
+ }
+ p.BottomPadding = padding
+ return &p
+}
+
+// WithRightPadding returns a new box with a specific RightPadding.
+func (p BoxPrinter) WithRightPadding(padding int) *BoxPrinter {
+ if padding < 0 {
+ padding = 0
+ }
+ p.RightPadding = padding
+ return &p
+}
+
+// WithLeftPadding returns a new box with a specific LeftPadding.
+func (p BoxPrinter) WithLeftPadding(padding int) *BoxPrinter {
+ if padding < 0 {
+ padding = 0
+ }
+ p.LeftPadding = padding
+ return &p
+}
+
+// Sprint formats using the default formats for its operands and returns the resulting string.
+// Spaces are added between operands when neither is a string.
+func (p BoxPrinter) Sprint(a ...interface{}) string {
+ if p.BoxStyle == nil {
+ p.BoxStyle = &ThemeDefault.BoxStyle
+ }
+ if p.TextStyle == nil {
+ p.TextStyle = &ThemeDefault.BoxTextStyle
+ }
+ maxWidth := internal.GetStringMaxWidth(Sprint(a...))
+
+ var topLine string
+ var bottomLine string
+
+ if p.Title == "" {
+ topLine = p.BoxStyle.Sprint(p.BottomRightCornerString) + strings.Repeat(p.BoxStyle.Sprint(p.HorizontalString),
+ maxWidth+p.LeftPadding+p.RightPadding) + p.BoxStyle.Sprint(p.BottomLeftCornerString)
+ bottomLine = p.BoxStyle.Sprint(p.TopRightCornerString) + strings.Repeat(p.BoxStyle.Sprint(p.HorizontalString),
+ maxWidth+p.LeftPadding+p.RightPadding) + p.BoxStyle.Sprint(p.TopLeftCornerString)
+ } else {
+ p.Title = strings.ReplaceAll(p.Title, "\n", " ")
+ if (maxWidth + p.RightPadding + p.LeftPadding - 4) < len(RemoveColorFromString(p.Title)) {
+ p.RightPadding = len(RemoveColorFromString(p.Title)) - (maxWidth + p.RightPadding + p.LeftPadding - 5)
+ }
+ if p.TitleTopLeft {
+ topLine = p.BoxStyle.Sprint(p.BottomRightCornerString) + internal.AddTitleToLine(p.Title, p.BoxStyle.Sprint(p.HorizontalString), maxWidth+p.LeftPadding+p.RightPadding, true) + p.BoxStyle.Sprint(p.BottomLeftCornerString)
+ bottomLine = p.BoxStyle.Sprint(p.TopRightCornerString) + strings.Repeat(p.BoxStyle.Sprint(p.HorizontalString),
+ maxWidth+p.LeftPadding+p.RightPadding) + p.BoxStyle.Sprint(p.TopLeftCornerString)
+ } else if p.TitleTopRight {
+ topLine = p.BoxStyle.Sprint(p.BottomRightCornerString) + internal.AddTitleToLine(p.Title, p.BoxStyle.Sprint(p.HorizontalString), maxWidth+p.LeftPadding+p.RightPadding, false) + p.BoxStyle.Sprint(p.BottomLeftCornerString)
+ bottomLine = p.BoxStyle.Sprint(p.TopRightCornerString) + strings.Repeat(p.BoxStyle.Sprint(p.HorizontalString),
+ maxWidth+p.LeftPadding+p.RightPadding) + p.BoxStyle.Sprint(p.TopLeftCornerString)
+ } else if p.TitleTopCenter {
+ topLine = p.BoxStyle.Sprint(p.BottomRightCornerString) + internal.AddTitleToLineCenter(p.Title, p.BoxStyle.Sprint(p.HorizontalString), maxWidth+p.LeftPadding+p.RightPadding) + p.BoxStyle.Sprint(p.BottomLeftCornerString)
+ bottomLine = p.BoxStyle.Sprint(p.TopRightCornerString) + strings.Repeat(p.BoxStyle.Sprint(p.HorizontalString),
+ maxWidth+p.LeftPadding+p.RightPadding) + p.BoxStyle.Sprint(p.TopLeftCornerString)
+ } else if p.TitleBottomLeft {
+ topLine = p.BoxStyle.Sprint(p.BottomRightCornerString) + strings.Repeat(p.BoxStyle.Sprint(p.HorizontalString),
+ maxWidth+p.LeftPadding+p.RightPadding) + p.BoxStyle.Sprint(p.BottomLeftCornerString)
+ bottomLine = p.BoxStyle.Sprint(p.TopRightCornerString) + internal.AddTitleToLine(p.Title, p.BoxStyle.Sprint(p.HorizontalString), maxWidth+p.LeftPadding+p.RightPadding, true) + p.BoxStyle.Sprint(p.TopLeftCornerString)
+ } else if p.TitleBottomRight {
+ topLine = p.BoxStyle.Sprint(p.BottomRightCornerString) + strings.Repeat(p.BoxStyle.Sprint(p.HorizontalString),
+ maxWidth+p.LeftPadding+p.RightPadding) + p.BoxStyle.Sprint(p.BottomLeftCornerString)
+ bottomLine = p.BoxStyle.Sprint(p.TopRightCornerString) + internal.AddTitleToLine(p.Title, p.BoxStyle.Sprint(p.HorizontalString), maxWidth+p.LeftPadding+p.RightPadding, false) + p.BoxStyle.Sprint(p.TopLeftCornerString)
+ } else if p.TitleBottomCenter {
+ topLine = p.BoxStyle.Sprint(p.BottomRightCornerString) + strings.Repeat(p.BoxStyle.Sprint(p.HorizontalString),
+ maxWidth+p.LeftPadding+p.RightPadding) + p.BoxStyle.Sprint(p.BottomLeftCornerString)
+ bottomLine = p.BoxStyle.Sprint(p.TopRightCornerString) + internal.AddTitleToLineCenter(p.Title, p.BoxStyle.Sprint(p.HorizontalString), maxWidth+p.LeftPadding+p.RightPadding) + p.BoxStyle.Sprint(p.TopLeftCornerString)
+ }
+ }
+
+ boxString := strings.Repeat("\n", p.TopPadding) + Sprint(a...) + strings.Repeat("\n", p.BottomPadding)
+
+ ss := strings.Split(boxString, "\n")
+ for i, s2 := range ss {
+ if runewidth.StringWidth(RemoveColorFromString(s2)) < maxWidth {
+ ss[i] = p.BoxStyle.Sprint(p.VerticalString) + strings.Repeat(" ", p.LeftPadding) + p.TextStyle.Sprint(s2) +
+ strings.Repeat(" ", maxWidth-runewidth.StringWidth(RemoveColorFromString(s2))+p.RightPadding) +
+ p.BoxStyle.Sprint(p.VerticalString)
+ } else {
+ ss[i] = p.BoxStyle.Sprint(p.VerticalString) + strings.Repeat(" ", p.LeftPadding) + p.TextStyle.Sprint(s2) +
+ strings.Repeat(" ", p.RightPadding) + p.BoxStyle.Sprint(p.VerticalString)
+ }
+ }
+ return topLine + "\n" + strings.Join(ss, "\n") + "\n" + bottomLine
+}
+
+// Sprintln formats using the default formats for its operands and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func (p BoxPrinter) Sprintln(a ...interface{}) string {
+ return p.Sprint(strings.TrimSuffix(Sprintln(a...), "\n")) + "\n"
+}
+
+// Sprintf formats according to a format specifier and returns the resulting string.
+func (p BoxPrinter) Sprintf(format string, a ...interface{}) string {
+ return p.Sprint(Sprintf(format, a...))
+}
+
+// Sprintfln formats according to a format specifier and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func (p BoxPrinter) Sprintfln(format string, a ...interface{}) string {
+ return p.Sprintf(format, a...) + "\n"
+}
+
+// Print formats using the default formats for its operands and writes to standard output.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+func (p BoxPrinter) Print(a ...interface{}) *TextPrinter {
+ Print(p.Sprint(a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Println formats using the default formats for its operands and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func (p BoxPrinter) Println(a ...interface{}) *TextPrinter {
+ Print(p.Sprintln(a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
+func (p BoxPrinter) Printf(format string, a ...interface{}) *TextPrinter {
+ Print(p.Sprintf(format, a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Printfln formats according to a format specifier and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func (p BoxPrinter) Printfln(format string, a ...interface{}) *TextPrinter {
+ Print(p.Sprintfln(format, a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// PrintOnError prints every error which is not nil.
+// If every error is nil, nothing will be printed.
+// This can be used for simple error checking.
+func (p BoxPrinter) PrintOnError(a ...interface{}) *TextPrinter {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ p.Println(err)
+ }
+ }
+ }
+
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// PrintOnErrorf wraps every error which is not nil and prints it.
+// If every error is nil, nothing will be printed.
+// This can be used for simple error checking.
+func (p BoxPrinter) PrintOnErrorf(format string, a ...interface{}) *TextPrinter {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ p.Println(fmt.Errorf(format, err))
+ }
+ }
+ }
+
+ tp := TextPrinter(p)
+ return &tp
+}
diff --git a/vendor/github.com/pterm/pterm/bulletlist_printer.go b/vendor/github.com/pterm/pterm/bulletlist_printer.go
new file mode 100644
index 0000000..688023a
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/bulletlist_printer.go
@@ -0,0 +1,143 @@
+package pterm
+
+import (
+ "strings"
+
+ "github.com/pterm/pterm/internal"
+)
+
+// NewBulletListFromStrings returns a BulletListPrinter with Text using the NewTreeListItemFromString method.
+func NewBulletListFromStrings(s []string, padding string) BulletListPrinter {
+ var lis []BulletListItem
+ for _, line := range s {
+ lis = append(lis, NewBulletListItemFromString(line, padding))
+ }
+ return *DefaultBulletList.WithItems(lis)
+}
+
+// NewBulletListItemFromString returns a BulletListItem with a Text. The padding is counted in the Text to define the Level of the ListItem.
+func NewBulletListItemFromString(text string, padding string) BulletListItem {
+ s, l := internal.RemoveAndCountPrefix(text, padding)
+ return BulletListItem{
+ Level: l,
+ Text: s,
+ }
+}
+
+// BulletListItem is able to render a ListItem.
+type BulletListItem struct {
+ Level int
+ Text string
+ TextStyle *Style
+ Bullet string
+ BulletStyle *Style
+}
+
+// WithLevel returns a new BulletListItem with a specific Level.
+func (p BulletListItem) WithLevel(level int) *BulletListItem {
+ p.Level = level
+ return &p
+}
+
+// WithText returns a new BulletListItem with a specific Text.
+func (p BulletListItem) WithText(text string) *BulletListItem {
+ p.Text = text
+ return &p
+}
+
+// WithTextStyle returns a new BulletListItem with a specific TextStyle.
+func (p BulletListItem) WithTextStyle(style *Style) *BulletListItem {
+ p.TextStyle = style
+ return &p
+}
+
+// WithBullet returns a new BulletListItem with a specific Prefix.
+func (p BulletListItem) WithBullet(bullet string) *BulletListItem {
+ p.Bullet = bullet
+ return &p
+}
+
+// WithBulletStyle returns a new BulletListItem with a specific BulletStyle.
+func (p BulletListItem) WithBulletStyle(style *Style) *BulletListItem {
+ p.BulletStyle = style
+ return &p
+}
+
+// NewBulletListFromString returns a BulletListPrinter with Text using the NewTreeListItemFromString method, splitting after return (\n).
+func NewBulletListFromString(s string, padding string) BulletListPrinter {
+ return NewBulletListFromStrings(strings.Split(s, "\n"), padding)
+}
+
+// DefaultBulletList contains standards, which can be used to print a BulletListPrinter.
+var DefaultBulletList = BulletListPrinter{
+ Bullet: "•",
+ TextStyle: &ThemeDefault.BulletListTextStyle,
+ BulletStyle: &ThemeDefault.BulletListBulletStyle,
+}
+
+// BulletListPrinter is able to render a list.
+type BulletListPrinter struct {
+ Items []BulletListItem
+ TextStyle *Style
+ Bullet string
+ BulletStyle *Style
+}
+
+// WithItems returns a new list with specific Items.
+func (l BulletListPrinter) WithItems(items []BulletListItem) *BulletListPrinter {
+ l.Items = append(l.Items, items...)
+ return &l
+}
+
+// WithTextStyle returns a new list with a specific text style.
+func (l BulletListPrinter) WithTextStyle(style *Style) *BulletListPrinter {
+ l.TextStyle = style
+ return &l
+}
+
+// WithBullet returns a new list with a specific bullet.
+func (l BulletListPrinter) WithBullet(bullet string) *BulletListPrinter {
+ l.Bullet = bullet
+ return &l
+}
+
+// WithBulletStyle returns a new list with a specific bullet style.
+func (l BulletListPrinter) WithBulletStyle(style *Style) *BulletListPrinter {
+ l.BulletStyle = style
+ return &l
+}
+
+// Render prints the list to the terminal.
+func (l BulletListPrinter) Render() error {
+ s, _ := l.Srender()
+ Println(s)
+
+ return nil
+}
+
+// Srender renders the list as a string.
+func (l BulletListPrinter) Srender() (string, error) {
+ var ret string
+ for _, item := range l.Items {
+ if item.TextStyle == nil {
+ if l.TextStyle == nil {
+ item.TextStyle = &ThemeDefault.BulletListTextStyle
+ } else {
+ item.TextStyle = l.TextStyle
+ }
+ }
+ if item.BulletStyle == nil {
+ if l.BulletStyle == nil {
+ item.BulletStyle = &ThemeDefault.BulletListBulletStyle
+ } else {
+ item.BulletStyle = l.BulletStyle
+ }
+ }
+ if item.Bullet == "" {
+ ret += strings.Repeat(" ", item.Level) + item.BulletStyle.Sprint(l.Bullet) + " " + item.TextStyle.Sprint(item.Text) + "\n"
+ } else {
+ ret += strings.Repeat(" ", item.Level) + item.BulletStyle.Sprint(item.Bullet) + " " + item.TextStyle.Sprint(item.Text) + "\n"
+ }
+ }
+ return ret, nil
+}
diff --git a/vendor/github.com/pterm/pterm/center_printer.go b/vendor/github.com/pterm/pterm/center_printer.go
new file mode 100644
index 0000000..78411de
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/center_printer.go
@@ -0,0 +1,160 @@
+package pterm
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/mattn/go-runewidth"
+
+ "github.com/pterm/pterm/internal"
+)
+
+// DefaultCenter is the default CenterPrinter.
+var DefaultCenter = CenterPrinter{
+ CenterEachLineSeparately: false,
+}
+
+// CenterPrinter prints centered text.
+type CenterPrinter struct {
+ CenterEachLineSeparately bool
+}
+
+// WithCenterEachLineSeparately centers each line separately.
+func (p CenterPrinter) WithCenterEachLineSeparately(b ...bool) *CenterPrinter {
+ bt := internal.WithBoolean(b)
+ p.CenterEachLineSeparately = bt
+ return &p
+}
+
+// Sprint formats using the default formats for its operands and returns the resulting string.
+// Spaces are added between operands when neither is a string.
+func (p CenterPrinter) Sprint(a ...interface{}) string {
+ if RawOutput {
+ return Sprint(a...)
+ }
+
+ lines := strings.Split(Sprint(a...), "\n")
+
+ var ret string
+
+ if p.CenterEachLineSeparately {
+ for _, line := range lines {
+ margin := (GetTerminalWidth() - runewidth.StringWidth(RemoveColorFromString(line))) / 2
+ if margin < 1 {
+ ret += line + "\n"
+ } else {
+ ret += strings.Repeat(" ", margin) + line + "\n"
+ }
+ }
+ return ret
+ }
+
+ var maxLineWidth int
+
+ for _, line := range lines {
+ lineLength := runewidth.StringWidth(RemoveColorFromString(line))
+ if maxLineWidth < lineLength {
+ maxLineWidth = lineLength
+ }
+ }
+
+ indent := GetTerminalWidth() - maxLineWidth
+
+ if indent/2 < 1 {
+ for _, line := range lines {
+ ret += line + "\n"
+ }
+
+ return ret
+ }
+
+ for _, line := range lines {
+ ret += strings.Repeat(" ", indent/2) + line + "\n"
+ }
+
+ return ret
+}
+
+// Sprintln formats using the default formats for its operands and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func (p CenterPrinter) Sprintln(a ...interface{}) string {
+ return p.Sprint(Sprintln(a...))
+}
+
+// Sprintf formats according to a format specifier and returns the resulting string.
+func (p CenterPrinter) Sprintf(format string, a ...interface{}) string {
+ return p.Sprint(Sprintf(format, a...))
+}
+
+// Sprintfln formats according to a format specifier and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func (p CenterPrinter) Sprintfln(format string, a ...interface{}) string {
+ return p.Sprintf(format, a...) + "\n"
+}
+
+// Print formats using the default formats for its operands and writes to standard output.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+func (p CenterPrinter) Print(a ...interface{}) *TextPrinter {
+ Print(p.Sprint(a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Println formats using the default formats for its operands and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func (p CenterPrinter) Println(a ...interface{}) *TextPrinter {
+ Print(p.Sprintln(a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
+func (p CenterPrinter) Printf(format string, a ...interface{}) *TextPrinter {
+ Print(p.Sprintf(format, a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Printfln formats according to a format specifier and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func (p CenterPrinter) Printfln(format string, a ...interface{}) *TextPrinter {
+ Print(p.Sprintfln(format, a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// PrintOnError prints every error which is not nil.
+// If every error is nil, nothing will be printed.
+// This can be used for simple error checking.
+func (p CenterPrinter) PrintOnError(a ...interface{}) *TextPrinter {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ p.Println(err)
+ }
+ }
+ }
+
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// PrintOnErrorf wraps every error which is not nil and prints it.
+// If every error is nil, nothing will be printed.
+// This can be used for simple error checking.
+func (p CenterPrinter) PrintOnErrorf(format string, a ...interface{}) *TextPrinter {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ p.Println(fmt.Errorf(format, err))
+ }
+ }
+ }
+
+ tp := TextPrinter(p)
+ return &tp
+}
diff --git a/vendor/github.com/pterm/pterm/color.go b/vendor/github.com/pterm/pterm/color.go
new file mode 100644
index 0000000..b1ef19b
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/color.go
@@ -0,0 +1,361 @@
+package pterm
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/gookit/color"
+)
+
+// PrintColor is false if PTerm should not print colored output.
+var PrintColor = true
+
+// EnableColor enables colors.
+func EnableColor() {
+ color.Enable = true
+ PrintColor = true
+}
+
+// DisableColor disables colors.
+func DisableColor() {
+ color.Enable = false
+ PrintColor = false
+}
+
+// Foreground colors. basic foreground colors 30 - 37.
+const (
+ FgBlack Color = iota + 30
+ FgRed
+ FgGreen
+ FgYellow
+ FgBlue
+ FgMagenta
+ FgCyan
+ FgWhite
+ // FgDefault revert default FG.
+ FgDefault Color = 39
+)
+
+// Extra foreground color 90 - 97.
+const (
+ FgDarkGray Color = iota + 90
+ FgLightRed
+ FgLightGreen
+ FgLightYellow
+ FgLightBlue
+ FgLightMagenta
+ FgLightCyan
+ FgLightWhite
+ // FgGray is an alias of FgDarkGray.
+ FgGray Color = 90
+)
+
+// Background colors. basic background colors 40 - 47.
+const (
+ BgBlack Color = iota + 40
+ BgRed
+ BgGreen
+ BgYellow // BgBrown like yellow
+ BgBlue
+ BgMagenta
+ BgCyan
+ BgWhite
+ // BgDefault reverts to the default background.
+ BgDefault Color = 49
+)
+
+// Extra background color 100 - 107.
+const (
+ BgDarkGray Color = iota + 100
+ BgLightRed
+ BgLightGreen
+ BgLightYellow
+ BgLightBlue
+ BgLightMagenta
+ BgLightCyan
+ BgLightWhite
+ // BgGray is an alias of BgDarkGray.
+ BgGray Color = 100
+)
+
+// Option settings.
+const (
+ Reset Color = iota
+ Bold
+ Fuzzy
+ Italic
+ Underscore
+ Blink
+ FastBlink
+ Reverse
+ Concealed
+ Strikethrough
+)
+
+var (
+ // Red is an alias for FgRed.Sprint.
+ Red = FgRed.Sprint
+ // Cyan is an alias for FgCyan.Sprint.
+ Cyan = FgCyan.Sprint
+ // Gray is an alias for FgGray.Sprint.
+ Gray = FgGray.Sprint
+ // Blue is an alias for FgBlue.Sprint.
+ Blue = FgBlue.Sprint
+ // Black is an alias for FgBlack.Sprint.
+ Black = FgBlack.Sprint
+ // Green is an alias for FgGreen.Sprint.
+ Green = FgGreen.Sprint
+ // White is an alias for FgWhite.Sprint.
+ White = FgWhite.Sprint
+ // Yellow is an alias for FgYellow.Sprint.
+ Yellow = FgYellow.Sprint
+ // Magenta is an alias for FgMagenta.Sprint.
+ Magenta = FgMagenta.Sprint
+
+ // Normal is an alias for FgDefault.Sprint.
+ Normal = FgDefault.Sprint
+
+ // extra light.
+
+ // LightRed is a shortcut for FgLightRed.Sprint.
+ LightRed = FgLightRed.Sprint
+ // LightCyan is a shortcut for FgLightCyan.Sprint.
+ LightCyan = FgLightCyan.Sprint
+ // LightBlue is a shortcut for FgLightBlue.Sprint.
+ LightBlue = FgLightBlue.Sprint
+ // LightGreen is a shortcut for FgLightGreen.Sprint.
+ LightGreen = FgLightGreen.Sprint
+ // LightWhite is a shortcut for FgLightWhite.Sprint.
+ LightWhite = FgLightWhite.Sprint
+ // LightYellow is a shortcut for FgLightYellow.Sprint.
+ LightYellow = FgLightYellow.Sprint
+ // LightMagenta is a shortcut for FgLightMagenta.Sprint.
+ LightMagenta = FgLightMagenta.Sprint
+)
+
+// Color is a number which will be used to color strings in the terminal.
+type Color uint8
+
+// Sprintln formats using the default formats for its operands and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+// Input will be colored with the parent Color.
+func (c Color) Sprintln(a ...interface{}) string {
+ str := fmt.Sprintln(a...)
+ return c.Sprint(str)
+}
+
+// Sprint formats using the default formats for its operands and returns the resulting string.
+// Spaces are added between operands when neither is a string.
+// Input will be colored with the parent Color.
+func (c Color) Sprint(a ...interface{}) string {
+ message := Sprint(a...)
+ messageLines := strings.Split(message, "\n")
+ for i, line := range messageLines {
+ messageLines[i] = color.RenderCode(c.String(), strings.ReplaceAll(line, color.ResetSet, Sprintf("\x1b[0m\u001B[%sm", c.String())))
+ }
+ message = strings.Join(messageLines, "\n")
+ return message
+}
+
+// Sprintf formats according to a format specifier and returns the resulting string.
+// Input will be colored with the parent Color.
+func (c Color) Sprintf(format string, a ...interface{}) string {
+ return c.Sprint(Sprintf(format, a...))
+}
+
+// Sprintfln formats according to a format specifier and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+// Input will be colored with the parent Color.
+func (c Color) Sprintfln(format string, a ...interface{}) string {
+ return c.Sprint(Sprintf(format, a...) + "\n")
+}
+
+// Println formats using the default formats for its operands and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+// Input will be colored with the parent Color.
+func (c Color) Println(a ...interface{}) *TextPrinter {
+ Print(c.Sprintln(a...))
+ tc := TextPrinter(c)
+ return &tc
+}
+
+// Print formats using the default formats for its operands and writes to standard output.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+// Input will be colored with the parent Color.
+func (c Color) Print(a ...interface{}) *TextPrinter {
+ Print(c.Sprint(a...))
+ tc := TextPrinter(c)
+ return &tc
+}
+
+// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
+// Input will be colored with the parent Color.
+func (c Color) Printf(format string, a ...interface{}) *TextPrinter {
+ Print(c.Sprintf(format, a...))
+ tc := TextPrinter(c)
+ return &tc
+}
+
+// Printfln formats according to a format specifier and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+// Input will be colored with the parent Color.
+func (c Color) Printfln(format string, a ...interface{}) *TextPrinter {
+ Print(c.Sprintfln(format, a...))
+ tp := TextPrinter(c)
+ return &tp
+}
+
+// PrintOnError prints every error which is not nil.
+// If every error is nil, nothing will be printed.
+// This can be used for simple error checking.
+func (p Color) PrintOnError(a ...interface{}) *TextPrinter {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ p.Println(err)
+ }
+ }
+ }
+
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// PrintOnErrorf wraps every error which is not nil and prints it.
+// If every error is nil, nothing will be printed.
+// This can be used for simple error checking.
+func (p Color) PrintOnErrorf(format string, a ...interface{}) *TextPrinter {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ p.Println(fmt.Errorf(format, err))
+ }
+ }
+ }
+
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// String converts the color to a string. eg "35".
+func (c Color) String() string {
+ return fmt.Sprintf("%d", c)
+}
+
+// Style is a collection of colors.
+// Can include foreground, background and styling (eg. Bold, Underscore, etc.) colors.
+type Style []Color
+
+// NewStyle returns a new Style.
+// Accepts multiple colors.
+func NewStyle(colors ...Color) *Style {
+ ret := Style{}
+ for _, c := range colors {
+ ret = append(ret, c)
+ }
+ return &ret
+}
+
+// Add styles to the current Style.
+func (s Style) Add(styles ...Style) Style {
+ ret := s
+
+ for _, st := range styles {
+ ret = append(ret, st...)
+ }
+
+ return ret
+}
+
+// Sprint formats using the default formats for its operands and returns the resulting string.
+// Spaces are added between operands when neither is a string.
+// Input will be colored with the parent Style.
+func (s Style) Sprint(a ...interface{}) string {
+ message := Sprint(a...)
+ messageLines := strings.Split(message, "\n")
+ for i, line := range messageLines {
+ messageLines[i] = color.RenderCode(s.String(), strings.ReplaceAll(line, color.ResetSet, Sprintf("\x1b[0m\u001B[%sm", s.String())))
+ }
+ message = strings.Join(messageLines, "\n")
+ return color.RenderCode(s.String(), message)
+}
+
+// Sprintln formats using the default formats for its operands and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+// Input will be colored with the parent Style.
+func (s Style) Sprintln(a ...interface{}) string {
+ return s.Sprint(a...) + "\n"
+}
+
+// Sprintf formats according to a format specifier and returns the resulting string.
+// Input will be colored with the parent Style.
+func (s Style) Sprintf(format string, a ...interface{}) string {
+ return s.Sprint(Sprintf(format, a...))
+}
+
+// Sprintfln formats according to a format specifier and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+// Input will be colored with the parent Style.
+func (s Style) Sprintfln(format string, a ...interface{}) string {
+ return s.Sprint(Sprintf(format, a...) + "\n")
+}
+
+// Print formats using the default formats for its operands and writes to standard output.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+// Input will be colored with the parent Style.
+func (s Style) Print(a ...interface{}) {
+ Print(s.Sprint(a...))
+}
+
+// Println formats using the default formats for its operands and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+// Input will be colored with the parent Style.
+func (s Style) Println(a ...interface{}) {
+ Println(s.Sprint(a...))
+}
+
+// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
+// Input will be colored with the parent Style.
+func (s Style) Printf(format string, a ...interface{}) {
+ Print(s.Sprintf(format, a...))
+}
+
+// Printfln formats according to a format specifier and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+// Input will be colored with the parent Style.
+func (s Style) Printfln(format string, a ...interface{}) {
+ Print(s.Sprintfln(format, a...))
+}
+
+// Code convert to code string. returns like "32;45;3".
+func (s Style) Code() string {
+ return s.String()
+}
+
+// String convert to code string. returns like "32;45;3".
+func (s Style) String() string {
+ return colors2code(s...)
+}
+
+// Converts colors to code.
+// Return format: "32;45;3".
+func colors2code(colors ...Color) string {
+ if len(colors) == 0 {
+ return ""
+ }
+
+ var codes []string
+ for _, c := range colors {
+ codes = append(codes, c.String())
+ }
+
+ return strings.Join(codes, ";")
+}
diff --git a/vendor/github.com/pterm/pterm/conventionalcommit.json b/vendor/github.com/pterm/pterm/conventionalcommit.json
new file mode 100644
index 0000000..adfae9b
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/conventionalcommit.json
@@ -0,0 +1,61 @@
+{
+ "types": {
+ "refactor": {
+ "description": "Changes which neither fix a bug nor add a feature",
+ },
+ "fix": {
+ "description": "Changes which patch a bug"
+ },
+ "feat": {
+ "description": "Changes which introduce a new feature"
+ },
+ "build": {
+ "description": "Changes which affect the build system or external dependencies (example scopes: gulp, broccoli, npm)"
+ },
+ "chore": {
+ "description": "Changes which aren’t user-facing"
+ },
+ "style": {
+ "description": "Changes which don't affect code logic.\nWhite-spaces, formatting, missing semi-colons, etc"
+ },
+ "test": {
+ "description": "Changes which add missing tests or correct existing tests"
+ },
+ "docs": {
+ "description": "Changes which affect documentation",
+ "scopes": {
+ "pterm-sh": {},
+ "examples": {},
+ "readme": {},
+ "contributing": {}
+ }
+ },
+ "perf": {
+ "description": "Changes which improve performance"
+ },
+ "ci": {
+ "description": "Changes which affect CI configuration files and scripts (example scopes: travis, circle, browser-stack, sauce-labs)"
+ },
+ "revert": {
+ "description": "Changes which revert a previous commit"
+ }
+ },
+ "footerTypes": [
+ {
+ "name": "BREAKING CHANGE",
+ "description": "The commit introduces breaking API changes"
+ },
+ {
+ "name": "Closes",
+ "description": "The commit closes issues or pull requests"
+ },
+ {
+ "name": "Implements",
+ "description": "The commit implements features"
+ },
+ {
+ "name": "Co-authored-by",
+ "description": "The commit is co-authored by another person (for multiple people use one line each)"
+ }
+ ]
+}
diff --git a/vendor/github.com/pterm/pterm/errors.go b/vendor/github.com/pterm/pterm/errors.go
new file mode 100644
index 0000000..a7d6fcc
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/errors.go
@@ -0,0 +1,11 @@
+package pterm
+
+import "errors"
+
+var (
+ // ErrTerminalSizeNotDetectable - the terminal size can not be detected and the fallback values are used.
+ ErrTerminalSizeNotDetectable = errors.New("terminal size could not be detected - using fallback value")
+
+ // ErrHexCodeIsInvalid - the given HEX code is invalid.
+ ErrHexCodeIsInvalid = errors.New("hex code is not valid")
+)
diff --git a/vendor/github.com/pterm/pterm/go.mod b/vendor/github.com/pterm/pterm/go.mod
new file mode 100644
index 0000000..6f26e18
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/go.mod
@@ -0,0 +1,11 @@
+module github.com/pterm/pterm
+
+go 1.15
+
+require (
+ github.com/MarvinJWendt/testza v0.2.12
+ github.com/atomicgo/cursor v0.0.1
+ github.com/gookit/color v1.4.2
+ github.com/mattn/go-runewidth v0.0.13
+ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
+)
diff --git a/vendor/github.com/pterm/pterm/go.sum b/vendor/github.com/pterm/pterm/go.sum
new file mode 100644
index 0000000..34d9cdd
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/go.sum
@@ -0,0 +1,46 @@
+github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs=
+github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8=
+github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII=
+github.com/MarvinJWendt/testza v0.2.10/go.mod h1:pd+VWsoGUiFtq+hRKSU1Bktnn+DMCSrDrXDpX2bG66k=
+github.com/MarvinJWendt/testza v0.2.12 h1:/PRp/BF+27t2ZxynTiqj0nyND5PbOtfJS0SuTuxmgeg=
+github.com/MarvinJWendt/testza v0.2.12/go.mod h1:JOIegYyV7rX+7VZ9r77L/eH6CfJHHzXjB69adAhzZkI=
+github.com/atomicgo/cursor v0.0.1 h1:xdogsqa6YYlLfM+GyClC/Lchf7aiMerFiZQn7soTOoU=
+github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk=
+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/gookit/color v1.4.2 h1:tXy44JFSFkKnELV6WaMo/lLfu/meqITX3iAV52do7lk=
+github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
+github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
+github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
+github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI=
+github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg=
+github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE=
+github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEejaWgXU=
+github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE=
+github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
+github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211013075003-97ac67df715c h1:taxlMj0D/1sOAuv/CbSD+MMDof2vbyPTqz5FNYKpXt8=
+golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/vendor/github.com/pterm/pterm/header_printer.go b/vendor/github.com/pterm/pterm/header_printer.go
new file mode 100644
index 0000000..ce677fe
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/header_printer.go
@@ -0,0 +1,228 @@
+package pterm
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/mattn/go-runewidth"
+
+ "github.com/pterm/pterm/internal"
+)
+
+var (
+ // DefaultHeader returns the printer for a default header text.
+ // Defaults to LightWhite, Bold Text and a Gray DefaultHeader background.
+ DefaultHeader = HeaderPrinter{
+ TextStyle: &ThemeDefault.HeaderTextStyle,
+ BackgroundStyle: &ThemeDefault.HeaderBackgroundStyle,
+ Margin: 5,
+ }
+)
+
+// HeaderPrinter contains the data used to craft a header.
+// A header is printed as a big box with text in it.
+// Can be used as title screens or section separator.
+type HeaderPrinter struct {
+ TextStyle *Style
+ BackgroundStyle *Style
+ Margin int
+ FullWidth bool
+}
+
+// WithTextStyle returns a new HeaderPrinter with changed
+func (p HeaderPrinter) WithTextStyle(style *Style) *HeaderPrinter {
+ p.TextStyle = style
+ return &p
+}
+
+// WithBackgroundStyle changes the background styling of the header.
+func (p HeaderPrinter) WithBackgroundStyle(style *Style) *HeaderPrinter {
+ p.BackgroundStyle = style
+ return &p
+}
+
+// WithMargin changes the background styling of the header.
+func (p HeaderPrinter) WithMargin(margin int) *HeaderPrinter {
+ p.Margin = margin
+ return &p
+}
+
+// WithFullWidth enables full width on a HeaderPrinter.
+func (p HeaderPrinter) WithFullWidth(b ...bool) *HeaderPrinter {
+ p.FullWidth = internal.WithBoolean(b)
+ return &p
+}
+
+// Sprint formats using the default formats for its operands and returns the resulting string.
+// Spaces are added between operands when neither is a string.
+func (p HeaderPrinter) Sprint(a ...interface{}) string {
+ if RawOutput {
+ return Sprint(a...)
+ }
+
+ if p.TextStyle == nil {
+ p.TextStyle = NewStyle()
+ }
+ if p.BackgroundStyle == nil {
+ p.BackgroundStyle = NewStyle()
+ }
+
+ text := Sprint(a...)
+
+ var blankLine string
+
+ longestLine := internal.ReturnLongestLine(text, "\n")
+ longestLineLen := runewidth.StringWidth(RemoveColorFromString(longestLine)) + p.Margin*2
+
+ if p.FullWidth {
+ text = splitText(text, GetTerminalWidth()-p.Margin*2)
+ blankLine = strings.Repeat(" ", GetTerminalWidth())
+ } else {
+ if longestLineLen > GetTerminalWidth() {
+ text = splitText(text, GetTerminalWidth()-p.Margin*2)
+ blankLine = strings.Repeat(" ", GetTerminalWidth())
+ } else {
+ text = splitText(text, longestLineLen-p.Margin*2)
+ blankLine = strings.Repeat(" ", longestLineLen)
+ }
+ }
+
+ var marginString string
+ var ret string
+
+ if p.FullWidth {
+ longestLineLen = runewidth.StringWidth(RemoveColorFromString(internal.ReturnLongestLine(text, "\n")))
+ marginString = strings.Repeat(" ", (GetTerminalWidth()-longestLineLen)/2)
+ } else {
+ marginString = strings.Repeat(" ", p.Margin)
+ }
+
+ ret += p.BackgroundStyle.Sprint(blankLine) + "\n"
+ for _, line := range strings.Split(text, "\n") {
+ line = strings.ReplaceAll(line, "\n", "")
+ line = marginString + line + marginString
+ if runewidth.StringWidth(line) < runewidth.StringWidth(blankLine) {
+ line += strings.Repeat(" ", runewidth.StringWidth(blankLine)-runewidth.StringWidth(line))
+ }
+ ret += p.BackgroundStyle.Sprint(p.TextStyle.Sprint(line)) + "\n"
+ }
+ ret += p.BackgroundStyle.Sprint(blankLine) + "\n"
+
+ return ret
+}
+
+func splitText(text string, width int) string {
+ var lines []string
+ linesTmp := strings.Split(text, "\n")
+ for _, line := range linesTmp {
+ if runewidth.StringWidth(RemoveColorFromString(line)) > width {
+ extraLines := []string{""}
+ extraLinesCounter := 0
+ for i, letter := range line {
+ if i%width == 0 && i != 0 {
+ extraLinesCounter++
+ extraLines = append(extraLines, "")
+ }
+ extraLines[extraLinesCounter] += string(letter)
+ }
+ for _, extraLine := range extraLines {
+ extraLine += "\n"
+ lines = append(lines, extraLine)
+ }
+ } else {
+ line += "\n"
+ lines = append(lines, line)
+ }
+ }
+
+ var line string
+ for _, s := range lines {
+ line += s
+ }
+
+ return strings.TrimSuffix(line, "\n")
+}
+
+// Sprintln formats using the default formats for its operands and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func (p HeaderPrinter) Sprintln(a ...interface{}) string {
+ return p.Sprint(strings.TrimSuffix(Sprintln(a...), "\n"))
+}
+
+// Sprintf formats according to a format specifier and returns the resulting string.
+func (p HeaderPrinter) Sprintf(format string, a ...interface{}) string {
+ return p.Sprint(Sprintf(format, a...))
+}
+
+// Sprintfln formats according to a format specifier and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func (p HeaderPrinter) Sprintfln(format string, a ...interface{}) string {
+ return p.Sprintf(format, a...) + "\n"
+}
+
+// Print formats using the default formats for its operands and writes to standard output.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+func (p *HeaderPrinter) Print(a ...interface{}) *TextPrinter {
+ Print(p.Sprint(a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Println formats using the default formats for its operands and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func (p *HeaderPrinter) Println(a ...interface{}) *TextPrinter {
+ Print(p.Sprintln(a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
+func (p *HeaderPrinter) Printf(format string, a ...interface{}) *TextPrinter {
+ Print(p.Sprintf(format, a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Printfln formats according to a format specifier and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func (p *HeaderPrinter) Printfln(format string, a ...interface{}) *TextPrinter {
+ Print(p.Sprintfln(format, a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// PrintOnError prints every error which is not nil.
+// If every error is nil, nothing will be printed.
+// This can be used for simple error checking.
+func (p *HeaderPrinter) PrintOnError(a ...interface{}) *TextPrinter {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ p.Println(err)
+ }
+ }
+ }
+
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// PrintOnErrorf wraps every error which is not nil and prints it.
+// If every error is nil, nothing will be printed.
+// This can be used for simple error checking.
+func (p *HeaderPrinter) PrintOnErrorf(format string, a ...interface{}) *TextPrinter {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ p.Println(fmt.Errorf(format, err))
+ }
+ }
+ }
+
+ tp := TextPrinter(p)
+ return &tp
+}
diff --git a/vendor/github.com/pterm/pterm/interface_live_printer.go b/vendor/github.com/pterm/pterm/interface_live_printer.go
new file mode 100644
index 0000000..b8d3dbe
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/interface_live_printer.go
@@ -0,0 +1,14 @@
+package pterm
+
+// LivePrinter is a printer which can update it's output live.
+type LivePrinter interface {
+ // GenericStart runs Start, but returns a LivePrinter.
+ // This is used for the interface LivePrinter.
+ // You most likely want to use Start instead of this in your program.
+ GenericStart() (*LivePrinter, error)
+
+ // GenericStop runs Stop, but returns a LivePrinter.
+ // This is used for the interface LivePrinter.
+ // You most likely want to use Stop instead of this in your program.
+ GenericStop() (*LivePrinter, error)
+}
diff --git a/vendor/github.com/pterm/pterm/interface_renderable_printer.go b/vendor/github.com/pterm/pterm/interface_renderable_printer.go
new file mode 100644
index 0000000..d2089b9
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/interface_renderable_printer.go
@@ -0,0 +1,11 @@
+package pterm
+
+// RenderPrinter is used to display renderable content.
+// Example for renderable content is a Table.
+type RenderPrinter interface {
+ // Render the XXX to the terminal.
+ Render() error
+
+ // Srender returns the rendered string of XXX.
+ Srender() (string, error)
+}
diff --git a/vendor/github.com/pterm/pterm/interface_text_printer.go b/vendor/github.com/pterm/pterm/interface_text_printer.go
new file mode 100644
index 0000000..ca45f65
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/interface_text_printer.go
@@ -0,0 +1,48 @@
+package pterm
+
+// TextPrinter contains methods to print formatted text to the console or return it as a string.
+type TextPrinter interface {
+ // Sprint formats using the default formats for its operands and returns the resulting string.
+ // Spaces are added between operands when neither is a string.
+ Sprint(a ...interface{}) string
+
+ // Sprintln formats using the default formats for its operands and returns the resulting string.
+ // Spaces are always added between operands and a newline is appended.
+ Sprintln(a ...interface{}) string
+
+ // Sprintf formats according to a format specifier and returns the resulting string.
+ Sprintf(format string, a ...interface{}) string
+
+ // Sprintfln formats according to a format specifier and returns the resulting string.
+ // Spaces are always added between operands and a newline is appended.
+ Sprintfln(format string, a ...interface{}) string
+
+ // Print formats using the default formats for its operands and writes to standard output.
+ // Spaces are added between operands when neither is a string.
+ // It returns the number of bytes written and any write error encountered.
+ Print(a ...interface{}) *TextPrinter
+
+ // Println formats using the default formats for its operands and writes to standard output.
+ // Spaces are always added between operands and a newline is appended.
+ // It returns the number of bytes written and any write error encountered.
+ Println(a ...interface{}) *TextPrinter
+
+ // Printf formats according to a format specifier and writes to standard output.
+ // It returns the number of bytes written and any write error encountered.
+ Printf(format string, a ...interface{}) *TextPrinter
+
+ // Printfln formats according to a format specifier and writes to standard output.
+ // Spaces are always added between operands and a newline is appended.
+ // It returns the number of bytes written and any write error encountered.
+ Printfln(format string, a ...interface{}) *TextPrinter
+
+ // PrintOnError prints every error which is not nil.
+ // If every error is nil, nothing will be printed.
+ // This can be used for simple error checking.
+ PrintOnError(a ...interface{}) *TextPrinter
+
+ // PrintOnErrorf wraps every error which is not nil and prints it.
+ // If every error is nil, nothing will be printed.
+ // This can be used for simple error checking.
+ PrintOnErrorf(format string, a ...interface{}) *TextPrinter
+}
diff --git a/vendor/github.com/pterm/pterm/internal/center_text.go b/vendor/github.com/pterm/pterm/internal/center_text.go
new file mode 100644
index 0000000..79ebb94
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/internal/center_text.go
@@ -0,0 +1,42 @@
+package internal
+
+import (
+ "strings"
+
+ "github.com/gookit/color"
+)
+
+// CenterText returns a centered string with a padding left and right
+func CenterText(text string, width int) string {
+ var lines []string
+ linesTmp := strings.Split(text, "\n")
+ for _, line := range linesTmp {
+ if len(color.ClearCode(line)) > width {
+ extraLines := []string{""}
+ extraLinesCounter := 0
+ for i, letter := range line {
+ if i%width == 0 && i != 0 {
+ extraLinesCounter++
+ extraLines = append(extraLines, "")
+ }
+ extraLines[extraLinesCounter] += string(letter)
+ }
+ for _, extraLine := range extraLines {
+ padding := width - len(color.ClearCode(extraLine))
+ extraLine = strings.Repeat(" ", padding/2) + extraLine + strings.Repeat(" ", padding/2) + "\n"
+ lines = append(lines, extraLine)
+ }
+ } else {
+ padding := width - len(color.ClearCode(line))
+ line = strings.Repeat(" ", padding/2) + line + strings.Repeat(" ", padding/2) + "\n"
+ lines = append(lines, line)
+ }
+ }
+
+ var line string
+ for _, s := range lines {
+ line += s
+ }
+
+ return strings.TrimSuffix(line, "\n")
+}
diff --git a/vendor/github.com/pterm/pterm/internal/collection.go b/vendor/github.com/pterm/pterm/internal/collection.go
new file mode 100644
index 0000000..b19f0ea
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/internal/collection.go
@@ -0,0 +1,7 @@
+package internal
+
+// RandomStrings contains a list of random strings to use while testing.
+var RandomStrings = []string{
+ "hello world", "²³14234!`§=)$-.€@_&", "This is a sentence.", "This\nstring\nhas\nmultiple\nlines",
+ "windows\r\nline\r\nendings", "\rtext",
+}
diff --git a/vendor/github.com/pterm/pterm/internal/longest_line.go b/vendor/github.com/pterm/pterm/internal/longest_line.go
new file mode 100644
index 0000000..a00e486
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/internal/longest_line.go
@@ -0,0 +1,21 @@
+package internal
+
+import (
+ "strings"
+
+ "github.com/gookit/color"
+ "github.com/mattn/go-runewidth"
+)
+
+// ReturnLongestLine returns the longest line with a given separator
+func ReturnLongestLine(text, sep string) string {
+ lines := strings.Split(text, sep)
+ var longest string
+ for _, line := range lines {
+ if runewidth.StringWidth(color.ClearCode(line)) > runewidth.StringWidth(color.ClearCode(longest)) {
+ longest = line
+ }
+ }
+
+ return longest
+}
diff --git a/vendor/github.com/pterm/pterm/internal/map_range_to_range.go b/vendor/github.com/pterm/pterm/internal/map_range_to_range.go
new file mode 100644
index 0000000..4673b11
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/internal/map_range_to_range.go
@@ -0,0 +1,8 @@
+package internal
+
+func MapRangeToRange(fromMin, fromMax, toMin, toMax, current float32) int {
+ if fromMax-fromMin == 0 {
+ return 0
+ }
+ return int(toMin + ((toMax-toMin)/(fromMax-fromMin))*(current-fromMin))
+}
diff --git a/vendor/github.com/pterm/pterm/internal/max_text_width.go b/vendor/github.com/pterm/pterm/internal/max_text_width.go
new file mode 100644
index 0000000..fe39475
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/internal/max_text_width.go
@@ -0,0 +1,20 @@
+package internal
+
+import (
+ "strings"
+
+ "github.com/gookit/color"
+ "github.com/mattn/go-runewidth"
+)
+
+// GetStringMaxWidth returns the maximum width of a string with multiple lines.
+func GetStringMaxWidth(s string) int {
+ var max int
+ ss := strings.Split(s, "\n")
+ for _, s2 := range ss {
+ if runewidth.StringWidth(color.ClearCode(s2)) > max {
+ max = runewidth.StringWidth(color.ClearCode(s2))
+ }
+ }
+ return max
+}
diff --git a/vendor/github.com/pterm/pterm/internal/percentage.go b/vendor/github.com/pterm/pterm/internal/percentage.go
new file mode 100644
index 0000000..ce61abc
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/internal/percentage.go
@@ -0,0 +1,13 @@
+package internal
+
+import "math"
+
+// Percentage calculates percentage.
+func Percentage(total, current float64) float64 {
+ return (current / total) * 100
+}
+
+// PercentageRound returns a rounded Percentage.
+func PercentageRound(total, current float64) float64 {
+ return math.Round(Percentage(total, current))
+}
diff --git a/vendor/github.com/pterm/pterm/internal/remove_and_count_prefix.go b/vendor/github.com/pterm/pterm/internal/remove_and_count_prefix.go
new file mode 100644
index 0000000..5c77031
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/internal/remove_and_count_prefix.go
@@ -0,0 +1,11 @@
+package internal
+
+import (
+ "strings"
+)
+
+func RemoveAndCountPrefix(input, subString string) (string, int) {
+ inputLength := len(input)
+ input = strings.TrimLeft(input, subString)
+ return input, inputLength - len(input)
+}
diff --git a/vendor/github.com/pterm/pterm/internal/title_in_line.go b/vendor/github.com/pterm/pterm/internal/title_in_line.go
new file mode 100644
index 0000000..3aae546
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/internal/title_in_line.go
@@ -0,0 +1,30 @@
+package internal
+
+import (
+ "strings"
+
+ "github.com/gookit/color"
+)
+
+// AddTitleToLine adds a title to a site of a line ex: "─ This is the title ──────"
+func AddTitleToLine(title, line string, length int, left bool) string {
+ var ret string
+ if left {
+ ret += line + " " + title + " " + line + strings.Repeat(line, length-(4+len(color.ClearCode(title))))
+ } else {
+ ret += strings.Repeat(line, length-(4+len(color.ClearCode(title)))) + line + " " + title + " " + line
+ }
+
+ return ret
+}
+
+// AddTitleToLineCenter adds a title to the center of a line ex: "─ This is the title ──────"
+func AddTitleToLineCenter(title, line string, length int) string {
+ var ret string
+ repeatString := length - (4 + len(color.ClearCode(title)))
+ unevenRepeatString := repeatString % 2
+
+ ret += strings.Repeat(line, repeatString/2) + line + " " + title + " " + line + strings.Repeat(line, repeatString/2+unevenRepeatString)
+
+ return ret
+}
diff --git a/vendor/github.com/pterm/pterm/internal/with_boolean.go b/vendor/github.com/pterm/pterm/internal/with_boolean.go
new file mode 100644
index 0000000..4dfdb86
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/internal/with_boolean.go
@@ -0,0 +1,9 @@
+package internal
+
+// WithBoolean helps an option setter (WithXXX(b ...bool) to return true, if no boolean is set, but false if it's explicitly set to false.
+func WithBoolean(b []bool) bool {
+ if len(b) == 0 {
+ b = append(b, true)
+ }
+ return b[0]
+}
diff --git a/vendor/github.com/pterm/pterm/panel_printer.go b/vendor/github.com/pterm/pterm/panel_printer.go
new file mode 100644
index 0000000..e9a0fc4
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/panel_printer.go
@@ -0,0 +1,182 @@
+package pterm
+
+import (
+ "strings"
+
+ "github.com/mattn/go-runewidth"
+
+ "github.com/pterm/pterm/internal"
+)
+
+// Panel contains the data, which should be printed inside a PanelPrinter.
+type Panel struct {
+ Data string
+}
+
+// Panels is a two dimensional coordinate system for Panel.
+type Panels [][]Panel
+
+// DefaultPanel is the default PanelPrinter.
+var DefaultPanel = PanelPrinter{
+ Padding: 1,
+}
+
+// PanelPrinter prints content in boxes.
+type PanelPrinter struct {
+ Panels Panels
+ Padding int
+ BottomPadding int
+ SameColumnWidth bool
+ BoxPrinter BoxPrinter
+}
+
+// WithPanels returns a new PanelPrinter with specific options.
+func (p PanelPrinter) WithPanels(panels Panels) *PanelPrinter {
+ p.Panels = panels
+ return &p
+}
+
+// WithPadding returns a new PanelPrinter with specific options.
+func (p PanelPrinter) WithPadding(padding int) *PanelPrinter {
+ if padding < 0 {
+ padding = 0
+ }
+ p.Padding = padding
+ return &p
+}
+
+// WithBottomPadding returns a new PanelPrinter with specific options.
+func (p PanelPrinter) WithBottomPadding(bottomPadding int) *PanelPrinter {
+ if bottomPadding < 0 {
+ bottomPadding = 0
+ }
+ p.BottomPadding = bottomPadding
+ return &p
+}
+
+// WithSameColumnWidth returns a new PanelPrinter with specific options.
+func (p PanelPrinter) WithSameColumnWidth(b ...bool) *PanelPrinter {
+ b2 := internal.WithBoolean(b)
+ p.SameColumnWidth = b2
+ return &p
+}
+
+// WithBoxPrinter returns a new PanelPrinter with specific options.
+func (p PanelPrinter) WithBoxPrinter(boxPrinter BoxPrinter) *PanelPrinter {
+ p.BoxPrinter = boxPrinter
+ return &p
+}
+
+func (p PanelPrinter) getRawOutput() string {
+ var ret string
+ for _, panel := range p.Panels {
+ for _, panel2 := range panel {
+ ret += panel2.Data + "\n\n"
+ }
+ ret += "\n"
+ }
+ return ret
+}
+
+// Srender renders the Template as a string.
+func (p PanelPrinter) Srender() (string, error) {
+ var ret string
+
+ if RawOutput {
+ return p.getRawOutput(), nil
+ }
+
+ for i := range p.Panels {
+ for i2 := range p.Panels[i] {
+ p.Panels[i][i2].Data = strings.TrimSuffix(p.Panels[i][i2].Data, "\n")
+ }
+ }
+
+ if p.BoxPrinter != (BoxPrinter{}) {
+ for i := range p.Panels {
+ for i2 := range p.Panels[i] {
+ p.Panels[i][i2].Data = p.BoxPrinter.Sprint(p.Panels[i][i2].Data)
+ }
+ }
+ }
+
+ for i := range p.Panels {
+ if len(p.Panels)-1 != i {
+ for i2 := range p.Panels[i] {
+ p.Panels[i][i2].Data += strings.Repeat("\n", p.BottomPadding)
+ }
+ }
+ }
+
+ columnMaxHeightMap := make(map[int]int)
+
+ if p.SameColumnWidth {
+ for _, panel := range p.Panels {
+ for i, p2 := range panel {
+ if columnMaxHeightMap[i] < internal.GetStringMaxWidth(p2.Data) {
+ columnMaxHeightMap[i] = internal.GetStringMaxWidth(p2.Data)
+ }
+ }
+ }
+ }
+
+ for _, boxLine := range p.Panels {
+ var maxHeight int
+
+ var renderedPanels []string
+
+ for _, box := range boxLine {
+ renderedPanels = append(renderedPanels, box.Data)
+ }
+
+ for i, panel := range renderedPanels {
+ renderedPanels[i] = strings.ReplaceAll(panel, "\n", Reset.Sprint()+"\n")
+ }
+
+ for _, box := range renderedPanels {
+ height := len(strings.Split(box, "\n"))
+ if height > maxHeight {
+ maxHeight = height
+ }
+ }
+
+ for i := 0; i < maxHeight; i++ {
+ if maxHeight != i {
+ for j, letter := range renderedPanels {
+ var letterLine string
+ letterLines := strings.Split(letter, "\n")
+ var maxLetterWidth int
+ if !p.SameColumnWidth {
+ maxLetterWidth = internal.GetStringMaxWidth(letter)
+ }
+ if len(letterLines) > i {
+ letterLine = letterLines[i]
+ }
+ letterLineLength := runewidth.StringWidth(RemoveColorFromString(letterLine))
+ if !p.SameColumnWidth {
+ if letterLineLength < maxLetterWidth {
+ letterLine += strings.Repeat(" ", maxLetterWidth-letterLineLength)
+ }
+ } else {
+ if letterLineLength < columnMaxHeightMap[j] {
+ letterLine += strings.Repeat(" ", columnMaxHeightMap[j]-letterLineLength)
+ }
+ }
+ letterLine += strings.Repeat(" ", p.Padding)
+ ret += letterLine
+ }
+ ret += "\n"
+ }
+ }
+ }
+
+ return ret, nil
+}
+
+// Render prints the Template to the terminal.
+func (p PanelPrinter) Render() error {
+ s, _ := p.Srender()
+ Println(s)
+
+ return nil
+}
diff --git a/vendor/github.com/pterm/pterm/paragraph_printer.go b/vendor/github.com/pterm/pterm/paragraph_printer.go
new file mode 100644
index 0000000..e9a8543
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/paragraph_printer.go
@@ -0,0 +1,134 @@
+package pterm
+
+import (
+ "fmt"
+ "strings"
+)
+
+// DefaultParagraph contains the default values for a ParagraphPrinter.
+var DefaultParagraph = ParagraphPrinter{
+ MaxWidth: GetTerminalWidth(),
+}
+
+// ParagraphPrinter can print paragraphs to a fixed line width.
+// The text will split between words, so that words will stick together.
+// It's like in a book.
+type ParagraphPrinter struct {
+ MaxWidth int
+}
+
+// WithMaxWidth returns a new ParagraphPrinter with a specific MaxWidth
+func (p ParagraphPrinter) WithMaxWidth(width int) *ParagraphPrinter {
+ p.MaxWidth = width
+ return &p
+}
+
+// Sprint formats using the default formats for its operands and returns the resulting string.
+// Spaces are added between operands when neither is a string.
+func (p ParagraphPrinter) Sprint(a ...interface{}) string {
+ if RawOutput {
+ return Sprint(a...)
+ }
+
+ words := strings.Fields(strings.TrimSpace(Sprint(a...)))
+ if len(words) == 0 {
+ return ""
+ }
+ wrapped := words[0]
+ spaceLeft := p.MaxWidth - len(wrapped)
+ for _, word := range words[1:] {
+ if len(word)+1 > spaceLeft {
+ wrapped += "\n" + word
+ spaceLeft = p.MaxWidth - len(word)
+ } else {
+ wrapped += " " + word
+ spaceLeft -= 1 + len(word)
+ }
+ }
+
+ return wrapped
+}
+
+// Sprintln formats using the default formats for its operands and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func (p ParagraphPrinter) Sprintln(a ...interface{}) string {
+ return p.Sprint(Sprintln(a...)) + "\n"
+}
+
+// Sprintf formats according to a format specifier and returns the resulting string.
+func (p ParagraphPrinter) Sprintf(format string, a ...interface{}) string {
+ return p.Sprint(Sprintf(format, a...))
+}
+
+// Sprintfln formats according to a format specifier and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func (p ParagraphPrinter) Sprintfln(format string, a ...interface{}) string {
+ return p.Sprintf(format, a...) + "\n"
+}
+
+// Print formats using the default formats for its operands and writes to standard output.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+func (p *ParagraphPrinter) Print(a ...interface{}) *TextPrinter {
+ Print(p.Sprint(a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Println formats using the default formats for its operands and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func (p *ParagraphPrinter) Println(a ...interface{}) *TextPrinter {
+ Print(p.Sprintln(a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
+func (p *ParagraphPrinter) Printf(format string, a ...interface{}) *TextPrinter {
+ Print(p.Sprintf(format, a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Printfln formats according to a format specifier and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func (p *ParagraphPrinter) Printfln(format string, a ...interface{}) *TextPrinter {
+ Print(p.Sprintfln(format, a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// PrintOnError prints every error which is not nil.
+// If every error is nil, nothing will be printed.
+// This can be used for simple error checking.
+func (p *ParagraphPrinter) PrintOnError(a ...interface{}) *TextPrinter {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ p.Println(err)
+ }
+ }
+ }
+
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// PrintOnErrorf wraps every error which is not nil and prints it.
+// If every error is nil, nothing will be printed.
+// This can be used for simple error checking.
+func (p *ParagraphPrinter) PrintOnErrorf(format string, a ...interface{}) *TextPrinter {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ p.Println(fmt.Errorf(format, err))
+ }
+ }
+ }
+
+ tp := TextPrinter(p)
+ return &tp
+}
diff --git a/vendor/github.com/pterm/pterm/prefix_printer.go b/vendor/github.com/pterm/pterm/prefix_printer.go
new file mode 100644
index 0000000..fde857a
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/prefix_printer.go
@@ -0,0 +1,342 @@
+package pterm
+
+import (
+ "fmt"
+ "runtime"
+ "strings"
+
+ "github.com/pterm/pterm/internal"
+)
+
+var (
+ // GrayBoxStyle wraps text in a gray box.
+ GrayBoxStyle = NewStyle(BgGray, FgLightWhite)
+)
+
+var (
+ // Info returns a PrefixPrinter, which can be used to print text with an "info" Prefix.
+ Info = PrefixPrinter{
+ MessageStyle: &ThemeDefault.InfoMessageStyle,
+ Prefix: Prefix{
+ Style: &ThemeDefault.InfoPrefixStyle,
+ Text: "INFO",
+ },
+ }
+
+ // Warning returns a PrefixPrinter, which can be used to print text with a "warning" Prefix.
+ Warning = PrefixPrinter{
+ MessageStyle: &ThemeDefault.WarningMessageStyle,
+ Prefix: Prefix{
+ Style: &ThemeDefault.WarningPrefixStyle,
+ Text: "WARNING",
+ },
+ }
+
+ // Success returns a PrefixPrinter, which can be used to print text with a "success" Prefix.
+ Success = PrefixPrinter{
+ MessageStyle: &ThemeDefault.SuccessMessageStyle,
+ Prefix: Prefix{
+ Style: &ThemeDefault.SuccessPrefixStyle,
+ Text: "SUCCESS",
+ },
+ }
+
+ // Error returns a PrefixPrinter, which can be used to print text with an "error" Prefix.
+ Error = PrefixPrinter{
+ MessageStyle: &ThemeDefault.ErrorMessageStyle,
+ Prefix: Prefix{
+ Style: &ThemeDefault.ErrorPrefixStyle,
+ Text: " ERROR ",
+ },
+ }
+
+ // Fatal returns a PrefixPrinter, which can be used to print text with an "fatal" Prefix.
+ // NOTICE: Fatal terminates the application immediately!
+ Fatal = PrefixPrinter{
+ MessageStyle: &ThemeDefault.FatalMessageStyle,
+ Prefix: Prefix{
+ Style: &ThemeDefault.FatalPrefixStyle,
+ Text: " FATAL ",
+ },
+ Fatal: true,
+ }
+
+ // Debug Prints debug messages. By default it will only print if PrintDebugMessages is true.
+ // You can change PrintDebugMessages with EnableDebugMessages and DisableDebugMessages, or by setting the variable itself.
+ Debug = PrefixPrinter{
+ MessageStyle: &ThemeDefault.DebugMessageStyle,
+ Prefix: Prefix{
+ Text: " DEBUG ",
+ Style: &ThemeDefault.DebugPrefixStyle,
+ },
+ Debugger: true,
+ }
+
+ // Description returns a PrefixPrinter, which can be used to print text with a "description" Prefix.
+ Description = PrefixPrinter{
+ MessageStyle: &ThemeDefault.DescriptionMessageStyle,
+ Prefix: Prefix{
+ Style: &ThemeDefault.DescriptionPrefixStyle,
+ Text: "Description",
+ },
+ }
+)
+
+// PrefixPrinter is the printer used to print a Prefix.
+type PrefixPrinter struct {
+ Prefix Prefix
+ Scope Scope
+ MessageStyle *Style
+ Fatal bool
+ ShowLineNumber bool
+ LineNumberOffset int
+ // If Debugger is true, the printer will only print if PrintDebugMessages is set to true.
+ // You can change PrintDebugMessages with EnableDebugMessages and DisableDebugMessages, or by setting the variable itself.
+ Debugger bool
+}
+
+// WithPrefix adds a custom prefix to the printer.
+func (p PrefixPrinter) WithPrefix(prefix Prefix) *PrefixPrinter {
+ p.Prefix = prefix
+ return &p
+}
+
+// WithScope adds a scope to the Prefix.
+func (p PrefixPrinter) WithScope(scope Scope) *PrefixPrinter {
+ p.Scope = scope
+ return &p
+}
+
+// WithMessageStyle adds a custom prefix to the printer.
+func (p PrefixPrinter) WithMessageStyle(style *Style) *PrefixPrinter {
+ p.MessageStyle = style
+ return &p
+}
+
+// WithFatal sets if the printer should panic after printing.
+// NOTE:
+// The printer will only panic if either PrefixPrinter.Println, PrefixPrinter.Print
+// or PrefixPrinter.Printf is called.
+func (p PrefixPrinter) WithFatal(b ...bool) *PrefixPrinter {
+ p.Fatal = internal.WithBoolean(b)
+ return &p
+}
+
+// WithShowLineNumber sets if the printer should print the line number from where it's called in a go file.
+func (p PrefixPrinter) WithShowLineNumber(b ...bool) *PrefixPrinter {
+ p.ShowLineNumber = internal.WithBoolean(b)
+ return &p
+}
+
+// WithDebugger returns a new Printer with specific Debugger value.
+// If Debugger is true, the printer will only print if PrintDebugMessages is set to true.
+// You can change PrintDebugMessages with EnableDebugMessages and DisableDebugMessages, or by setting the variable itself.
+func (p PrefixPrinter) WithDebugger(b ...bool) *PrefixPrinter {
+ p.Debugger = internal.WithBoolean(b)
+ return &p
+}
+
+// WithLineNumberOffset can be used to exclude a specific amount of calls in the call stack.
+// If you make a wrapper function for example, you can set this to one.
+// The printed line number will then be the line number where your wrapper function is called.
+func (p PrefixPrinter) WithLineNumberOffset(offset int) *PrefixPrinter {
+ p.LineNumberOffset = offset
+ return &p
+}
+
+// Sprint formats using the default formats for its operands and returns the resulting string.
+// Spaces are added between operands when neither is a string.
+func (p *PrefixPrinter) Sprint(a ...interface{}) string {
+ m := Sprint(a...)
+ if p.Debugger && !PrintDebugMessages {
+ return ""
+ }
+
+ if RawOutput {
+ if p.Prefix.Text != "" {
+ return Sprintf("%s: %s", strings.TrimSpace(p.Prefix.Text), Sprint(a...))
+ } else {
+ return Sprint(a...)
+ }
+ }
+
+ if p.Prefix.Style == nil {
+ p.Prefix.Style = NewStyle()
+ }
+ if p.Scope.Style == nil {
+ p.Scope.Style = NewStyle()
+ }
+ if p.MessageStyle == nil {
+ p.MessageStyle = NewStyle()
+ }
+
+ var ret string
+ var newLine bool
+
+ if strings.HasSuffix(m, "\n") {
+ m = strings.TrimRight(m, "\n")
+ newLine = true
+ }
+
+ messageLines := strings.Split(m, "\n")
+ for i, m := range messageLines {
+ if i == 0 {
+ ret += p.GetFormattedPrefix() + " "
+ if p.Scope.Text != "" {
+ ret += NewStyle(*p.Scope.Style...).Sprint(" (" + p.Scope.Text + ") ")
+ }
+ ret += p.MessageStyle.Sprint(m)
+ } else {
+ ret += "\n" + p.Prefix.Style.Sprint(strings.Repeat(" ", len(p.Prefix.Text)+2)) + " " + p.MessageStyle.Sprint(m)
+ }
+ }
+
+ _, fileName, line, _ := runtime.Caller(3 + p.LineNumberOffset)
+
+ if p.ShowLineNumber {
+ ret += FgGray.Sprint("\n└ " + fmt.Sprintf("(%s:%d)\n", fileName, line))
+ newLine = false
+ }
+
+ if newLine {
+ ret += "\n"
+ }
+
+ return Sprint(ret)
+}
+
+// Sprintln formats using the default formats for its operands and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func (p PrefixPrinter) Sprintln(a ...interface{}) string {
+ if p.Debugger && !PrintDebugMessages {
+ return ""
+ }
+ str := fmt.Sprintln(a...)
+ return p.Sprint(str)
+}
+
+// Sprintf formats according to a format specifier and returns the resulting string.
+func (p PrefixPrinter) Sprintf(format string, a ...interface{}) string {
+ if p.Debugger && !PrintDebugMessages {
+ return ""
+ }
+ return p.Sprint(Sprintf(format, a...))
+}
+
+// Sprintfln formats according to a format specifier and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func (p PrefixPrinter) Sprintfln(format string, a ...interface{}) string {
+ if p.Debugger && !PrintDebugMessages {
+ return ""
+ }
+ return p.Sprintf(format, a...) + "\n"
+}
+
+// Print formats using the default formats for its operands and writes to standard output.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+func (p *PrefixPrinter) Print(a ...interface{}) *TextPrinter {
+ tp := TextPrinter(p)
+ if p.Debugger && !PrintDebugMessages {
+ return &tp
+ }
+ Print(p.Sprint(a...))
+ checkFatal(p)
+ return &tp
+}
+
+// Println formats using the default formats for its operands and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func (p *PrefixPrinter) Println(a ...interface{}) *TextPrinter {
+ tp := TextPrinter(p)
+ if p.Debugger && !PrintDebugMessages {
+ return &tp
+ }
+ Print(p.Sprintln(a...))
+ checkFatal(p)
+ return &tp
+}
+
+// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
+func (p *PrefixPrinter) Printf(format string, a ...interface{}) *TextPrinter {
+ tp := TextPrinter(p)
+ if p.Debugger && !PrintDebugMessages {
+ return &tp
+ }
+ Print(p.Sprintf(format, a...))
+ checkFatal(p)
+ return &tp
+}
+
+// Printfln formats according to a format specifier and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func (p *PrefixPrinter) Printfln(format string, a ...interface{}) *TextPrinter {
+ tp := TextPrinter(p)
+ if p.Debugger && !PrintDebugMessages {
+ return &tp
+ }
+ Print(p.Sprintfln(format, a...))
+ checkFatal(p)
+ return &tp
+}
+
+// PrintOnError prints every error which is not nil.
+// If every error is nil, nothing will be printed.
+// This can be used for simple error checking.
+//
+// Note: Use WithFatal(true) or Fatal to panic after first non nil error.
+func (p *PrefixPrinter) PrintOnError(a ...interface{}) *TextPrinter {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ p.Println(err)
+ }
+ }
+ }
+
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// PrintOnErrorf wraps every error which is not nil and prints it.
+// If every error is nil, nothing will be printed.
+// This can be used for simple error checking.
+func (p *PrefixPrinter) PrintOnErrorf(format string, a ...interface{}) *TextPrinter {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ p.Println(fmt.Errorf(format, err))
+ }
+ }
+ }
+
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// GetFormattedPrefix returns the Prefix as a styled text string.
+func (p PrefixPrinter) GetFormattedPrefix() string {
+ return p.Prefix.Style.Sprint(" " + p.Prefix.Text + " ")
+}
+
+// Prefix contains the data used as the beginning of a printed text via a PrefixPrinter.
+type Prefix struct {
+ Text string
+ Style *Style
+}
+
+// Scope contains the data of the optional scope of a prefix.
+// If it has a text, it will be printed after the Prefix in brackets.
+type Scope struct {
+ Text string
+ Style *Style
+}
+
+func checkFatal(p *PrefixPrinter) {
+ if p.Fatal {
+ panic("")
+ }
+}
diff --git a/vendor/github.com/pterm/pterm/print.go b/vendor/github.com/pterm/pterm/print.go
new file mode 100644
index 0000000..8daeee3
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/print.go
@@ -0,0 +1,179 @@
+package pterm
+
+import (
+ "fmt"
+ "io"
+ "strings"
+
+ "github.com/gookit/color"
+)
+
+// SetDefaultOutput sets the default output of pterm.
+func SetDefaultOutput(w io.Writer) {
+ color.SetOutput(w)
+}
+
+// Sprint formats using the default formats for its operands and returns the resulting string.
+// Spaces are added between operands when neither is a string.
+func Sprint(a ...interface{}) string {
+ return color.Sprint(a...)
+}
+
+// Sprintf formats according to a format specifier and returns the resulting string.
+func Sprintf(format string, a ...interface{}) string {
+ return color.Sprintf(format, a...)
+}
+
+// Sprintfln formats according to a format specifier and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func Sprintfln(format string, a ...interface{}) string {
+ return color.Sprintf(format, a...) + "\n"
+}
+
+// Sprintln returns what Println would print to the terminal.
+func Sprintln(a ...interface{}) string {
+ str := fmt.Sprintln(a...)
+ return Sprint(str)
+}
+
+// Sprinto returns what Printo would print.
+func Sprinto(a ...interface{}) string {
+ return "\r" + Sprint(a...)
+}
+
+// Print formats using the default formats for its operands and writes to standard output.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+func Print(a ...interface{}) {
+ if !Output {
+ return
+ }
+
+ var ret string
+ var printed bool
+
+ for _, bar := range ActiveProgressBarPrinters {
+ if bar.IsActive {
+ ret += sClearLine()
+ ret += Sprinto(a...)
+ printed = true
+ }
+ }
+
+ for _, spinner := range activeSpinnerPrinters {
+ if spinner.IsActive {
+ ret += sClearLine()
+ ret += Sprinto(a...)
+ printed = true
+ }
+ }
+
+ if !printed {
+ ret = color.Sprint(Sprint(a...))
+ }
+
+ color.Print(Sprint(ret))
+
+ // Refresh all progressbars in case they were overwritten previously. Reference: #302
+ for _, bar := range ActiveProgressBarPrinters {
+ if bar.IsActive {
+ bar.UpdateTitle(bar.Title)
+ }
+ }
+}
+
+// Println formats using the default formats for its operands and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func Println(a ...interface{}) {
+ Print(Sprintln(a...))
+}
+
+// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
+func Printf(format string, a ...interface{}) {
+ Print(Sprintf(format, a...))
+}
+
+// Printfln formats according to a format specifier and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func Printfln(format string, a ...interface{}) {
+ Print(Sprintfln(format, a...))
+}
+
+// PrintOnError prints every error which is not nil.
+// If every error is nil, nothing will be printed.
+// This can be used for simple error checking.
+func PrintOnError(a ...interface{}) {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ Println(err)
+ }
+ }
+ }
+}
+
+// PrintOnErrorf wraps every error which is not nil and prints it.
+// If every error is nil, nothing will be printed.
+// This can be used for simple error checking.
+func PrintOnErrorf(format string, a ...interface{}) {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ Println(fmt.Errorf(format, err))
+ }
+ }
+ }
+}
+
+// Fprint formats using the default formats for its operands and writes to w.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+func Fprint(writer io.Writer, a ...interface{}) {
+ if !Output {
+ return
+ }
+
+ color.Fprint(writer, Sprint(a...))
+}
+
+// Fprintln formats using the default formats for its operands and writes to w.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func Fprintln(writer io.Writer, a ...interface{}) {
+ Fprint(writer, Sprint(a...)+"\n")
+}
+
+// Printo overrides the current line in a terminal.
+// If the current line is empty, the text will be printed like with pterm.Print.
+// Example:
+// pterm.Printo("Hello, World")
+// time.Sleep(time.Second)
+// pterm.Printo("Hello, Earth!")
+func Printo(a ...interface{}) {
+ if !Output {
+ return
+ }
+
+ color.Print("\r" + Sprint(a...))
+}
+
+// Fprinto prints Printo to a custom writer.
+func Fprinto(w io.Writer, a ...interface{}) {
+ Fprint(w, "\r", Sprint(a...))
+}
+
+// RemoveColorFromString removes color codes from a string.
+func RemoveColorFromString(a ...interface{}) string {
+ return color.ClearCode(Sprint(a...))
+}
+
+func clearLine() {
+ Printo(strings.Repeat(" ", GetTerminalWidth()))
+}
+
+func sClearLine() string {
+ return Sprinto(strings.Repeat(" ", GetTerminalWidth()))
+}
diff --git a/vendor/github.com/pterm/pterm/progressbar_printer.go b/vendor/github.com/pterm/pterm/progressbar_printer.go
new file mode 100644
index 0000000..7960d49
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/progressbar_printer.go
@@ -0,0 +1,271 @@
+package pterm
+
+import (
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/gookit/color"
+
+ "github.com/pterm/pterm/internal"
+)
+
+// ActiveProgressBarPrinters contains all running ProgressbarPrinters.
+// Generally, there should only be one active ProgressbarPrinter at a time.
+var ActiveProgressBarPrinters []*ProgressbarPrinter
+
+var (
+ // DefaultProgressbar is the default ProgressbarPrinter.
+ DefaultProgressbar = ProgressbarPrinter{
+ Total: 100,
+ BarCharacter: "█",
+ LastCharacter: "█",
+ ElapsedTimeRoundingFactor: time.Second,
+ BarStyle: &ThemeDefault.ProgressbarBarStyle,
+ TitleStyle: &ThemeDefault.ProgressbarTitleStyle,
+ ShowTitle: true,
+ ShowCount: true,
+ ShowPercentage: true,
+ ShowElapsedTime: true,
+ BarFiller: " ",
+ }
+)
+
+// ProgressbarPrinter shows a progress animation in the terminal.
+type ProgressbarPrinter struct {
+ Title string
+ Total int
+ Current int
+ BarCharacter string
+ LastCharacter string
+ ElapsedTimeRoundingFactor time.Duration
+ BarFiller string
+
+ ShowElapsedTime bool
+ ShowCount bool
+ ShowTitle bool
+ ShowPercentage bool
+ RemoveWhenDone bool
+
+ TitleStyle *Style
+ BarStyle *Style
+
+ IsActive bool
+
+ startedAt time.Time
+}
+
+// WithTitle sets the name of the ProgressbarPrinter.
+func (p ProgressbarPrinter) WithTitle(name string) *ProgressbarPrinter {
+ p.Title = name
+ return &p
+}
+
+// WithTotal sets the total value of the ProgressbarPrinter.
+func (p ProgressbarPrinter) WithTotal(total int) *ProgressbarPrinter {
+ p.Total = total
+ return &p
+}
+
+// WithCurrent sets the current value of the ProgressbarPrinter.
+func (p ProgressbarPrinter) WithCurrent(current int) *ProgressbarPrinter {
+ p.Current = current
+ return &p
+}
+
+// WithBarCharacter sets the bar character of the ProgressbarPrinter.
+func (p ProgressbarPrinter) WithBarCharacter(char string) *ProgressbarPrinter {
+ p.BarCharacter = char
+ return &p
+}
+
+// WithLastCharacter sets the last character of the ProgressbarPrinter.
+func (p ProgressbarPrinter) WithLastCharacter(char string) *ProgressbarPrinter {
+ p.LastCharacter = char
+ return &p
+}
+
+// WithElapsedTimeRoundingFactor sets the rounding factor of the elapsed time.
+func (p ProgressbarPrinter) WithElapsedTimeRoundingFactor(duration time.Duration) *ProgressbarPrinter {
+ p.ElapsedTimeRoundingFactor = duration
+ return &p
+}
+
+// WithShowElapsedTime sets if the elapsed time should be displayed in the ProgressbarPrinter.
+func (p ProgressbarPrinter) WithShowElapsedTime(b ...bool) *ProgressbarPrinter {
+ p.ShowElapsedTime = internal.WithBoolean(b)
+ return &p
+}
+
+// WithShowCount sets if the total and current count should be displayed in the ProgressbarPrinter.
+func (p ProgressbarPrinter) WithShowCount(b ...bool) *ProgressbarPrinter {
+ p.ShowCount = internal.WithBoolean(b)
+ return &p
+}
+
+// WithShowTitle sets if the title should be displayed in the ProgressbarPrinter.
+func (p ProgressbarPrinter) WithShowTitle(b ...bool) *ProgressbarPrinter {
+ p.ShowTitle = internal.WithBoolean(b)
+ return &p
+}
+
+// WithShowPercentage sets if the completed percentage should be displayed in the ProgressbarPrinter.
+func (p ProgressbarPrinter) WithShowPercentage(b ...bool) *ProgressbarPrinter {
+ p.ShowPercentage = internal.WithBoolean(b)
+ return &p
+}
+
+// WithTitleStyle sets the style of the title.
+func (p ProgressbarPrinter) WithTitleStyle(style *Style) *ProgressbarPrinter {
+ p.TitleStyle = style
+ return &p
+}
+
+// WithBarStyle sets the style of the bar.
+func (p ProgressbarPrinter) WithBarStyle(style *Style) *ProgressbarPrinter {
+ p.BarStyle = style
+ return &p
+}
+
+// WithRemoveWhenDone sets if the ProgressbarPrinter should be removed when it is done.
+func (p ProgressbarPrinter) WithRemoveWhenDone(b ...bool) *ProgressbarPrinter {
+ p.RemoveWhenDone = internal.WithBoolean(b)
+ return &p
+}
+
+// Increment current value by one.
+func (p *ProgressbarPrinter) Increment() *ProgressbarPrinter {
+ p.Add(1)
+ return p
+}
+
+// This method changed the title and re-renders the progressbar
+func (p *ProgressbarPrinter) UpdateTitle(title string) *ProgressbarPrinter {
+ p.Title = title
+ p.updateProgress()
+ return p
+}
+
+// This is the update logic, renders the progressbar
+func (p *ProgressbarPrinter) updateProgress() *ProgressbarPrinter {
+ if p.TitleStyle == nil {
+ p.TitleStyle = NewStyle()
+ }
+ if p.BarStyle == nil {
+ p.BarStyle = NewStyle()
+ }
+ if p.Total == 0 {
+ return nil
+ }
+
+ var before string
+ var after string
+
+ width := GetTerminalWidth()
+ currentPercentage := int(internal.PercentageRound(float64(int64(p.Total)), float64(int64(p.Current))))
+
+ decoratorCount := Gray("[") + LightWhite(p.Current) + Gray("/") + LightWhite(p.Total) + Gray("]")
+
+ decoratorCurrentPercentage := color.RGB(NewRGB(255, 0, 0).Fade(0, float32(p.Total), float32(p.Current), NewRGB(0, 255, 0)).GetValues()).
+ Sprint(strconv.Itoa(currentPercentage) + "%")
+
+ decoratorTitle := p.TitleStyle.Sprint(p.Title)
+
+ if p.ShowTitle {
+ before += decoratorTitle + " "
+ }
+ if p.ShowCount {
+ before += decoratorCount + " "
+ }
+
+ after += " "
+
+ if p.ShowPercentage {
+ after += decoratorCurrentPercentage + " "
+ }
+ if p.ShowElapsedTime {
+ after += "| " + p.parseElapsedTime()
+ }
+
+ barMaxLength := width - len(RemoveColorFromString(before)) - len(RemoveColorFromString(after)) - 1
+ barCurrentLength := (p.Current * barMaxLength) / p.Total
+ barFiller := strings.Repeat(p.BarFiller, barMaxLength-barCurrentLength)
+
+ bar := p.BarStyle.Sprint(strings.Repeat(p.BarCharacter, barCurrentLength)+p.LastCharacter) + barFiller
+ if !RawOutput {
+ Printo(before + bar + after)
+ }
+ return p
+}
+
+// Add to current value.
+func (p *ProgressbarPrinter) Add(count int) *ProgressbarPrinter {
+ if p.Total == 0 {
+ return nil
+ }
+
+ p.Current += count
+ p.updateProgress()
+
+ if p.Current == p.Total {
+ p.Stop()
+ }
+ return p
+}
+
+// Start the ProgressbarPrinter.
+func (p ProgressbarPrinter) Start() (*ProgressbarPrinter, error) {
+ if RawOutput && p.ShowTitle {
+ Println(p.Title)
+ }
+ p.IsActive = true
+ ActiveProgressBarPrinters = append(ActiveProgressBarPrinters, &p)
+ p.startedAt = time.Now()
+
+ p.updateProgress()
+
+ return &p, nil
+}
+
+// Stop the ProgressbarPrinter.
+func (p *ProgressbarPrinter) Stop() (*ProgressbarPrinter, error) {
+ if !p.IsActive {
+ return p, nil
+ }
+ p.IsActive = false
+ if p.RemoveWhenDone {
+ clearLine()
+ Printo()
+ } else {
+ Println()
+ }
+ return p, nil
+}
+
+// GenericStart runs Start, but returns a LivePrinter.
+// This is used for the interface LivePrinter.
+// You most likely want to use Start instead of this in your program.
+func (p ProgressbarPrinter) GenericStart() (*LivePrinter, error) {
+ p2, _ := p.Start()
+ lp := LivePrinter(p2)
+ return &lp, nil
+}
+
+// GenericStop runs Stop, but returns a LivePrinter.
+// This is used for the interface LivePrinter.
+// You most likely want to use Stop instead of this in your program.
+func (p ProgressbarPrinter) GenericStop() (*LivePrinter, error) {
+ p2, _ := p.Stop()
+ lp := LivePrinter(p2)
+ return &lp, nil
+}
+
+// GetElapsedTime returns the elapsed time, since the ProgressbarPrinter was started.
+func (p *ProgressbarPrinter) GetElapsedTime() time.Duration {
+ return time.Since(p.startedAt)
+}
+
+func (p *ProgressbarPrinter) parseElapsedTime() string {
+ s := p.GetElapsedTime().Round(p.ElapsedTimeRoundingFactor).String()
+ return s
+}
diff --git a/vendor/github.com/pterm/pterm/pterm.go b/vendor/github.com/pterm/pterm/pterm.go
new file mode 100644
index 0000000..851c3b4
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/pterm.go
@@ -0,0 +1,67 @@
+// Package pterm is a modern go module to beautify console output.
+// It can be used without configuration, but if desired, everything can be customized down to the smallest detail.
+// View the animated examples here: https://github.com/pterm/pterm#-examples
+package pterm
+
+import "github.com/gookit/color"
+
+var (
+ // Output completely disables output from pterm if set to false. Can be used in CLI application quiet mode.
+ Output = true
+
+ // PrintDebugMessages sets if messages printed by the DebugPrinter should be printed.
+ PrintDebugMessages = false
+
+ // RawOutput is set to true if pterm.DisableStyling() was called.
+ // The variable indicates that PTerm will not add additional styling to text.
+ // Use pterm.DisableStyling() or pterm.EnableStyling() to change this variable.
+ // Changing this variable directly, will disable or enable the output of colored text.
+ RawOutput = false
+)
+
+func init() {
+ color.ForceColor()
+}
+
+// EnableOutput enables the output of PTerm.
+func EnableOutput() {
+ Output = true
+}
+
+// DisableOutput disables the output of PTerm.
+func DisableOutput() {
+ Output = false
+}
+
+// EnableDebugMessages enables the output of debug printers.
+func EnableDebugMessages() {
+ PrintDebugMessages = true
+}
+
+// DisableDebugMessages disables the output of debug printers.
+func DisableDebugMessages() {
+ PrintDebugMessages = false
+}
+
+// EnableStyling enables the default PTerm styling.
+// This also calls EnableColor.
+func EnableStyling() {
+ RawOutput = false
+ EnableColor()
+}
+
+// DisableStyling sets PTerm to RawOutput mode and disables all of PTerms styling.
+// You can use this to print to text files etc.
+// This also calls DisableColor.
+func DisableStyling() {
+ RawOutput = true
+ DisableColor()
+}
+
+// RecalculateTerminalSize updates already initialized terminal dimensions. Has to be called after a termina resize to guarantee proper rendering. Applies only to new instances.
+func RecalculateTerminalSize() {
+ // keep in sync with DefaultBarChart
+ DefaultBarChart.Width = GetTerminalWidth() * 2 / 3
+ DefaultBarChart.Height = GetTerminalHeight() * 2 / 3
+ DefaultParagraph.MaxWidth = GetTerminalWidth()
+}
diff --git a/vendor/github.com/pterm/pterm/rgb.go b/vendor/github.com/pterm/pterm/rgb.go
new file mode 100644
index 0000000..02acce0
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/rgb.go
@@ -0,0 +1,176 @@
+package pterm
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+
+ "github.com/gookit/color"
+
+ "github.com/pterm/pterm/internal"
+)
+
+// RGB color model is an additive color model in which red, green, and blue light are added together in various ways to reproduce a broad array of colors.
+// The name of the model comes from the initials of the three additive primary colors, red, green, and blue.
+// https://en.wikipedia.org/wiki/RGB_color_model
+type RGB struct {
+ R uint8
+ G uint8
+ B uint8
+}
+
+// GetValues returns the RGB values separately.
+func (p RGB) GetValues() (r, g, b uint8) {
+ return p.R, p.G, p.B
+}
+
+// NewRGB returns a new RGB.
+func NewRGB(r, g, b uint8) RGB {
+ return RGB{R: r, G: g, B: b}
+}
+
+// NewRGBFromHEX converts a HEX and returns a new RGB.
+func NewRGBFromHEX(hex string) (RGB, error) {
+ hex = strings.ToLower(hex)
+ hex = strings.ReplaceAll(hex, "#", "")
+ hex = strings.ReplaceAll(hex, "0x", "")
+
+ if len(hex) == 3 {
+ hex = string([]byte{hex[0], hex[0], hex[1], hex[1], hex[2], hex[2]})
+ }
+ if len(hex) != 6 {
+ return RGB{}, ErrHexCodeIsInvalid
+ }
+
+ i64, err := strconv.ParseInt(hex, 16, 32)
+ if err != nil {
+ return RGB{}, err
+ }
+ c := int(i64)
+
+ return RGB{
+ R: uint8(c >> 16),
+ G: uint8((c & 0x00FF00) >> 8),
+ B: uint8(c & 0x0000FF),
+ }, nil
+}
+
+// Fade fades one RGB value (over other RGB values) to another RGB value, by giving the function a minimum, maximum and current value.
+func (p RGB) Fade(min, max, current float32, end ...RGB) RGB {
+ if min < 0 {
+ max -= min
+ current -= min
+ min = 0
+ }
+ if len(end) == 1 {
+ return RGB{
+ R: uint8(internal.MapRangeToRange(min, max, float32(p.R), float32(end[0].R), current)),
+ G: uint8(internal.MapRangeToRange(min, max, float32(p.G), float32(end[0].G), current)),
+ B: uint8(internal.MapRangeToRange(min, max, float32(p.B), float32(end[0].B), current)),
+ }
+ } else if len(end) > 1 {
+ f := (max - min) / float32(len(end))
+ tempCurrent := current
+ if f > current {
+ return p.Fade(min, f, current, end[0])
+ } else {
+ for i := 0; i < len(end)-1; i++ {
+ tempCurrent -= f
+ if f > tempCurrent {
+ return end[i].Fade(min, min+f, tempCurrent, end[i+1])
+ }
+ }
+ }
+ }
+ return p
+}
+
+// Sprint formats using the default formats for its operands and returns the resulting string.
+// Spaces are added between operands when neither is a string.
+func (p RGB) Sprint(a ...interface{}) string {
+ return color.RGB(p.R, p.G, p.B).Sprint(a...)
+}
+
+// Sprintln formats using the default formats for its operands and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func (p RGB) Sprintln(a ...interface{}) string {
+ return p.Sprint(Sprintln(a...))
+}
+
+// Sprintf formats according to a format specifier and returns the resulting string.
+func (p RGB) Sprintf(format string, a ...interface{}) string {
+ return p.Sprint(Sprintf(format, a...))
+}
+
+// Sprintfln formats according to a format specifier and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func (p RGB) Sprintfln(format string, a ...interface{}) string {
+ return p.Sprintf(format, a...) + "\n"
+}
+
+// Print formats using the default formats for its operands and writes to standard output.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+func (p RGB) Print(a ...interface{}) *TextPrinter {
+ Print(p.Sprint(a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Println formats using the default formats for its operands and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func (p RGB) Println(a ...interface{}) *TextPrinter {
+ Print(p.Sprintln(a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
+func (p RGB) Printf(format string, a ...interface{}) *TextPrinter {
+ Print(p.Sprintf(format, a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Printfln formats according to a format specifier and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func (p RGB) Printfln(format string, a ...interface{}) *TextPrinter {
+ Print(p.Sprintfln(format, a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// PrintOnError prints every error which is not nil.
+// If every error is nil, nothing will be printed.
+// This can be used for simple error checking.
+func (p RGB) PrintOnError(a ...interface{}) *TextPrinter {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ p.Println(err)
+ }
+ }
+ }
+
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// PrintOnErrorf wraps every error which is not nil and prints it.
+// If every error is nil, nothing will be printed.
+// This can be used for simple error checking.
+func (p RGB) PrintOnErrorf(format string, a ...interface{}) *TextPrinter {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ p.Println(fmt.Errorf(format, err))
+ }
+ }
+ }
+
+ tp := TextPrinter(p)
+ return &tp
+}
diff --git a/vendor/github.com/pterm/pterm/section_printer.go b/vendor/github.com/pterm/pterm/section_printer.go
new file mode 100644
index 0000000..d0e6402
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/section_printer.go
@@ -0,0 +1,166 @@
+package pterm
+
+import (
+ "fmt"
+ "strings"
+)
+
+// DefaultSection is the default section printer.
+var DefaultSection = SectionPrinter{
+ Style: &ThemeDefault.SectionStyle,
+ Level: 1,
+ TopPadding: 1,
+ BottomPadding: 1,
+ IndentCharacter: "#",
+}
+
+// SectionPrinter prints a new section title.
+// It can be used to structure longer text, or different chapters of your program.
+type SectionPrinter struct {
+ Style *Style
+ Level int
+ IndentCharacter string
+ TopPadding int
+ BottomPadding int
+}
+
+// WithStyle returns a new SectionPrinter with a specific style.
+func (p SectionPrinter) WithStyle(style *Style) *SectionPrinter {
+ p.Style = style
+ return &p
+}
+
+// WithLevel returns a new SectionPrinter with a specific level.
+func (p SectionPrinter) WithLevel(level int) *SectionPrinter {
+ p.Level = level
+ return &p
+}
+
+// WithIndentCharacter returns a new SectionPrinter with a specific IndentCharacter.
+func (p SectionPrinter) WithIndentCharacter(char string) *SectionPrinter {
+ p.IndentCharacter = char
+ return &p
+}
+
+// WithTopPadding returns a new SectionPrinter with a specific top padding.
+func (p SectionPrinter) WithTopPadding(padding int) *SectionPrinter {
+ p.TopPadding = padding
+ return &p
+}
+
+// WithBottomPadding returns a new SectionPrinter with a specific top padding.
+func (p SectionPrinter) WithBottomPadding(padding int) *SectionPrinter {
+ p.BottomPadding = padding
+ return &p
+}
+
+// Sprint formats using the default formats for its operands and returns the resulting string.
+// Spaces are added between operands when neither is a string.
+func (p SectionPrinter) Sprint(a ...interface{}) string {
+ if p.Style == nil {
+ p.Style = NewStyle()
+ }
+
+ var ret string
+
+ for i := 0; i < p.TopPadding; i++ {
+ ret += "\n"
+ }
+
+ if p.Level > 0 {
+ ret += strings.Repeat(p.IndentCharacter, p.Level) + " "
+ }
+
+ ret += p.Style.Sprint(a...)
+
+ for i := 0; i < p.BottomPadding; i++ {
+ ret += "\n"
+ }
+
+ return ret
+}
+
+// Sprintln formats using the default formats for its operands and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func (p SectionPrinter) Sprintln(a ...interface{}) string {
+ str := fmt.Sprintln(a...)
+ return Sprint(p.Sprint(str))
+}
+
+// Sprintf formats according to a format specifier and returns the resulting string.
+func (p SectionPrinter) Sprintf(format string, a ...interface{}) string {
+ return p.Sprint(Sprintf(format, a...))
+}
+
+// Sprintfln formats according to a format specifier and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func (p SectionPrinter) Sprintfln(format string, a ...interface{}) string {
+ return p.Sprintf(format, a...) + "\n"
+}
+
+// Print formats using the default formats for its operands and writes to standard output.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+func (p *SectionPrinter) Print(a ...interface{}) *TextPrinter {
+ Print(p.Sprint(a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Println formats using the default formats for its operands and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func (p *SectionPrinter) Println(a ...interface{}) *TextPrinter {
+ Print(p.Sprintln(a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
+func (p *SectionPrinter) Printf(format string, a ...interface{}) *TextPrinter {
+ Print(p.Sprintf(format, a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Printfln formats according to a format specifier and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func (p *SectionPrinter) Printfln(format string, a ...interface{}) *TextPrinter {
+ Print(p.Sprintfln(format, a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// PrintOnError prints every error which is not nil.
+// If every error is nil, nothing will be printed.
+// This can be used for simple error checking.
+func (p *SectionPrinter) PrintOnError(a ...interface{}) *TextPrinter {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ p.Println(err)
+ }
+ }
+ }
+
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// PrintOnErrorf wraps every error which is not nil and prints it.
+// If every error is nil, nothing will be printed.
+// This can be used for simple error checking.
+func (p *SectionPrinter) PrintOnErrorf(format string, a ...interface{}) *TextPrinter {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ p.Println(fmt.Errorf(format, err))
+ }
+ }
+ }
+
+ tp := TextPrinter(p)
+ return &tp
+}
diff --git a/vendor/github.com/pterm/pterm/spinner_printer.go b/vendor/github.com/pterm/pterm/spinner_printer.go
new file mode 100644
index 0000000..aaeda39
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/spinner_printer.go
@@ -0,0 +1,223 @@
+package pterm
+
+import (
+ "time"
+
+ "github.com/pterm/pterm/internal"
+)
+
+var activeSpinnerPrinters []*SpinnerPrinter
+
+// DefaultSpinner is the default SpinnerPrinter.
+var DefaultSpinner = SpinnerPrinter{
+ Sequence: []string{"▀ ", " ▀", " ▄", "▄ "},
+ Style: &ThemeDefault.SpinnerStyle,
+ Delay: time.Millisecond * 200,
+ ShowTimer: true,
+ TimerRoundingFactor: time.Second,
+ TimerStyle: &ThemeDefault.TimerStyle,
+ MessageStyle: &ThemeDefault.SpinnerTextStyle,
+ SuccessPrinter: &Success,
+ FailPrinter: &Error,
+ WarningPrinter: &Warning,
+}
+
+// SpinnerPrinter is a loading animation, which can be used if the progress is unknown.
+// It's an animation loop, which can have a text and supports throwing errors or warnings.
+// A TextPrinter is used to display all outputs, after the SpinnerPrinter is done.
+type SpinnerPrinter struct {
+ Text string
+ Sequence []string
+ Style *Style
+ Delay time.Duration
+ MessageStyle *Style
+ SuccessPrinter TextPrinter
+ FailPrinter TextPrinter
+ WarningPrinter TextPrinter
+ RemoveWhenDone bool
+ ShowTimer bool
+ TimerRoundingFactor time.Duration
+ TimerStyle *Style
+
+ IsActive bool
+
+ startedAt time.Time
+ currentSequence string
+}
+
+// WithText adds a text to the SpinnerPrinter.
+func (s SpinnerPrinter) WithText(text string) *SpinnerPrinter {
+ s.Text = text
+ return &s
+}
+
+// WithSequence adds a sequence to the SpinnerPrinter.
+func (s SpinnerPrinter) WithSequence(sequence ...string) *SpinnerPrinter {
+ s.Sequence = sequence
+ return &s
+}
+
+// WithStyle adds a style to the SpinnerPrinter.
+func (s SpinnerPrinter) WithStyle(style *Style) *SpinnerPrinter {
+ s.Style = style
+ return &s
+}
+
+// WithDelay adds a delay to the SpinnerPrinter.
+func (s SpinnerPrinter) WithDelay(delay time.Duration) *SpinnerPrinter {
+ s.Delay = delay
+ return &s
+}
+
+// WithMessageStyle adds a style to the SpinnerPrinter message.
+func (s SpinnerPrinter) WithMessageStyle(style *Style) *SpinnerPrinter {
+ s.MessageStyle = style
+ return &s
+}
+
+// WithRemoveWhenDone removes the SpinnerPrinter after it is done.
+func (s SpinnerPrinter) WithRemoveWhenDone(b ...bool) *SpinnerPrinter {
+ s.RemoveWhenDone = internal.WithBoolean(b)
+ return &s
+}
+
+// WithShowTimer shows how long the spinner is running.
+func (s SpinnerPrinter) WithShowTimer(b ...bool) *SpinnerPrinter {
+ s.ShowTimer = internal.WithBoolean(b)
+ return &s
+}
+
+// WithTimerRoundingFactor sets the rounding factor for the timer.
+func (s SpinnerPrinter) WithTimerRoundingFactor(factor time.Duration) *SpinnerPrinter {
+ s.TimerRoundingFactor = factor
+ return &s
+}
+
+// WithTimerStyle adds a style to the SpinnerPrinter timer.
+func (s SpinnerPrinter) WithTimerStyle(style *Style) *SpinnerPrinter {
+ s.TimerStyle = style
+ return &s
+}
+
+// UpdateText updates the message of the active SpinnerPrinter.
+// Can be used live.
+func (s *SpinnerPrinter) UpdateText(text string) {
+ s.Text = text
+ if !RawOutput {
+ clearLine()
+ Printo(s.Style.Sprint(s.currentSequence) + " " + s.MessageStyle.Sprint(s.Text))
+ }
+ if RawOutput {
+ Println(s.Text)
+ }
+}
+
+// Start the SpinnerPrinter.
+func (s SpinnerPrinter) Start(text ...interface{}) (*SpinnerPrinter, error) {
+ s.IsActive = true
+ s.startedAt = time.Now()
+ activeSpinnerPrinters = append(activeSpinnerPrinters, &s)
+
+ if len(text) != 0 {
+ s.Text = Sprint(text...)
+ }
+
+ if RawOutput {
+ Println(s.Text)
+ }
+
+ go func() {
+ for s.IsActive {
+ for _, seq := range s.Sequence {
+ if !s.IsActive || RawOutput {
+ continue
+ }
+
+ var timer string
+ if s.ShowTimer {
+ timer = " (" + time.Since(s.startedAt).Round(s.TimerRoundingFactor).String() + ")"
+ }
+ Printo(s.Style.Sprint(seq) + " " + s.MessageStyle.Sprint(s.Text) + s.TimerStyle.Sprint(timer))
+ s.currentSequence = seq
+ time.Sleep(s.Delay)
+ }
+ }
+ }()
+ return &s, nil
+}
+
+// Stop terminates the SpinnerPrinter immediately.
+// The SpinnerPrinter will not resolve into anything.
+func (s *SpinnerPrinter) Stop() error {
+ s.IsActive = false
+ if s.RemoveWhenDone {
+ clearLine()
+ Printo()
+ } else {
+ Println()
+ }
+ return nil
+}
+
+// GenericStart runs Start, but returns a LivePrinter.
+// This is used for the interface LivePrinter.
+// You most likely want to use Start instead of this in your program.
+func (s *SpinnerPrinter) GenericStart() (*LivePrinter, error) {
+ _, _ = s.Start()
+ lp := LivePrinter(s)
+ return &lp, nil
+}
+
+// GenericStop runs Stop, but returns a LivePrinter.
+// This is used for the interface LivePrinter.
+// You most likely want to use Stop instead of this in your program.
+func (s *SpinnerPrinter) GenericStop() (*LivePrinter, error) {
+ _ = s.Stop()
+ lp := LivePrinter(s)
+ return &lp, nil
+}
+
+// Success displays the success printer.
+// If no message is given, the text of the SpinnerPrinter will be reused as the default message.
+func (s *SpinnerPrinter) Success(message ...interface{}) {
+ if s.SuccessPrinter == nil {
+ s.SuccessPrinter = &Success
+ }
+
+ if len(message) == 0 {
+ message = []interface{}{s.Text}
+ }
+ clearLine()
+ Printo(s.SuccessPrinter.Sprint(message...))
+ _ = s.Stop()
+}
+
+// Fail displays the fail printer.
+// If no message is given, the text of the SpinnerPrinter will be reused as the default message.
+func (s *SpinnerPrinter) Fail(message ...interface{}) {
+ if s.FailPrinter == nil {
+ s.FailPrinter = &Error
+ }
+
+ if len(message) == 0 {
+ message = []interface{}{s.Text}
+ }
+ clearLine()
+ Printo(s.FailPrinter.Sprint(message...))
+ _ = s.Stop()
+}
+
+// Warning displays the warning printer.
+// If no message is given, the text of the SpinnerPrinter will be reused as the default message.
+func (s *SpinnerPrinter) Warning(message ...interface{}) {
+ if s.WarningPrinter == nil {
+ s.WarningPrinter = &Warning
+ }
+
+ if len(message) == 0 {
+ message = []interface{}{s.Text}
+ }
+ clearLine()
+ Printo(s.WarningPrinter.Sprint(message...))
+ _ = s.Stop()
+}
diff --git a/vendor/github.com/pterm/pterm/table_printer.go b/vendor/github.com/pterm/pterm/table_printer.go
new file mode 100644
index 0000000..96bbb67
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/table_printer.go
@@ -0,0 +1,168 @@
+package pterm
+
+import (
+ "encoding/csv"
+ "strings"
+ "unicode/utf8"
+
+ "github.com/pterm/pterm/internal"
+)
+
+// DefaultTable contains standards, which can be used to print a TablePrinter.
+var DefaultTable = TablePrinter{
+ Style: &ThemeDefault.TableStyle,
+ HeaderStyle: &ThemeDefault.TableHeaderStyle,
+ Separator: " | ",
+ SeparatorStyle: &ThemeDefault.TableSeparatorStyle,
+ LeftAlignment: true,
+ RightAlignment: false,
+}
+
+// TableData is the type that contains the data of a TablePrinter.
+type TableData [][]string
+
+// TablePrinter is able to render tables.
+type TablePrinter struct {
+ Style *Style
+ HasHeader bool
+ HeaderStyle *Style
+ Separator string
+ SeparatorStyle *Style
+ Data TableData
+ Boxed bool
+ LeftAlignment bool
+ RightAlignment bool
+}
+
+// WithStyle returns a new TablePrinter with a specific Style.
+func (p TablePrinter) WithStyle(style *Style) *TablePrinter {
+ p.Style = style
+ return &p
+}
+
+// WithHasHeader returns a new TablePrinter, where the first line is marked as a header.
+func (p TablePrinter) WithHasHeader(b ...bool) *TablePrinter {
+ p.HasHeader = internal.WithBoolean(b)
+ return &p
+}
+
+// WithHeaderStyle returns a new TablePrinter with a specific HeaderStyle.
+func (p TablePrinter) WithHeaderStyle(style *Style) *TablePrinter {
+ p.HeaderStyle = style
+ return &p
+}
+
+// WithSeparator returns a new TablePrinter with a specific separator.
+func (p TablePrinter) WithSeparator(separator string) *TablePrinter {
+ p.Separator = separator
+ return &p
+}
+
+// WithSeparatorStyle returns a new TablePrinter with a specific SeparatorStyle.
+func (p TablePrinter) WithSeparatorStyle(style *Style) *TablePrinter {
+ p.SeparatorStyle = style
+ return &p
+}
+
+// WithData returns a new TablePrinter with specific Data.
+func (p TablePrinter) WithData(data [][]string) *TablePrinter {
+ p.Data = data
+ return &p
+}
+
+// WithCSVReader return a new TablePrinter with specified Data extracted from CSV.
+func (p TablePrinter) WithCSVReader(reader *csv.Reader) *TablePrinter {
+ if records, err := reader.ReadAll(); err == nil {
+ p.Data = records
+ }
+ return &p
+}
+
+// WithBoxed returns a new TablePrinter with a box around the table.
+func (p TablePrinter) WithBoxed(b ...bool) *TablePrinter {
+ p.Boxed = internal.WithBoolean(b)
+ return &p
+}
+
+// WithLeftAlignment returns a new TablePrinter with left alignment.
+func (p TablePrinter) WithLeftAlignment(b ...bool) *TablePrinter {
+ b2 := internal.WithBoolean(b)
+ p.LeftAlignment = b2
+ p.RightAlignment = false
+ return &p
+}
+
+// WithRightAlignment returns a new TablePrinter with right alignment.
+func (p TablePrinter) WithRightAlignment(b ...bool) *TablePrinter {
+ b2 := internal.WithBoolean(b)
+ p.LeftAlignment = false
+ p.RightAlignment = b2
+ return &p
+}
+
+// Srender renders the TablePrinter as a string.
+func (p TablePrinter) Srender() (string, error) {
+ if p.Style == nil {
+ p.Style = NewStyle()
+ }
+ if p.SeparatorStyle == nil {
+ p.SeparatorStyle = NewStyle()
+ }
+ if p.HeaderStyle == nil {
+ p.HeaderStyle = NewStyle()
+ }
+
+ var ret string
+ maxColumnWidth := make(map[int]int)
+
+ for _, row := range p.Data {
+ for ci, column := range row {
+ columnLength := utf8.RuneCountInString(RemoveColorFromString(column))
+ if columnLength > maxColumnWidth[ci] {
+ maxColumnWidth[ci] = columnLength
+ }
+ }
+ }
+
+ for ri, row := range p.Data {
+ for ci, column := range row {
+ columnString := p.createColumnString(column, maxColumnWidth[ci])
+
+ if ci != len(row) && ci != 0 {
+ ret += p.Style.Sprint(p.SeparatorStyle.Sprint(p.Separator))
+ }
+
+ if p.HasHeader && ri == 0 {
+ ret += p.Style.Sprint(p.HeaderStyle.Sprint(columnString))
+ } else {
+ ret += p.Style.Sprint(columnString)
+ }
+ }
+
+ ret += "\n"
+ }
+
+ ret = strings.TrimSuffix(ret, "\n")
+
+ if p.Boxed {
+ ret = DefaultBox.Sprint(ret)
+ }
+
+ return ret, nil
+}
+
+func (p TablePrinter) createColumnString(data string, maxColumnWidth int) string {
+ columnLength := utf8.RuneCountInString(RemoveColorFromString(data))
+ if p.RightAlignment {
+ return strings.Repeat(" ", maxColumnWidth-columnLength) + data
+ }
+ return data + strings.Repeat(" ", maxColumnWidth-columnLength)
+}
+
+// Render prints the TablePrinter to the terminal.
+func (p TablePrinter) Render() error {
+ s, _ := p.Srender()
+ Println(s)
+
+ return nil
+}
diff --git a/vendor/github.com/pterm/pterm/terminal.go b/vendor/github.com/pterm/pterm/terminal.go
new file mode 100644
index 0000000..24d95e3
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/terminal.go
@@ -0,0 +1,64 @@
+package pterm
+
+import (
+ "os"
+
+ "golang.org/x/term"
+)
+
+// FallbackTerminalWidth is the value used for GetTerminalWidth, if the actual width can not be detected
+// You can override that value if necessary.
+var FallbackTerminalWidth = 80
+
+// FallbackTerminalHeight is the value used for GetTerminalHeight, if the actual height can not be detected
+// You can override that value if necessary.
+var FallbackTerminalHeight = 10
+
+// forcedTerminalWidth, when set along with forcedTerminalHeight, forces the terminal width value.
+var forcedTerminalWidth int = 0
+
+// forcedTerminalHeight, when set along with forcedTerminalWidth, forces the terminal height value.
+var forcedTerminalHeight int = 0
+
+// GetTerminalWidth returns the terminal width of the active terminal.
+func GetTerminalWidth() int {
+ if forcedTerminalWidth > 0 {
+ return forcedTerminalWidth
+ }
+ width, _, _ := GetTerminalSize()
+ return width
+}
+
+// GetTerminalHeight returns the terminal height of the active terminal.
+func GetTerminalHeight() int {
+ if forcedTerminalHeight > 0 {
+ return forcedTerminalHeight
+ }
+ _, height, _ := GetTerminalSize()
+ return height
+}
+
+// GetTerminalSize returns the width and the height of the active terminal.
+func GetTerminalSize() (width, height int, err error) {
+ if forcedTerminalWidth > 0 && forcedTerminalHeight > 0 {
+ return forcedTerminalWidth, forcedTerminalHeight, nil
+ }
+ w, h, err := term.GetSize(int(os.Stdout.Fd()))
+ if w <= 0 {
+ w = FallbackTerminalWidth
+ }
+ if h <= 0 {
+ h = FallbackTerminalHeight
+ }
+ if err != nil {
+ err = ErrTerminalSizeNotDetectable
+ }
+ return w, h, err
+}
+
+// setForcedTerminalSize turns off terminal size autodetection. Usuful for unified tests.
+func SetForcedTerminalSize(width int, height int) {
+ forcedTerminalWidth = width
+ forcedTerminalHeight = height
+ RecalculateTerminalSize()
+}
diff --git a/vendor/github.com/pterm/pterm/theme.go b/vendor/github.com/pterm/pterm/theme.go
new file mode 100644
index 0000000..9418642
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/theme.go
@@ -0,0 +1,246 @@
+package pterm
+
+var (
+ // ThemeDefault is the default theme used by PTerm.
+ // If this variable is overwritten, the new value is used as default theme.
+ ThemeDefault = Theme{
+ PrimaryStyle: Style{FgCyan},
+ SecondaryStyle: Style{FgLightMagenta},
+ HighlightStyle: Style{Bold, FgYellow},
+ InfoMessageStyle: Style{FgLightCyan},
+ InfoPrefixStyle: Style{FgBlack, BgCyan},
+ SuccessMessageStyle: Style{FgGreen},
+ SuccessPrefixStyle: Style{FgBlack, BgGreen},
+ WarningMessageStyle: Style{FgYellow},
+ WarningPrefixStyle: Style{FgBlack, BgYellow},
+ ErrorMessageStyle: Style{FgLightRed},
+ ErrorPrefixStyle: Style{FgBlack, BgLightRed},
+ FatalMessageStyle: Style{FgLightRed},
+ FatalPrefixStyle: Style{FgBlack, BgLightRed},
+ DescriptionMessageStyle: Style{FgDefault},
+ DescriptionPrefixStyle: Style{FgLightWhite, BgDarkGray},
+ ScopeStyle: Style{FgGray},
+ ProgressbarBarStyle: Style{FgCyan},
+ ProgressbarTitleStyle: Style{FgLightCyan},
+ HeaderTextStyle: Style{FgLightWhite, Bold},
+ HeaderBackgroundStyle: Style{BgGray},
+ SpinnerStyle: Style{FgLightCyan},
+ SpinnerTextStyle: Style{FgLightWhite},
+ TableStyle: Style{FgDefault},
+ TableHeaderStyle: Style{FgLightCyan},
+ TableSeparatorStyle: Style{FgGray},
+ SectionStyle: Style{Bold, FgYellow},
+ BulletListTextStyle: Style{FgDefault},
+ BulletListBulletStyle: Style{FgGray},
+ TreeStyle: Style{FgGray},
+ TreeTextStyle: Style{FgDefault},
+ LetterStyle: Style{FgDefault},
+ DebugMessageStyle: Style{FgGray},
+ DebugPrefixStyle: Style{FgBlack, BgGray},
+ BoxStyle: Style{FgDefault},
+ BoxTextStyle: Style{FgDefault},
+ BarLabelStyle: Style{FgLightCyan},
+ BarStyle: Style{FgCyan},
+ TimerStyle: Style{FgGray},
+ }
+)
+
+// Theme for PTerm.
+// Theme contains every Style used in PTerm. You can create own themes for your application or use one
+// of the existing themes.
+type Theme struct {
+ PrimaryStyle Style
+ SecondaryStyle Style
+ HighlightStyle Style
+ InfoMessageStyle Style
+ InfoPrefixStyle Style
+ SuccessMessageStyle Style
+ SuccessPrefixStyle Style
+ WarningMessageStyle Style
+ WarningPrefixStyle Style
+ ErrorMessageStyle Style
+ ErrorPrefixStyle Style
+ FatalMessageStyle Style
+ FatalPrefixStyle Style
+ DescriptionMessageStyle Style
+ DescriptionPrefixStyle Style
+ ScopeStyle Style
+ ProgressbarBarStyle Style
+ ProgressbarTitleStyle Style
+ HeaderTextStyle Style
+ HeaderBackgroundStyle Style
+ SpinnerStyle Style
+ SpinnerTextStyle Style
+ TimerStyle Style
+ TableStyle Style
+ TableHeaderStyle Style
+ TableSeparatorStyle Style
+ SectionStyle Style
+ BulletListTextStyle Style
+ BulletListBulletStyle Style
+ TreeStyle Style
+ TreeTextStyle Style
+ LetterStyle Style
+ DebugMessageStyle Style
+ DebugPrefixStyle Style
+ BoxStyle Style
+ BoxTextStyle Style
+ BarLabelStyle Style
+ BarStyle Style
+}
+
+// WithPrimaryStyle returns a new theme with overridden value.
+func (t Theme) WithPrimaryStyle(style Style) Theme {
+ t.PrimaryStyle = style
+ return t
+}
+
+// WithSecondaryStyle returns a new theme with overridden value.
+func (t Theme) WithSecondaryStyle(style Style) Theme {
+ t.SecondaryStyle = style
+ return t
+}
+
+// WithHighlightStyle returns a new theme with overridden value.
+func (t Theme) WithHighlightStyle(style Style) Theme {
+ t.HighlightStyle = style
+ return t
+}
+
+// WithInfoMessageStyle returns a new theme with overridden value.
+func (t Theme) WithInfoMessageStyle(style Style) Theme {
+ t.InfoMessageStyle = style
+ return t
+}
+
+// WithInfoPrefixStyle returns a new theme with overridden value.
+func (t Theme) WithInfoPrefixStyle(style Style) Theme {
+ t.InfoPrefixStyle = style
+ return t
+}
+
+// WithSuccessMessageStyle returns a new theme with overridden value.
+func (t Theme) WithSuccessMessageStyle(style Style) Theme {
+ t.SuccessMessageStyle = style
+ return t
+}
+
+// WithSuccessPrefixStyle returns a new theme with overridden value.
+func (t Theme) WithSuccessPrefixStyle(style Style) Theme {
+ t.SuccessPrefixStyle = style
+ return t
+}
+
+// WithWarningMessageStyle returns a new theme with overridden value.
+func (t Theme) WithWarningMessageStyle(style Style) Theme {
+ t.WarningMessageStyle = style
+ return t
+}
+
+// WithWarningPrefixStyle returns a new theme with overridden value.
+func (t Theme) WithWarningPrefixStyle(style Style) Theme {
+ t.WarningPrefixStyle = style
+ return t
+}
+
+// WithErrorMessageStyle returns a new theme with overridden value.
+func (t Theme) WithErrorMessageStyle(style Style) Theme {
+ t.ErrorMessageStyle = style
+ return t
+}
+
+// WithErrorPrefixStyle returns a new theme with overridden value.
+func (t Theme) WithErrorPrefixStyle(style Style) Theme {
+ t.ErrorPrefixStyle = style
+ return t
+}
+
+// WithFatalMessageStyle returns a new theme with overridden value.
+func (t Theme) WithFatalMessageStyle(style Style) Theme {
+ t.FatalMessageStyle = style
+ return t
+}
+
+// WithFatalPrefixStyle returns a new theme with overridden value.
+func (t Theme) WithFatalPrefixStyle(style Style) Theme {
+ t.FatalPrefixStyle = style
+ return t
+}
+
+// WithDescriptionMessageStyle returns a new theme with overridden value.
+func (t Theme) WithDescriptionMessageStyle(style Style) Theme {
+ t.DescriptionMessageStyle = style
+ return t
+}
+
+// WithDescriptionPrefixStyle returns a new theme with overridden value.
+func (t Theme) WithDescriptionPrefixStyle(style Style) Theme {
+ t.DescriptionPrefixStyle = style
+ return t
+}
+
+// WithBulletListTextStyle returns a new theme with overridden value.
+func (t Theme) WithBulletListTextStyle(style Style) Theme {
+ t.BulletListTextStyle = style
+ return t
+}
+
+// WithBulletListBulletStyle returns a new theme with overridden value.
+func (t Theme) WithBulletListBulletStyle(style Style) Theme {
+ t.BulletListBulletStyle = style
+ return t
+}
+
+// WithLetterStyle returns a new theme with overridden value.
+func (t Theme) WithLetterStyle(style Style) Theme {
+ t.LetterStyle = style
+ return t
+}
+
+// WithDebugMessageStyle returns a new theme with overridden value.
+func (t Theme) WithDebugMessageStyle(style Style) Theme {
+ t.DebugMessageStyle = style
+ return t
+}
+
+// WithDebugPrefixStyle returns a new theme with overridden value.
+func (t Theme) WithDebugPrefixStyle(style Style) Theme {
+ t.DebugPrefixStyle = style
+ return t
+}
+
+// WithTreeStyle returns a new theme with overridden value.
+func (t Theme) WithTreeStyle(style Style) Theme {
+ t.TreeStyle = style
+ return t
+}
+
+// WithTreeTextStyle returns a new theme with overridden value.
+func (t Theme) WithTreeTextStyle(style Style) Theme {
+ t.TreeTextStyle = style
+ return t
+}
+
+// WithBoxStyle returns a new theme with overridden value.
+func (t Theme) WithBoxStyle(style Style) Theme {
+ t.BoxStyle = style
+ return t
+}
+
+// WithBoxTextStyle returns a new theme with overridden value.
+func (t Theme) WithBoxTextStyle(style Style) Theme {
+ t.BoxTextStyle = style
+ return t
+}
+
+// WithBarLabelStyle returns a new theme with overridden value.
+func (t Theme) WithBarLabelStyle(style Style) Theme {
+ t.BarLabelStyle = style
+ return t
+}
+
+// WithBarStyle returns a new theme with overridden value.
+func (t Theme) WithBarStyle(style Style) Theme {
+ t.BarStyle = style
+ return t
+}
diff --git a/vendor/github.com/pterm/pterm/tree_printer.go b/vendor/github.com/pterm/pterm/tree_printer.go
new file mode 100644
index 0000000..d12f4e9
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/tree_printer.go
@@ -0,0 +1,185 @@
+package pterm
+
+import (
+ "strings"
+)
+
+// TreeNode is used as items in a TreePrinter.
+type TreeNode struct {
+ Children []TreeNode
+ Text string
+}
+
+// LeveledList is a list, which contains multiple LeveledListItem.
+type LeveledList []LeveledListItem
+
+// LeveledListItem combines a text with a specific level.
+// The level is the indent, which would normally be seen in a BulletListPrinter.
+type LeveledListItem struct {
+ Level int
+ Text string
+}
+
+// DefaultTree contains standards, which can be used to render a TreePrinter.
+var DefaultTree = TreePrinter{
+ TreeStyle: &ThemeDefault.TreeStyle,
+ TextStyle: &ThemeDefault.TreeTextStyle,
+ TopRightCornerString: "└",
+ HorizontalString: "─",
+ TopRightDownString: "├",
+ VerticalString: "│",
+ RightDownLeftString: "┬",
+ Indent: 2,
+}
+
+// TreePrinter is able to render a list.
+type TreePrinter struct {
+ Root TreeNode
+ TreeStyle *Style
+ TextStyle *Style
+ TopRightCornerString string
+ TopRightDownString string
+ HorizontalString string
+ VerticalString string
+ RightDownLeftString string
+ Indent int
+}
+
+// WithTreeStyle returns a new list with a specific tree style.
+func (p TreePrinter) WithTreeStyle(style *Style) *TreePrinter {
+ p.TreeStyle = style
+ return &p
+}
+
+// WithTextStyle returns a new list with a specific text style.
+func (p TreePrinter) WithTextStyle(style *Style) *TreePrinter {
+ p.TextStyle = style
+ return &p
+}
+
+// WithTopRightCornerString returns a new list with a specific TopRightCornerString.
+func (p TreePrinter) WithTopRightCornerString(s string) *TreePrinter {
+ p.TopRightCornerString = s
+ return &p
+}
+
+// WithTopRightDownStringOngoing returns a new list with a specific TopRightDownString.
+func (p TreePrinter) WithTopRightDownStringOngoing(s string) *TreePrinter {
+ p.TopRightDownString = s
+ return &p
+}
+
+// WithHorizontalString returns a new list with a specific HorizontalString.
+func (p TreePrinter) WithHorizontalString(s string) *TreePrinter {
+ p.HorizontalString = s
+ return &p
+}
+
+// WithVerticalString returns a new list with a specific VerticalString.
+func (p TreePrinter) WithVerticalString(s string) *TreePrinter {
+ p.VerticalString = s
+ return &p
+}
+
+// WithRoot returns a new list with a specific Root.
+func (p TreePrinter) WithRoot(root TreeNode) *TreePrinter {
+ p.Root = root
+ return &p
+}
+
+// WithIndent returns a new list with a specific amount of spacing between the levels.
+// Indent must be at least 1.
+func (p TreePrinter) WithIndent(indent int) *TreePrinter {
+ if indent < 1 {
+ indent = 1
+ }
+ p.Indent = indent
+ return &p
+}
+
+// Render prints the list to the terminal.
+func (p TreePrinter) Render() error {
+ s, _ := p.Srender()
+ Println(s)
+
+ return nil
+}
+
+// Srender renders the list as a string.
+func (p TreePrinter) Srender() (string, error) {
+ if p.TreeStyle == nil {
+ p.TreeStyle = NewStyle()
+ }
+ if p.TextStyle == nil {
+ p.TextStyle = NewStyle()
+ }
+
+ return walkOverTree(p.Root.Children, p, ""), nil
+}
+
+// walkOverTree is a recursive function,
+// which analyzes a TreePrinter and connects the items with specific characters.
+// Returns TreePrinter as string.
+func walkOverTree(list []TreeNode, p TreePrinter, prefix string) string {
+ var ret string
+ for i, item := range list {
+ if len(list) > i+1 { // if not last in list
+ if len(item.Children) == 0 { // if there are no children
+ ret += prefix + p.TreeStyle.Sprint(p.TopRightDownString) + strings.Repeat(p.TreeStyle.Sprint(p.HorizontalString), p.Indent) +
+ p.TextStyle.Sprint(item.Text) + "\n"
+ } else { // if there are children
+ ret += prefix + p.TreeStyle.Sprint(p.TopRightDownString) + strings.Repeat(p.TreeStyle.Sprint(p.HorizontalString), p.Indent-1) +
+ p.TreeStyle.Sprint(p.RightDownLeftString) + p.TextStyle.Sprint(item.Text) + "\n"
+ ret += walkOverTree(item.Children, p, prefix+p.TreeStyle.Sprint(p.VerticalString)+strings.Repeat(" ", p.Indent-1))
+ }
+ } else if len(list) == i+1 { // if last in list
+ if len(item.Children) == 0 { // if there are no children
+ ret += prefix + p.TreeStyle.Sprint(p.TopRightCornerString) + strings.Repeat(p.TreeStyle.Sprint(p.HorizontalString), p.Indent) +
+ p.TextStyle.Sprint(item.Text) + "\n"
+ } else { // if there are children
+ ret += prefix + p.TreeStyle.Sprint(p.TopRightCornerString) + strings.Repeat(p.TreeStyle.Sprint(p.HorizontalString), p.Indent-1) +
+ p.TreeStyle.Sprint(p.RightDownLeftString) + p.TextStyle.Sprint(item.Text) + "\n"
+ ret += walkOverTree(item.Children, p, prefix+strings.Repeat(" ", p.Indent))
+ }
+ }
+ }
+ return ret
+}
+
+// NewTreeFromLeveledList converts a TreeItems list to a TreeNode and returns it.
+func NewTreeFromLeveledList(leveledListItems LeveledList) TreeNode {
+ if len(leveledListItems) == 0 {
+ return TreeNode{}
+ }
+
+ root := &TreeNode{
+ Children: []TreeNode{},
+ Text: leveledListItems[0].Text,
+ }
+
+ for i, record := range leveledListItems {
+ last := root
+
+ if record.Level < 0 {
+ record.Level = 0
+ leveledListItems[i].Level = 0
+ }
+
+ if len(leveledListItems)-1 != i {
+ if leveledListItems[i+1].Level-1 > record.Level {
+ leveledListItems[i+1].Level = record.Level + 1
+ }
+ }
+
+ for i := 0; i < record.Level; i++ {
+ lastIndex := len(last.Children) - 1
+ last = &last.Children[lastIndex]
+ }
+ last.Children = append(last.Children, TreeNode{
+ Children: []TreeNode{},
+ Text: record.Text,
+ })
+ }
+
+ return *root
+}
diff --git a/vendor/github.com/rivo/uniseg/LICENSE.txt b/vendor/github.com/rivo/uniseg/LICENSE.txt
new file mode 100644
index 0000000..5040f1e
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/LICENSE.txt
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Oliver Kuederle
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/rivo/uniseg/README.md b/vendor/github.com/rivo/uniseg/README.md
new file mode 100644
index 0000000..f8da293
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/README.md
@@ -0,0 +1,62 @@
+# Unicode Text Segmentation for Go
+
+[![Godoc Reference](https://img.shields.io/badge/godoc-reference-blue.svg)](https://godoc.org/github.com/rivo/uniseg)
+[![Go Report](https://img.shields.io/badge/go%20report-A%2B-brightgreen.svg)](https://goreportcard.com/report/github.com/rivo/uniseg)
+
+This Go package implements Unicode Text Segmentation according to [Unicode Standard Annex #29](http://unicode.org/reports/tr29/) (Unicode version 12.0.0).
+
+At this point, only the determination of grapheme cluster boundaries is implemented.
+
+## Background
+
+In Go, [strings are read-only slices of bytes](https://blog.golang.org/strings). They can be turned into Unicode code points using the `for` loop or by casting: `[]rune(str)`. However, multiple code points may be combined into one user-perceived character or what the Unicode specification calls "grapheme cluster". Here are some examples:
+
+|String|Bytes (UTF-8)|Code points (runes)|Grapheme clusters|
+|-|-|-|-|
+|Käse|6 bytes: `4b 61 cc 88 73 65`|5 code points: `4b 61 308 73 65`|4 clusters: `[4b],[61 308],[73],[65]`|
+|🏳️🌈|14 bytes: `f0 9f 8f b3 ef b8 8f e2 80 8d f0 9f 8c 88`|4 code points: `1f3f3 fe0f 200d 1f308`|1 cluster: `[1f3f3 fe0f 200d 1f308]`|
+|🇩🇪|8 bytes: `f0 9f 87 a9 f0 9f 87 aa`|2 code points: `1f1e9 1f1ea`|1 cluster: `[1f1e9 1f1ea]`|
+
+This package provides a tool to iterate over these grapheme clusters. This may be used to determine the number of user-perceived characters, to split strings in their intended places, or to extract individual characters which form a unit.
+
+## Installation
+
+```bash
+go get github.com/rivo/uniseg
+```
+
+## Basic Example
+
+```go
+package uniseg
+
+import (
+ "fmt"
+
+ "github.com/rivo/uniseg"
+)
+
+func main() {
+ gr := uniseg.NewGraphemes("👍🏼!")
+ for gr.Next() {
+ fmt.Printf("%x ", gr.Runes())
+ }
+ // Output: [1f44d 1f3fc] [21]
+}
+```
+
+## Documentation
+
+Refer to https://godoc.org/github.com/rivo/uniseg for the package's documentation.
+
+## Dependencies
+
+This package does not depend on any packages outside the standard library.
+
+## Your Feedback
+
+Add your issue here on GitHub. Feel free to get in touch if you have any questions.
+
+## Version
+
+Version tags will be introduced once Golang modules are official. Consider this version 0.1.
diff --git a/vendor/github.com/rivo/uniseg/doc.go b/vendor/github.com/rivo/uniseg/doc.go
new file mode 100644
index 0000000..60c737d
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/doc.go
@@ -0,0 +1,8 @@
+/*
+Package uniseg implements Unicode Text Segmentation according to Unicode
+Standard Annex #29 (http://unicode.org/reports/tr29/).
+
+At this point, only the determination of grapheme cluster boundaries is
+implemented.
+*/
+package uniseg
diff --git a/vendor/github.com/rivo/uniseg/go.mod b/vendor/github.com/rivo/uniseg/go.mod
new file mode 100644
index 0000000..a54280b
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/go.mod
@@ -0,0 +1,3 @@
+module github.com/rivo/uniseg
+
+go 1.12
diff --git a/vendor/github.com/rivo/uniseg/grapheme.go b/vendor/github.com/rivo/uniseg/grapheme.go
new file mode 100644
index 0000000..207157f
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/grapheme.go
@@ -0,0 +1,268 @@
+package uniseg
+
+import "unicode/utf8"
+
+// The states of the grapheme cluster parser.
+const (
+ grAny = iota
+ grCR
+ grControlLF
+ grL
+ grLVV
+ grLVTT
+ grPrepend
+ grExtendedPictographic
+ grExtendedPictographicZWJ
+ grRIOdd
+ grRIEven
+)
+
+// The grapheme cluster parser's breaking instructions.
+const (
+ grNoBoundary = iota
+ grBoundary
+)
+
+// The grapheme cluster parser's state transitions. Maps (state, property) to
+// (new state, breaking instruction, rule number). The breaking instruction
+// always refers to the boundary between the last and next code point.
+//
+// This map is queried as follows:
+//
+// 1. Find specific state + specific property. Stop if found.
+// 2. Find specific state + any property.
+// 3. Find any state + specific property.
+// 4. If only (2) or (3) (but not both) was found, stop.
+// 5. If both (2) and (3) were found, use state and breaking instruction from
+// the transition with the lower rule number, prefer (3) if rule numbers
+// are equal. Stop.
+// 6. Assume grAny and grBoundary.
+var grTransitions = map[[2]int][3]int{
+ // GB5
+ {grAny, prCR}: {grCR, grBoundary, 50},
+ {grAny, prLF}: {grControlLF, grBoundary, 50},
+ {grAny, prControl}: {grControlLF, grBoundary, 50},
+
+ // GB4
+ {grCR, prAny}: {grAny, grBoundary, 40},
+ {grControlLF, prAny}: {grAny, grBoundary, 40},
+
+ // GB3.
+ {grCR, prLF}: {grAny, grNoBoundary, 30},
+
+ // GB6.
+ {grAny, prL}: {grL, grBoundary, 9990},
+ {grL, prL}: {grL, grNoBoundary, 60},
+ {grL, prV}: {grLVV, grNoBoundary, 60},
+ {grL, prLV}: {grLVV, grNoBoundary, 60},
+ {grL, prLVT}: {grLVTT, grNoBoundary, 60},
+
+ // GB7.
+ {grAny, prLV}: {grLVV, grBoundary, 9990},
+ {grAny, prV}: {grLVV, grBoundary, 9990},
+ {grLVV, prV}: {grLVV, grNoBoundary, 70},
+ {grLVV, prT}: {grLVTT, grNoBoundary, 70},
+
+ // GB8.
+ {grAny, prLVT}: {grLVTT, grBoundary, 9990},
+ {grAny, prT}: {grLVTT, grBoundary, 9990},
+ {grLVTT, prT}: {grLVTT, grNoBoundary, 80},
+
+ // GB9.
+ {grAny, prExtend}: {grAny, grNoBoundary, 90},
+ {grAny, prZWJ}: {grAny, grNoBoundary, 90},
+
+ // GB9a.
+ {grAny, prSpacingMark}: {grAny, grNoBoundary, 91},
+
+ // GB9b.
+ {grAny, prPreprend}: {grPrepend, grBoundary, 9990},
+ {grPrepend, prAny}: {grAny, grNoBoundary, 92},
+
+ // GB11.
+ {grAny, prExtendedPictographic}: {grExtendedPictographic, grBoundary, 9990},
+ {grExtendedPictographic, prExtend}: {grExtendedPictographic, grNoBoundary, 110},
+ {grExtendedPictographic, prZWJ}: {grExtendedPictographicZWJ, grNoBoundary, 110},
+ {grExtendedPictographicZWJ, prExtendedPictographic}: {grExtendedPictographic, grNoBoundary, 110},
+
+ // GB12 / GB13.
+ {grAny, prRegionalIndicator}: {grRIOdd, grBoundary, 9990},
+ {grRIOdd, prRegionalIndicator}: {grRIEven, grNoBoundary, 120},
+ {grRIEven, prRegionalIndicator}: {grRIOdd, grBoundary, 120},
+}
+
+// Graphemes implements an iterator over Unicode extended grapheme clusters,
+// specified in the Unicode Standard Annex #29. Grapheme clusters correspond to
+// "user-perceived characters". These characters often consist of multiple
+// code points (e.g. the "woman kissing woman" emoji consists of 8 code points:
+// woman + ZWJ + heavy black heart (2 code points) + ZWJ + kiss mark + ZWJ +
+// woman) and the rules described in Annex #29 must be applied to group those
+// code points into clusters perceived by the user as one character.
+type Graphemes struct {
+ // The code points over which this class iterates.
+ codePoints []rune
+
+ // The (byte-based) indices of the code points into the original string plus
+ // len(original string). Thus, len(indices) = len(codePoints) + 1.
+ indices []int
+
+ // The current grapheme cluster to be returned. These are indices into
+ // codePoints/indices. If start == end, we either haven't started iterating
+ // yet (0) or the iteration has already completed (1).
+ start, end int
+
+ // The index of the next code point to be parsed.
+ pos int
+
+ // The current state of the code point parser.
+ state int
+}
+
+// NewGraphemes returns a new grapheme cluster iterator.
+func NewGraphemes(s string) *Graphemes {
+ l := utf8.RuneCountInString(s)
+ codePoints := make([]rune, l)
+ indices := make([]int, l+1)
+ i := 0
+ for pos, r := range s {
+ codePoints[i] = r
+ indices[i] = pos
+ i++
+ }
+ indices[l] = len(s)
+ g := &Graphemes{
+ codePoints: codePoints,
+ indices: indices,
+ }
+ g.Next() // Parse ahead.
+ return g
+}
+
+// Next advances the iterator by one grapheme cluster and returns false if no
+// clusters are left. This function must be called before the first cluster is
+// accessed.
+func (g *Graphemes) Next() bool {
+ g.start = g.end
+
+ // The state transition gives us a boundary instruction BEFORE the next code
+ // point so we always need to stay ahead by one code point.
+
+ // Parse the next code point.
+ for g.pos <= len(g.codePoints) {
+ // GB2.
+ if g.pos == len(g.codePoints) {
+ g.end = g.pos
+ g.pos++
+ break
+ }
+
+ // Determine the property of the next character.
+ nextProperty := property(g.codePoints[g.pos])
+ g.pos++
+
+ // Find the applicable transition.
+ var boundary bool
+ transition, ok := grTransitions[[2]int{g.state, nextProperty}]
+ if ok {
+ // We have a specific transition. We'll use it.
+ g.state = transition[0]
+ boundary = transition[1] == grBoundary
+ } else {
+ // No specific transition found. Try the less specific ones.
+ transAnyProp, okAnyProp := grTransitions[[2]int{g.state, prAny}]
+ transAnyState, okAnyState := grTransitions[[2]int{grAny, nextProperty}]
+ if okAnyProp && okAnyState {
+ // Both apply. We'll use a mix (see comments for grTransitions).
+ g.state = transAnyState[0]
+ boundary = transAnyState[1] == grBoundary
+ if transAnyProp[2] < transAnyState[2] {
+ g.state = transAnyProp[0]
+ boundary = transAnyProp[1] == grBoundary
+ }
+ } else if okAnyProp {
+ // We only have a specific state.
+ g.state = transAnyProp[0]
+ boundary = transAnyProp[1] == grBoundary
+ // This branch will probably never be reached because okAnyState will
+ // always be true given the current transition map. But we keep it here
+ // for future modifications to the transition map where this may not be
+ // true anymore.
+ } else if okAnyState {
+ // We only have a specific property.
+ g.state = transAnyState[0]
+ boundary = transAnyState[1] == grBoundary
+ } else {
+ // No known transition. GB999: Any x Any.
+ g.state = grAny
+ boundary = true
+ }
+ }
+
+ // If we found a cluster boundary, let's stop here. The current cluster will
+ // be the one that just ended.
+ if g.pos-1 == 0 /* GB1 */ || boundary {
+ g.end = g.pos - 1
+ break
+ }
+ }
+
+ return g.start != g.end
+}
+
+// Runes returns a slice of runes (code points) which corresponds to the current
+// grapheme cluster. If the iterator is already past the end or Next() has not
+// yet been called, nil is returned.
+func (g *Graphemes) Runes() []rune {
+ if g.start == g.end {
+ return nil
+ }
+ return g.codePoints[g.start:g.end]
+}
+
+// Str returns a substring of the original string which corresponds to the
+// current grapheme cluster. If the iterator is already past the end or Next()
+// has not yet been called, an empty string is returned.
+func (g *Graphemes) Str() string {
+ if g.start == g.end {
+ return ""
+ }
+ return string(g.codePoints[g.start:g.end])
+}
+
+// Bytes returns a byte slice which corresponds to the current grapheme cluster.
+// If the iterator is already past the end or Next() has not yet been called,
+// nil is returned.
+func (g *Graphemes) Bytes() []byte {
+ if g.start == g.end {
+ return nil
+ }
+ return []byte(string(g.codePoints[g.start:g.end]))
+}
+
+// Positions returns the interval of the current grapheme cluster as byte
+// positions into the original string. The first returned value "from" indexes
+// the first byte and the second returned value "to" indexes the first byte that
+// is not included anymore, i.e. str[from:to] is the current grapheme cluster of
+// the original string "str". If Next() has not yet been called, both values are
+// 0. If the iterator is already past the end, both values are 1.
+func (g *Graphemes) Positions() (int, int) {
+ return g.indices[g.start], g.indices[g.end]
+}
+
+// Reset puts the iterator into its initial state such that the next call to
+// Next() sets it to the first grapheme cluster again.
+func (g *Graphemes) Reset() {
+ g.start, g.end, g.pos, g.state = 0, 0, 0, grAny
+ g.Next() // Parse ahead again.
+}
+
+// GraphemeClusterCount returns the number of user-perceived characters
+// (grapheme clusters) for the given string. To calculate this number, it
+// iterates through the string using the Graphemes iterator.
+func GraphemeClusterCount(s string) (n int) {
+ g := NewGraphemes(s)
+ for g.Next() {
+ n++
+ }
+ return
+}
diff --git a/vendor/github.com/rivo/uniseg/properties.go b/vendor/github.com/rivo/uniseg/properties.go
new file mode 100644
index 0000000..a75ab58
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/properties.go
@@ -0,0 +1,1658 @@
+package uniseg
+
+// The unicode properties. Only the ones needed in the context of this package
+// are included.
+const (
+ prAny = iota
+ prPreprend
+ prCR
+ prLF
+ prControl
+ prExtend
+ prRegionalIndicator
+ prSpacingMark
+ prL
+ prV
+ prT
+ prLV
+ prLVT
+ prZWJ
+ prExtendedPictographic
+)
+
+// Maps code point ranges to their properties. In the context of this package,
+// any code point that is not contained may map to "prAny". The code point
+// ranges in this slice are numerically sorted.
+//
+// These ranges were taken from
+// http://www.unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakProperty.txt
+// as well as
+// https://unicode.org/Public/emoji/latest/emoji-data.txt
+// ("Extended_Pictographic" only) on March 11, 2019. See
+// https://www.unicode.org/license.html for the Unicode license agreement.
+var codePoints = [][3]int{
+ {0x0000, 0x0009, prControl}, // Cc [10] ..
+ {0x000A, 0x000A, prLF}, // Cc
+ {0x000B, 0x000C, prControl}, // Cc [2] ..
+ {0x000D, 0x000D, prCR}, // Cc
+ {0x000E, 0x001F, prControl}, // Cc [18] ..
+ {0x007F, 0x009F, prControl}, // Cc [33] ..
+ {0x00A9, 0x00A9, prExtendedPictographic}, // 1.1 [1] (©️) copyright
+ {0x00AD, 0x00AD, prControl}, // Cf SOFT HYPHEN
+ {0x00AE, 0x00AE, prExtendedPictographic}, // 1.1 [1] (®️) registered
+ {0x0300, 0x036F, prExtend}, // Mn [112] COMBINING GRAVE ACCENT..COMBINING LATIN SMALL LETTER X
+ {0x0483, 0x0487, prExtend}, // Mn [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE
+ {0x0488, 0x0489, prExtend}, // Me [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN
+ {0x0591, 0x05BD, prExtend}, // Mn [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG
+ {0x05BF, 0x05BF, prExtend}, // Mn HEBREW POINT RAFE
+ {0x05C1, 0x05C2, prExtend}, // Mn [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT
+ {0x05C4, 0x05C5, prExtend}, // Mn [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT
+ {0x05C7, 0x05C7, prExtend}, // Mn HEBREW POINT QAMATS QATAN
+ {0x0600, 0x0605, prPreprend}, // Cf [6] ARABIC NUMBER SIGN..ARABIC NUMBER MARK ABOVE
+ {0x0610, 0x061A, prExtend}, // Mn [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA
+ {0x061C, 0x061C, prControl}, // Cf ARABIC LETTER MARK
+ {0x064B, 0x065F, prExtend}, // Mn [21] ARABIC FATHATAN..ARABIC WAVY HAMZA BELOW
+ {0x0670, 0x0670, prExtend}, // Mn ARABIC LETTER SUPERSCRIPT ALEF
+ {0x06D6, 0x06DC, prExtend}, // Mn [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN
+ {0x06DD, 0x06DD, prPreprend}, // Cf ARABIC END OF AYAH
+ {0x06DF, 0x06E4, prExtend}, // Mn [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA
+ {0x06E7, 0x06E8, prExtend}, // Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON
+ {0x06EA, 0x06ED, prExtend}, // Mn [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM
+ {0x070F, 0x070F, prPreprend}, // Cf SYRIAC ABBREVIATION MARK
+ {0x0711, 0x0711, prExtend}, // Mn SYRIAC LETTER SUPERSCRIPT ALAPH
+ {0x0730, 0x074A, prExtend}, // Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH
+ {0x07A6, 0x07B0, prExtend}, // Mn [11] THAANA ABAFILI..THAANA SUKUN
+ {0x07EB, 0x07F3, prExtend}, // Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE
+ {0x07FD, 0x07FD, prExtend}, // Mn NKO DANTAYALAN
+ {0x0816, 0x0819, prExtend}, // Mn [4] SAMARITAN MARK IN..SAMARITAN MARK DAGESH
+ {0x081B, 0x0823, prExtend}, // Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A
+ {0x0825, 0x0827, prExtend}, // Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U
+ {0x0829, 0x082D, prExtend}, // Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA
+ {0x0859, 0x085B, prExtend}, // Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK
+ {0x08D3, 0x08E1, prExtend}, // Mn [15] ARABIC SMALL LOW WAW..ARABIC SMALL HIGH SIGN SAFHA
+ {0x08E2, 0x08E2, prPreprend}, // Cf ARABIC DISPUTED END OF AYAH
+ {0x08E3, 0x0902, prExtend}, // Mn [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA
+ {0x0903, 0x0903, prSpacingMark}, // Mc DEVANAGARI SIGN VISARGA
+ {0x093A, 0x093A, prExtend}, // Mn DEVANAGARI VOWEL SIGN OE
+ {0x093B, 0x093B, prSpacingMark}, // Mc DEVANAGARI VOWEL SIGN OOE
+ {0x093C, 0x093C, prExtend}, // Mn DEVANAGARI SIGN NUKTA
+ {0x093E, 0x0940, prSpacingMark}, // Mc [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II
+ {0x0941, 0x0948, prExtend}, // Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI
+ {0x0949, 0x094C, prSpacingMark}, // Mc [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU
+ {0x094D, 0x094D, prExtend}, // Mn DEVANAGARI SIGN VIRAMA
+ {0x094E, 0x094F, prSpacingMark}, // Mc [2] DEVANAGARI VOWEL SIGN PRISHTHAMATRA E..DEVANAGARI VOWEL SIGN AW
+ {0x0951, 0x0957, prExtend}, // Mn [7] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI VOWEL SIGN UUE
+ {0x0962, 0x0963, prExtend}, // Mn [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL
+ {0x0981, 0x0981, prExtend}, // Mn BENGALI SIGN CANDRABINDU
+ {0x0982, 0x0983, prSpacingMark}, // Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA
+ {0x09BC, 0x09BC, prExtend}, // Mn BENGALI SIGN NUKTA
+ {0x09BE, 0x09BE, prExtend}, // Mc BENGALI VOWEL SIGN AA
+ {0x09BF, 0x09C0, prSpacingMark}, // Mc [2] BENGALI VOWEL SIGN I..BENGALI VOWEL SIGN II
+ {0x09C1, 0x09C4, prExtend}, // Mn [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR
+ {0x09C7, 0x09C8, prSpacingMark}, // Mc [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI
+ {0x09CB, 0x09CC, prSpacingMark}, // Mc [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU
+ {0x09CD, 0x09CD, prExtend}, // Mn BENGALI SIGN VIRAMA
+ {0x09D7, 0x09D7, prExtend}, // Mc BENGALI AU LENGTH MARK
+ {0x09E2, 0x09E3, prExtend}, // Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL
+ {0x09FE, 0x09FE, prExtend}, // Mn BENGALI SANDHI MARK
+ {0x0A01, 0x0A02, prExtend}, // Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI
+ {0x0A03, 0x0A03, prSpacingMark}, // Mc GURMUKHI SIGN VISARGA
+ {0x0A3C, 0x0A3C, prExtend}, // Mn GURMUKHI SIGN NUKTA
+ {0x0A3E, 0x0A40, prSpacingMark}, // Mc [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II
+ {0x0A41, 0x0A42, prExtend}, // Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU
+ {0x0A47, 0x0A48, prExtend}, // Mn [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI
+ {0x0A4B, 0x0A4D, prExtend}, // Mn [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA
+ {0x0A51, 0x0A51, prExtend}, // Mn GURMUKHI SIGN UDAAT
+ {0x0A70, 0x0A71, prExtend}, // Mn [2] GURMUKHI TIPPI..GURMUKHI ADDAK
+ {0x0A75, 0x0A75, prExtend}, // Mn GURMUKHI SIGN YAKASH
+ {0x0A81, 0x0A82, prExtend}, // Mn [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA
+ {0x0A83, 0x0A83, prSpacingMark}, // Mc GUJARATI SIGN VISARGA
+ {0x0ABC, 0x0ABC, prExtend}, // Mn GUJARATI SIGN NUKTA
+ {0x0ABE, 0x0AC0, prSpacingMark}, // Mc [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II
+ {0x0AC1, 0x0AC5, prExtend}, // Mn [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E
+ {0x0AC7, 0x0AC8, prExtend}, // Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI
+ {0x0AC9, 0x0AC9, prSpacingMark}, // Mc GUJARATI VOWEL SIGN CANDRA O
+ {0x0ACB, 0x0ACC, prSpacingMark}, // Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU
+ {0x0ACD, 0x0ACD, prExtend}, // Mn GUJARATI SIGN VIRAMA
+ {0x0AE2, 0x0AE3, prExtend}, // Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL
+ {0x0AFA, 0x0AFF, prExtend}, // Mn [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE
+ {0x0B01, 0x0B01, prExtend}, // Mn ORIYA SIGN CANDRABINDU
+ {0x0B02, 0x0B03, prSpacingMark}, // Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA
+ {0x0B3C, 0x0B3C, prExtend}, // Mn ORIYA SIGN NUKTA
+ {0x0B3E, 0x0B3E, prExtend}, // Mc ORIYA VOWEL SIGN AA
+ {0x0B3F, 0x0B3F, prExtend}, // Mn ORIYA VOWEL SIGN I
+ {0x0B40, 0x0B40, prSpacingMark}, // Mc ORIYA VOWEL SIGN II
+ {0x0B41, 0x0B44, prExtend}, // Mn [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR
+ {0x0B47, 0x0B48, prSpacingMark}, // Mc [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI
+ {0x0B4B, 0x0B4C, prSpacingMark}, // Mc [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU
+ {0x0B4D, 0x0B4D, prExtend}, // Mn ORIYA SIGN VIRAMA
+ {0x0B56, 0x0B56, prExtend}, // Mn ORIYA AI LENGTH MARK
+ {0x0B57, 0x0B57, prExtend}, // Mc ORIYA AU LENGTH MARK
+ {0x0B62, 0x0B63, prExtend}, // Mn [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL
+ {0x0B82, 0x0B82, prExtend}, // Mn TAMIL SIGN ANUSVARA
+ {0x0BBE, 0x0BBE, prExtend}, // Mc TAMIL VOWEL SIGN AA
+ {0x0BBF, 0x0BBF, prSpacingMark}, // Mc TAMIL VOWEL SIGN I
+ {0x0BC0, 0x0BC0, prExtend}, // Mn TAMIL VOWEL SIGN II
+ {0x0BC1, 0x0BC2, prSpacingMark}, // Mc [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU
+ {0x0BC6, 0x0BC8, prSpacingMark}, // Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI
+ {0x0BCA, 0x0BCC, prSpacingMark}, // Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU
+ {0x0BCD, 0x0BCD, prExtend}, // Mn TAMIL SIGN VIRAMA
+ {0x0BD7, 0x0BD7, prExtend}, // Mc TAMIL AU LENGTH MARK
+ {0x0C00, 0x0C00, prExtend}, // Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE
+ {0x0C01, 0x0C03, prSpacingMark}, // Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA
+ {0x0C04, 0x0C04, prExtend}, // Mn TELUGU SIGN COMBINING ANUSVARA ABOVE
+ {0x0C3E, 0x0C40, prExtend}, // Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II
+ {0x0C41, 0x0C44, prSpacingMark}, // Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR
+ {0x0C46, 0x0C48, prExtend}, // Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI
+ {0x0C4A, 0x0C4D, prExtend}, // Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA
+ {0x0C55, 0x0C56, prExtend}, // Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK
+ {0x0C62, 0x0C63, prExtend}, // Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL
+ {0x0C81, 0x0C81, prExtend}, // Mn KANNADA SIGN CANDRABINDU
+ {0x0C82, 0x0C83, prSpacingMark}, // Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA
+ {0x0CBC, 0x0CBC, prExtend}, // Mn KANNADA SIGN NUKTA
+ {0x0CBE, 0x0CBE, prSpacingMark}, // Mc KANNADA VOWEL SIGN AA
+ {0x0CBF, 0x0CBF, prExtend}, // Mn KANNADA VOWEL SIGN I
+ {0x0CC0, 0x0CC1, prSpacingMark}, // Mc [2] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN U
+ {0x0CC2, 0x0CC2, prExtend}, // Mc KANNADA VOWEL SIGN UU
+ {0x0CC3, 0x0CC4, prSpacingMark}, // Mc [2] KANNADA VOWEL SIGN VOCALIC R..KANNADA VOWEL SIGN VOCALIC RR
+ {0x0CC6, 0x0CC6, prExtend}, // Mn KANNADA VOWEL SIGN E
+ {0x0CC7, 0x0CC8, prSpacingMark}, // Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI
+ {0x0CCA, 0x0CCB, prSpacingMark}, // Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO
+ {0x0CCC, 0x0CCD, prExtend}, // Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA
+ {0x0CD5, 0x0CD6, prExtend}, // Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK
+ {0x0CE2, 0x0CE3, prExtend}, // Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL
+ {0x0D00, 0x0D01, prExtend}, // Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU
+ {0x0D02, 0x0D03, prSpacingMark}, // Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA
+ {0x0D3B, 0x0D3C, prExtend}, // Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA
+ {0x0D3E, 0x0D3E, prExtend}, // Mc MALAYALAM VOWEL SIGN AA
+ {0x0D3F, 0x0D40, prSpacingMark}, // Mc [2] MALAYALAM VOWEL SIGN I..MALAYALAM VOWEL SIGN II
+ {0x0D41, 0x0D44, prExtend}, // Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR
+ {0x0D46, 0x0D48, prSpacingMark}, // Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI
+ {0x0D4A, 0x0D4C, prSpacingMark}, // Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU
+ {0x0D4D, 0x0D4D, prExtend}, // Mn MALAYALAM SIGN VIRAMA
+ {0x0D4E, 0x0D4E, prPreprend}, // Lo MALAYALAM LETTER DOT REPH
+ {0x0D57, 0x0D57, prExtend}, // Mc MALAYALAM AU LENGTH MARK
+ {0x0D62, 0x0D63, prExtend}, // Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL
+ {0x0D82, 0x0D83, prSpacingMark}, // Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA
+ {0x0DCA, 0x0DCA, prExtend}, // Mn SINHALA SIGN AL-LAKUNA
+ {0x0DCF, 0x0DCF, prExtend}, // Mc SINHALA VOWEL SIGN AELA-PILLA
+ {0x0DD0, 0x0DD1, prSpacingMark}, // Mc [2] SINHALA VOWEL SIGN KETTI AEDA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA
+ {0x0DD2, 0x0DD4, prExtend}, // Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA
+ {0x0DD6, 0x0DD6, prExtend}, // Mn SINHALA VOWEL SIGN DIGA PAA-PILLA
+ {0x0DD8, 0x0DDE, prSpacingMark}, // Mc [7] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA
+ {0x0DDF, 0x0DDF, prExtend}, // Mc SINHALA VOWEL SIGN GAYANUKITTA
+ {0x0DF2, 0x0DF3, prSpacingMark}, // Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA
+ {0x0E31, 0x0E31, prExtend}, // Mn THAI CHARACTER MAI HAN-AKAT
+ {0x0E33, 0x0E33, prSpacingMark}, // Lo THAI CHARACTER SARA AM
+ {0x0E34, 0x0E3A, prExtend}, // Mn [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU
+ {0x0E47, 0x0E4E, prExtend}, // Mn [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN
+ {0x0EB1, 0x0EB1, prExtend}, // Mn LAO VOWEL SIGN MAI KAN
+ {0x0EB3, 0x0EB3, prSpacingMark}, // Lo LAO VOWEL SIGN AM
+ {0x0EB4, 0x0EBC, prExtend}, // Mn [9] LAO VOWEL SIGN I..LAO SEMIVOWEL SIGN LO
+ {0x0EC8, 0x0ECD, prExtend}, // Mn [6] LAO TONE MAI EK..LAO NIGGAHITA
+ {0x0F18, 0x0F19, prExtend}, // Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS
+ {0x0F35, 0x0F35, prExtend}, // Mn TIBETAN MARK NGAS BZUNG NYI ZLA
+ {0x0F37, 0x0F37, prExtend}, // Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS
+ {0x0F39, 0x0F39, prExtend}, // Mn TIBETAN MARK TSA -PHRU
+ {0x0F3E, 0x0F3F, prSpacingMark}, // Mc [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES
+ {0x0F71, 0x0F7E, prExtend}, // Mn [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO
+ {0x0F7F, 0x0F7F, prSpacingMark}, // Mc TIBETAN SIGN RNAM BCAD
+ {0x0F80, 0x0F84, prExtend}, // Mn [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA
+ {0x0F86, 0x0F87, prExtend}, // Mn [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS
+ {0x0F8D, 0x0F97, prExtend}, // Mn [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA
+ {0x0F99, 0x0FBC, prExtend}, // Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA
+ {0x0FC6, 0x0FC6, prExtend}, // Mn TIBETAN SYMBOL PADMA GDAN
+ {0x102D, 0x1030, prExtend}, // Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU
+ {0x1031, 0x1031, prSpacingMark}, // Mc MYANMAR VOWEL SIGN E
+ {0x1032, 0x1037, prExtend}, // Mn [6] MYANMAR VOWEL SIGN AI..MYANMAR SIGN DOT BELOW
+ {0x1039, 0x103A, prExtend}, // Mn [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT
+ {0x103B, 0x103C, prSpacingMark}, // Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA
+ {0x103D, 0x103E, prExtend}, // Mn [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA
+ {0x1056, 0x1057, prSpacingMark}, // Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR
+ {0x1058, 0x1059, prExtend}, // Mn [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL
+ {0x105E, 0x1060, prExtend}, // Mn [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA
+ {0x1071, 0x1074, prExtend}, // Mn [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE
+ {0x1082, 0x1082, prExtend}, // Mn MYANMAR CONSONANT SIGN SHAN MEDIAL WA
+ {0x1084, 0x1084, prSpacingMark}, // Mc MYANMAR VOWEL SIGN SHAN E
+ {0x1085, 0x1086, prExtend}, // Mn [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y
+ {0x108D, 0x108D, prExtend}, // Mn MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE
+ {0x109D, 0x109D, prExtend}, // Mn MYANMAR VOWEL SIGN AITON AI
+ {0x1100, 0x115F, prL}, // Lo [96] HANGUL CHOSEONG KIYEOK..HANGUL CHOSEONG FILLER
+ {0x1160, 0x11A7, prV}, // Lo [72] HANGUL JUNGSEONG FILLER..HANGUL JUNGSEONG O-YAE
+ {0x11A8, 0x11FF, prT}, // Lo [88] HANGUL JONGSEONG KIYEOK..HANGUL JONGSEONG SSANGNIEUN
+ {0x135D, 0x135F, prExtend}, // Mn [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK
+ {0x1712, 0x1714, prExtend}, // Mn [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA
+ {0x1732, 0x1734, prExtend}, // Mn [3] HANUNOO VOWEL SIGN I..HANUNOO SIGN PAMUDPOD
+ {0x1752, 0x1753, prExtend}, // Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U
+ {0x1772, 0x1773, prExtend}, // Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U
+ {0x17B4, 0x17B5, prExtend}, // Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
+ {0x17B6, 0x17B6, prSpacingMark}, // Mc KHMER VOWEL SIGN AA
+ {0x17B7, 0x17BD, prExtend}, // Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA
+ {0x17BE, 0x17C5, prSpacingMark}, // Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU
+ {0x17C6, 0x17C6, prExtend}, // Mn KHMER SIGN NIKAHIT
+ {0x17C7, 0x17C8, prSpacingMark}, // Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU
+ {0x17C9, 0x17D3, prExtend}, // Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT
+ {0x17DD, 0x17DD, prExtend}, // Mn KHMER SIGN ATTHACAN
+ {0x180B, 0x180D, prExtend}, // Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
+ {0x180E, 0x180E, prControl}, // Cf MONGOLIAN VOWEL SEPARATOR
+ {0x1885, 0x1886, prExtend}, // Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA
+ {0x18A9, 0x18A9, prExtend}, // Mn MONGOLIAN LETTER ALI GALI DAGALGA
+ {0x1920, 0x1922, prExtend}, // Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U
+ {0x1923, 0x1926, prSpacingMark}, // Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU
+ {0x1927, 0x1928, prExtend}, // Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O
+ {0x1929, 0x192B, prSpacingMark}, // Mc [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA
+ {0x1930, 0x1931, prSpacingMark}, // Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA
+ {0x1932, 0x1932, prExtend}, // Mn LIMBU SMALL LETTER ANUSVARA
+ {0x1933, 0x1938, prSpacingMark}, // Mc [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA
+ {0x1939, 0x193B, prExtend}, // Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I
+ {0x1A17, 0x1A18, prExtend}, // Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U
+ {0x1A19, 0x1A1A, prSpacingMark}, // Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O
+ {0x1A1B, 0x1A1B, prExtend}, // Mn BUGINESE VOWEL SIGN AE
+ {0x1A55, 0x1A55, prSpacingMark}, // Mc TAI THAM CONSONANT SIGN MEDIAL RA
+ {0x1A56, 0x1A56, prExtend}, // Mn TAI THAM CONSONANT SIGN MEDIAL LA
+ {0x1A57, 0x1A57, prSpacingMark}, // Mc TAI THAM CONSONANT SIGN LA TANG LAI
+ {0x1A58, 0x1A5E, prExtend}, // Mn [7] TAI THAM SIGN MAI KANG LAI..TAI THAM CONSONANT SIGN SA
+ {0x1A60, 0x1A60, prExtend}, // Mn TAI THAM SIGN SAKOT
+ {0x1A62, 0x1A62, prExtend}, // Mn TAI THAM VOWEL SIGN MAI SAT
+ {0x1A65, 0x1A6C, prExtend}, // Mn [8] TAI THAM VOWEL SIGN I..TAI THAM VOWEL SIGN OA BELOW
+ {0x1A6D, 0x1A72, prSpacingMark}, // Mc [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI
+ {0x1A73, 0x1A7C, prExtend}, // Mn [10] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN KHUEN-LUE KARAN
+ {0x1A7F, 0x1A7F, prExtend}, // Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT
+ {0x1AB0, 0x1ABD, prExtend}, // Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW
+ {0x1ABE, 0x1ABE, prExtend}, // Me COMBINING PARENTHESES OVERLAY
+ {0x1B00, 0x1B03, prExtend}, // Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG
+ {0x1B04, 0x1B04, prSpacingMark}, // Mc BALINESE SIGN BISAH
+ {0x1B34, 0x1B34, prExtend}, // Mn BALINESE SIGN REREKAN
+ {0x1B35, 0x1B35, prExtend}, // Mc BALINESE VOWEL SIGN TEDUNG
+ {0x1B36, 0x1B3A, prExtend}, // Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA
+ {0x1B3B, 0x1B3B, prSpacingMark}, // Mc BALINESE VOWEL SIGN RA REPA TEDUNG
+ {0x1B3C, 0x1B3C, prExtend}, // Mn BALINESE VOWEL SIGN LA LENGA
+ {0x1B3D, 0x1B41, prSpacingMark}, // Mc [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG
+ {0x1B42, 0x1B42, prExtend}, // Mn BALINESE VOWEL SIGN PEPET
+ {0x1B43, 0x1B44, prSpacingMark}, // Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG
+ {0x1B6B, 0x1B73, prExtend}, // Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG
+ {0x1B80, 0x1B81, prExtend}, // Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR
+ {0x1B82, 0x1B82, prSpacingMark}, // Mc SUNDANESE SIGN PANGWISAD
+ {0x1BA1, 0x1BA1, prSpacingMark}, // Mc SUNDANESE CONSONANT SIGN PAMINGKAL
+ {0x1BA2, 0x1BA5, prExtend}, // Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU
+ {0x1BA6, 0x1BA7, prSpacingMark}, // Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG
+ {0x1BA8, 0x1BA9, prExtend}, // Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG
+ {0x1BAA, 0x1BAA, prSpacingMark}, // Mc SUNDANESE SIGN PAMAAEH
+ {0x1BAB, 0x1BAD, prExtend}, // Mn [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA
+ {0x1BE6, 0x1BE6, prExtend}, // Mn BATAK SIGN TOMPI
+ {0x1BE7, 0x1BE7, prSpacingMark}, // Mc BATAK VOWEL SIGN E
+ {0x1BE8, 0x1BE9, prExtend}, // Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE
+ {0x1BEA, 0x1BEC, prSpacingMark}, // Mc [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O
+ {0x1BED, 0x1BED, prExtend}, // Mn BATAK VOWEL SIGN KARO O
+ {0x1BEE, 0x1BEE, prSpacingMark}, // Mc BATAK VOWEL SIGN U
+ {0x1BEF, 0x1BF1, prExtend}, // Mn [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H
+ {0x1BF2, 0x1BF3, prSpacingMark}, // Mc [2] BATAK PANGOLAT..BATAK PANONGONAN
+ {0x1C24, 0x1C2B, prSpacingMark}, // Mc [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU
+ {0x1C2C, 0x1C33, prExtend}, // Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T
+ {0x1C34, 0x1C35, prSpacingMark}, // Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG
+ {0x1C36, 0x1C37, prExtend}, // Mn [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA
+ {0x1CD0, 0x1CD2, prExtend}, // Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA
+ {0x1CD4, 0x1CE0, prExtend}, // Mn [13] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA
+ {0x1CE1, 0x1CE1, prSpacingMark}, // Mc VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA
+ {0x1CE2, 0x1CE8, prExtend}, // Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL
+ {0x1CED, 0x1CED, prExtend}, // Mn VEDIC SIGN TIRYAK
+ {0x1CF4, 0x1CF4, prExtend}, // Mn VEDIC TONE CANDRA ABOVE
+ {0x1CF7, 0x1CF7, prSpacingMark}, // Mc VEDIC SIGN ATIKRAMA
+ {0x1CF8, 0x1CF9, prExtend}, // Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE
+ {0x1DC0, 0x1DF9, prExtend}, // Mn [58] COMBINING DOTTED GRAVE ACCENT..COMBINING WIDE INVERTED BRIDGE BELOW
+ {0x1DFB, 0x1DFF, prExtend}, // Mn [5] COMBINING DELETION MARK..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW
+ {0x200B, 0x200B, prControl}, // Cf ZERO WIDTH SPACE
+ {0x200C, 0x200C, prExtend}, // Cf ZERO WIDTH NON-JOINER
+ {0x200D, 0x200D, prZWJ}, // Cf ZERO WIDTH JOINER
+ {0x200E, 0x200F, prControl}, // Cf [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK
+ {0x2028, 0x2028, prControl}, // Zl LINE SEPARATOR
+ {0x2029, 0x2029, prControl}, // Zp PARAGRAPH SEPARATOR
+ {0x202A, 0x202E, prControl}, // Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE
+ {0x203C, 0x203C, prExtendedPictographic}, // 1.1 [1] (‼️) double exclamation mark
+ {0x2049, 0x2049, prExtendedPictographic}, // 3.0 [1] (⁉️) exclamation question mark
+ {0x2060, 0x2064, prControl}, // Cf [5] WORD JOINER..INVISIBLE PLUS
+ {0x2065, 0x2065, prControl}, // Cn
+ {0x2066, 0x206F, prControl}, // Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES
+ {0x20D0, 0x20DC, prExtend}, // Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE
+ {0x20DD, 0x20E0, prExtend}, // Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH
+ {0x20E1, 0x20E1, prExtend}, // Mn COMBINING LEFT RIGHT ARROW ABOVE
+ {0x20E2, 0x20E4, prExtend}, // Me [3] COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING UPWARD POINTING TRIANGLE
+ {0x20E5, 0x20F0, prExtend}, // Mn [12] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING ASTERISK ABOVE
+ {0x2122, 0x2122, prExtendedPictographic}, // 1.1 [1] (™️) trade mark
+ {0x2139, 0x2139, prExtendedPictographic}, // 3.0 [1] (ℹ️) information
+ {0x2194, 0x2199, prExtendedPictographic}, // 1.1 [6] (↔️..↙️) left-right arrow..down-left arrow
+ {0x21A9, 0x21AA, prExtendedPictographic}, // 1.1 [2] (↩️..↪️) right arrow curving left..left arrow curving right
+ {0x231A, 0x231B, prExtendedPictographic}, // 1.1 [2] (⌚..⌛) watch..hourglass done
+ {0x2328, 0x2328, prExtendedPictographic}, // 1.1 [1] (⌨️) keyboard
+ {0x2388, 0x2388, prExtendedPictographic}, // 3.0 [1] (⎈) HELM SYMBOL
+ {0x23CF, 0x23CF, prExtendedPictographic}, // 4.0 [1] (⏏️) eject button
+ {0x23E9, 0x23F3, prExtendedPictographic}, // 6.0 [11] (⏩..⏳) fast-forward button..hourglass not done
+ {0x23F8, 0x23FA, prExtendedPictographic}, // 7.0 [3] (⏸️..⏺️) pause button..record button
+ {0x24C2, 0x24C2, prExtendedPictographic}, // 1.1 [1] (Ⓜ️) circled M
+ {0x25AA, 0x25AB, prExtendedPictographic}, // 1.1 [2] (▪️..▫️) black small square..white small square
+ {0x25B6, 0x25B6, prExtendedPictographic}, // 1.1 [1] (▶️) play button
+ {0x25C0, 0x25C0, prExtendedPictographic}, // 1.1 [1] (◀️) reverse button
+ {0x25FB, 0x25FE, prExtendedPictographic}, // 3.2 [4] (◻️..◾) white medium square..black medium-small square
+ {0x2600, 0x2605, prExtendedPictographic}, // 1.1 [6] (☀️..★) sun..BLACK STAR
+ {0x2607, 0x2612, prExtendedPictographic}, // 1.1 [12] (☇..☒) LIGHTNING..BALLOT BOX WITH X
+ {0x2614, 0x2615, prExtendedPictographic}, // 4.0 [2] (☔..☕) umbrella with rain drops..hot beverage
+ {0x2616, 0x2617, prExtendedPictographic}, // 3.2 [2] (☖..☗) WHITE SHOGI PIECE..BLACK SHOGI PIECE
+ {0x2618, 0x2618, prExtendedPictographic}, // 4.1 [1] (☘️) shamrock
+ {0x2619, 0x2619, prExtendedPictographic}, // 3.0 [1] (☙) REVERSED ROTATED FLORAL HEART BULLET
+ {0x261A, 0x266F, prExtendedPictographic}, // 1.1 [86] (☚..♯) BLACK LEFT POINTING INDEX..MUSIC SHARP SIGN
+ {0x2670, 0x2671, prExtendedPictographic}, // 3.0 [2] (♰..♱) WEST SYRIAC CROSS..EAST SYRIAC CROSS
+ {0x2672, 0x267D, prExtendedPictographic}, // 3.2 [12] (♲..♽) UNIVERSAL RECYCLING SYMBOL..PARTIALLY-RECYCLED PAPER SYMBOL
+ {0x267E, 0x267F, prExtendedPictographic}, // 4.1 [2] (♾️..♿) infinity..wheelchair symbol
+ {0x2680, 0x2685, prExtendedPictographic}, // 3.2 [6] (⚀..⚅) DIE FACE-1..DIE FACE-6
+ {0x2690, 0x2691, prExtendedPictographic}, // 4.0 [2] (⚐..⚑) WHITE FLAG..BLACK FLAG
+ {0x2692, 0x269C, prExtendedPictographic}, // 4.1 [11] (⚒️..⚜️) hammer and pick..fleur-de-lis
+ {0x269D, 0x269D, prExtendedPictographic}, // 5.1 [1] (⚝) OUTLINED WHITE STAR
+ {0x269E, 0x269F, prExtendedPictographic}, // 5.2 [2] (⚞..⚟) THREE LINES CONVERGING RIGHT..THREE LINES CONVERGING LEFT
+ {0x26A0, 0x26A1, prExtendedPictographic}, // 4.0 [2] (⚠️..⚡) warning..high voltage
+ {0x26A2, 0x26B1, prExtendedPictographic}, // 4.1 [16] (⚢..⚱️) DOUBLED FEMALE SIGN..funeral urn
+ {0x26B2, 0x26B2, prExtendedPictographic}, // 5.0 [1] (⚲) NEUTER
+ {0x26B3, 0x26BC, prExtendedPictographic}, // 5.1 [10] (⚳..⚼) CERES..SESQUIQUADRATE
+ {0x26BD, 0x26BF, prExtendedPictographic}, // 5.2 [3] (⚽..⚿) soccer ball..SQUARED KEY
+ {0x26C0, 0x26C3, prExtendedPictographic}, // 5.1 [4] (⛀..⛃) WHITE DRAUGHTS MAN..BLACK DRAUGHTS KING
+ {0x26C4, 0x26CD, prExtendedPictographic}, // 5.2 [10] (⛄..⛍) snowman without snow..DISABLED CAR
+ {0x26CE, 0x26CE, prExtendedPictographic}, // 6.0 [1] (⛎) Ophiuchus
+ {0x26CF, 0x26E1, prExtendedPictographic}, // 5.2 [19] (⛏️..⛡) pick..RESTRICTED LEFT ENTRY-2
+ {0x26E2, 0x26E2, prExtendedPictographic}, // 6.0 [1] (⛢) ASTRONOMICAL SYMBOL FOR URANUS
+ {0x26E3, 0x26E3, prExtendedPictographic}, // 5.2 [1] (⛣) HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVE
+ {0x26E4, 0x26E7, prExtendedPictographic}, // 6.0 [4] (⛤..⛧) PENTAGRAM..INVERTED PENTAGRAM
+ {0x26E8, 0x26FF, prExtendedPictographic}, // 5.2 [24] (⛨..⛿) BLACK CROSS ON SHIELD..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE
+ {0x2700, 0x2700, prExtendedPictographic}, // 7.0 [1] (✀) BLACK SAFETY SCISSORS
+ {0x2701, 0x2704, prExtendedPictographic}, // 1.1 [4] (✁..✄) UPPER BLADE SCISSORS..WHITE SCISSORS
+ {0x2705, 0x2705, prExtendedPictographic}, // 6.0 [1] (✅) check mark button
+ {0x2708, 0x2709, prExtendedPictographic}, // 1.1 [2] (✈️..✉️) airplane..envelope
+ {0x270A, 0x270B, prExtendedPictographic}, // 6.0 [2] (✊..✋) raised fist..raised hand
+ {0x270C, 0x2712, prExtendedPictographic}, // 1.1 [7] (✌️..✒️) victory hand..black nib
+ {0x2714, 0x2714, prExtendedPictographic}, // 1.1 [1] (✔️) check mark
+ {0x2716, 0x2716, prExtendedPictographic}, // 1.1 [1] (✖️) multiplication sign
+ {0x271D, 0x271D, prExtendedPictographic}, // 1.1 [1] (✝️) latin cross
+ {0x2721, 0x2721, prExtendedPictographic}, // 1.1 [1] (✡️) star of David
+ {0x2728, 0x2728, prExtendedPictographic}, // 6.0 [1] (✨) sparkles
+ {0x2733, 0x2734, prExtendedPictographic}, // 1.1 [2] (✳️..✴️) eight-spoked asterisk..eight-pointed star
+ {0x2744, 0x2744, prExtendedPictographic}, // 1.1 [1] (❄️) snowflake
+ {0x2747, 0x2747, prExtendedPictographic}, // 1.1 [1] (❇️) sparkle
+ {0x274C, 0x274C, prExtendedPictographic}, // 6.0 [1] (❌) cross mark
+ {0x274E, 0x274E, prExtendedPictographic}, // 6.0 [1] (❎) cross mark button
+ {0x2753, 0x2755, prExtendedPictographic}, // 6.0 [3] (❓..❕) question mark..white exclamation mark
+ {0x2757, 0x2757, prExtendedPictographic}, // 5.2 [1] (❗) exclamation mark
+ {0x2763, 0x2767, prExtendedPictographic}, // 1.1 [5] (❣️..❧) heart exclamation..ROTATED FLORAL HEART BULLET
+ {0x2795, 0x2797, prExtendedPictographic}, // 6.0 [3] (➕..➗) plus sign..division sign
+ {0x27A1, 0x27A1, prExtendedPictographic}, // 1.1 [1] (➡️) right arrow
+ {0x27B0, 0x27B0, prExtendedPictographic}, // 6.0 [1] (➰) curly loop
+ {0x27BF, 0x27BF, prExtendedPictographic}, // 6.0 [1] (➿) double curly loop
+ {0x2934, 0x2935, prExtendedPictographic}, // 3.2 [2] (⤴️..⤵️) right arrow curving up..right arrow curving down
+ {0x2B05, 0x2B07, prExtendedPictographic}, // 4.0 [3] (⬅️..⬇️) left arrow..down arrow
+ {0x2B1B, 0x2B1C, prExtendedPictographic}, // 5.1 [2] (⬛..⬜) black large square..white large square
+ {0x2B50, 0x2B50, prExtendedPictographic}, // 5.1 [1] (⭐) star
+ {0x2B55, 0x2B55, prExtendedPictographic}, // 5.2 [1] (⭕) hollow red circle
+ {0x2CEF, 0x2CF1, prExtend}, // Mn [3] COPTIC COMBINING NI ABOVE..COPTIC COMBINING SPIRITUS LENIS
+ {0x2D7F, 0x2D7F, prExtend}, // Mn TIFINAGH CONSONANT JOINER
+ {0x2DE0, 0x2DFF, prExtend}, // Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS
+ {0x302A, 0x302D, prExtend}, // Mn [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK
+ {0x302E, 0x302F, prExtend}, // Mc [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK
+ {0x3030, 0x3030, prExtendedPictographic}, // 1.1 [1] (〰️) wavy dash
+ {0x303D, 0x303D, prExtendedPictographic}, // 3.2 [1] (〽️) part alternation mark
+ {0x3099, 0x309A, prExtend}, // Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+ {0x3297, 0x3297, prExtendedPictographic}, // 1.1 [1] (㊗️) Japanese “congratulations” button
+ {0x3299, 0x3299, prExtendedPictographic}, // 1.1 [1] (㊙️) Japanese “secret” button
+ {0xA66F, 0xA66F, prExtend}, // Mn COMBINING CYRILLIC VZMET
+ {0xA670, 0xA672, prExtend}, // Me [3] COMBINING CYRILLIC TEN MILLIONS SIGN..COMBINING CYRILLIC THOUSAND MILLIONS SIGN
+ {0xA674, 0xA67D, prExtend}, // Mn [10] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC PAYEROK
+ {0xA69E, 0xA69F, prExtend}, // Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E
+ {0xA6F0, 0xA6F1, prExtend}, // Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS
+ {0xA802, 0xA802, prExtend}, // Mn SYLOTI NAGRI SIGN DVISVARA
+ {0xA806, 0xA806, prExtend}, // Mn SYLOTI NAGRI SIGN HASANTA
+ {0xA80B, 0xA80B, prExtend}, // Mn SYLOTI NAGRI SIGN ANUSVARA
+ {0xA823, 0xA824, prSpacingMark}, // Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I
+ {0xA825, 0xA826, prExtend}, // Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E
+ {0xA827, 0xA827, prSpacingMark}, // Mc SYLOTI NAGRI VOWEL SIGN OO
+ {0xA880, 0xA881, prSpacingMark}, // Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA
+ {0xA8B4, 0xA8C3, prSpacingMark}, // Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU
+ {0xA8C4, 0xA8C5, prExtend}, // Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU
+ {0xA8E0, 0xA8F1, prExtend}, // Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA
+ {0xA8FF, 0xA8FF, prExtend}, // Mn DEVANAGARI VOWEL SIGN AY
+ {0xA926, 0xA92D, prExtend}, // Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU
+ {0xA947, 0xA951, prExtend}, // Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R
+ {0xA952, 0xA953, prSpacingMark}, // Mc [2] REJANG CONSONANT SIGN H..REJANG VIRAMA
+ {0xA960, 0xA97C, prL}, // Lo [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANGYEORINHIEUH
+ {0xA980, 0xA982, prExtend}, // Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR
+ {0xA983, 0xA983, prSpacingMark}, // Mc JAVANESE SIGN WIGNYAN
+ {0xA9B3, 0xA9B3, prExtend}, // Mn JAVANESE SIGN CECAK TELU
+ {0xA9B4, 0xA9B5, prSpacingMark}, // Mc [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN TOLONG
+ {0xA9B6, 0xA9B9, prExtend}, // Mn [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT
+ {0xA9BA, 0xA9BB, prSpacingMark}, // Mc [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE
+ {0xA9BC, 0xA9BD, prExtend}, // Mn [2] JAVANESE VOWEL SIGN PEPET..JAVANESE CONSONANT SIGN KERET
+ {0xA9BE, 0xA9C0, prSpacingMark}, // Mc [3] JAVANESE CONSONANT SIGN PENGKAL..JAVANESE PANGKON
+ {0xA9E5, 0xA9E5, prExtend}, // Mn MYANMAR SIGN SHAN SAW
+ {0xAA29, 0xAA2E, prExtend}, // Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE
+ {0xAA2F, 0xAA30, prSpacingMark}, // Mc [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI
+ {0xAA31, 0xAA32, prExtend}, // Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE
+ {0xAA33, 0xAA34, prSpacingMark}, // Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA
+ {0xAA35, 0xAA36, prExtend}, // Mn [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA
+ {0xAA43, 0xAA43, prExtend}, // Mn CHAM CONSONANT SIGN FINAL NG
+ {0xAA4C, 0xAA4C, prExtend}, // Mn CHAM CONSONANT SIGN FINAL M
+ {0xAA4D, 0xAA4D, prSpacingMark}, // Mc CHAM CONSONANT SIGN FINAL H
+ {0xAA7C, 0xAA7C, prExtend}, // Mn MYANMAR SIGN TAI LAING TONE-2
+ {0xAAB0, 0xAAB0, prExtend}, // Mn TAI VIET MAI KANG
+ {0xAAB2, 0xAAB4, prExtend}, // Mn [3] TAI VIET VOWEL I..TAI VIET VOWEL U
+ {0xAAB7, 0xAAB8, prExtend}, // Mn [2] TAI VIET MAI KHIT..TAI VIET VOWEL IA
+ {0xAABE, 0xAABF, prExtend}, // Mn [2] TAI VIET VOWEL AM..TAI VIET TONE MAI EK
+ {0xAAC1, 0xAAC1, prExtend}, // Mn TAI VIET TONE MAI THO
+ {0xAAEB, 0xAAEB, prSpacingMark}, // Mc MEETEI MAYEK VOWEL SIGN II
+ {0xAAEC, 0xAAED, prExtend}, // Mn [2] MEETEI MAYEK VOWEL SIGN UU..MEETEI MAYEK VOWEL SIGN AAI
+ {0xAAEE, 0xAAEF, prSpacingMark}, // Mc [2] MEETEI MAYEK VOWEL SIGN AU..MEETEI MAYEK VOWEL SIGN AAU
+ {0xAAF5, 0xAAF5, prSpacingMark}, // Mc MEETEI MAYEK VOWEL SIGN VISARGA
+ {0xAAF6, 0xAAF6, prExtend}, // Mn MEETEI MAYEK VIRAMA
+ {0xABE3, 0xABE4, prSpacingMark}, // Mc [2] MEETEI MAYEK VOWEL SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP
+ {0xABE5, 0xABE5, prExtend}, // Mn MEETEI MAYEK VOWEL SIGN ANAP
+ {0xABE6, 0xABE7, prSpacingMark}, // Mc [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETEI MAYEK VOWEL SIGN SOUNAP
+ {0xABE8, 0xABE8, prExtend}, // Mn MEETEI MAYEK VOWEL SIGN UNAP
+ {0xABE9, 0xABEA, prSpacingMark}, // Mc [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG
+ {0xABEC, 0xABEC, prSpacingMark}, // Mc MEETEI MAYEK LUM IYEK
+ {0xABED, 0xABED, prExtend}, // Mn MEETEI MAYEK APUN IYEK
+ {0xAC00, 0xAC00, prLV}, // Lo HANGUL SYLLABLE GA
+ {0xAC01, 0xAC1B, prLVT}, // Lo [27] HANGUL SYLLABLE GAG..HANGUL SYLLABLE GAH
+ {0xAC1C, 0xAC1C, prLV}, // Lo HANGUL SYLLABLE GAE
+ {0xAC1D, 0xAC37, prLVT}, // Lo [27] HANGUL SYLLABLE GAEG..HANGUL SYLLABLE GAEH
+ {0xAC38, 0xAC38, prLV}, // Lo HANGUL SYLLABLE GYA
+ {0xAC39, 0xAC53, prLVT}, // Lo [27] HANGUL SYLLABLE GYAG..HANGUL SYLLABLE GYAH
+ {0xAC54, 0xAC54, prLV}, // Lo HANGUL SYLLABLE GYAE
+ {0xAC55, 0xAC6F, prLVT}, // Lo [27] HANGUL SYLLABLE GYAEG..HANGUL SYLLABLE GYAEH
+ {0xAC70, 0xAC70, prLV}, // Lo HANGUL SYLLABLE GEO
+ {0xAC71, 0xAC8B, prLVT}, // Lo [27] HANGUL SYLLABLE GEOG..HANGUL SYLLABLE GEOH
+ {0xAC8C, 0xAC8C, prLV}, // Lo HANGUL SYLLABLE GE
+ {0xAC8D, 0xACA7, prLVT}, // Lo [27] HANGUL SYLLABLE GEG..HANGUL SYLLABLE GEH
+ {0xACA8, 0xACA8, prLV}, // Lo HANGUL SYLLABLE GYEO
+ {0xACA9, 0xACC3, prLVT}, // Lo [27] HANGUL SYLLABLE GYEOG..HANGUL SYLLABLE GYEOH
+ {0xACC4, 0xACC4, prLV}, // Lo HANGUL SYLLABLE GYE
+ {0xACC5, 0xACDF, prLVT}, // Lo [27] HANGUL SYLLABLE GYEG..HANGUL SYLLABLE GYEH
+ {0xACE0, 0xACE0, prLV}, // Lo HANGUL SYLLABLE GO
+ {0xACE1, 0xACFB, prLVT}, // Lo [27] HANGUL SYLLABLE GOG..HANGUL SYLLABLE GOH
+ {0xACFC, 0xACFC, prLV}, // Lo HANGUL SYLLABLE GWA
+ {0xACFD, 0xAD17, prLVT}, // Lo [27] HANGUL SYLLABLE GWAG..HANGUL SYLLABLE GWAH
+ {0xAD18, 0xAD18, prLV}, // Lo HANGUL SYLLABLE GWAE
+ {0xAD19, 0xAD33, prLVT}, // Lo [27] HANGUL SYLLABLE GWAEG..HANGUL SYLLABLE GWAEH
+ {0xAD34, 0xAD34, prLV}, // Lo HANGUL SYLLABLE GOE
+ {0xAD35, 0xAD4F, prLVT}, // Lo [27] HANGUL SYLLABLE GOEG..HANGUL SYLLABLE GOEH
+ {0xAD50, 0xAD50, prLV}, // Lo HANGUL SYLLABLE GYO
+ {0xAD51, 0xAD6B, prLVT}, // Lo [27] HANGUL SYLLABLE GYOG..HANGUL SYLLABLE GYOH
+ {0xAD6C, 0xAD6C, prLV}, // Lo HANGUL SYLLABLE GU
+ {0xAD6D, 0xAD87, prLVT}, // Lo [27] HANGUL SYLLABLE GUG..HANGUL SYLLABLE GUH
+ {0xAD88, 0xAD88, prLV}, // Lo HANGUL SYLLABLE GWEO
+ {0xAD89, 0xADA3, prLVT}, // Lo [27] HANGUL SYLLABLE GWEOG..HANGUL SYLLABLE GWEOH
+ {0xADA4, 0xADA4, prLV}, // Lo HANGUL SYLLABLE GWE
+ {0xADA5, 0xADBF, prLVT}, // Lo [27] HANGUL SYLLABLE GWEG..HANGUL SYLLABLE GWEH
+ {0xADC0, 0xADC0, prLV}, // Lo HANGUL SYLLABLE GWI
+ {0xADC1, 0xADDB, prLVT}, // Lo [27] HANGUL SYLLABLE GWIG..HANGUL SYLLABLE GWIH
+ {0xADDC, 0xADDC, prLV}, // Lo HANGUL SYLLABLE GYU
+ {0xADDD, 0xADF7, prLVT}, // Lo [27] HANGUL SYLLABLE GYUG..HANGUL SYLLABLE GYUH
+ {0xADF8, 0xADF8, prLV}, // Lo HANGUL SYLLABLE GEU
+ {0xADF9, 0xAE13, prLVT}, // Lo [27] HANGUL SYLLABLE GEUG..HANGUL SYLLABLE GEUH
+ {0xAE14, 0xAE14, prLV}, // Lo HANGUL SYLLABLE GYI
+ {0xAE15, 0xAE2F, prLVT}, // Lo [27] HANGUL SYLLABLE GYIG..HANGUL SYLLABLE GYIH
+ {0xAE30, 0xAE30, prLV}, // Lo HANGUL SYLLABLE GI
+ {0xAE31, 0xAE4B, prLVT}, // Lo [27] HANGUL SYLLABLE GIG..HANGUL SYLLABLE GIH
+ {0xAE4C, 0xAE4C, prLV}, // Lo HANGUL SYLLABLE GGA
+ {0xAE4D, 0xAE67, prLVT}, // Lo [27] HANGUL SYLLABLE GGAG..HANGUL SYLLABLE GGAH
+ {0xAE68, 0xAE68, prLV}, // Lo HANGUL SYLLABLE GGAE
+ {0xAE69, 0xAE83, prLVT}, // Lo [27] HANGUL SYLLABLE GGAEG..HANGUL SYLLABLE GGAEH
+ {0xAE84, 0xAE84, prLV}, // Lo HANGUL SYLLABLE GGYA
+ {0xAE85, 0xAE9F, prLVT}, // Lo [27] HANGUL SYLLABLE GGYAG..HANGUL SYLLABLE GGYAH
+ {0xAEA0, 0xAEA0, prLV}, // Lo HANGUL SYLLABLE GGYAE
+ {0xAEA1, 0xAEBB, prLVT}, // Lo [27] HANGUL SYLLABLE GGYAEG..HANGUL SYLLABLE GGYAEH
+ {0xAEBC, 0xAEBC, prLV}, // Lo HANGUL SYLLABLE GGEO
+ {0xAEBD, 0xAED7, prLVT}, // Lo [27] HANGUL SYLLABLE GGEOG..HANGUL SYLLABLE GGEOH
+ {0xAED8, 0xAED8, prLV}, // Lo HANGUL SYLLABLE GGE
+ {0xAED9, 0xAEF3, prLVT}, // Lo [27] HANGUL SYLLABLE GGEG..HANGUL SYLLABLE GGEH
+ {0xAEF4, 0xAEF4, prLV}, // Lo HANGUL SYLLABLE GGYEO
+ {0xAEF5, 0xAF0F, prLVT}, // Lo [27] HANGUL SYLLABLE GGYEOG..HANGUL SYLLABLE GGYEOH
+ {0xAF10, 0xAF10, prLV}, // Lo HANGUL SYLLABLE GGYE
+ {0xAF11, 0xAF2B, prLVT}, // Lo [27] HANGUL SYLLABLE GGYEG..HANGUL SYLLABLE GGYEH
+ {0xAF2C, 0xAF2C, prLV}, // Lo HANGUL SYLLABLE GGO
+ {0xAF2D, 0xAF47, prLVT}, // Lo [27] HANGUL SYLLABLE GGOG..HANGUL SYLLABLE GGOH
+ {0xAF48, 0xAF48, prLV}, // Lo HANGUL SYLLABLE GGWA
+ {0xAF49, 0xAF63, prLVT}, // Lo [27] HANGUL SYLLABLE GGWAG..HANGUL SYLLABLE GGWAH
+ {0xAF64, 0xAF64, prLV}, // Lo HANGUL SYLLABLE GGWAE
+ {0xAF65, 0xAF7F, prLVT}, // Lo [27] HANGUL SYLLABLE GGWAEG..HANGUL SYLLABLE GGWAEH
+ {0xAF80, 0xAF80, prLV}, // Lo HANGUL SYLLABLE GGOE
+ {0xAF81, 0xAF9B, prLVT}, // Lo [27] HANGUL SYLLABLE GGOEG..HANGUL SYLLABLE GGOEH
+ {0xAF9C, 0xAF9C, prLV}, // Lo HANGUL SYLLABLE GGYO
+ {0xAF9D, 0xAFB7, prLVT}, // Lo [27] HANGUL SYLLABLE GGYOG..HANGUL SYLLABLE GGYOH
+ {0xAFB8, 0xAFB8, prLV}, // Lo HANGUL SYLLABLE GGU
+ {0xAFB9, 0xAFD3, prLVT}, // Lo [27] HANGUL SYLLABLE GGUG..HANGUL SYLLABLE GGUH
+ {0xAFD4, 0xAFD4, prLV}, // Lo HANGUL SYLLABLE GGWEO
+ {0xAFD5, 0xAFEF, prLVT}, // Lo [27] HANGUL SYLLABLE GGWEOG..HANGUL SYLLABLE GGWEOH
+ {0xAFF0, 0xAFF0, prLV}, // Lo HANGUL SYLLABLE GGWE
+ {0xAFF1, 0xB00B, prLVT}, // Lo [27] HANGUL SYLLABLE GGWEG..HANGUL SYLLABLE GGWEH
+ {0xB00C, 0xB00C, prLV}, // Lo HANGUL SYLLABLE GGWI
+ {0xB00D, 0xB027, prLVT}, // Lo [27] HANGUL SYLLABLE GGWIG..HANGUL SYLLABLE GGWIH
+ {0xB028, 0xB028, prLV}, // Lo HANGUL SYLLABLE GGYU
+ {0xB029, 0xB043, prLVT}, // Lo [27] HANGUL SYLLABLE GGYUG..HANGUL SYLLABLE GGYUH
+ {0xB044, 0xB044, prLV}, // Lo HANGUL SYLLABLE GGEU
+ {0xB045, 0xB05F, prLVT}, // Lo [27] HANGUL SYLLABLE GGEUG..HANGUL SYLLABLE GGEUH
+ {0xB060, 0xB060, prLV}, // Lo HANGUL SYLLABLE GGYI
+ {0xB061, 0xB07B, prLVT}, // Lo [27] HANGUL SYLLABLE GGYIG..HANGUL SYLLABLE GGYIH
+ {0xB07C, 0xB07C, prLV}, // Lo HANGUL SYLLABLE GGI
+ {0xB07D, 0xB097, prLVT}, // Lo [27] HANGUL SYLLABLE GGIG..HANGUL SYLLABLE GGIH
+ {0xB098, 0xB098, prLV}, // Lo HANGUL SYLLABLE NA
+ {0xB099, 0xB0B3, prLVT}, // Lo [27] HANGUL SYLLABLE NAG..HANGUL SYLLABLE NAH
+ {0xB0B4, 0xB0B4, prLV}, // Lo HANGUL SYLLABLE NAE
+ {0xB0B5, 0xB0CF, prLVT}, // Lo [27] HANGUL SYLLABLE NAEG..HANGUL SYLLABLE NAEH
+ {0xB0D0, 0xB0D0, prLV}, // Lo HANGUL SYLLABLE NYA
+ {0xB0D1, 0xB0EB, prLVT}, // Lo [27] HANGUL SYLLABLE NYAG..HANGUL SYLLABLE NYAH
+ {0xB0EC, 0xB0EC, prLV}, // Lo HANGUL SYLLABLE NYAE
+ {0xB0ED, 0xB107, prLVT}, // Lo [27] HANGUL SYLLABLE NYAEG..HANGUL SYLLABLE NYAEH
+ {0xB108, 0xB108, prLV}, // Lo HANGUL SYLLABLE NEO
+ {0xB109, 0xB123, prLVT}, // Lo [27] HANGUL SYLLABLE NEOG..HANGUL SYLLABLE NEOH
+ {0xB124, 0xB124, prLV}, // Lo HANGUL SYLLABLE NE
+ {0xB125, 0xB13F, prLVT}, // Lo [27] HANGUL SYLLABLE NEG..HANGUL SYLLABLE NEH
+ {0xB140, 0xB140, prLV}, // Lo HANGUL SYLLABLE NYEO
+ {0xB141, 0xB15B, prLVT}, // Lo [27] HANGUL SYLLABLE NYEOG..HANGUL SYLLABLE NYEOH
+ {0xB15C, 0xB15C, prLV}, // Lo HANGUL SYLLABLE NYE
+ {0xB15D, 0xB177, prLVT}, // Lo [27] HANGUL SYLLABLE NYEG..HANGUL SYLLABLE NYEH
+ {0xB178, 0xB178, prLV}, // Lo HANGUL SYLLABLE NO
+ {0xB179, 0xB193, prLVT}, // Lo [27] HANGUL SYLLABLE NOG..HANGUL SYLLABLE NOH
+ {0xB194, 0xB194, prLV}, // Lo HANGUL SYLLABLE NWA
+ {0xB195, 0xB1AF, prLVT}, // Lo [27] HANGUL SYLLABLE NWAG..HANGUL SYLLABLE NWAH
+ {0xB1B0, 0xB1B0, prLV}, // Lo HANGUL SYLLABLE NWAE
+ {0xB1B1, 0xB1CB, prLVT}, // Lo [27] HANGUL SYLLABLE NWAEG..HANGUL SYLLABLE NWAEH
+ {0xB1CC, 0xB1CC, prLV}, // Lo HANGUL SYLLABLE NOE
+ {0xB1CD, 0xB1E7, prLVT}, // Lo [27] HANGUL SYLLABLE NOEG..HANGUL SYLLABLE NOEH
+ {0xB1E8, 0xB1E8, prLV}, // Lo HANGUL SYLLABLE NYO
+ {0xB1E9, 0xB203, prLVT}, // Lo [27] HANGUL SYLLABLE NYOG..HANGUL SYLLABLE NYOH
+ {0xB204, 0xB204, prLV}, // Lo HANGUL SYLLABLE NU
+ {0xB205, 0xB21F, prLVT}, // Lo [27] HANGUL SYLLABLE NUG..HANGUL SYLLABLE NUH
+ {0xB220, 0xB220, prLV}, // Lo HANGUL SYLLABLE NWEO
+ {0xB221, 0xB23B, prLVT}, // Lo [27] HANGUL SYLLABLE NWEOG..HANGUL SYLLABLE NWEOH
+ {0xB23C, 0xB23C, prLV}, // Lo HANGUL SYLLABLE NWE
+ {0xB23D, 0xB257, prLVT}, // Lo [27] HANGUL SYLLABLE NWEG..HANGUL SYLLABLE NWEH
+ {0xB258, 0xB258, prLV}, // Lo HANGUL SYLLABLE NWI
+ {0xB259, 0xB273, prLVT}, // Lo [27] HANGUL SYLLABLE NWIG..HANGUL SYLLABLE NWIH
+ {0xB274, 0xB274, prLV}, // Lo HANGUL SYLLABLE NYU
+ {0xB275, 0xB28F, prLVT}, // Lo [27] HANGUL SYLLABLE NYUG..HANGUL SYLLABLE NYUH
+ {0xB290, 0xB290, prLV}, // Lo HANGUL SYLLABLE NEU
+ {0xB291, 0xB2AB, prLVT}, // Lo [27] HANGUL SYLLABLE NEUG..HANGUL SYLLABLE NEUH
+ {0xB2AC, 0xB2AC, prLV}, // Lo HANGUL SYLLABLE NYI
+ {0xB2AD, 0xB2C7, prLVT}, // Lo [27] HANGUL SYLLABLE NYIG..HANGUL SYLLABLE NYIH
+ {0xB2C8, 0xB2C8, prLV}, // Lo HANGUL SYLLABLE NI
+ {0xB2C9, 0xB2E3, prLVT}, // Lo [27] HANGUL SYLLABLE NIG..HANGUL SYLLABLE NIH
+ {0xB2E4, 0xB2E4, prLV}, // Lo HANGUL SYLLABLE DA
+ {0xB2E5, 0xB2FF, prLVT}, // Lo [27] HANGUL SYLLABLE DAG..HANGUL SYLLABLE DAH
+ {0xB300, 0xB300, prLV}, // Lo HANGUL SYLLABLE DAE
+ {0xB301, 0xB31B, prLVT}, // Lo [27] HANGUL SYLLABLE DAEG..HANGUL SYLLABLE DAEH
+ {0xB31C, 0xB31C, prLV}, // Lo HANGUL SYLLABLE DYA
+ {0xB31D, 0xB337, prLVT}, // Lo [27] HANGUL SYLLABLE DYAG..HANGUL SYLLABLE DYAH
+ {0xB338, 0xB338, prLV}, // Lo HANGUL SYLLABLE DYAE
+ {0xB339, 0xB353, prLVT}, // Lo [27] HANGUL SYLLABLE DYAEG..HANGUL SYLLABLE DYAEH
+ {0xB354, 0xB354, prLV}, // Lo HANGUL SYLLABLE DEO
+ {0xB355, 0xB36F, prLVT}, // Lo [27] HANGUL SYLLABLE DEOG..HANGUL SYLLABLE DEOH
+ {0xB370, 0xB370, prLV}, // Lo HANGUL SYLLABLE DE
+ {0xB371, 0xB38B, prLVT}, // Lo [27] HANGUL SYLLABLE DEG..HANGUL SYLLABLE DEH
+ {0xB38C, 0xB38C, prLV}, // Lo HANGUL SYLLABLE DYEO
+ {0xB38D, 0xB3A7, prLVT}, // Lo [27] HANGUL SYLLABLE DYEOG..HANGUL SYLLABLE DYEOH
+ {0xB3A8, 0xB3A8, prLV}, // Lo HANGUL SYLLABLE DYE
+ {0xB3A9, 0xB3C3, prLVT}, // Lo [27] HANGUL SYLLABLE DYEG..HANGUL SYLLABLE DYEH
+ {0xB3C4, 0xB3C4, prLV}, // Lo HANGUL SYLLABLE DO
+ {0xB3C5, 0xB3DF, prLVT}, // Lo [27] HANGUL SYLLABLE DOG..HANGUL SYLLABLE DOH
+ {0xB3E0, 0xB3E0, prLV}, // Lo HANGUL SYLLABLE DWA
+ {0xB3E1, 0xB3FB, prLVT}, // Lo [27] HANGUL SYLLABLE DWAG..HANGUL SYLLABLE DWAH
+ {0xB3FC, 0xB3FC, prLV}, // Lo HANGUL SYLLABLE DWAE
+ {0xB3FD, 0xB417, prLVT}, // Lo [27] HANGUL SYLLABLE DWAEG..HANGUL SYLLABLE DWAEH
+ {0xB418, 0xB418, prLV}, // Lo HANGUL SYLLABLE DOE
+ {0xB419, 0xB433, prLVT}, // Lo [27] HANGUL SYLLABLE DOEG..HANGUL SYLLABLE DOEH
+ {0xB434, 0xB434, prLV}, // Lo HANGUL SYLLABLE DYO
+ {0xB435, 0xB44F, prLVT}, // Lo [27] HANGUL SYLLABLE DYOG..HANGUL SYLLABLE DYOH
+ {0xB450, 0xB450, prLV}, // Lo HANGUL SYLLABLE DU
+ {0xB451, 0xB46B, prLVT}, // Lo [27] HANGUL SYLLABLE DUG..HANGUL SYLLABLE DUH
+ {0xB46C, 0xB46C, prLV}, // Lo HANGUL SYLLABLE DWEO
+ {0xB46D, 0xB487, prLVT}, // Lo [27] HANGUL SYLLABLE DWEOG..HANGUL SYLLABLE DWEOH
+ {0xB488, 0xB488, prLV}, // Lo HANGUL SYLLABLE DWE
+ {0xB489, 0xB4A3, prLVT}, // Lo [27] HANGUL SYLLABLE DWEG..HANGUL SYLLABLE DWEH
+ {0xB4A4, 0xB4A4, prLV}, // Lo HANGUL SYLLABLE DWI
+ {0xB4A5, 0xB4BF, prLVT}, // Lo [27] HANGUL SYLLABLE DWIG..HANGUL SYLLABLE DWIH
+ {0xB4C0, 0xB4C0, prLV}, // Lo HANGUL SYLLABLE DYU
+ {0xB4C1, 0xB4DB, prLVT}, // Lo [27] HANGUL SYLLABLE DYUG..HANGUL SYLLABLE DYUH
+ {0xB4DC, 0xB4DC, prLV}, // Lo HANGUL SYLLABLE DEU
+ {0xB4DD, 0xB4F7, prLVT}, // Lo [27] HANGUL SYLLABLE DEUG..HANGUL SYLLABLE DEUH
+ {0xB4F8, 0xB4F8, prLV}, // Lo HANGUL SYLLABLE DYI
+ {0xB4F9, 0xB513, prLVT}, // Lo [27] HANGUL SYLLABLE DYIG..HANGUL SYLLABLE DYIH
+ {0xB514, 0xB514, prLV}, // Lo HANGUL SYLLABLE DI
+ {0xB515, 0xB52F, prLVT}, // Lo [27] HANGUL SYLLABLE DIG..HANGUL SYLLABLE DIH
+ {0xB530, 0xB530, prLV}, // Lo HANGUL SYLLABLE DDA
+ {0xB531, 0xB54B, prLVT}, // Lo [27] HANGUL SYLLABLE DDAG..HANGUL SYLLABLE DDAH
+ {0xB54C, 0xB54C, prLV}, // Lo HANGUL SYLLABLE DDAE
+ {0xB54D, 0xB567, prLVT}, // Lo [27] HANGUL SYLLABLE DDAEG..HANGUL SYLLABLE DDAEH
+ {0xB568, 0xB568, prLV}, // Lo HANGUL SYLLABLE DDYA
+ {0xB569, 0xB583, prLVT}, // Lo [27] HANGUL SYLLABLE DDYAG..HANGUL SYLLABLE DDYAH
+ {0xB584, 0xB584, prLV}, // Lo HANGUL SYLLABLE DDYAE
+ {0xB585, 0xB59F, prLVT}, // Lo [27] HANGUL SYLLABLE DDYAEG..HANGUL SYLLABLE DDYAEH
+ {0xB5A0, 0xB5A0, prLV}, // Lo HANGUL SYLLABLE DDEO
+ {0xB5A1, 0xB5BB, prLVT}, // Lo [27] HANGUL SYLLABLE DDEOG..HANGUL SYLLABLE DDEOH
+ {0xB5BC, 0xB5BC, prLV}, // Lo HANGUL SYLLABLE DDE
+ {0xB5BD, 0xB5D7, prLVT}, // Lo [27] HANGUL SYLLABLE DDEG..HANGUL SYLLABLE DDEH
+ {0xB5D8, 0xB5D8, prLV}, // Lo HANGUL SYLLABLE DDYEO
+ {0xB5D9, 0xB5F3, prLVT}, // Lo [27] HANGUL SYLLABLE DDYEOG..HANGUL SYLLABLE DDYEOH
+ {0xB5F4, 0xB5F4, prLV}, // Lo HANGUL SYLLABLE DDYE
+ {0xB5F5, 0xB60F, prLVT}, // Lo [27] HANGUL SYLLABLE DDYEG..HANGUL SYLLABLE DDYEH
+ {0xB610, 0xB610, prLV}, // Lo HANGUL SYLLABLE DDO
+ {0xB611, 0xB62B, prLVT}, // Lo [27] HANGUL SYLLABLE DDOG..HANGUL SYLLABLE DDOH
+ {0xB62C, 0xB62C, prLV}, // Lo HANGUL SYLLABLE DDWA
+ {0xB62D, 0xB647, prLVT}, // Lo [27] HANGUL SYLLABLE DDWAG..HANGUL SYLLABLE DDWAH
+ {0xB648, 0xB648, prLV}, // Lo HANGUL SYLLABLE DDWAE
+ {0xB649, 0xB663, prLVT}, // Lo [27] HANGUL SYLLABLE DDWAEG..HANGUL SYLLABLE DDWAEH
+ {0xB664, 0xB664, prLV}, // Lo HANGUL SYLLABLE DDOE
+ {0xB665, 0xB67F, prLVT}, // Lo [27] HANGUL SYLLABLE DDOEG..HANGUL SYLLABLE DDOEH
+ {0xB680, 0xB680, prLV}, // Lo HANGUL SYLLABLE DDYO
+ {0xB681, 0xB69B, prLVT}, // Lo [27] HANGUL SYLLABLE DDYOG..HANGUL SYLLABLE DDYOH
+ {0xB69C, 0xB69C, prLV}, // Lo HANGUL SYLLABLE DDU
+ {0xB69D, 0xB6B7, prLVT}, // Lo [27] HANGUL SYLLABLE DDUG..HANGUL SYLLABLE DDUH
+ {0xB6B8, 0xB6B8, prLV}, // Lo HANGUL SYLLABLE DDWEO
+ {0xB6B9, 0xB6D3, prLVT}, // Lo [27] HANGUL SYLLABLE DDWEOG..HANGUL SYLLABLE DDWEOH
+ {0xB6D4, 0xB6D4, prLV}, // Lo HANGUL SYLLABLE DDWE
+ {0xB6D5, 0xB6EF, prLVT}, // Lo [27] HANGUL SYLLABLE DDWEG..HANGUL SYLLABLE DDWEH
+ {0xB6F0, 0xB6F0, prLV}, // Lo HANGUL SYLLABLE DDWI
+ {0xB6F1, 0xB70B, prLVT}, // Lo [27] HANGUL SYLLABLE DDWIG..HANGUL SYLLABLE DDWIH
+ {0xB70C, 0xB70C, prLV}, // Lo HANGUL SYLLABLE DDYU
+ {0xB70D, 0xB727, prLVT}, // Lo [27] HANGUL SYLLABLE DDYUG..HANGUL SYLLABLE DDYUH
+ {0xB728, 0xB728, prLV}, // Lo HANGUL SYLLABLE DDEU
+ {0xB729, 0xB743, prLVT}, // Lo [27] HANGUL SYLLABLE DDEUG..HANGUL SYLLABLE DDEUH
+ {0xB744, 0xB744, prLV}, // Lo HANGUL SYLLABLE DDYI
+ {0xB745, 0xB75F, prLVT}, // Lo [27] HANGUL SYLLABLE DDYIG..HANGUL SYLLABLE DDYIH
+ {0xB760, 0xB760, prLV}, // Lo HANGUL SYLLABLE DDI
+ {0xB761, 0xB77B, prLVT}, // Lo [27] HANGUL SYLLABLE DDIG..HANGUL SYLLABLE DDIH
+ {0xB77C, 0xB77C, prLV}, // Lo HANGUL SYLLABLE RA
+ {0xB77D, 0xB797, prLVT}, // Lo [27] HANGUL SYLLABLE RAG..HANGUL SYLLABLE RAH
+ {0xB798, 0xB798, prLV}, // Lo HANGUL SYLLABLE RAE
+ {0xB799, 0xB7B3, prLVT}, // Lo [27] HANGUL SYLLABLE RAEG..HANGUL SYLLABLE RAEH
+ {0xB7B4, 0xB7B4, prLV}, // Lo HANGUL SYLLABLE RYA
+ {0xB7B5, 0xB7CF, prLVT}, // Lo [27] HANGUL SYLLABLE RYAG..HANGUL SYLLABLE RYAH
+ {0xB7D0, 0xB7D0, prLV}, // Lo HANGUL SYLLABLE RYAE
+ {0xB7D1, 0xB7EB, prLVT}, // Lo [27] HANGUL SYLLABLE RYAEG..HANGUL SYLLABLE RYAEH
+ {0xB7EC, 0xB7EC, prLV}, // Lo HANGUL SYLLABLE REO
+ {0xB7ED, 0xB807, prLVT}, // Lo [27] HANGUL SYLLABLE REOG..HANGUL SYLLABLE REOH
+ {0xB808, 0xB808, prLV}, // Lo HANGUL SYLLABLE RE
+ {0xB809, 0xB823, prLVT}, // Lo [27] HANGUL SYLLABLE REG..HANGUL SYLLABLE REH
+ {0xB824, 0xB824, prLV}, // Lo HANGUL SYLLABLE RYEO
+ {0xB825, 0xB83F, prLVT}, // Lo [27] HANGUL SYLLABLE RYEOG..HANGUL SYLLABLE RYEOH
+ {0xB840, 0xB840, prLV}, // Lo HANGUL SYLLABLE RYE
+ {0xB841, 0xB85B, prLVT}, // Lo [27] HANGUL SYLLABLE RYEG..HANGUL SYLLABLE RYEH
+ {0xB85C, 0xB85C, prLV}, // Lo HANGUL SYLLABLE RO
+ {0xB85D, 0xB877, prLVT}, // Lo [27] HANGUL SYLLABLE ROG..HANGUL SYLLABLE ROH
+ {0xB878, 0xB878, prLV}, // Lo HANGUL SYLLABLE RWA
+ {0xB879, 0xB893, prLVT}, // Lo [27] HANGUL SYLLABLE RWAG..HANGUL SYLLABLE RWAH
+ {0xB894, 0xB894, prLV}, // Lo HANGUL SYLLABLE RWAE
+ {0xB895, 0xB8AF, prLVT}, // Lo [27] HANGUL SYLLABLE RWAEG..HANGUL SYLLABLE RWAEH
+ {0xB8B0, 0xB8B0, prLV}, // Lo HANGUL SYLLABLE ROE
+ {0xB8B1, 0xB8CB, prLVT}, // Lo [27] HANGUL SYLLABLE ROEG..HANGUL SYLLABLE ROEH
+ {0xB8CC, 0xB8CC, prLV}, // Lo HANGUL SYLLABLE RYO
+ {0xB8CD, 0xB8E7, prLVT}, // Lo [27] HANGUL SYLLABLE RYOG..HANGUL SYLLABLE RYOH
+ {0xB8E8, 0xB8E8, prLV}, // Lo HANGUL SYLLABLE RU
+ {0xB8E9, 0xB903, prLVT}, // Lo [27] HANGUL SYLLABLE RUG..HANGUL SYLLABLE RUH
+ {0xB904, 0xB904, prLV}, // Lo HANGUL SYLLABLE RWEO
+ {0xB905, 0xB91F, prLVT}, // Lo [27] HANGUL SYLLABLE RWEOG..HANGUL SYLLABLE RWEOH
+ {0xB920, 0xB920, prLV}, // Lo HANGUL SYLLABLE RWE
+ {0xB921, 0xB93B, prLVT}, // Lo [27] HANGUL SYLLABLE RWEG..HANGUL SYLLABLE RWEH
+ {0xB93C, 0xB93C, prLV}, // Lo HANGUL SYLLABLE RWI
+ {0xB93D, 0xB957, prLVT}, // Lo [27] HANGUL SYLLABLE RWIG..HANGUL SYLLABLE RWIH
+ {0xB958, 0xB958, prLV}, // Lo HANGUL SYLLABLE RYU
+ {0xB959, 0xB973, prLVT}, // Lo [27] HANGUL SYLLABLE RYUG..HANGUL SYLLABLE RYUH
+ {0xB974, 0xB974, prLV}, // Lo HANGUL SYLLABLE REU
+ {0xB975, 0xB98F, prLVT}, // Lo [27] HANGUL SYLLABLE REUG..HANGUL SYLLABLE REUH
+ {0xB990, 0xB990, prLV}, // Lo HANGUL SYLLABLE RYI
+ {0xB991, 0xB9AB, prLVT}, // Lo [27] HANGUL SYLLABLE RYIG..HANGUL SYLLABLE RYIH
+ {0xB9AC, 0xB9AC, prLV}, // Lo HANGUL SYLLABLE RI
+ {0xB9AD, 0xB9C7, prLVT}, // Lo [27] HANGUL SYLLABLE RIG..HANGUL SYLLABLE RIH
+ {0xB9C8, 0xB9C8, prLV}, // Lo HANGUL SYLLABLE MA
+ {0xB9C9, 0xB9E3, prLVT}, // Lo [27] HANGUL SYLLABLE MAG..HANGUL SYLLABLE MAH
+ {0xB9E4, 0xB9E4, prLV}, // Lo HANGUL SYLLABLE MAE
+ {0xB9E5, 0xB9FF, prLVT}, // Lo [27] HANGUL SYLLABLE MAEG..HANGUL SYLLABLE MAEH
+ {0xBA00, 0xBA00, prLV}, // Lo HANGUL SYLLABLE MYA
+ {0xBA01, 0xBA1B, prLVT}, // Lo [27] HANGUL SYLLABLE MYAG..HANGUL SYLLABLE MYAH
+ {0xBA1C, 0xBA1C, prLV}, // Lo HANGUL SYLLABLE MYAE
+ {0xBA1D, 0xBA37, prLVT}, // Lo [27] HANGUL SYLLABLE MYAEG..HANGUL SYLLABLE MYAEH
+ {0xBA38, 0xBA38, prLV}, // Lo HANGUL SYLLABLE MEO
+ {0xBA39, 0xBA53, prLVT}, // Lo [27] HANGUL SYLLABLE MEOG..HANGUL SYLLABLE MEOH
+ {0xBA54, 0xBA54, prLV}, // Lo HANGUL SYLLABLE ME
+ {0xBA55, 0xBA6F, prLVT}, // Lo [27] HANGUL SYLLABLE MEG..HANGUL SYLLABLE MEH
+ {0xBA70, 0xBA70, prLV}, // Lo HANGUL SYLLABLE MYEO
+ {0xBA71, 0xBA8B, prLVT}, // Lo [27] HANGUL SYLLABLE MYEOG..HANGUL SYLLABLE MYEOH
+ {0xBA8C, 0xBA8C, prLV}, // Lo HANGUL SYLLABLE MYE
+ {0xBA8D, 0xBAA7, prLVT}, // Lo [27] HANGUL SYLLABLE MYEG..HANGUL SYLLABLE MYEH
+ {0xBAA8, 0xBAA8, prLV}, // Lo HANGUL SYLLABLE MO
+ {0xBAA9, 0xBAC3, prLVT}, // Lo [27] HANGUL SYLLABLE MOG..HANGUL SYLLABLE MOH
+ {0xBAC4, 0xBAC4, prLV}, // Lo HANGUL SYLLABLE MWA
+ {0xBAC5, 0xBADF, prLVT}, // Lo [27] HANGUL SYLLABLE MWAG..HANGUL SYLLABLE MWAH
+ {0xBAE0, 0xBAE0, prLV}, // Lo HANGUL SYLLABLE MWAE
+ {0xBAE1, 0xBAFB, prLVT}, // Lo [27] HANGUL SYLLABLE MWAEG..HANGUL SYLLABLE MWAEH
+ {0xBAFC, 0xBAFC, prLV}, // Lo HANGUL SYLLABLE MOE
+ {0xBAFD, 0xBB17, prLVT}, // Lo [27] HANGUL SYLLABLE MOEG..HANGUL SYLLABLE MOEH
+ {0xBB18, 0xBB18, prLV}, // Lo HANGUL SYLLABLE MYO
+ {0xBB19, 0xBB33, prLVT}, // Lo [27] HANGUL SYLLABLE MYOG..HANGUL SYLLABLE MYOH
+ {0xBB34, 0xBB34, prLV}, // Lo HANGUL SYLLABLE MU
+ {0xBB35, 0xBB4F, prLVT}, // Lo [27] HANGUL SYLLABLE MUG..HANGUL SYLLABLE MUH
+ {0xBB50, 0xBB50, prLV}, // Lo HANGUL SYLLABLE MWEO
+ {0xBB51, 0xBB6B, prLVT}, // Lo [27] HANGUL SYLLABLE MWEOG..HANGUL SYLLABLE MWEOH
+ {0xBB6C, 0xBB6C, prLV}, // Lo HANGUL SYLLABLE MWE
+ {0xBB6D, 0xBB87, prLVT}, // Lo [27] HANGUL SYLLABLE MWEG..HANGUL SYLLABLE MWEH
+ {0xBB88, 0xBB88, prLV}, // Lo HANGUL SYLLABLE MWI
+ {0xBB89, 0xBBA3, prLVT}, // Lo [27] HANGUL SYLLABLE MWIG..HANGUL SYLLABLE MWIH
+ {0xBBA4, 0xBBA4, prLV}, // Lo HANGUL SYLLABLE MYU
+ {0xBBA5, 0xBBBF, prLVT}, // Lo [27] HANGUL SYLLABLE MYUG..HANGUL SYLLABLE MYUH
+ {0xBBC0, 0xBBC0, prLV}, // Lo HANGUL SYLLABLE MEU
+ {0xBBC1, 0xBBDB, prLVT}, // Lo [27] HANGUL SYLLABLE MEUG..HANGUL SYLLABLE MEUH
+ {0xBBDC, 0xBBDC, prLV}, // Lo HANGUL SYLLABLE MYI
+ {0xBBDD, 0xBBF7, prLVT}, // Lo [27] HANGUL SYLLABLE MYIG..HANGUL SYLLABLE MYIH
+ {0xBBF8, 0xBBF8, prLV}, // Lo HANGUL SYLLABLE MI
+ {0xBBF9, 0xBC13, prLVT}, // Lo [27] HANGUL SYLLABLE MIG..HANGUL SYLLABLE MIH
+ {0xBC14, 0xBC14, prLV}, // Lo HANGUL SYLLABLE BA
+ {0xBC15, 0xBC2F, prLVT}, // Lo [27] HANGUL SYLLABLE BAG..HANGUL SYLLABLE BAH
+ {0xBC30, 0xBC30, prLV}, // Lo HANGUL SYLLABLE BAE
+ {0xBC31, 0xBC4B, prLVT}, // Lo [27] HANGUL SYLLABLE BAEG..HANGUL SYLLABLE BAEH
+ {0xBC4C, 0xBC4C, prLV}, // Lo HANGUL SYLLABLE BYA
+ {0xBC4D, 0xBC67, prLVT}, // Lo [27] HANGUL SYLLABLE BYAG..HANGUL SYLLABLE BYAH
+ {0xBC68, 0xBC68, prLV}, // Lo HANGUL SYLLABLE BYAE
+ {0xBC69, 0xBC83, prLVT}, // Lo [27] HANGUL SYLLABLE BYAEG..HANGUL SYLLABLE BYAEH
+ {0xBC84, 0xBC84, prLV}, // Lo HANGUL SYLLABLE BEO
+ {0xBC85, 0xBC9F, prLVT}, // Lo [27] HANGUL SYLLABLE BEOG..HANGUL SYLLABLE BEOH
+ {0xBCA0, 0xBCA0, prLV}, // Lo HANGUL SYLLABLE BE
+ {0xBCA1, 0xBCBB, prLVT}, // Lo [27] HANGUL SYLLABLE BEG..HANGUL SYLLABLE BEH
+ {0xBCBC, 0xBCBC, prLV}, // Lo HANGUL SYLLABLE BYEO
+ {0xBCBD, 0xBCD7, prLVT}, // Lo [27] HANGUL SYLLABLE BYEOG..HANGUL SYLLABLE BYEOH
+ {0xBCD8, 0xBCD8, prLV}, // Lo HANGUL SYLLABLE BYE
+ {0xBCD9, 0xBCF3, prLVT}, // Lo [27] HANGUL SYLLABLE BYEG..HANGUL SYLLABLE BYEH
+ {0xBCF4, 0xBCF4, prLV}, // Lo HANGUL SYLLABLE BO
+ {0xBCF5, 0xBD0F, prLVT}, // Lo [27] HANGUL SYLLABLE BOG..HANGUL SYLLABLE BOH
+ {0xBD10, 0xBD10, prLV}, // Lo HANGUL SYLLABLE BWA
+ {0xBD11, 0xBD2B, prLVT}, // Lo [27] HANGUL SYLLABLE BWAG..HANGUL SYLLABLE BWAH
+ {0xBD2C, 0xBD2C, prLV}, // Lo HANGUL SYLLABLE BWAE
+ {0xBD2D, 0xBD47, prLVT}, // Lo [27] HANGUL SYLLABLE BWAEG..HANGUL SYLLABLE BWAEH
+ {0xBD48, 0xBD48, prLV}, // Lo HANGUL SYLLABLE BOE
+ {0xBD49, 0xBD63, prLVT}, // Lo [27] HANGUL SYLLABLE BOEG..HANGUL SYLLABLE BOEH
+ {0xBD64, 0xBD64, prLV}, // Lo HANGUL SYLLABLE BYO
+ {0xBD65, 0xBD7F, prLVT}, // Lo [27] HANGUL SYLLABLE BYOG..HANGUL SYLLABLE BYOH
+ {0xBD80, 0xBD80, prLV}, // Lo HANGUL SYLLABLE BU
+ {0xBD81, 0xBD9B, prLVT}, // Lo [27] HANGUL SYLLABLE BUG..HANGUL SYLLABLE BUH
+ {0xBD9C, 0xBD9C, prLV}, // Lo HANGUL SYLLABLE BWEO
+ {0xBD9D, 0xBDB7, prLVT}, // Lo [27] HANGUL SYLLABLE BWEOG..HANGUL SYLLABLE BWEOH
+ {0xBDB8, 0xBDB8, prLV}, // Lo HANGUL SYLLABLE BWE
+ {0xBDB9, 0xBDD3, prLVT}, // Lo [27] HANGUL SYLLABLE BWEG..HANGUL SYLLABLE BWEH
+ {0xBDD4, 0xBDD4, prLV}, // Lo HANGUL SYLLABLE BWI
+ {0xBDD5, 0xBDEF, prLVT}, // Lo [27] HANGUL SYLLABLE BWIG..HANGUL SYLLABLE BWIH
+ {0xBDF0, 0xBDF0, prLV}, // Lo HANGUL SYLLABLE BYU
+ {0xBDF1, 0xBE0B, prLVT}, // Lo [27] HANGUL SYLLABLE BYUG..HANGUL SYLLABLE BYUH
+ {0xBE0C, 0xBE0C, prLV}, // Lo HANGUL SYLLABLE BEU
+ {0xBE0D, 0xBE27, prLVT}, // Lo [27] HANGUL SYLLABLE BEUG..HANGUL SYLLABLE BEUH
+ {0xBE28, 0xBE28, prLV}, // Lo HANGUL SYLLABLE BYI
+ {0xBE29, 0xBE43, prLVT}, // Lo [27] HANGUL SYLLABLE BYIG..HANGUL SYLLABLE BYIH
+ {0xBE44, 0xBE44, prLV}, // Lo HANGUL SYLLABLE BI
+ {0xBE45, 0xBE5F, prLVT}, // Lo [27] HANGUL SYLLABLE BIG..HANGUL SYLLABLE BIH
+ {0xBE60, 0xBE60, prLV}, // Lo HANGUL SYLLABLE BBA
+ {0xBE61, 0xBE7B, prLVT}, // Lo [27] HANGUL SYLLABLE BBAG..HANGUL SYLLABLE BBAH
+ {0xBE7C, 0xBE7C, prLV}, // Lo HANGUL SYLLABLE BBAE
+ {0xBE7D, 0xBE97, prLVT}, // Lo [27] HANGUL SYLLABLE BBAEG..HANGUL SYLLABLE BBAEH
+ {0xBE98, 0xBE98, prLV}, // Lo HANGUL SYLLABLE BBYA
+ {0xBE99, 0xBEB3, prLVT}, // Lo [27] HANGUL SYLLABLE BBYAG..HANGUL SYLLABLE BBYAH
+ {0xBEB4, 0xBEB4, prLV}, // Lo HANGUL SYLLABLE BBYAE
+ {0xBEB5, 0xBECF, prLVT}, // Lo [27] HANGUL SYLLABLE BBYAEG..HANGUL SYLLABLE BBYAEH
+ {0xBED0, 0xBED0, prLV}, // Lo HANGUL SYLLABLE BBEO
+ {0xBED1, 0xBEEB, prLVT}, // Lo [27] HANGUL SYLLABLE BBEOG..HANGUL SYLLABLE BBEOH
+ {0xBEEC, 0xBEEC, prLV}, // Lo HANGUL SYLLABLE BBE
+ {0xBEED, 0xBF07, prLVT}, // Lo [27] HANGUL SYLLABLE BBEG..HANGUL SYLLABLE BBEH
+ {0xBF08, 0xBF08, prLV}, // Lo HANGUL SYLLABLE BBYEO
+ {0xBF09, 0xBF23, prLVT}, // Lo [27] HANGUL SYLLABLE BBYEOG..HANGUL SYLLABLE BBYEOH
+ {0xBF24, 0xBF24, prLV}, // Lo HANGUL SYLLABLE BBYE
+ {0xBF25, 0xBF3F, prLVT}, // Lo [27] HANGUL SYLLABLE BBYEG..HANGUL SYLLABLE BBYEH
+ {0xBF40, 0xBF40, prLV}, // Lo HANGUL SYLLABLE BBO
+ {0xBF41, 0xBF5B, prLVT}, // Lo [27] HANGUL SYLLABLE BBOG..HANGUL SYLLABLE BBOH
+ {0xBF5C, 0xBF5C, prLV}, // Lo HANGUL SYLLABLE BBWA
+ {0xBF5D, 0xBF77, prLVT}, // Lo [27] HANGUL SYLLABLE BBWAG..HANGUL SYLLABLE BBWAH
+ {0xBF78, 0xBF78, prLV}, // Lo HANGUL SYLLABLE BBWAE
+ {0xBF79, 0xBF93, prLVT}, // Lo [27] HANGUL SYLLABLE BBWAEG..HANGUL SYLLABLE BBWAEH
+ {0xBF94, 0xBF94, prLV}, // Lo HANGUL SYLLABLE BBOE
+ {0xBF95, 0xBFAF, prLVT}, // Lo [27] HANGUL SYLLABLE BBOEG..HANGUL SYLLABLE BBOEH
+ {0xBFB0, 0xBFB0, prLV}, // Lo HANGUL SYLLABLE BBYO
+ {0xBFB1, 0xBFCB, prLVT}, // Lo [27] HANGUL SYLLABLE BBYOG..HANGUL SYLLABLE BBYOH
+ {0xBFCC, 0xBFCC, prLV}, // Lo HANGUL SYLLABLE BBU
+ {0xBFCD, 0xBFE7, prLVT}, // Lo [27] HANGUL SYLLABLE BBUG..HANGUL SYLLABLE BBUH
+ {0xBFE8, 0xBFE8, prLV}, // Lo HANGUL SYLLABLE BBWEO
+ {0xBFE9, 0xC003, prLVT}, // Lo [27] HANGUL SYLLABLE BBWEOG..HANGUL SYLLABLE BBWEOH
+ {0xC004, 0xC004, prLV}, // Lo HANGUL SYLLABLE BBWE
+ {0xC005, 0xC01F, prLVT}, // Lo [27] HANGUL SYLLABLE BBWEG..HANGUL SYLLABLE BBWEH
+ {0xC020, 0xC020, prLV}, // Lo HANGUL SYLLABLE BBWI
+ {0xC021, 0xC03B, prLVT}, // Lo [27] HANGUL SYLLABLE BBWIG..HANGUL SYLLABLE BBWIH
+ {0xC03C, 0xC03C, prLV}, // Lo HANGUL SYLLABLE BBYU
+ {0xC03D, 0xC057, prLVT}, // Lo [27] HANGUL SYLLABLE BBYUG..HANGUL SYLLABLE BBYUH
+ {0xC058, 0xC058, prLV}, // Lo HANGUL SYLLABLE BBEU
+ {0xC059, 0xC073, prLVT}, // Lo [27] HANGUL SYLLABLE BBEUG..HANGUL SYLLABLE BBEUH
+ {0xC074, 0xC074, prLV}, // Lo HANGUL SYLLABLE BBYI
+ {0xC075, 0xC08F, prLVT}, // Lo [27] HANGUL SYLLABLE BBYIG..HANGUL SYLLABLE BBYIH
+ {0xC090, 0xC090, prLV}, // Lo HANGUL SYLLABLE BBI
+ {0xC091, 0xC0AB, prLVT}, // Lo [27] HANGUL SYLLABLE BBIG..HANGUL SYLLABLE BBIH
+ {0xC0AC, 0xC0AC, prLV}, // Lo HANGUL SYLLABLE SA
+ {0xC0AD, 0xC0C7, prLVT}, // Lo [27] HANGUL SYLLABLE SAG..HANGUL SYLLABLE SAH
+ {0xC0C8, 0xC0C8, prLV}, // Lo HANGUL SYLLABLE SAE
+ {0xC0C9, 0xC0E3, prLVT}, // Lo [27] HANGUL SYLLABLE SAEG..HANGUL SYLLABLE SAEH
+ {0xC0E4, 0xC0E4, prLV}, // Lo HANGUL SYLLABLE SYA
+ {0xC0E5, 0xC0FF, prLVT}, // Lo [27] HANGUL SYLLABLE SYAG..HANGUL SYLLABLE SYAH
+ {0xC100, 0xC100, prLV}, // Lo HANGUL SYLLABLE SYAE
+ {0xC101, 0xC11B, prLVT}, // Lo [27] HANGUL SYLLABLE SYAEG..HANGUL SYLLABLE SYAEH
+ {0xC11C, 0xC11C, prLV}, // Lo HANGUL SYLLABLE SEO
+ {0xC11D, 0xC137, prLVT}, // Lo [27] HANGUL SYLLABLE SEOG..HANGUL SYLLABLE SEOH
+ {0xC138, 0xC138, prLV}, // Lo HANGUL SYLLABLE SE
+ {0xC139, 0xC153, prLVT}, // Lo [27] HANGUL SYLLABLE SEG..HANGUL SYLLABLE SEH
+ {0xC154, 0xC154, prLV}, // Lo HANGUL SYLLABLE SYEO
+ {0xC155, 0xC16F, prLVT}, // Lo [27] HANGUL SYLLABLE SYEOG..HANGUL SYLLABLE SYEOH
+ {0xC170, 0xC170, prLV}, // Lo HANGUL SYLLABLE SYE
+ {0xC171, 0xC18B, prLVT}, // Lo [27] HANGUL SYLLABLE SYEG..HANGUL SYLLABLE SYEH
+ {0xC18C, 0xC18C, prLV}, // Lo HANGUL SYLLABLE SO
+ {0xC18D, 0xC1A7, prLVT}, // Lo [27] HANGUL SYLLABLE SOG..HANGUL SYLLABLE SOH
+ {0xC1A8, 0xC1A8, prLV}, // Lo HANGUL SYLLABLE SWA
+ {0xC1A9, 0xC1C3, prLVT}, // Lo [27] HANGUL SYLLABLE SWAG..HANGUL SYLLABLE SWAH
+ {0xC1C4, 0xC1C4, prLV}, // Lo HANGUL SYLLABLE SWAE
+ {0xC1C5, 0xC1DF, prLVT}, // Lo [27] HANGUL SYLLABLE SWAEG..HANGUL SYLLABLE SWAEH
+ {0xC1E0, 0xC1E0, prLV}, // Lo HANGUL SYLLABLE SOE
+ {0xC1E1, 0xC1FB, prLVT}, // Lo [27] HANGUL SYLLABLE SOEG..HANGUL SYLLABLE SOEH
+ {0xC1FC, 0xC1FC, prLV}, // Lo HANGUL SYLLABLE SYO
+ {0xC1FD, 0xC217, prLVT}, // Lo [27] HANGUL SYLLABLE SYOG..HANGUL SYLLABLE SYOH
+ {0xC218, 0xC218, prLV}, // Lo HANGUL SYLLABLE SU
+ {0xC219, 0xC233, prLVT}, // Lo [27] HANGUL SYLLABLE SUG..HANGUL SYLLABLE SUH
+ {0xC234, 0xC234, prLV}, // Lo HANGUL SYLLABLE SWEO
+ {0xC235, 0xC24F, prLVT}, // Lo [27] HANGUL SYLLABLE SWEOG..HANGUL SYLLABLE SWEOH
+ {0xC250, 0xC250, prLV}, // Lo HANGUL SYLLABLE SWE
+ {0xC251, 0xC26B, prLVT}, // Lo [27] HANGUL SYLLABLE SWEG..HANGUL SYLLABLE SWEH
+ {0xC26C, 0xC26C, prLV}, // Lo HANGUL SYLLABLE SWI
+ {0xC26D, 0xC287, prLVT}, // Lo [27] HANGUL SYLLABLE SWIG..HANGUL SYLLABLE SWIH
+ {0xC288, 0xC288, prLV}, // Lo HANGUL SYLLABLE SYU
+ {0xC289, 0xC2A3, prLVT}, // Lo [27] HANGUL SYLLABLE SYUG..HANGUL SYLLABLE SYUH
+ {0xC2A4, 0xC2A4, prLV}, // Lo HANGUL SYLLABLE SEU
+ {0xC2A5, 0xC2BF, prLVT}, // Lo [27] HANGUL SYLLABLE SEUG..HANGUL SYLLABLE SEUH
+ {0xC2C0, 0xC2C0, prLV}, // Lo HANGUL SYLLABLE SYI
+ {0xC2C1, 0xC2DB, prLVT}, // Lo [27] HANGUL SYLLABLE SYIG..HANGUL SYLLABLE SYIH
+ {0xC2DC, 0xC2DC, prLV}, // Lo HANGUL SYLLABLE SI
+ {0xC2DD, 0xC2F7, prLVT}, // Lo [27] HANGUL SYLLABLE SIG..HANGUL SYLLABLE SIH
+ {0xC2F8, 0xC2F8, prLV}, // Lo HANGUL SYLLABLE SSA
+ {0xC2F9, 0xC313, prLVT}, // Lo [27] HANGUL SYLLABLE SSAG..HANGUL SYLLABLE SSAH
+ {0xC314, 0xC314, prLV}, // Lo HANGUL SYLLABLE SSAE
+ {0xC315, 0xC32F, prLVT}, // Lo [27] HANGUL SYLLABLE SSAEG..HANGUL SYLLABLE SSAEH
+ {0xC330, 0xC330, prLV}, // Lo HANGUL SYLLABLE SSYA
+ {0xC331, 0xC34B, prLVT}, // Lo [27] HANGUL SYLLABLE SSYAG..HANGUL SYLLABLE SSYAH
+ {0xC34C, 0xC34C, prLV}, // Lo HANGUL SYLLABLE SSYAE
+ {0xC34D, 0xC367, prLVT}, // Lo [27] HANGUL SYLLABLE SSYAEG..HANGUL SYLLABLE SSYAEH
+ {0xC368, 0xC368, prLV}, // Lo HANGUL SYLLABLE SSEO
+ {0xC369, 0xC383, prLVT}, // Lo [27] HANGUL SYLLABLE SSEOG..HANGUL SYLLABLE SSEOH
+ {0xC384, 0xC384, prLV}, // Lo HANGUL SYLLABLE SSE
+ {0xC385, 0xC39F, prLVT}, // Lo [27] HANGUL SYLLABLE SSEG..HANGUL SYLLABLE SSEH
+ {0xC3A0, 0xC3A0, prLV}, // Lo HANGUL SYLLABLE SSYEO
+ {0xC3A1, 0xC3BB, prLVT}, // Lo [27] HANGUL SYLLABLE SSYEOG..HANGUL SYLLABLE SSYEOH
+ {0xC3BC, 0xC3BC, prLV}, // Lo HANGUL SYLLABLE SSYE
+ {0xC3BD, 0xC3D7, prLVT}, // Lo [27] HANGUL SYLLABLE SSYEG..HANGUL SYLLABLE SSYEH
+ {0xC3D8, 0xC3D8, prLV}, // Lo HANGUL SYLLABLE SSO
+ {0xC3D9, 0xC3F3, prLVT}, // Lo [27] HANGUL SYLLABLE SSOG..HANGUL SYLLABLE SSOH
+ {0xC3F4, 0xC3F4, prLV}, // Lo HANGUL SYLLABLE SSWA
+ {0xC3F5, 0xC40F, prLVT}, // Lo [27] HANGUL SYLLABLE SSWAG..HANGUL SYLLABLE SSWAH
+ {0xC410, 0xC410, prLV}, // Lo HANGUL SYLLABLE SSWAE
+ {0xC411, 0xC42B, prLVT}, // Lo [27] HANGUL SYLLABLE SSWAEG..HANGUL SYLLABLE SSWAEH
+ {0xC42C, 0xC42C, prLV}, // Lo HANGUL SYLLABLE SSOE
+ {0xC42D, 0xC447, prLVT}, // Lo [27] HANGUL SYLLABLE SSOEG..HANGUL SYLLABLE SSOEH
+ {0xC448, 0xC448, prLV}, // Lo HANGUL SYLLABLE SSYO
+ {0xC449, 0xC463, prLVT}, // Lo [27] HANGUL SYLLABLE SSYOG..HANGUL SYLLABLE SSYOH
+ {0xC464, 0xC464, prLV}, // Lo HANGUL SYLLABLE SSU
+ {0xC465, 0xC47F, prLVT}, // Lo [27] HANGUL SYLLABLE SSUG..HANGUL SYLLABLE SSUH
+ {0xC480, 0xC480, prLV}, // Lo HANGUL SYLLABLE SSWEO
+ {0xC481, 0xC49B, prLVT}, // Lo [27] HANGUL SYLLABLE SSWEOG..HANGUL SYLLABLE SSWEOH
+ {0xC49C, 0xC49C, prLV}, // Lo HANGUL SYLLABLE SSWE
+ {0xC49D, 0xC4B7, prLVT}, // Lo [27] HANGUL SYLLABLE SSWEG..HANGUL SYLLABLE SSWEH
+ {0xC4B8, 0xC4B8, prLV}, // Lo HANGUL SYLLABLE SSWI
+ {0xC4B9, 0xC4D3, prLVT}, // Lo [27] HANGUL SYLLABLE SSWIG..HANGUL SYLLABLE SSWIH
+ {0xC4D4, 0xC4D4, prLV}, // Lo HANGUL SYLLABLE SSYU
+ {0xC4D5, 0xC4EF, prLVT}, // Lo [27] HANGUL SYLLABLE SSYUG..HANGUL SYLLABLE SSYUH
+ {0xC4F0, 0xC4F0, prLV}, // Lo HANGUL SYLLABLE SSEU
+ {0xC4F1, 0xC50B, prLVT}, // Lo [27] HANGUL SYLLABLE SSEUG..HANGUL SYLLABLE SSEUH
+ {0xC50C, 0xC50C, prLV}, // Lo HANGUL SYLLABLE SSYI
+ {0xC50D, 0xC527, prLVT}, // Lo [27] HANGUL SYLLABLE SSYIG..HANGUL SYLLABLE SSYIH
+ {0xC528, 0xC528, prLV}, // Lo HANGUL SYLLABLE SSI
+ {0xC529, 0xC543, prLVT}, // Lo [27] HANGUL SYLLABLE SSIG..HANGUL SYLLABLE SSIH
+ {0xC544, 0xC544, prLV}, // Lo HANGUL SYLLABLE A
+ {0xC545, 0xC55F, prLVT}, // Lo [27] HANGUL SYLLABLE AG..HANGUL SYLLABLE AH
+ {0xC560, 0xC560, prLV}, // Lo HANGUL SYLLABLE AE
+ {0xC561, 0xC57B, prLVT}, // Lo [27] HANGUL SYLLABLE AEG..HANGUL SYLLABLE AEH
+ {0xC57C, 0xC57C, prLV}, // Lo HANGUL SYLLABLE YA
+ {0xC57D, 0xC597, prLVT}, // Lo [27] HANGUL SYLLABLE YAG..HANGUL SYLLABLE YAH
+ {0xC598, 0xC598, prLV}, // Lo HANGUL SYLLABLE YAE
+ {0xC599, 0xC5B3, prLVT}, // Lo [27] HANGUL SYLLABLE YAEG..HANGUL SYLLABLE YAEH
+ {0xC5B4, 0xC5B4, prLV}, // Lo HANGUL SYLLABLE EO
+ {0xC5B5, 0xC5CF, prLVT}, // Lo [27] HANGUL SYLLABLE EOG..HANGUL SYLLABLE EOH
+ {0xC5D0, 0xC5D0, prLV}, // Lo HANGUL SYLLABLE E
+ {0xC5D1, 0xC5EB, prLVT}, // Lo [27] HANGUL SYLLABLE EG..HANGUL SYLLABLE EH
+ {0xC5EC, 0xC5EC, prLV}, // Lo HANGUL SYLLABLE YEO
+ {0xC5ED, 0xC607, prLVT}, // Lo [27] HANGUL SYLLABLE YEOG..HANGUL SYLLABLE YEOH
+ {0xC608, 0xC608, prLV}, // Lo HANGUL SYLLABLE YE
+ {0xC609, 0xC623, prLVT}, // Lo [27] HANGUL SYLLABLE YEG..HANGUL SYLLABLE YEH
+ {0xC624, 0xC624, prLV}, // Lo HANGUL SYLLABLE O
+ {0xC625, 0xC63F, prLVT}, // Lo [27] HANGUL SYLLABLE OG..HANGUL SYLLABLE OH
+ {0xC640, 0xC640, prLV}, // Lo HANGUL SYLLABLE WA
+ {0xC641, 0xC65B, prLVT}, // Lo [27] HANGUL SYLLABLE WAG..HANGUL SYLLABLE WAH
+ {0xC65C, 0xC65C, prLV}, // Lo HANGUL SYLLABLE WAE
+ {0xC65D, 0xC677, prLVT}, // Lo [27] HANGUL SYLLABLE WAEG..HANGUL SYLLABLE WAEH
+ {0xC678, 0xC678, prLV}, // Lo HANGUL SYLLABLE OE
+ {0xC679, 0xC693, prLVT}, // Lo [27] HANGUL SYLLABLE OEG..HANGUL SYLLABLE OEH
+ {0xC694, 0xC694, prLV}, // Lo HANGUL SYLLABLE YO
+ {0xC695, 0xC6AF, prLVT}, // Lo [27] HANGUL SYLLABLE YOG..HANGUL SYLLABLE YOH
+ {0xC6B0, 0xC6B0, prLV}, // Lo HANGUL SYLLABLE U
+ {0xC6B1, 0xC6CB, prLVT}, // Lo [27] HANGUL SYLLABLE UG..HANGUL SYLLABLE UH
+ {0xC6CC, 0xC6CC, prLV}, // Lo HANGUL SYLLABLE WEO
+ {0xC6CD, 0xC6E7, prLVT}, // Lo [27] HANGUL SYLLABLE WEOG..HANGUL SYLLABLE WEOH
+ {0xC6E8, 0xC6E8, prLV}, // Lo HANGUL SYLLABLE WE
+ {0xC6E9, 0xC703, prLVT}, // Lo [27] HANGUL SYLLABLE WEG..HANGUL SYLLABLE WEH
+ {0xC704, 0xC704, prLV}, // Lo HANGUL SYLLABLE WI
+ {0xC705, 0xC71F, prLVT}, // Lo [27] HANGUL SYLLABLE WIG..HANGUL SYLLABLE WIH
+ {0xC720, 0xC720, prLV}, // Lo HANGUL SYLLABLE YU
+ {0xC721, 0xC73B, prLVT}, // Lo [27] HANGUL SYLLABLE YUG..HANGUL SYLLABLE YUH
+ {0xC73C, 0xC73C, prLV}, // Lo HANGUL SYLLABLE EU
+ {0xC73D, 0xC757, prLVT}, // Lo [27] HANGUL SYLLABLE EUG..HANGUL SYLLABLE EUH
+ {0xC758, 0xC758, prLV}, // Lo HANGUL SYLLABLE YI
+ {0xC759, 0xC773, prLVT}, // Lo [27] HANGUL SYLLABLE YIG..HANGUL SYLLABLE YIH
+ {0xC774, 0xC774, prLV}, // Lo HANGUL SYLLABLE I
+ {0xC775, 0xC78F, prLVT}, // Lo [27] HANGUL SYLLABLE IG..HANGUL SYLLABLE IH
+ {0xC790, 0xC790, prLV}, // Lo HANGUL SYLLABLE JA
+ {0xC791, 0xC7AB, prLVT}, // Lo [27] HANGUL SYLLABLE JAG..HANGUL SYLLABLE JAH
+ {0xC7AC, 0xC7AC, prLV}, // Lo HANGUL SYLLABLE JAE
+ {0xC7AD, 0xC7C7, prLVT}, // Lo [27] HANGUL SYLLABLE JAEG..HANGUL SYLLABLE JAEH
+ {0xC7C8, 0xC7C8, prLV}, // Lo HANGUL SYLLABLE JYA
+ {0xC7C9, 0xC7E3, prLVT}, // Lo [27] HANGUL SYLLABLE JYAG..HANGUL SYLLABLE JYAH
+ {0xC7E4, 0xC7E4, prLV}, // Lo HANGUL SYLLABLE JYAE
+ {0xC7E5, 0xC7FF, prLVT}, // Lo [27] HANGUL SYLLABLE JYAEG..HANGUL SYLLABLE JYAEH
+ {0xC800, 0xC800, prLV}, // Lo HANGUL SYLLABLE JEO
+ {0xC801, 0xC81B, prLVT}, // Lo [27] HANGUL SYLLABLE JEOG..HANGUL SYLLABLE JEOH
+ {0xC81C, 0xC81C, prLV}, // Lo HANGUL SYLLABLE JE
+ {0xC81D, 0xC837, prLVT}, // Lo [27] HANGUL SYLLABLE JEG..HANGUL SYLLABLE JEH
+ {0xC838, 0xC838, prLV}, // Lo HANGUL SYLLABLE JYEO
+ {0xC839, 0xC853, prLVT}, // Lo [27] HANGUL SYLLABLE JYEOG..HANGUL SYLLABLE JYEOH
+ {0xC854, 0xC854, prLV}, // Lo HANGUL SYLLABLE JYE
+ {0xC855, 0xC86F, prLVT}, // Lo [27] HANGUL SYLLABLE JYEG..HANGUL SYLLABLE JYEH
+ {0xC870, 0xC870, prLV}, // Lo HANGUL SYLLABLE JO
+ {0xC871, 0xC88B, prLVT}, // Lo [27] HANGUL SYLLABLE JOG..HANGUL SYLLABLE JOH
+ {0xC88C, 0xC88C, prLV}, // Lo HANGUL SYLLABLE JWA
+ {0xC88D, 0xC8A7, prLVT}, // Lo [27] HANGUL SYLLABLE JWAG..HANGUL SYLLABLE JWAH
+ {0xC8A8, 0xC8A8, prLV}, // Lo HANGUL SYLLABLE JWAE
+ {0xC8A9, 0xC8C3, prLVT}, // Lo [27] HANGUL SYLLABLE JWAEG..HANGUL SYLLABLE JWAEH
+ {0xC8C4, 0xC8C4, prLV}, // Lo HANGUL SYLLABLE JOE
+ {0xC8C5, 0xC8DF, prLVT}, // Lo [27] HANGUL SYLLABLE JOEG..HANGUL SYLLABLE JOEH
+ {0xC8E0, 0xC8E0, prLV}, // Lo HANGUL SYLLABLE JYO
+ {0xC8E1, 0xC8FB, prLVT}, // Lo [27] HANGUL SYLLABLE JYOG..HANGUL SYLLABLE JYOH
+ {0xC8FC, 0xC8FC, prLV}, // Lo HANGUL SYLLABLE JU
+ {0xC8FD, 0xC917, prLVT}, // Lo [27] HANGUL SYLLABLE JUG..HANGUL SYLLABLE JUH
+ {0xC918, 0xC918, prLV}, // Lo HANGUL SYLLABLE JWEO
+ {0xC919, 0xC933, prLVT}, // Lo [27] HANGUL SYLLABLE JWEOG..HANGUL SYLLABLE JWEOH
+ {0xC934, 0xC934, prLV}, // Lo HANGUL SYLLABLE JWE
+ {0xC935, 0xC94F, prLVT}, // Lo [27] HANGUL SYLLABLE JWEG..HANGUL SYLLABLE JWEH
+ {0xC950, 0xC950, prLV}, // Lo HANGUL SYLLABLE JWI
+ {0xC951, 0xC96B, prLVT}, // Lo [27] HANGUL SYLLABLE JWIG..HANGUL SYLLABLE JWIH
+ {0xC96C, 0xC96C, prLV}, // Lo HANGUL SYLLABLE JYU
+ {0xC96D, 0xC987, prLVT}, // Lo [27] HANGUL SYLLABLE JYUG..HANGUL SYLLABLE JYUH
+ {0xC988, 0xC988, prLV}, // Lo HANGUL SYLLABLE JEU
+ {0xC989, 0xC9A3, prLVT}, // Lo [27] HANGUL SYLLABLE JEUG..HANGUL SYLLABLE JEUH
+ {0xC9A4, 0xC9A4, prLV}, // Lo HANGUL SYLLABLE JYI
+ {0xC9A5, 0xC9BF, prLVT}, // Lo [27] HANGUL SYLLABLE JYIG..HANGUL SYLLABLE JYIH
+ {0xC9C0, 0xC9C0, prLV}, // Lo HANGUL SYLLABLE JI
+ {0xC9C1, 0xC9DB, prLVT}, // Lo [27] HANGUL SYLLABLE JIG..HANGUL SYLLABLE JIH
+ {0xC9DC, 0xC9DC, prLV}, // Lo HANGUL SYLLABLE JJA
+ {0xC9DD, 0xC9F7, prLVT}, // Lo [27] HANGUL SYLLABLE JJAG..HANGUL SYLLABLE JJAH
+ {0xC9F8, 0xC9F8, prLV}, // Lo HANGUL SYLLABLE JJAE
+ {0xC9F9, 0xCA13, prLVT}, // Lo [27] HANGUL SYLLABLE JJAEG..HANGUL SYLLABLE JJAEH
+ {0xCA14, 0xCA14, prLV}, // Lo HANGUL SYLLABLE JJYA
+ {0xCA15, 0xCA2F, prLVT}, // Lo [27] HANGUL SYLLABLE JJYAG..HANGUL SYLLABLE JJYAH
+ {0xCA30, 0xCA30, prLV}, // Lo HANGUL SYLLABLE JJYAE
+ {0xCA31, 0xCA4B, prLVT}, // Lo [27] HANGUL SYLLABLE JJYAEG..HANGUL SYLLABLE JJYAEH
+ {0xCA4C, 0xCA4C, prLV}, // Lo HANGUL SYLLABLE JJEO
+ {0xCA4D, 0xCA67, prLVT}, // Lo [27] HANGUL SYLLABLE JJEOG..HANGUL SYLLABLE JJEOH
+ {0xCA68, 0xCA68, prLV}, // Lo HANGUL SYLLABLE JJE
+ {0xCA69, 0xCA83, prLVT}, // Lo [27] HANGUL SYLLABLE JJEG..HANGUL SYLLABLE JJEH
+ {0xCA84, 0xCA84, prLV}, // Lo HANGUL SYLLABLE JJYEO
+ {0xCA85, 0xCA9F, prLVT}, // Lo [27] HANGUL SYLLABLE JJYEOG..HANGUL SYLLABLE JJYEOH
+ {0xCAA0, 0xCAA0, prLV}, // Lo HANGUL SYLLABLE JJYE
+ {0xCAA1, 0xCABB, prLVT}, // Lo [27] HANGUL SYLLABLE JJYEG..HANGUL SYLLABLE JJYEH
+ {0xCABC, 0xCABC, prLV}, // Lo HANGUL SYLLABLE JJO
+ {0xCABD, 0xCAD7, prLVT}, // Lo [27] HANGUL SYLLABLE JJOG..HANGUL SYLLABLE JJOH
+ {0xCAD8, 0xCAD8, prLV}, // Lo HANGUL SYLLABLE JJWA
+ {0xCAD9, 0xCAF3, prLVT}, // Lo [27] HANGUL SYLLABLE JJWAG..HANGUL SYLLABLE JJWAH
+ {0xCAF4, 0xCAF4, prLV}, // Lo HANGUL SYLLABLE JJWAE
+ {0xCAF5, 0xCB0F, prLVT}, // Lo [27] HANGUL SYLLABLE JJWAEG..HANGUL SYLLABLE JJWAEH
+ {0xCB10, 0xCB10, prLV}, // Lo HANGUL SYLLABLE JJOE
+ {0xCB11, 0xCB2B, prLVT}, // Lo [27] HANGUL SYLLABLE JJOEG..HANGUL SYLLABLE JJOEH
+ {0xCB2C, 0xCB2C, prLV}, // Lo HANGUL SYLLABLE JJYO
+ {0xCB2D, 0xCB47, prLVT}, // Lo [27] HANGUL SYLLABLE JJYOG..HANGUL SYLLABLE JJYOH
+ {0xCB48, 0xCB48, prLV}, // Lo HANGUL SYLLABLE JJU
+ {0xCB49, 0xCB63, prLVT}, // Lo [27] HANGUL SYLLABLE JJUG..HANGUL SYLLABLE JJUH
+ {0xCB64, 0xCB64, prLV}, // Lo HANGUL SYLLABLE JJWEO
+ {0xCB65, 0xCB7F, prLVT}, // Lo [27] HANGUL SYLLABLE JJWEOG..HANGUL SYLLABLE JJWEOH
+ {0xCB80, 0xCB80, prLV}, // Lo HANGUL SYLLABLE JJWE
+ {0xCB81, 0xCB9B, prLVT}, // Lo [27] HANGUL SYLLABLE JJWEG..HANGUL SYLLABLE JJWEH
+ {0xCB9C, 0xCB9C, prLV}, // Lo HANGUL SYLLABLE JJWI
+ {0xCB9D, 0xCBB7, prLVT}, // Lo [27] HANGUL SYLLABLE JJWIG..HANGUL SYLLABLE JJWIH
+ {0xCBB8, 0xCBB8, prLV}, // Lo HANGUL SYLLABLE JJYU
+ {0xCBB9, 0xCBD3, prLVT}, // Lo [27] HANGUL SYLLABLE JJYUG..HANGUL SYLLABLE JJYUH
+ {0xCBD4, 0xCBD4, prLV}, // Lo HANGUL SYLLABLE JJEU
+ {0xCBD5, 0xCBEF, prLVT}, // Lo [27] HANGUL SYLLABLE JJEUG..HANGUL SYLLABLE JJEUH
+ {0xCBF0, 0xCBF0, prLV}, // Lo HANGUL SYLLABLE JJYI
+ {0xCBF1, 0xCC0B, prLVT}, // Lo [27] HANGUL SYLLABLE JJYIG..HANGUL SYLLABLE JJYIH
+ {0xCC0C, 0xCC0C, prLV}, // Lo HANGUL SYLLABLE JJI
+ {0xCC0D, 0xCC27, prLVT}, // Lo [27] HANGUL SYLLABLE JJIG..HANGUL SYLLABLE JJIH
+ {0xCC28, 0xCC28, prLV}, // Lo HANGUL SYLLABLE CA
+ {0xCC29, 0xCC43, prLVT}, // Lo [27] HANGUL SYLLABLE CAG..HANGUL SYLLABLE CAH
+ {0xCC44, 0xCC44, prLV}, // Lo HANGUL SYLLABLE CAE
+ {0xCC45, 0xCC5F, prLVT}, // Lo [27] HANGUL SYLLABLE CAEG..HANGUL SYLLABLE CAEH
+ {0xCC60, 0xCC60, prLV}, // Lo HANGUL SYLLABLE CYA
+ {0xCC61, 0xCC7B, prLVT}, // Lo [27] HANGUL SYLLABLE CYAG..HANGUL SYLLABLE CYAH
+ {0xCC7C, 0xCC7C, prLV}, // Lo HANGUL SYLLABLE CYAE
+ {0xCC7D, 0xCC97, prLVT}, // Lo [27] HANGUL SYLLABLE CYAEG..HANGUL SYLLABLE CYAEH
+ {0xCC98, 0xCC98, prLV}, // Lo HANGUL SYLLABLE CEO
+ {0xCC99, 0xCCB3, prLVT}, // Lo [27] HANGUL SYLLABLE CEOG..HANGUL SYLLABLE CEOH
+ {0xCCB4, 0xCCB4, prLV}, // Lo HANGUL SYLLABLE CE
+ {0xCCB5, 0xCCCF, prLVT}, // Lo [27] HANGUL SYLLABLE CEG..HANGUL SYLLABLE CEH
+ {0xCCD0, 0xCCD0, prLV}, // Lo HANGUL SYLLABLE CYEO
+ {0xCCD1, 0xCCEB, prLVT}, // Lo [27] HANGUL SYLLABLE CYEOG..HANGUL SYLLABLE CYEOH
+ {0xCCEC, 0xCCEC, prLV}, // Lo HANGUL SYLLABLE CYE
+ {0xCCED, 0xCD07, prLVT}, // Lo [27] HANGUL SYLLABLE CYEG..HANGUL SYLLABLE CYEH
+ {0xCD08, 0xCD08, prLV}, // Lo HANGUL SYLLABLE CO
+ {0xCD09, 0xCD23, prLVT}, // Lo [27] HANGUL SYLLABLE COG..HANGUL SYLLABLE COH
+ {0xCD24, 0xCD24, prLV}, // Lo HANGUL SYLLABLE CWA
+ {0xCD25, 0xCD3F, prLVT}, // Lo [27] HANGUL SYLLABLE CWAG..HANGUL SYLLABLE CWAH
+ {0xCD40, 0xCD40, prLV}, // Lo HANGUL SYLLABLE CWAE
+ {0xCD41, 0xCD5B, prLVT}, // Lo [27] HANGUL SYLLABLE CWAEG..HANGUL SYLLABLE CWAEH
+ {0xCD5C, 0xCD5C, prLV}, // Lo HANGUL SYLLABLE COE
+ {0xCD5D, 0xCD77, prLVT}, // Lo [27] HANGUL SYLLABLE COEG..HANGUL SYLLABLE COEH
+ {0xCD78, 0xCD78, prLV}, // Lo HANGUL SYLLABLE CYO
+ {0xCD79, 0xCD93, prLVT}, // Lo [27] HANGUL SYLLABLE CYOG..HANGUL SYLLABLE CYOH
+ {0xCD94, 0xCD94, prLV}, // Lo HANGUL SYLLABLE CU
+ {0xCD95, 0xCDAF, prLVT}, // Lo [27] HANGUL SYLLABLE CUG..HANGUL SYLLABLE CUH
+ {0xCDB0, 0xCDB0, prLV}, // Lo HANGUL SYLLABLE CWEO
+ {0xCDB1, 0xCDCB, prLVT}, // Lo [27] HANGUL SYLLABLE CWEOG..HANGUL SYLLABLE CWEOH
+ {0xCDCC, 0xCDCC, prLV}, // Lo HANGUL SYLLABLE CWE
+ {0xCDCD, 0xCDE7, prLVT}, // Lo [27] HANGUL SYLLABLE CWEG..HANGUL SYLLABLE CWEH
+ {0xCDE8, 0xCDE8, prLV}, // Lo HANGUL SYLLABLE CWI
+ {0xCDE9, 0xCE03, prLVT}, // Lo [27] HANGUL SYLLABLE CWIG..HANGUL SYLLABLE CWIH
+ {0xCE04, 0xCE04, prLV}, // Lo HANGUL SYLLABLE CYU
+ {0xCE05, 0xCE1F, prLVT}, // Lo [27] HANGUL SYLLABLE CYUG..HANGUL SYLLABLE CYUH
+ {0xCE20, 0xCE20, prLV}, // Lo HANGUL SYLLABLE CEU
+ {0xCE21, 0xCE3B, prLVT}, // Lo [27] HANGUL SYLLABLE CEUG..HANGUL SYLLABLE CEUH
+ {0xCE3C, 0xCE3C, prLV}, // Lo HANGUL SYLLABLE CYI
+ {0xCE3D, 0xCE57, prLVT}, // Lo [27] HANGUL SYLLABLE CYIG..HANGUL SYLLABLE CYIH
+ {0xCE58, 0xCE58, prLV}, // Lo HANGUL SYLLABLE CI
+ {0xCE59, 0xCE73, prLVT}, // Lo [27] HANGUL SYLLABLE CIG..HANGUL SYLLABLE CIH
+ {0xCE74, 0xCE74, prLV}, // Lo HANGUL SYLLABLE KA
+ {0xCE75, 0xCE8F, prLVT}, // Lo [27] HANGUL SYLLABLE KAG..HANGUL SYLLABLE KAH
+ {0xCE90, 0xCE90, prLV}, // Lo HANGUL SYLLABLE KAE
+ {0xCE91, 0xCEAB, prLVT}, // Lo [27] HANGUL SYLLABLE KAEG..HANGUL SYLLABLE KAEH
+ {0xCEAC, 0xCEAC, prLV}, // Lo HANGUL SYLLABLE KYA
+ {0xCEAD, 0xCEC7, prLVT}, // Lo [27] HANGUL SYLLABLE KYAG..HANGUL SYLLABLE KYAH
+ {0xCEC8, 0xCEC8, prLV}, // Lo HANGUL SYLLABLE KYAE
+ {0xCEC9, 0xCEE3, prLVT}, // Lo [27] HANGUL SYLLABLE KYAEG..HANGUL SYLLABLE KYAEH
+ {0xCEE4, 0xCEE4, prLV}, // Lo HANGUL SYLLABLE KEO
+ {0xCEE5, 0xCEFF, prLVT}, // Lo [27] HANGUL SYLLABLE KEOG..HANGUL SYLLABLE KEOH
+ {0xCF00, 0xCF00, prLV}, // Lo HANGUL SYLLABLE KE
+ {0xCF01, 0xCF1B, prLVT}, // Lo [27] HANGUL SYLLABLE KEG..HANGUL SYLLABLE KEH
+ {0xCF1C, 0xCF1C, prLV}, // Lo HANGUL SYLLABLE KYEO
+ {0xCF1D, 0xCF37, prLVT}, // Lo [27] HANGUL SYLLABLE KYEOG..HANGUL SYLLABLE KYEOH
+ {0xCF38, 0xCF38, prLV}, // Lo HANGUL SYLLABLE KYE
+ {0xCF39, 0xCF53, prLVT}, // Lo [27] HANGUL SYLLABLE KYEG..HANGUL SYLLABLE KYEH
+ {0xCF54, 0xCF54, prLV}, // Lo HANGUL SYLLABLE KO
+ {0xCF55, 0xCF6F, prLVT}, // Lo [27] HANGUL SYLLABLE KOG..HANGUL SYLLABLE KOH
+ {0xCF70, 0xCF70, prLV}, // Lo HANGUL SYLLABLE KWA
+ {0xCF71, 0xCF8B, prLVT}, // Lo [27] HANGUL SYLLABLE KWAG..HANGUL SYLLABLE KWAH
+ {0xCF8C, 0xCF8C, prLV}, // Lo HANGUL SYLLABLE KWAE
+ {0xCF8D, 0xCFA7, prLVT}, // Lo [27] HANGUL SYLLABLE KWAEG..HANGUL SYLLABLE KWAEH
+ {0xCFA8, 0xCFA8, prLV}, // Lo HANGUL SYLLABLE KOE
+ {0xCFA9, 0xCFC3, prLVT}, // Lo [27] HANGUL SYLLABLE KOEG..HANGUL SYLLABLE KOEH
+ {0xCFC4, 0xCFC4, prLV}, // Lo HANGUL SYLLABLE KYO
+ {0xCFC5, 0xCFDF, prLVT}, // Lo [27] HANGUL SYLLABLE KYOG..HANGUL SYLLABLE KYOH
+ {0xCFE0, 0xCFE0, prLV}, // Lo HANGUL SYLLABLE KU
+ {0xCFE1, 0xCFFB, prLVT}, // Lo [27] HANGUL SYLLABLE KUG..HANGUL SYLLABLE KUH
+ {0xCFFC, 0xCFFC, prLV}, // Lo HANGUL SYLLABLE KWEO
+ {0xCFFD, 0xD017, prLVT}, // Lo [27] HANGUL SYLLABLE KWEOG..HANGUL SYLLABLE KWEOH
+ {0xD018, 0xD018, prLV}, // Lo HANGUL SYLLABLE KWE
+ {0xD019, 0xD033, prLVT}, // Lo [27] HANGUL SYLLABLE KWEG..HANGUL SYLLABLE KWEH
+ {0xD034, 0xD034, prLV}, // Lo HANGUL SYLLABLE KWI
+ {0xD035, 0xD04F, prLVT}, // Lo [27] HANGUL SYLLABLE KWIG..HANGUL SYLLABLE KWIH
+ {0xD050, 0xD050, prLV}, // Lo HANGUL SYLLABLE KYU
+ {0xD051, 0xD06B, prLVT}, // Lo [27] HANGUL SYLLABLE KYUG..HANGUL SYLLABLE KYUH
+ {0xD06C, 0xD06C, prLV}, // Lo HANGUL SYLLABLE KEU
+ {0xD06D, 0xD087, prLVT}, // Lo [27] HANGUL SYLLABLE KEUG..HANGUL SYLLABLE KEUH
+ {0xD088, 0xD088, prLV}, // Lo HANGUL SYLLABLE KYI
+ {0xD089, 0xD0A3, prLVT}, // Lo [27] HANGUL SYLLABLE KYIG..HANGUL SYLLABLE KYIH
+ {0xD0A4, 0xD0A4, prLV}, // Lo HANGUL SYLLABLE KI
+ {0xD0A5, 0xD0BF, prLVT}, // Lo [27] HANGUL SYLLABLE KIG..HANGUL SYLLABLE KIH
+ {0xD0C0, 0xD0C0, prLV}, // Lo HANGUL SYLLABLE TA
+ {0xD0C1, 0xD0DB, prLVT}, // Lo [27] HANGUL SYLLABLE TAG..HANGUL SYLLABLE TAH
+ {0xD0DC, 0xD0DC, prLV}, // Lo HANGUL SYLLABLE TAE
+ {0xD0DD, 0xD0F7, prLVT}, // Lo [27] HANGUL SYLLABLE TAEG..HANGUL SYLLABLE TAEH
+ {0xD0F8, 0xD0F8, prLV}, // Lo HANGUL SYLLABLE TYA
+ {0xD0F9, 0xD113, prLVT}, // Lo [27] HANGUL SYLLABLE TYAG..HANGUL SYLLABLE TYAH
+ {0xD114, 0xD114, prLV}, // Lo HANGUL SYLLABLE TYAE
+ {0xD115, 0xD12F, prLVT}, // Lo [27] HANGUL SYLLABLE TYAEG..HANGUL SYLLABLE TYAEH
+ {0xD130, 0xD130, prLV}, // Lo HANGUL SYLLABLE TEO
+ {0xD131, 0xD14B, prLVT}, // Lo [27] HANGUL SYLLABLE TEOG..HANGUL SYLLABLE TEOH
+ {0xD14C, 0xD14C, prLV}, // Lo HANGUL SYLLABLE TE
+ {0xD14D, 0xD167, prLVT}, // Lo [27] HANGUL SYLLABLE TEG..HANGUL SYLLABLE TEH
+ {0xD168, 0xD168, prLV}, // Lo HANGUL SYLLABLE TYEO
+ {0xD169, 0xD183, prLVT}, // Lo [27] HANGUL SYLLABLE TYEOG..HANGUL SYLLABLE TYEOH
+ {0xD184, 0xD184, prLV}, // Lo HANGUL SYLLABLE TYE
+ {0xD185, 0xD19F, prLVT}, // Lo [27] HANGUL SYLLABLE TYEG..HANGUL SYLLABLE TYEH
+ {0xD1A0, 0xD1A0, prLV}, // Lo HANGUL SYLLABLE TO
+ {0xD1A1, 0xD1BB, prLVT}, // Lo [27] HANGUL SYLLABLE TOG..HANGUL SYLLABLE TOH
+ {0xD1BC, 0xD1BC, prLV}, // Lo HANGUL SYLLABLE TWA
+ {0xD1BD, 0xD1D7, prLVT}, // Lo [27] HANGUL SYLLABLE TWAG..HANGUL SYLLABLE TWAH
+ {0xD1D8, 0xD1D8, prLV}, // Lo HANGUL SYLLABLE TWAE
+ {0xD1D9, 0xD1F3, prLVT}, // Lo [27] HANGUL SYLLABLE TWAEG..HANGUL SYLLABLE TWAEH
+ {0xD1F4, 0xD1F4, prLV}, // Lo HANGUL SYLLABLE TOE
+ {0xD1F5, 0xD20F, prLVT}, // Lo [27] HANGUL SYLLABLE TOEG..HANGUL SYLLABLE TOEH
+ {0xD210, 0xD210, prLV}, // Lo HANGUL SYLLABLE TYO
+ {0xD211, 0xD22B, prLVT}, // Lo [27] HANGUL SYLLABLE TYOG..HANGUL SYLLABLE TYOH
+ {0xD22C, 0xD22C, prLV}, // Lo HANGUL SYLLABLE TU
+ {0xD22D, 0xD247, prLVT}, // Lo [27] HANGUL SYLLABLE TUG..HANGUL SYLLABLE TUH
+ {0xD248, 0xD248, prLV}, // Lo HANGUL SYLLABLE TWEO
+ {0xD249, 0xD263, prLVT}, // Lo [27] HANGUL SYLLABLE TWEOG..HANGUL SYLLABLE TWEOH
+ {0xD264, 0xD264, prLV}, // Lo HANGUL SYLLABLE TWE
+ {0xD265, 0xD27F, prLVT}, // Lo [27] HANGUL SYLLABLE TWEG..HANGUL SYLLABLE TWEH
+ {0xD280, 0xD280, prLV}, // Lo HANGUL SYLLABLE TWI
+ {0xD281, 0xD29B, prLVT}, // Lo [27] HANGUL SYLLABLE TWIG..HANGUL SYLLABLE TWIH
+ {0xD29C, 0xD29C, prLV}, // Lo HANGUL SYLLABLE TYU
+ {0xD29D, 0xD2B7, prLVT}, // Lo [27] HANGUL SYLLABLE TYUG..HANGUL SYLLABLE TYUH
+ {0xD2B8, 0xD2B8, prLV}, // Lo HANGUL SYLLABLE TEU
+ {0xD2B9, 0xD2D3, prLVT}, // Lo [27] HANGUL SYLLABLE TEUG..HANGUL SYLLABLE TEUH
+ {0xD2D4, 0xD2D4, prLV}, // Lo HANGUL SYLLABLE TYI
+ {0xD2D5, 0xD2EF, prLVT}, // Lo [27] HANGUL SYLLABLE TYIG..HANGUL SYLLABLE TYIH
+ {0xD2F0, 0xD2F0, prLV}, // Lo HANGUL SYLLABLE TI
+ {0xD2F1, 0xD30B, prLVT}, // Lo [27] HANGUL SYLLABLE TIG..HANGUL SYLLABLE TIH
+ {0xD30C, 0xD30C, prLV}, // Lo HANGUL SYLLABLE PA
+ {0xD30D, 0xD327, prLVT}, // Lo [27] HANGUL SYLLABLE PAG..HANGUL SYLLABLE PAH
+ {0xD328, 0xD328, prLV}, // Lo HANGUL SYLLABLE PAE
+ {0xD329, 0xD343, prLVT}, // Lo [27] HANGUL SYLLABLE PAEG..HANGUL SYLLABLE PAEH
+ {0xD344, 0xD344, prLV}, // Lo HANGUL SYLLABLE PYA
+ {0xD345, 0xD35F, prLVT}, // Lo [27] HANGUL SYLLABLE PYAG..HANGUL SYLLABLE PYAH
+ {0xD360, 0xD360, prLV}, // Lo HANGUL SYLLABLE PYAE
+ {0xD361, 0xD37B, prLVT}, // Lo [27] HANGUL SYLLABLE PYAEG..HANGUL SYLLABLE PYAEH
+ {0xD37C, 0xD37C, prLV}, // Lo HANGUL SYLLABLE PEO
+ {0xD37D, 0xD397, prLVT}, // Lo [27] HANGUL SYLLABLE PEOG..HANGUL SYLLABLE PEOH
+ {0xD398, 0xD398, prLV}, // Lo HANGUL SYLLABLE PE
+ {0xD399, 0xD3B3, prLVT}, // Lo [27] HANGUL SYLLABLE PEG..HANGUL SYLLABLE PEH
+ {0xD3B4, 0xD3B4, prLV}, // Lo HANGUL SYLLABLE PYEO
+ {0xD3B5, 0xD3CF, prLVT}, // Lo [27] HANGUL SYLLABLE PYEOG..HANGUL SYLLABLE PYEOH
+ {0xD3D0, 0xD3D0, prLV}, // Lo HANGUL SYLLABLE PYE
+ {0xD3D1, 0xD3EB, prLVT}, // Lo [27] HANGUL SYLLABLE PYEG..HANGUL SYLLABLE PYEH
+ {0xD3EC, 0xD3EC, prLV}, // Lo HANGUL SYLLABLE PO
+ {0xD3ED, 0xD407, prLVT}, // Lo [27] HANGUL SYLLABLE POG..HANGUL SYLLABLE POH
+ {0xD408, 0xD408, prLV}, // Lo HANGUL SYLLABLE PWA
+ {0xD409, 0xD423, prLVT}, // Lo [27] HANGUL SYLLABLE PWAG..HANGUL SYLLABLE PWAH
+ {0xD424, 0xD424, prLV}, // Lo HANGUL SYLLABLE PWAE
+ {0xD425, 0xD43F, prLVT}, // Lo [27] HANGUL SYLLABLE PWAEG..HANGUL SYLLABLE PWAEH
+ {0xD440, 0xD440, prLV}, // Lo HANGUL SYLLABLE POE
+ {0xD441, 0xD45B, prLVT}, // Lo [27] HANGUL SYLLABLE POEG..HANGUL SYLLABLE POEH
+ {0xD45C, 0xD45C, prLV}, // Lo HANGUL SYLLABLE PYO
+ {0xD45D, 0xD477, prLVT}, // Lo [27] HANGUL SYLLABLE PYOG..HANGUL SYLLABLE PYOH
+ {0xD478, 0xD478, prLV}, // Lo HANGUL SYLLABLE PU
+ {0xD479, 0xD493, prLVT}, // Lo [27] HANGUL SYLLABLE PUG..HANGUL SYLLABLE PUH
+ {0xD494, 0xD494, prLV}, // Lo HANGUL SYLLABLE PWEO
+ {0xD495, 0xD4AF, prLVT}, // Lo [27] HANGUL SYLLABLE PWEOG..HANGUL SYLLABLE PWEOH
+ {0xD4B0, 0xD4B0, prLV}, // Lo HANGUL SYLLABLE PWE
+ {0xD4B1, 0xD4CB, prLVT}, // Lo [27] HANGUL SYLLABLE PWEG..HANGUL SYLLABLE PWEH
+ {0xD4CC, 0xD4CC, prLV}, // Lo HANGUL SYLLABLE PWI
+ {0xD4CD, 0xD4E7, prLVT}, // Lo [27] HANGUL SYLLABLE PWIG..HANGUL SYLLABLE PWIH
+ {0xD4E8, 0xD4E8, prLV}, // Lo HANGUL SYLLABLE PYU
+ {0xD4E9, 0xD503, prLVT}, // Lo [27] HANGUL SYLLABLE PYUG..HANGUL SYLLABLE PYUH
+ {0xD504, 0xD504, prLV}, // Lo HANGUL SYLLABLE PEU
+ {0xD505, 0xD51F, prLVT}, // Lo [27] HANGUL SYLLABLE PEUG..HANGUL SYLLABLE PEUH
+ {0xD520, 0xD520, prLV}, // Lo HANGUL SYLLABLE PYI
+ {0xD521, 0xD53B, prLVT}, // Lo [27] HANGUL SYLLABLE PYIG..HANGUL SYLLABLE PYIH
+ {0xD53C, 0xD53C, prLV}, // Lo HANGUL SYLLABLE PI
+ {0xD53D, 0xD557, prLVT}, // Lo [27] HANGUL SYLLABLE PIG..HANGUL SYLLABLE PIH
+ {0xD558, 0xD558, prLV}, // Lo HANGUL SYLLABLE HA
+ {0xD559, 0xD573, prLVT}, // Lo [27] HANGUL SYLLABLE HAG..HANGUL SYLLABLE HAH
+ {0xD574, 0xD574, prLV}, // Lo HANGUL SYLLABLE HAE
+ {0xD575, 0xD58F, prLVT}, // Lo [27] HANGUL SYLLABLE HAEG..HANGUL SYLLABLE HAEH
+ {0xD590, 0xD590, prLV}, // Lo HANGUL SYLLABLE HYA
+ {0xD591, 0xD5AB, prLVT}, // Lo [27] HANGUL SYLLABLE HYAG..HANGUL SYLLABLE HYAH
+ {0xD5AC, 0xD5AC, prLV}, // Lo HANGUL SYLLABLE HYAE
+ {0xD5AD, 0xD5C7, prLVT}, // Lo [27] HANGUL SYLLABLE HYAEG..HANGUL SYLLABLE HYAEH
+ {0xD5C8, 0xD5C8, prLV}, // Lo HANGUL SYLLABLE HEO
+ {0xD5C9, 0xD5E3, prLVT}, // Lo [27] HANGUL SYLLABLE HEOG..HANGUL SYLLABLE HEOH
+ {0xD5E4, 0xD5E4, prLV}, // Lo HANGUL SYLLABLE HE
+ {0xD5E5, 0xD5FF, prLVT}, // Lo [27] HANGUL SYLLABLE HEG..HANGUL SYLLABLE HEH
+ {0xD600, 0xD600, prLV}, // Lo HANGUL SYLLABLE HYEO
+ {0xD601, 0xD61B, prLVT}, // Lo [27] HANGUL SYLLABLE HYEOG..HANGUL SYLLABLE HYEOH
+ {0xD61C, 0xD61C, prLV}, // Lo HANGUL SYLLABLE HYE
+ {0xD61D, 0xD637, prLVT}, // Lo [27] HANGUL SYLLABLE HYEG..HANGUL SYLLABLE HYEH
+ {0xD638, 0xD638, prLV}, // Lo HANGUL SYLLABLE HO
+ {0xD639, 0xD653, prLVT}, // Lo [27] HANGUL SYLLABLE HOG..HANGUL SYLLABLE HOH
+ {0xD654, 0xD654, prLV}, // Lo HANGUL SYLLABLE HWA
+ {0xD655, 0xD66F, prLVT}, // Lo [27] HANGUL SYLLABLE HWAG..HANGUL SYLLABLE HWAH
+ {0xD670, 0xD670, prLV}, // Lo HANGUL SYLLABLE HWAE
+ {0xD671, 0xD68B, prLVT}, // Lo [27] HANGUL SYLLABLE HWAEG..HANGUL SYLLABLE HWAEH
+ {0xD68C, 0xD68C, prLV}, // Lo HANGUL SYLLABLE HOE
+ {0xD68D, 0xD6A7, prLVT}, // Lo [27] HANGUL SYLLABLE HOEG..HANGUL SYLLABLE HOEH
+ {0xD6A8, 0xD6A8, prLV}, // Lo HANGUL SYLLABLE HYO
+ {0xD6A9, 0xD6C3, prLVT}, // Lo [27] HANGUL SYLLABLE HYOG..HANGUL SYLLABLE HYOH
+ {0xD6C4, 0xD6C4, prLV}, // Lo HANGUL SYLLABLE HU
+ {0xD6C5, 0xD6DF, prLVT}, // Lo [27] HANGUL SYLLABLE HUG..HANGUL SYLLABLE HUH
+ {0xD6E0, 0xD6E0, prLV}, // Lo HANGUL SYLLABLE HWEO
+ {0xD6E1, 0xD6FB, prLVT}, // Lo [27] HANGUL SYLLABLE HWEOG..HANGUL SYLLABLE HWEOH
+ {0xD6FC, 0xD6FC, prLV}, // Lo HANGUL SYLLABLE HWE
+ {0xD6FD, 0xD717, prLVT}, // Lo [27] HANGUL SYLLABLE HWEG..HANGUL SYLLABLE HWEH
+ {0xD718, 0xD718, prLV}, // Lo HANGUL SYLLABLE HWI
+ {0xD719, 0xD733, prLVT}, // Lo [27] HANGUL SYLLABLE HWIG..HANGUL SYLLABLE HWIH
+ {0xD734, 0xD734, prLV}, // Lo HANGUL SYLLABLE HYU
+ {0xD735, 0xD74F, prLVT}, // Lo [27] HANGUL SYLLABLE HYUG..HANGUL SYLLABLE HYUH
+ {0xD750, 0xD750, prLV}, // Lo HANGUL SYLLABLE HEU
+ {0xD751, 0xD76B, prLVT}, // Lo [27] HANGUL SYLLABLE HEUG..HANGUL SYLLABLE HEUH
+ {0xD76C, 0xD76C, prLV}, // Lo HANGUL SYLLABLE HYI
+ {0xD76D, 0xD787, prLVT}, // Lo [27] HANGUL SYLLABLE HYIG..HANGUL SYLLABLE HYIH
+ {0xD788, 0xD788, prLV}, // Lo HANGUL SYLLABLE HI
+ {0xD789, 0xD7A3, prLVT}, // Lo [27] HANGUL SYLLABLE HIG..HANGUL SYLLABLE HIH
+ {0xD7B0, 0xD7C6, prV}, // Lo [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E
+ {0xD7CB, 0xD7FB, prT}, // Lo [49] HANGUL JONGSEONG NIEUN-RIEUL..HANGUL JONGSEONG PHIEUPH-THIEUTH
+ {0xFB1E, 0xFB1E, prExtend}, // Mn HEBREW POINT JUDEO-SPANISH VARIKA
+ {0xFE00, 0xFE0F, prExtend}, // Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
+ {0xFE20, 0xFE2F, prExtend}, // Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF
+ {0xFEFF, 0xFEFF, prControl}, // Cf ZERO WIDTH NO-BREAK SPACE
+ {0xFF9E, 0xFF9F, prExtend}, // Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
+ {0xFFF0, 0xFFF8, prControl}, // Cn [9] ..
+ {0xFFF9, 0xFFFB, prControl}, // Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR
+ {0x101FD, 0x101FD, prExtend}, // Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE
+ {0x102E0, 0x102E0, prExtend}, // Mn COPTIC EPACT THOUSANDS MARK
+ {0x10376, 0x1037A, prExtend}, // Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII
+ {0x10A01, 0x10A03, prExtend}, // Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R
+ {0x10A05, 0x10A06, prExtend}, // Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O
+ {0x10A0C, 0x10A0F, prExtend}, // Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA
+ {0x10A38, 0x10A3A, prExtend}, // Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW
+ {0x10A3F, 0x10A3F, prExtend}, // Mn KHAROSHTHI VIRAMA
+ {0x10AE5, 0x10AE6, prExtend}, // Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW
+ {0x10D24, 0x10D27, prExtend}, // Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI
+ {0x10F46, 0x10F50, prExtend}, // Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW
+ {0x11000, 0x11000, prSpacingMark}, // Mc BRAHMI SIGN CANDRABINDU
+ {0x11001, 0x11001, prExtend}, // Mn BRAHMI SIGN ANUSVARA
+ {0x11002, 0x11002, prSpacingMark}, // Mc BRAHMI SIGN VISARGA
+ {0x11038, 0x11046, prExtend}, // Mn [15] BRAHMI VOWEL SIGN AA..BRAHMI VIRAMA
+ {0x1107F, 0x11081, prExtend}, // Mn [3] BRAHMI NUMBER JOINER..KAITHI SIGN ANUSVARA
+ {0x11082, 0x11082, prSpacingMark}, // Mc KAITHI SIGN VISARGA
+ {0x110B0, 0x110B2, prSpacingMark}, // Mc [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II
+ {0x110B3, 0x110B6, prExtend}, // Mn [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI
+ {0x110B7, 0x110B8, prSpacingMark}, // Mc [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU
+ {0x110B9, 0x110BA, prExtend}, // Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA
+ {0x110BD, 0x110BD, prPreprend}, // Cf KAITHI NUMBER SIGN
+ {0x110CD, 0x110CD, prPreprend}, // Cf KAITHI NUMBER SIGN ABOVE
+ {0x11100, 0x11102, prExtend}, // Mn [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA
+ {0x11127, 0x1112B, prExtend}, // Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU
+ {0x1112C, 0x1112C, prSpacingMark}, // Mc CHAKMA VOWEL SIGN E
+ {0x1112D, 0x11134, prExtend}, // Mn [8] CHAKMA VOWEL SIGN AI..CHAKMA MAAYYAA
+ {0x11145, 0x11146, prSpacingMark}, // Mc [2] CHAKMA VOWEL SIGN AA..CHAKMA VOWEL SIGN EI
+ {0x11173, 0x11173, prExtend}, // Mn MAHAJANI SIGN NUKTA
+ {0x11180, 0x11181, prExtend}, // Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA
+ {0x11182, 0x11182, prSpacingMark}, // Mc SHARADA SIGN VISARGA
+ {0x111B3, 0x111B5, prSpacingMark}, // Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II
+ {0x111B6, 0x111BE, prExtend}, // Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O
+ {0x111BF, 0x111C0, prSpacingMark}, // Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA
+ {0x111C2, 0x111C3, prPreprend}, // Lo [2] SHARADA SIGN JIHVAMULIYA..SHARADA SIGN UPADHMANIYA
+ {0x111C9, 0x111CC, prExtend}, // Mn [4] SHARADA SANDHI MARK..SHARADA EXTRA SHORT VOWEL MARK
+ {0x1122C, 0x1122E, prSpacingMark}, // Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II
+ {0x1122F, 0x11231, prExtend}, // Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI
+ {0x11232, 0x11233, prSpacingMark}, // Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU
+ {0x11234, 0x11234, prExtend}, // Mn KHOJKI SIGN ANUSVARA
+ {0x11235, 0x11235, prSpacingMark}, // Mc KHOJKI SIGN VIRAMA
+ {0x11236, 0x11237, prExtend}, // Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA
+ {0x1123E, 0x1123E, prExtend}, // Mn KHOJKI SIGN SUKUN
+ {0x112DF, 0x112DF, prExtend}, // Mn KHUDAWADI SIGN ANUSVARA
+ {0x112E0, 0x112E2, prSpacingMark}, // Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II
+ {0x112E3, 0x112EA, prExtend}, // Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA
+ {0x11300, 0x11301, prExtend}, // Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU
+ {0x11302, 0x11303, prSpacingMark}, // Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA
+ {0x1133B, 0x1133C, prExtend}, // Mn [2] COMBINING BINDU BELOW..GRANTHA SIGN NUKTA
+ {0x1133E, 0x1133E, prExtend}, // Mc GRANTHA VOWEL SIGN AA
+ {0x1133F, 0x1133F, prSpacingMark}, // Mc GRANTHA VOWEL SIGN I
+ {0x11340, 0x11340, prExtend}, // Mn GRANTHA VOWEL SIGN II
+ {0x11341, 0x11344, prSpacingMark}, // Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR
+ {0x11347, 0x11348, prSpacingMark}, // Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI
+ {0x1134B, 0x1134D, prSpacingMark}, // Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA
+ {0x11357, 0x11357, prExtend}, // Mc GRANTHA AU LENGTH MARK
+ {0x11362, 0x11363, prSpacingMark}, // Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL
+ {0x11366, 0x1136C, prExtend}, // Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX
+ {0x11370, 0x11374, prExtend}, // Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA
+ {0x11435, 0x11437, prSpacingMark}, // Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II
+ {0x11438, 0x1143F, prExtend}, // Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI
+ {0x11440, 0x11441, prSpacingMark}, // Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU
+ {0x11442, 0x11444, prExtend}, // Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA
+ {0x11445, 0x11445, prSpacingMark}, // Mc NEWA SIGN VISARGA
+ {0x11446, 0x11446, prExtend}, // Mn NEWA SIGN NUKTA
+ {0x1145E, 0x1145E, prExtend}, // Mn NEWA SANDHI MARK
+ {0x114B0, 0x114B0, prExtend}, // Mc TIRHUTA VOWEL SIGN AA
+ {0x114B1, 0x114B2, prSpacingMark}, // Mc [2] TIRHUTA VOWEL SIGN I..TIRHUTA VOWEL SIGN II
+ {0x114B3, 0x114B8, prExtend}, // Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL
+ {0x114B9, 0x114B9, prSpacingMark}, // Mc TIRHUTA VOWEL SIGN E
+ {0x114BA, 0x114BA, prExtend}, // Mn TIRHUTA VOWEL SIGN SHORT E
+ {0x114BB, 0x114BC, prSpacingMark}, // Mc [2] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN O
+ {0x114BD, 0x114BD, prExtend}, // Mc TIRHUTA VOWEL SIGN SHORT O
+ {0x114BE, 0x114BE, prSpacingMark}, // Mc TIRHUTA VOWEL SIGN AU
+ {0x114BF, 0x114C0, prExtend}, // Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA
+ {0x114C1, 0x114C1, prSpacingMark}, // Mc TIRHUTA SIGN VISARGA
+ {0x114C2, 0x114C3, prExtend}, // Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA
+ {0x115AF, 0x115AF, prExtend}, // Mc SIDDHAM VOWEL SIGN AA
+ {0x115B0, 0x115B1, prSpacingMark}, // Mc [2] SIDDHAM VOWEL SIGN I..SIDDHAM VOWEL SIGN II
+ {0x115B2, 0x115B5, prExtend}, // Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR
+ {0x115B8, 0x115BB, prSpacingMark}, // Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU
+ {0x115BC, 0x115BD, prExtend}, // Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA
+ {0x115BE, 0x115BE, prSpacingMark}, // Mc SIDDHAM SIGN VISARGA
+ {0x115BF, 0x115C0, prExtend}, // Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA
+ {0x115DC, 0x115DD, prExtend}, // Mn [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU
+ {0x11630, 0x11632, prSpacingMark}, // Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II
+ {0x11633, 0x1163A, prExtend}, // Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI
+ {0x1163B, 0x1163C, prSpacingMark}, // Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU
+ {0x1163D, 0x1163D, prExtend}, // Mn MODI SIGN ANUSVARA
+ {0x1163E, 0x1163E, prSpacingMark}, // Mc MODI SIGN VISARGA
+ {0x1163F, 0x11640, prExtend}, // Mn [2] MODI SIGN VIRAMA..MODI SIGN ARDHACANDRA
+ {0x116AB, 0x116AB, prExtend}, // Mn TAKRI SIGN ANUSVARA
+ {0x116AC, 0x116AC, prSpacingMark}, // Mc TAKRI SIGN VISARGA
+ {0x116AD, 0x116AD, prExtend}, // Mn TAKRI VOWEL SIGN AA
+ {0x116AE, 0x116AF, prSpacingMark}, // Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II
+ {0x116B0, 0x116B5, prExtend}, // Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU
+ {0x116B6, 0x116B6, prSpacingMark}, // Mc TAKRI SIGN VIRAMA
+ {0x116B7, 0x116B7, prExtend}, // Mn TAKRI SIGN NUKTA
+ {0x1171D, 0x1171F, prExtend}, // Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA
+ {0x11720, 0x11721, prSpacingMark}, // Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA
+ {0x11722, 0x11725, prExtend}, // Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU
+ {0x11726, 0x11726, prSpacingMark}, // Mc AHOM VOWEL SIGN E
+ {0x11727, 0x1172B, prExtend}, // Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER
+ {0x1182C, 0x1182E, prSpacingMark}, // Mc [3] DOGRA VOWEL SIGN AA..DOGRA VOWEL SIGN II
+ {0x1182F, 0x11837, prExtend}, // Mn [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA
+ {0x11838, 0x11838, prSpacingMark}, // Mc DOGRA SIGN VISARGA
+ {0x11839, 0x1183A, prExtend}, // Mn [2] DOGRA SIGN VIRAMA..DOGRA SIGN NUKTA
+ {0x119D1, 0x119D3, prSpacingMark}, // Mc [3] NANDINAGARI VOWEL SIGN AA..NANDINAGARI VOWEL SIGN II
+ {0x119D4, 0x119D7, prExtend}, // Mn [4] NANDINAGARI VOWEL SIGN U..NANDINAGARI VOWEL SIGN VOCALIC RR
+ {0x119DA, 0x119DB, prExtend}, // Mn [2] NANDINAGARI VOWEL SIGN E..NANDINAGARI VOWEL SIGN AI
+ {0x119DC, 0x119DF, prSpacingMark}, // Mc [4] NANDINAGARI VOWEL SIGN O..NANDINAGARI SIGN VISARGA
+ {0x119E0, 0x119E0, prExtend}, // Mn NANDINAGARI SIGN VIRAMA
+ {0x119E4, 0x119E4, prSpacingMark}, // Mc NANDINAGARI VOWEL SIGN PRISHTHAMATRA E
+ {0x11A01, 0x11A0A, prExtend}, // Mn [10] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL LENGTH MARK
+ {0x11A33, 0x11A38, prExtend}, // Mn [6] ZANABAZAR SQUARE FINAL CONSONANT MARK..ZANABAZAR SQUARE SIGN ANUSVARA
+ {0x11A39, 0x11A39, prSpacingMark}, // Mc ZANABAZAR SQUARE SIGN VISARGA
+ {0x11A3A, 0x11A3A, prPreprend}, // Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA
+ {0x11A3B, 0x11A3E, prExtend}, // Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA
+ {0x11A47, 0x11A47, prExtend}, // Mn ZANABAZAR SQUARE SUBJOINER
+ {0x11A51, 0x11A56, prExtend}, // Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE
+ {0x11A57, 0x11A58, prSpacingMark}, // Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU
+ {0x11A59, 0x11A5B, prExtend}, // Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK
+ {0x11A84, 0x11A89, prPreprend}, // Lo [6] SOYOMBO SIGN JIHVAMULIYA..SOYOMBO CLUSTER-INITIAL LETTER SA
+ {0x11A8A, 0x11A96, prExtend}, // Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA
+ {0x11A97, 0x11A97, prSpacingMark}, // Mc SOYOMBO SIGN VISARGA
+ {0x11A98, 0x11A99, prExtend}, // Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER
+ {0x11C2F, 0x11C2F, prSpacingMark}, // Mc BHAIKSUKI VOWEL SIGN AA
+ {0x11C30, 0x11C36, prExtend}, // Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L
+ {0x11C38, 0x11C3D, prExtend}, // Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA
+ {0x11C3E, 0x11C3E, prSpacingMark}, // Mc BHAIKSUKI SIGN VISARGA
+ {0x11C3F, 0x11C3F, prExtend}, // Mn BHAIKSUKI SIGN VIRAMA
+ {0x11C92, 0x11CA7, prExtend}, // Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA
+ {0x11CA9, 0x11CA9, prSpacingMark}, // Mc MARCHEN SUBJOINED LETTER YA
+ {0x11CAA, 0x11CB0, prExtend}, // Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA
+ {0x11CB1, 0x11CB1, prSpacingMark}, // Mc MARCHEN VOWEL SIGN I
+ {0x11CB2, 0x11CB3, prExtend}, // Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E
+ {0x11CB4, 0x11CB4, prSpacingMark}, // Mc MARCHEN VOWEL SIGN O
+ {0x11CB5, 0x11CB6, prExtend}, // Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU
+ {0x11D31, 0x11D36, prExtend}, // Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R
+ {0x11D3A, 0x11D3A, prExtend}, // Mn MASARAM GONDI VOWEL SIGN E
+ {0x11D3C, 0x11D3D, prExtend}, // Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O
+ {0x11D3F, 0x11D45, prExtend}, // Mn [7] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI VIRAMA
+ {0x11D46, 0x11D46, prPreprend}, // Lo MASARAM GONDI REPHA
+ {0x11D47, 0x11D47, prExtend}, // Mn MASARAM GONDI RA-KARA
+ {0x11D8A, 0x11D8E, prSpacingMark}, // Mc [5] GUNJALA GONDI VOWEL SIGN AA..GUNJALA GONDI VOWEL SIGN UU
+ {0x11D90, 0x11D91, prExtend}, // Mn [2] GUNJALA GONDI VOWEL SIGN EE..GUNJALA GONDI VOWEL SIGN AI
+ {0x11D93, 0x11D94, prSpacingMark}, // Mc [2] GUNJALA GONDI VOWEL SIGN OO..GUNJALA GONDI VOWEL SIGN AU
+ {0x11D95, 0x11D95, prExtend}, // Mn GUNJALA GONDI SIGN ANUSVARA
+ {0x11D96, 0x11D96, prSpacingMark}, // Mc GUNJALA GONDI SIGN VISARGA
+ {0x11D97, 0x11D97, prExtend}, // Mn GUNJALA GONDI VIRAMA
+ {0x11EF3, 0x11EF4, prExtend}, // Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U
+ {0x11EF5, 0x11EF6, prSpacingMark}, // Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O
+ {0x13430, 0x13438, prControl}, // Cf [9] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH END SEGMENT
+ {0x16AF0, 0x16AF4, prExtend}, // Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE
+ {0x16B30, 0x16B36, prExtend}, // Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
+ {0x16F4F, 0x16F4F, prExtend}, // Mn MIAO SIGN CONSONANT MODIFIER BAR
+ {0x16F51, 0x16F87, prSpacingMark}, // Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI
+ {0x16F8F, 0x16F92, prExtend}, // Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW
+ {0x1BC9D, 0x1BC9E, prExtend}, // Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK
+ {0x1BCA0, 0x1BCA3, prControl}, // Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP
+ {0x1D165, 0x1D165, prExtend}, // Mc MUSICAL SYMBOL COMBINING STEM
+ {0x1D166, 0x1D166, prSpacingMark}, // Mc MUSICAL SYMBOL COMBINING SPRECHGESANG STEM
+ {0x1D167, 0x1D169, prExtend}, // Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3
+ {0x1D16D, 0x1D16D, prSpacingMark}, // Mc MUSICAL SYMBOL COMBINING AUGMENTATION DOT
+ {0x1D16E, 0x1D172, prExtend}, // Mc [5] MUSICAL SYMBOL COMBINING FLAG-1..MUSICAL SYMBOL COMBINING FLAG-5
+ {0x1D173, 0x1D17A, prControl}, // Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE
+ {0x1D17B, 0x1D182, prExtend}, // Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE
+ {0x1D185, 0x1D18B, prExtend}, // Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE
+ {0x1D1AA, 0x1D1AD, prExtend}, // Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO
+ {0x1D242, 0x1D244, prExtend}, // Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME
+ {0x1DA00, 0x1DA36, prExtend}, // Mn [55] SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN
+ {0x1DA3B, 0x1DA6C, prExtend}, // Mn [50] SIGNWRITING MOUTH CLOSED NEUTRAL..SIGNWRITING EXCITEMENT
+ {0x1DA75, 0x1DA75, prExtend}, // Mn SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS
+ {0x1DA84, 0x1DA84, prExtend}, // Mn SIGNWRITING LOCATION HEAD NECK
+ {0x1DA9B, 0x1DA9F, prExtend}, // Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6
+ {0x1DAA1, 0x1DAAF, prExtend}, // Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16
+ {0x1E000, 0x1E006, prExtend}, // Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE
+ {0x1E008, 0x1E018, prExtend}, // Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU
+ {0x1E01B, 0x1E021, prExtend}, // Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI
+ {0x1E023, 0x1E024, prExtend}, // Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS
+ {0x1E026, 0x1E02A, prExtend}, // Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA
+ {0x1E130, 0x1E136, prExtend}, // Mn [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D
+ {0x1E2EC, 0x1E2EF, prExtend}, // Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI
+ {0x1E8D0, 0x1E8D6, prExtend}, // Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS
+ {0x1E944, 0x1E94A, prExtend}, // Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA
+ {0x1F000, 0x1F02B, prExtendedPictographic}, // 5.1 [44] (🀀..🀫) MAHJONG TILE EAST WIND..MAHJONG TILE BACK
+ {0x1F02C, 0x1F02F, prExtendedPictographic}, // NA [4] (..) ..
+ {0x1F030, 0x1F093, prExtendedPictographic}, // 5.1[100] (🀰..🂓) DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06
+ {0x1F094, 0x1F09F, prExtendedPictographic}, // NA [12] (..) ..
+ {0x1F0A0, 0x1F0AE, prExtendedPictographic}, // 6.0 [15] (🂠..🂮) PLAYING CARD BACK..PLAYING CARD KING OF SPADES
+ {0x1F0AF, 0x1F0B0, prExtendedPictographic}, // NA [2] (..) ..
+ {0x1F0B1, 0x1F0BE, prExtendedPictographic}, // 6.0 [14] (🂱..🂾) PLAYING CARD ACE OF HEARTS..PLAYING CARD KING OF HEARTS
+ {0x1F0BF, 0x1F0BF, prExtendedPictographic}, // 7.0 [1] (🂿) PLAYING CARD RED JOKER
+ {0x1F0C0, 0x1F0C0, prExtendedPictographic}, // NA [1] ()
+ {0x1F0C1, 0x1F0CF, prExtendedPictographic}, // 6.0 [15] (🃁..🃏) PLAYING CARD ACE OF DIAMONDS..joker
+ {0x1F0D0, 0x1F0D0, prExtendedPictographic}, // NA [1] ()
+ {0x1F0D1, 0x1F0DF, prExtendedPictographic}, // 6.0 [15] (🃑..🃟) PLAYING CARD ACE OF CLUBS..PLAYING CARD WHITE JOKER
+ {0x1F0E0, 0x1F0F5, prExtendedPictographic}, // 7.0 [22] (🃠..🃵) PLAYING CARD FOOL..PLAYING CARD TRUMP-21
+ {0x1F0F6, 0x1F0FF, prExtendedPictographic}, // NA [10] (..) ..
+ {0x1F10D, 0x1F10F, prExtendedPictographic}, // NA [3] (🄍..🄏) ..
+ {0x1F12F, 0x1F12F, prExtendedPictographic}, // 11.0 [1] (🄯) COPYLEFT SYMBOL
+ {0x1F16C, 0x1F16C, prExtendedPictographic}, // 12.0 [1] (🅬) RAISED MR SIGN
+ {0x1F16D, 0x1F16F, prExtendedPictographic}, // NA [3] (🅭..🅯) ..
+ {0x1F170, 0x1F171, prExtendedPictographic}, // 6.0 [2] (🅰️..🅱️) A button (blood type)..B button (blood type)
+ {0x1F17E, 0x1F17E, prExtendedPictographic}, // 6.0 [1] (🅾️) O button (blood type)
+ {0x1F17F, 0x1F17F, prExtendedPictographic}, // 5.2 [1] (🅿️) P button
+ {0x1F18E, 0x1F18E, prExtendedPictographic}, // 6.0 [1] (🆎) AB button (blood type)
+ {0x1F191, 0x1F19A, prExtendedPictographic}, // 6.0 [10] (🆑..🆚) CL button..VS button
+ {0x1F1AD, 0x1F1E5, prExtendedPictographic}, // NA [57] (🆭..) ..
+ {0x1F1E6, 0x1F1FF, prRegionalIndicator}, // So [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z
+ {0x1F201, 0x1F202, prExtendedPictographic}, // 6.0 [2] (🈁..🈂️) Japanese “here” button..Japanese “service charge” button
+ {0x1F203, 0x1F20F, prExtendedPictographic}, // NA [13] (..) ..
+ {0x1F21A, 0x1F21A, prExtendedPictographic}, // 5.2 [1] (🈚) Japanese “free of charge” button
+ {0x1F22F, 0x1F22F, prExtendedPictographic}, // 5.2 [1] (🈯) Japanese “reserved” button
+ {0x1F232, 0x1F23A, prExtendedPictographic}, // 6.0 [9] (🈲..🈺) Japanese “prohibited” button..Japanese “open for business” button
+ {0x1F23C, 0x1F23F, prExtendedPictographic}, // NA [4] (..) ..
+ {0x1F249, 0x1F24F, prExtendedPictographic}, // NA [7] (..) ..
+ {0x1F250, 0x1F251, prExtendedPictographic}, // 6.0 [2] (🉐..🉑) Japanese “bargain” button..Japanese “acceptable” button
+ {0x1F252, 0x1F25F, prExtendedPictographic}, // NA [14] (..) ..
+ {0x1F260, 0x1F265, prExtendedPictographic}, // 10.0 [6] (🉠..🉥) ROUNDED SYMBOL FOR FU..ROUNDED SYMBOL FOR CAI
+ {0x1F266, 0x1F2FF, prExtendedPictographic}, // NA[154] (..) ..
+ {0x1F300, 0x1F320, prExtendedPictographic}, // 6.0 [33] (🌀..🌠) cyclone..shooting star
+ {0x1F321, 0x1F32C, prExtendedPictographic}, // 7.0 [12] (🌡️..🌬️) thermometer..wind face
+ {0x1F32D, 0x1F32F, prExtendedPictographic}, // 8.0 [3] (🌭..🌯) hot dog..burrito
+ {0x1F330, 0x1F335, prExtendedPictographic}, // 6.0 [6] (🌰..🌵) chestnut..cactus
+ {0x1F336, 0x1F336, prExtendedPictographic}, // 7.0 [1] (🌶️) hot pepper
+ {0x1F337, 0x1F37C, prExtendedPictographic}, // 6.0 [70] (🌷..🍼) tulip..baby bottle
+ {0x1F37D, 0x1F37D, prExtendedPictographic}, // 7.0 [1] (🍽️) fork and knife with plate
+ {0x1F37E, 0x1F37F, prExtendedPictographic}, // 8.0 [2] (🍾..🍿) bottle with popping cork..popcorn
+ {0x1F380, 0x1F393, prExtendedPictographic}, // 6.0 [20] (🎀..🎓) ribbon..graduation cap
+ {0x1F394, 0x1F39F, prExtendedPictographic}, // 7.0 [12] (🎔..🎟️) HEART WITH TIP ON THE LEFT..admission tickets
+ {0x1F3A0, 0x1F3C4, prExtendedPictographic}, // 6.0 [37] (🎠..🏄) carousel horse..person surfing
+ {0x1F3C5, 0x1F3C5, prExtendedPictographic}, // 7.0 [1] (🏅) sports medal
+ {0x1F3C6, 0x1F3CA, prExtendedPictographic}, // 6.0 [5] (🏆..🏊) trophy..person swimming
+ {0x1F3CB, 0x1F3CE, prExtendedPictographic}, // 7.0 [4] (🏋️..🏎️) person lifting weights..racing car
+ {0x1F3CF, 0x1F3D3, prExtendedPictographic}, // 8.0 [5] (🏏..🏓) cricket game..ping pong
+ {0x1F3D4, 0x1F3DF, prExtendedPictographic}, // 7.0 [12] (🏔️..🏟️) snow-capped mountain..stadium
+ {0x1F3E0, 0x1F3F0, prExtendedPictographic}, // 6.0 [17] (🏠..🏰) house..castle
+ {0x1F3F1, 0x1F3F7, prExtendedPictographic}, // 7.0 [7] (🏱..🏷️) WHITE PENNANT..label
+ {0x1F3F8, 0x1F3FA, prExtendedPictographic}, // 8.0 [3] (🏸..🏺) badminton..amphora
+ {0x1F3FB, 0x1F3FF, prExtend}, // Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6
+ {0x1F400, 0x1F43E, prExtendedPictographic}, // 6.0 [63] (🐀..🐾) rat..paw prints
+ {0x1F43F, 0x1F43F, prExtendedPictographic}, // 7.0 [1] (🐿️) chipmunk
+ {0x1F440, 0x1F440, prExtendedPictographic}, // 6.0 [1] (👀) eyes
+ {0x1F441, 0x1F441, prExtendedPictographic}, // 7.0 [1] (👁️) eye
+ {0x1F442, 0x1F4F7, prExtendedPictographic}, // 6.0[182] (👂..📷) ear..camera
+ {0x1F4F8, 0x1F4F8, prExtendedPictographic}, // 7.0 [1] (📸) camera with flash
+ {0x1F4F9, 0x1F4FC, prExtendedPictographic}, // 6.0 [4] (📹..📼) video camera..videocassette
+ {0x1F4FD, 0x1F4FE, prExtendedPictographic}, // 7.0 [2] (📽️..📾) film projector..PORTABLE STEREO
+ {0x1F4FF, 0x1F4FF, prExtendedPictographic}, // 8.0 [1] (📿) prayer beads
+ {0x1F500, 0x1F53D, prExtendedPictographic}, // 6.0 [62] (🔀..🔽) shuffle tracks button..downwards button
+ {0x1F546, 0x1F54A, prExtendedPictographic}, // 7.0 [5] (🕆..🕊️) WHITE LATIN CROSS..dove
+ {0x1F54B, 0x1F54F, prExtendedPictographic}, // 8.0 [5] (🕋..🕏) kaaba..BOWL OF HYGIEIA
+ {0x1F550, 0x1F567, prExtendedPictographic}, // 6.0 [24] (🕐..🕧) one o’clock..twelve-thirty
+ {0x1F568, 0x1F579, prExtendedPictographic}, // 7.0 [18] (🕨..🕹️) RIGHT SPEAKER..joystick
+ {0x1F57A, 0x1F57A, prExtendedPictographic}, // 9.0 [1] (🕺) man dancing
+ {0x1F57B, 0x1F5A3, prExtendedPictographic}, // 7.0 [41] (🕻..🖣) LEFT HAND TELEPHONE RECEIVER..BLACK DOWN POINTING BACKHAND INDEX
+ {0x1F5A4, 0x1F5A4, prExtendedPictographic}, // 9.0 [1] (🖤) black heart
+ {0x1F5A5, 0x1F5FA, prExtendedPictographic}, // 7.0 [86] (🖥️..🗺️) desktop computer..world map
+ {0x1F5FB, 0x1F5FF, prExtendedPictographic}, // 6.0 [5] (🗻..🗿) mount fuji..moai
+ {0x1F600, 0x1F600, prExtendedPictographic}, // 6.1 [1] (😀) grinning face
+ {0x1F601, 0x1F610, prExtendedPictographic}, // 6.0 [16] (😁..😐) beaming face with smiling eyes..neutral face
+ {0x1F611, 0x1F611, prExtendedPictographic}, // 6.1 [1] (😑) expressionless face
+ {0x1F612, 0x1F614, prExtendedPictographic}, // 6.0 [3] (😒..😔) unamused face..pensive face
+ {0x1F615, 0x1F615, prExtendedPictographic}, // 6.1 [1] (😕) confused face
+ {0x1F616, 0x1F616, prExtendedPictographic}, // 6.0 [1] (😖) confounded face
+ {0x1F617, 0x1F617, prExtendedPictographic}, // 6.1 [1] (😗) kissing face
+ {0x1F618, 0x1F618, prExtendedPictographic}, // 6.0 [1] (😘) face blowing a kiss
+ {0x1F619, 0x1F619, prExtendedPictographic}, // 6.1 [1] (😙) kissing face with smiling eyes
+ {0x1F61A, 0x1F61A, prExtendedPictographic}, // 6.0 [1] (😚) kissing face with closed eyes
+ {0x1F61B, 0x1F61B, prExtendedPictographic}, // 6.1 [1] (😛) face with tongue
+ {0x1F61C, 0x1F61E, prExtendedPictographic}, // 6.0 [3] (😜..😞) winking face with tongue..disappointed face
+ {0x1F61F, 0x1F61F, prExtendedPictographic}, // 6.1 [1] (😟) worried face
+ {0x1F620, 0x1F625, prExtendedPictographic}, // 6.0 [6] (😠..😥) angry face..sad but relieved face
+ {0x1F626, 0x1F627, prExtendedPictographic}, // 6.1 [2] (😦..😧) frowning face with open mouth..anguished face
+ {0x1F628, 0x1F62B, prExtendedPictographic}, // 6.0 [4] (😨..😫) fearful face..tired face
+ {0x1F62C, 0x1F62C, prExtendedPictographic}, // 6.1 [1] (😬) grimacing face
+ {0x1F62D, 0x1F62D, prExtendedPictographic}, // 6.0 [1] (😭) loudly crying face
+ {0x1F62E, 0x1F62F, prExtendedPictographic}, // 6.1 [2] (😮..😯) face with open mouth..hushed face
+ {0x1F630, 0x1F633, prExtendedPictographic}, // 6.0 [4] (😰..😳) anxious face with sweat..flushed face
+ {0x1F634, 0x1F634, prExtendedPictographic}, // 6.1 [1] (😴) sleeping face
+ {0x1F635, 0x1F640, prExtendedPictographic}, // 6.0 [12] (😵..🙀) dizzy face..weary cat
+ {0x1F641, 0x1F642, prExtendedPictographic}, // 7.0 [2] (🙁..🙂) slightly frowning face..slightly smiling face
+ {0x1F643, 0x1F644, prExtendedPictographic}, // 8.0 [2] (🙃..🙄) upside-down face..face with rolling eyes
+ {0x1F645, 0x1F64F, prExtendedPictographic}, // 6.0 [11] (🙅..🙏) person gesturing NO..folded hands
+ {0x1F680, 0x1F6C5, prExtendedPictographic}, // 6.0 [70] (🚀..🛅) rocket..left luggage
+ {0x1F6C6, 0x1F6CF, prExtendedPictographic}, // 7.0 [10] (🛆..🛏️) TRIANGLE WITH ROUNDED CORNERS..bed
+ {0x1F6D0, 0x1F6D0, prExtendedPictographic}, // 8.0 [1] (🛐) place of worship
+ {0x1F6D1, 0x1F6D2, prExtendedPictographic}, // 9.0 [2] (🛑..🛒) stop sign..shopping cart
+ {0x1F6D3, 0x1F6D4, prExtendedPictographic}, // 10.0 [2] (🛓..🛔) STUPA..PAGODA
+ {0x1F6D5, 0x1F6D5, prExtendedPictographic}, // 12.0 [1] (🛕) hindu temple
+ {0x1F6D6, 0x1F6DF, prExtendedPictographic}, // NA [10] (🛖..🛟) ..
+ {0x1F6E0, 0x1F6EC, prExtendedPictographic}, // 7.0 [13] (🛠️..🛬) hammer and wrench..airplane arrival
+ {0x1F6ED, 0x1F6EF, prExtendedPictographic}, // NA [3] (..) ..
+ {0x1F6F0, 0x1F6F3, prExtendedPictographic}, // 7.0 [4] (🛰️..🛳️) satellite..passenger ship
+ {0x1F6F4, 0x1F6F6, prExtendedPictographic}, // 9.0 [3] (🛴..🛶) kick scooter..canoe
+ {0x1F6F7, 0x1F6F8, prExtendedPictographic}, // 10.0 [2] (🛷..🛸) sled..flying saucer
+ {0x1F6F9, 0x1F6F9, prExtendedPictographic}, // 11.0 [1] (🛹) skateboard
+ {0x1F6FA, 0x1F6FA, prExtendedPictographic}, // 12.0 [1] (🛺) auto rickshaw
+ {0x1F6FB, 0x1F6FF, prExtendedPictographic}, // NA [5] (🛻..) ..
+ {0x1F774, 0x1F77F, prExtendedPictographic}, // NA [12] (🝴..🝿) ..
+ {0x1F7D5, 0x1F7D8, prExtendedPictographic}, // 11.0 [4] (🟕..🟘) CIRCLED TRIANGLE..NEGATIVE CIRCLED SQUARE
+ {0x1F7D9, 0x1F7DF, prExtendedPictographic}, // NA [7] (🟙..) ..
+ {0x1F7E0, 0x1F7EB, prExtendedPictographic}, // 12.0 [12] (🟠..🟫) orange circle..brown square
+ {0x1F7EC, 0x1F7FF, prExtendedPictographic}, // NA [20] (..) ..
+ {0x1F80C, 0x1F80F, prExtendedPictographic}, // NA [4] (..) ..
+ {0x1F848, 0x1F84F, prExtendedPictographic}, // NA [8] (..) ..
+ {0x1F85A, 0x1F85F, prExtendedPictographic}, // NA [6] (..) ..
+ {0x1F888, 0x1F88F, prExtendedPictographic}, // NA [8] (..) ..
+ {0x1F8AE, 0x1F8FF, prExtendedPictographic}, // NA [82] (..) ..
+ {0x1F90C, 0x1F90C, prExtendedPictographic}, // NA [1] (🤌)
+ {0x1F90D, 0x1F90F, prExtendedPictographic}, // 12.0 [3] (🤍..🤏) white heart..pinching hand
+ {0x1F910, 0x1F918, prExtendedPictographic}, // 8.0 [9] (🤐..🤘) zipper-mouth face..sign of the horns
+ {0x1F919, 0x1F91E, prExtendedPictographic}, // 9.0 [6] (🤙..🤞) call me hand..crossed fingers
+ {0x1F91F, 0x1F91F, prExtendedPictographic}, // 10.0 [1] (🤟) love-you gesture
+ {0x1F920, 0x1F927, prExtendedPictographic}, // 9.0 [8] (🤠..🤧) cowboy hat face..sneezing face
+ {0x1F928, 0x1F92F, prExtendedPictographic}, // 10.0 [8] (🤨..🤯) face with raised eyebrow..exploding head
+ {0x1F930, 0x1F930, prExtendedPictographic}, // 9.0 [1] (🤰) pregnant woman
+ {0x1F931, 0x1F932, prExtendedPictographic}, // 10.0 [2] (🤱..🤲) breast-feeding..palms up together
+ {0x1F933, 0x1F93A, prExtendedPictographic}, // 9.0 [8] (🤳..🤺) selfie..person fencing
+ {0x1F93C, 0x1F93E, prExtendedPictographic}, // 9.0 [3] (🤼..🤾) people wrestling..person playing handball
+ {0x1F93F, 0x1F93F, prExtendedPictographic}, // 12.0 [1] (🤿) diving mask
+ {0x1F940, 0x1F945, prExtendedPictographic}, // 9.0 [6] (🥀..🥅) wilted flower..goal net
+ {0x1F947, 0x1F94B, prExtendedPictographic}, // 9.0 [5] (🥇..🥋) 1st place medal..martial arts uniform
+ {0x1F94C, 0x1F94C, prExtendedPictographic}, // 10.0 [1] (🥌) curling stone
+ {0x1F94D, 0x1F94F, prExtendedPictographic}, // 11.0 [3] (🥍..🥏) lacrosse..flying disc
+ {0x1F950, 0x1F95E, prExtendedPictographic}, // 9.0 [15] (🥐..🥞) croissant..pancakes
+ {0x1F95F, 0x1F96B, prExtendedPictographic}, // 10.0 [13] (🥟..🥫) dumpling..canned food
+ {0x1F96C, 0x1F970, prExtendedPictographic}, // 11.0 [5] (🥬..🥰) leafy green..smiling face with hearts
+ {0x1F971, 0x1F971, prExtendedPictographic}, // 12.0 [1] (🥱) yawning face
+ {0x1F972, 0x1F972, prExtendedPictographic}, // NA [1] (🥲)
+ {0x1F973, 0x1F976, prExtendedPictographic}, // 11.0 [4] (🥳..🥶) partying face..cold face
+ {0x1F977, 0x1F979, prExtendedPictographic}, // NA [3] (🥷..🥹) ..
+ {0x1F97A, 0x1F97A, prExtendedPictographic}, // 11.0 [1] (🥺) pleading face
+ {0x1F97B, 0x1F97B, prExtendedPictographic}, // 12.0 [1] (🥻) sari
+ {0x1F97C, 0x1F97F, prExtendedPictographic}, // 11.0 [4] (🥼..🥿) lab coat..flat shoe
+ {0x1F980, 0x1F984, prExtendedPictographic}, // 8.0 [5] (🦀..🦄) crab..unicorn
+ {0x1F985, 0x1F991, prExtendedPictographic}, // 9.0 [13] (🦅..🦑) eagle..squid
+ {0x1F992, 0x1F997, prExtendedPictographic}, // 10.0 [6] (🦒..🦗) giraffe..cricket
+ {0x1F998, 0x1F9A2, prExtendedPictographic}, // 11.0 [11] (🦘..🦢) kangaroo..swan
+ {0x1F9A3, 0x1F9A4, prExtendedPictographic}, // NA [2] (🦣..🦤) ..
+ {0x1F9A5, 0x1F9AA, prExtendedPictographic}, // 12.0 [6] (🦥..🦪) sloth..oyster
+ {0x1F9AB, 0x1F9AD, prExtendedPictographic}, // NA [3] (🦫..🦭) ..
+ {0x1F9AE, 0x1F9AF, prExtendedPictographic}, // 12.0 [2] (🦮..🦯) guide dog..probing cane
+ {0x1F9B0, 0x1F9B9, prExtendedPictographic}, // 11.0 [10] (🦰..🦹) red hair..supervillain
+ {0x1F9BA, 0x1F9BF, prExtendedPictographic}, // 12.0 [6] (🦺..🦿) safety vest..mechanical leg
+ {0x1F9C0, 0x1F9C0, prExtendedPictographic}, // 8.0 [1] (🧀) cheese wedge
+ {0x1F9C1, 0x1F9C2, prExtendedPictographic}, // 11.0 [2] (🧁..🧂) cupcake..salt
+ {0x1F9C3, 0x1F9CA, prExtendedPictographic}, // 12.0 [8] (🧃..🧊) beverage box..ice cube
+ {0x1F9CB, 0x1F9CC, prExtendedPictographic}, // NA [2] (🧋..🧌) ..
+ {0x1F9CD, 0x1F9CF, prExtendedPictographic}, // 12.0 [3] (🧍..🧏) person standing..deaf person
+ {0x1F9D0, 0x1F9E6, prExtendedPictographic}, // 10.0 [23] (🧐..🧦) face with monocle..socks
+ {0x1F9E7, 0x1F9FF, prExtendedPictographic}, // 11.0 [25] (🧧..🧿) red envelope..nazar amulet
+ {0x1FA00, 0x1FA53, prExtendedPictographic}, // 12.0 [84] (🨀..🩓) NEUTRAL CHESS KING..BLACK CHESS KNIGHT-BISHOP
+ {0x1FA54, 0x1FA5F, prExtendedPictographic}, // NA [12] (..) ..
+ {0x1FA60, 0x1FA6D, prExtendedPictographic}, // 11.0 [14] (🩠..🩭) XIANGQI RED GENERAL..XIANGQI BLACK SOLDIER
+ {0x1FA6E, 0x1FA6F, prExtendedPictographic}, // NA [2] (..) ..
+ {0x1FA70, 0x1FA73, prExtendedPictographic}, // 12.0 [4] (🩰..🩳) ballet shoes..shorts
+ {0x1FA74, 0x1FA77, prExtendedPictographic}, // NA [4] (🩴..🩷) ..
+ {0x1FA78, 0x1FA7A, prExtendedPictographic}, // 12.0 [3] (🩸..🩺) drop of blood..stethoscope
+ {0x1FA7B, 0x1FA7F, prExtendedPictographic}, // NA [5] (🩻..) ..
+ {0x1FA80, 0x1FA82, prExtendedPictographic}, // 12.0 [3] (🪀..🪂) yo-yo..parachute
+ {0x1FA83, 0x1FA8F, prExtendedPictographic}, // NA [13] (🪃..) ..
+ {0x1FA90, 0x1FA95, prExtendedPictographic}, // 12.0 [6] (🪐..🪕) ringed planet..banjo
+ {0x1FA96, 0x1FFFD, prExtendedPictographic}, // NA[1384] (🪖..) ..
+ {0xE0000, 0xE0000, prControl}, // Cn
+ {0xE0001, 0xE0001, prControl}, // Cf LANGUAGE TAG
+ {0xE0002, 0xE001F, prControl}, // Cn [30] ..
+ {0xE0020, 0xE007F, prExtend}, // Cf [96] TAG SPACE..CANCEL TAG
+ {0xE0080, 0xE00FF, prControl}, // Cn [128] ..
+ {0xE0100, 0xE01EF, prExtend}, // Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
+ {0xE01F0, 0xE0FFF, prControl}, // Cn [3600] ..
+}
+
+// property returns the Unicode property value (see constants above) of the
+// given code point.
+func property(r rune) int {
+ // Run a binary search.
+ from := 0
+ to := len(codePoints)
+ for to > from {
+ middle := (from + to) / 2
+ cpRange := codePoints[middle]
+ if int(r) < cpRange[0] {
+ to = middle
+ continue
+ }
+ if int(r) > cpRange[1] {
+ from = middle + 1
+ continue
+ }
+ return cpRange[2]
+ }
+ return prAny
+}
diff --git a/vendor/github.com/russross/blackfriday/v2/.gitignore b/vendor/github.com/russross/blackfriday/v2/.gitignore
new file mode 100644
index 0000000..75623dc
--- /dev/null
+++ b/vendor/github.com/russross/blackfriday/v2/.gitignore
@@ -0,0 +1,8 @@
+*.out
+*.swp
+*.8
+*.6
+_obj
+_test*
+markdown
+tags
diff --git a/vendor/github.com/russross/blackfriday/v2/.travis.yml b/vendor/github.com/russross/blackfriday/v2/.travis.yml
new file mode 100644
index 0000000..b0b525a
--- /dev/null
+++ b/vendor/github.com/russross/blackfriday/v2/.travis.yml
@@ -0,0 +1,17 @@
+sudo: false
+language: go
+go:
+ - "1.10.x"
+ - "1.11.x"
+ - tip
+matrix:
+ fast_finish: true
+ allow_failures:
+ - go: tip
+install:
+ - # Do nothing. This is needed to prevent default install action "go get -t -v ./..." from happening here (we want it to happen inside script step).
+script:
+ - go get -t -v ./...
+ - diff -u <(echo -n) <(gofmt -d -s .)
+ - go tool vet .
+ - go test -v ./...
diff --git a/vendor/github.com/russross/blackfriday/v2/LICENSE.txt b/vendor/github.com/russross/blackfriday/v2/LICENSE.txt
new file mode 100644
index 0000000..2885af3
--- /dev/null
+++ b/vendor/github.com/russross/blackfriday/v2/LICENSE.txt
@@ -0,0 +1,29 @@
+Blackfriday is distributed under the Simplified BSD License:
+
+> Copyright © 2011 Russ Ross
+> All rights reserved.
+>
+> Redistribution and use in source and binary forms, with or without
+> modification, are permitted provided that the following conditions
+> are met:
+>
+> 1. Redistributions of source code must retain the above copyright
+> notice, this list of conditions and the following disclaimer.
+>
+> 2. Redistributions in binary form must reproduce the above
+> copyright notice, this list of conditions and the following
+> disclaimer in the documentation and/or other materials provided with
+> the distribution.
+>
+> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+> "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+> LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+> FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+> COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+> INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+> BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+> LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+> CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+> LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+> ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+> POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/russross/blackfriday/v2/README.md b/vendor/github.com/russross/blackfriday/v2/README.md
new file mode 100644
index 0000000..d5a8649
--- /dev/null
+++ b/vendor/github.com/russross/blackfriday/v2/README.md
@@ -0,0 +1,291 @@
+Blackfriday [![Build Status](https://travis-ci.org/russross/blackfriday.svg?branch=master)](https://travis-ci.org/russross/blackfriday)
+===========
+
+Blackfriday is a [Markdown][1] processor implemented in [Go][2]. It
+is paranoid about its input (so you can safely feed it user-supplied
+data), it is fast, it supports common extensions (tables, smart
+punctuation substitutions, etc.), and it is safe for all utf-8
+(unicode) input.
+
+HTML output is currently supported, along with Smartypants
+extensions.
+
+It started as a translation from C of [Sundown][3].
+
+
+Installation
+------------
+
+Blackfriday is compatible with any modern Go release. With Go 1.7 and git
+installed:
+
+ go get gopkg.in/russross/blackfriday.v2
+
+will download, compile, and install the package into your `$GOPATH`
+directory hierarchy. Alternatively, you can achieve the same if you
+import it into a project:
+
+ import "gopkg.in/russross/blackfriday.v2"
+
+and `go get` without parameters.
+
+
+Versions
+--------
+
+Currently maintained and recommended version of Blackfriday is `v2`. It's being
+developed on its own branch: https://github.com/russross/blackfriday/tree/v2 and the
+documentation is available at
+https://godoc.org/gopkg.in/russross/blackfriday.v2.
+
+It is `go get`-able via via [gopkg.in][6] at `gopkg.in/russross/blackfriday.v2`,
+but we highly recommend using package management tool like [dep][7] or
+[Glide][8] and make use of semantic versioning. With package management you
+should import `github.com/russross/blackfriday` and specify that you're using
+version 2.0.0.
+
+Version 2 offers a number of improvements over v1:
+
+* Cleaned up API
+* A separate call to [`Parse`][4], which produces an abstract syntax tree for
+ the document
+* Latest bug fixes
+* Flexibility to easily add your own rendering extensions
+
+Potential drawbacks:
+
+* Our benchmarks show v2 to be slightly slower than v1. Currently in the
+ ballpark of around 15%.
+* API breakage. If you can't afford modifying your code to adhere to the new API
+ and don't care too much about the new features, v2 is probably not for you.
+* Several bug fixes are trailing behind and still need to be forward-ported to
+ v2. See issue [#348](https://github.com/russross/blackfriday/issues/348) for
+ tracking.
+
+Usage
+-----
+
+For the most sensible markdown processing, it is as simple as getting your input
+into a byte slice and calling:
+
+```go
+output := blackfriday.Run(input)
+```
+
+Your input will be parsed and the output rendered with a set of most popular
+extensions enabled. If you want the most basic feature set, corresponding with
+the bare Markdown specification, use:
+
+```go
+output := blackfriday.Run(input, blackfriday.WithNoExtensions())
+```
+
+### Sanitize untrusted content
+
+Blackfriday itself does nothing to protect against malicious content. If you are
+dealing with user-supplied markdown, we recommend running Blackfriday's output
+through HTML sanitizer such as [Bluemonday][5].
+
+Here's an example of simple usage of Blackfriday together with Bluemonday:
+
+```go
+import (
+ "github.com/microcosm-cc/bluemonday"
+ "github.com/russross/blackfriday"
+)
+
+// ...
+unsafe := blackfriday.Run(input)
+html := bluemonday.UGCPolicy().SanitizeBytes(unsafe)
+```
+
+### Custom options
+
+If you want to customize the set of options, use `blackfriday.WithExtensions`,
+`blackfriday.WithRenderer` and `blackfriday.WithRefOverride`.
+
+You can also check out `blackfriday-tool` for a more complete example
+of how to use it. Download and install it using:
+
+ go get github.com/russross/blackfriday-tool
+
+This is a simple command-line tool that allows you to process a
+markdown file using a standalone program. You can also browse the
+source directly on github if you are just looking for some example
+code:
+
+*
+
+Note that if you have not already done so, installing
+`blackfriday-tool` will be sufficient to download and install
+blackfriday in addition to the tool itself. The tool binary will be
+installed in `$GOPATH/bin`. This is a statically-linked binary that
+can be copied to wherever you need it without worrying about
+dependencies and library versions.
+
+
+Features
+--------
+
+All features of Sundown are supported, including:
+
+* **Compatibility**. The Markdown v1.0.3 test suite passes with
+ the `--tidy` option. Without `--tidy`, the differences are
+ mostly in whitespace and entity escaping, where blackfriday is
+ more consistent and cleaner.
+
+* **Common extensions**, including table support, fenced code
+ blocks, autolinks, strikethroughs, non-strict emphasis, etc.
+
+* **Safety**. Blackfriday is paranoid when parsing, making it safe
+ to feed untrusted user input without fear of bad things
+ happening. The test suite stress tests this and there are no
+ known inputs that make it crash. If you find one, please let me
+ know and send me the input that does it.
+
+ NOTE: "safety" in this context means *runtime safety only*. In order to
+ protect yourself against JavaScript injection in untrusted content, see
+ [this example](https://github.com/russross/blackfriday#sanitize-untrusted-content).
+
+* **Fast processing**. It is fast enough to render on-demand in
+ most web applications without having to cache the output.
+
+* **Thread safety**. You can run multiple parsers in different
+ goroutines without ill effect. There is no dependence on global
+ shared state.
+
+* **Minimal dependencies**. Blackfriday only depends on standard
+ library packages in Go. The source code is pretty
+ self-contained, so it is easy to add to any project, including
+ Google App Engine projects.
+
+* **Standards compliant**. Output successfully validates using the
+ W3C validation tool for HTML 4.01 and XHTML 1.0 Transitional.
+
+
+Extensions
+----------
+
+In addition to the standard markdown syntax, this package
+implements the following extensions:
+
+* **Intra-word emphasis supression**. The `_` character is
+ commonly used inside words when discussing code, so having
+ markdown interpret it as an emphasis command is usually the
+ wrong thing. Blackfriday lets you treat all emphasis markers as
+ normal characters when they occur inside a word.
+
+* **Tables**. Tables can be created by drawing them in the input
+ using a simple syntax:
+
+ ```
+ Name | Age
+ --------|------
+ Bob | 27
+ Alice | 23
+ ```
+
+* **Fenced code blocks**. In addition to the normal 4-space
+ indentation to mark code blocks, you can explicitly mark them
+ and supply a language (to make syntax highlighting simple). Just
+ mark it like this:
+
+ ```go
+ func getTrue() bool {
+ return true
+ }
+ ```
+
+ You can use 3 or more backticks to mark the beginning of the
+ block, and the same number to mark the end of the block.
+
+* **Definition lists**. A simple definition list is made of a single-line
+ term followed by a colon and the definition for that term.
+
+ Cat
+ : Fluffy animal everyone likes
+
+ Internet
+ : Vector of transmission for pictures of cats
+
+ Terms must be separated from the previous definition by a blank line.
+
+* **Footnotes**. A marker in the text that will become a superscript number;
+ a footnote definition that will be placed in a list of footnotes at the
+ end of the document. A footnote looks like this:
+
+ This is a footnote.[^1]
+
+ [^1]: the footnote text.
+
+* **Autolinking**. Blackfriday can find URLs that have not been
+ explicitly marked as links and turn them into links.
+
+* **Strikethrough**. Use two tildes (`~~`) to mark text that
+ should be crossed out.
+
+* **Hard line breaks**. With this extension enabled newlines in the input
+ translate into line breaks in the output. This extension is off by default.
+
+* **Smart quotes**. Smartypants-style punctuation substitution is
+ supported, turning normal double- and single-quote marks into
+ curly quotes, etc.
+
+* **LaTeX-style dash parsing** is an additional option, where `--`
+ is translated into `–`, and `---` is translated into
+ `—`. This differs from most smartypants processors, which
+ turn a single hyphen into an ndash and a double hyphen into an
+ mdash.
+
+* **Smart fractions**, where anything that looks like a fraction
+ is translated into suitable HTML (instead of just a few special
+ cases like most smartypant processors). For example, `4/5`
+ becomes `4⁄5`, which renders as
+ 4⁄5.
+
+
+Other renderers
+---------------
+
+Blackfriday is structured to allow alternative rendering engines. Here
+are a few of note:
+
+* [github_flavored_markdown](https://godoc.org/github.com/shurcooL/github_flavored_markdown):
+ provides a GitHub Flavored Markdown renderer with fenced code block
+ highlighting, clickable heading anchor links.
+
+ It's not customizable, and its goal is to produce HTML output
+ equivalent to the [GitHub Markdown API endpoint](https://developer.github.com/v3/markdown/#render-a-markdown-document-in-raw-mode),
+ except the rendering is performed locally.
+
+* [markdownfmt](https://github.com/shurcooL/markdownfmt): like gofmt,
+ but for markdown.
+
+* [LaTeX output](https://github.com/Ambrevar/Blackfriday-LaTeX):
+ renders output as LaTeX.
+
+* [Blackfriday-Confluence](https://github.com/kentaro-m/blackfriday-confluence): provides a [Confluence Wiki Markup](https://confluence.atlassian.com/doc/confluence-wiki-markup-251003035.html) renderer.
+
+
+Todo
+----
+
+* More unit testing
+* Improve unicode support. It does not understand all unicode
+ rules (about what constitutes a letter, a punctuation symbol,
+ etc.), so it may fail to detect word boundaries correctly in
+ some instances. It is safe on all utf-8 input.
+
+
+License
+-------
+
+[Blackfriday is distributed under the Simplified BSD License](LICENSE.txt)
+
+
+ [1]: https://daringfireball.net/projects/markdown/ "Markdown"
+ [2]: https://golang.org/ "Go Language"
+ [3]: https://github.com/vmg/sundown "Sundown"
+ [4]: https://godoc.org/gopkg.in/russross/blackfriday.v2#Parse "Parse func"
+ [5]: https://github.com/microcosm-cc/bluemonday "Bluemonday"
+ [6]: https://labix.org/gopkg.in "gopkg.in"
diff --git a/vendor/github.com/russross/blackfriday/v2/block.go b/vendor/github.com/russross/blackfriday/v2/block.go
new file mode 100644
index 0000000..b860747
--- /dev/null
+++ b/vendor/github.com/russross/blackfriday/v2/block.go
@@ -0,0 +1,1590 @@
+//
+// Blackfriday Markdown Processor
+// Available at http://github.com/russross/blackfriday
+//
+// Copyright © 2011 Russ Ross .
+// Distributed under the Simplified BSD License.
+// See README.md for details.
+//
+
+//
+// Functions to parse block-level elements.
+//
+
+package blackfriday
+
+import (
+ "bytes"
+ "html"
+ "regexp"
+ "strings"
+
+ "github.com/shurcooL/sanitized_anchor_name"
+)
+
+const (
+ charEntity = "&(?:#x[a-f0-9]{1,8}|#[0-9]{1,8}|[a-z][a-z0-9]{1,31});"
+ escapable = "[!\"#$%&'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]"
+)
+
+var (
+ reBackslashOrAmp = regexp.MustCompile("[\\&]")
+ reEntityOrEscapedChar = regexp.MustCompile("(?i)\\\\" + escapable + "|" + charEntity)
+)
+
+// Parse block-level data.
+// Note: this function and many that it calls assume that
+// the input buffer ends with a newline.
+func (p *Markdown) block(data []byte) {
+ // this is called recursively: enforce a maximum depth
+ if p.nesting >= p.maxNesting {
+ return
+ }
+ p.nesting++
+
+ // parse out one block-level construct at a time
+ for len(data) > 0 {
+ // prefixed heading:
+ //
+ // # Heading 1
+ // ## Heading 2
+ // ...
+ // ###### Heading 6
+ if p.isPrefixHeading(data) {
+ data = data[p.prefixHeading(data):]
+ continue
+ }
+
+ // block of preformatted HTML:
+ //
+ //
+ // ...
+ //
+ if data[0] == '<' {
+ if i := p.html(data, true); i > 0 {
+ data = data[i:]
+ continue
+ }
+ }
+
+ // title block
+ //
+ // % stuff
+ // % more stuff
+ // % even more stuff
+ if p.extensions&Titleblock != 0 {
+ if data[0] == '%' {
+ if i := p.titleBlock(data, true); i > 0 {
+ data = data[i:]
+ continue
+ }
+ }
+ }
+
+ // blank lines. note: returns the # of bytes to skip
+ if i := p.isEmpty(data); i > 0 {
+ data = data[i:]
+ continue
+ }
+
+ // indented code block:
+ //
+ // func max(a, b int) int {
+ // if a > b {
+ // return a
+ // }
+ // return b
+ // }
+ if p.codePrefix(data) > 0 {
+ data = data[p.code(data):]
+ continue
+ }
+
+ // fenced code block:
+ //
+ // ``` go
+ // func fact(n int) int {
+ // if n <= 1 {
+ // return n
+ // }
+ // return n * fact(n-1)
+ // }
+ // ```
+ if p.extensions&FencedCode != 0 {
+ if i := p.fencedCodeBlock(data, true); i > 0 {
+ data = data[i:]
+ continue
+ }
+ }
+
+ // horizontal rule:
+ //
+ // ------
+ // or
+ // ******
+ // or
+ // ______
+ if p.isHRule(data) {
+ p.addBlock(HorizontalRule, nil)
+ var i int
+ for i = 0; i < len(data) && data[i] != '\n'; i++ {
+ }
+ data = data[i:]
+ continue
+ }
+
+ // block quote:
+ //
+ // > A big quote I found somewhere
+ // > on the web
+ if p.quotePrefix(data) > 0 {
+ data = data[p.quote(data):]
+ continue
+ }
+
+ // table:
+ //
+ // Name | Age | Phone
+ // ------|-----|---------
+ // Bob | 31 | 555-1234
+ // Alice | 27 | 555-4321
+ if p.extensions&Tables != 0 {
+ if i := p.table(data); i > 0 {
+ data = data[i:]
+ continue
+ }
+ }
+
+ // an itemized/unordered list:
+ //
+ // * Item 1
+ // * Item 2
+ //
+ // also works with + or -
+ if p.uliPrefix(data) > 0 {
+ data = data[p.list(data, 0):]
+ continue
+ }
+
+ // a numbered/ordered list:
+ //
+ // 1. Item 1
+ // 2. Item 2
+ if p.oliPrefix(data) > 0 {
+ data = data[p.list(data, ListTypeOrdered):]
+ continue
+ }
+
+ // definition lists:
+ //
+ // Term 1
+ // : Definition a
+ // : Definition b
+ //
+ // Term 2
+ // : Definition c
+ if p.extensions&DefinitionLists != 0 {
+ if p.dliPrefix(data) > 0 {
+ data = data[p.list(data, ListTypeDefinition):]
+ continue
+ }
+ }
+
+ // anything else must look like a normal paragraph
+ // note: this finds underlined headings, too
+ data = data[p.paragraph(data):]
+ }
+
+ p.nesting--
+}
+
+func (p *Markdown) addBlock(typ NodeType, content []byte) *Node {
+ p.closeUnmatchedBlocks()
+ container := p.addChild(typ, 0)
+ container.content = content
+ return container
+}
+
+func (p *Markdown) isPrefixHeading(data []byte) bool {
+ if data[0] != '#' {
+ return false
+ }
+
+ if p.extensions&SpaceHeadings != 0 {
+ level := 0
+ for level < 6 && level < len(data) && data[level] == '#' {
+ level++
+ }
+ if level == len(data) || data[level] != ' ' {
+ return false
+ }
+ }
+ return true
+}
+
+func (p *Markdown) prefixHeading(data []byte) int {
+ level := 0
+ for level < 6 && level < len(data) && data[level] == '#' {
+ level++
+ }
+ i := skipChar(data, level, ' ')
+ end := skipUntilChar(data, i, '\n')
+ skip := end
+ id := ""
+ if p.extensions&HeadingIDs != 0 {
+ j, k := 0, 0
+ // find start/end of heading id
+ for j = i; j < end-1 && (data[j] != '{' || data[j+1] != '#'); j++ {
+ }
+ for k = j + 1; k < end && data[k] != '}'; k++ {
+ }
+ // extract heading id iff found
+ if j < end && k < end {
+ id = string(data[j+2 : k])
+ end = j
+ skip = k + 1
+ for end > 0 && data[end-1] == ' ' {
+ end--
+ }
+ }
+ }
+ for end > 0 && data[end-1] == '#' {
+ if isBackslashEscaped(data, end-1) {
+ break
+ }
+ end--
+ }
+ for end > 0 && data[end-1] == ' ' {
+ end--
+ }
+ if end > i {
+ if id == "" && p.extensions&AutoHeadingIDs != 0 {
+ id = sanitized_anchor_name.Create(string(data[i:end]))
+ }
+ block := p.addBlock(Heading, data[i:end])
+ block.HeadingID = id
+ block.Level = level
+ }
+ return skip
+}
+
+func (p *Markdown) isUnderlinedHeading(data []byte) int {
+ // test of level 1 heading
+ if data[0] == '=' {
+ i := skipChar(data, 1, '=')
+ i = skipChar(data, i, ' ')
+ if i < len(data) && data[i] == '\n' {
+ return 1
+ }
+ return 0
+ }
+
+ // test of level 2 heading
+ if data[0] == '-' {
+ i := skipChar(data, 1, '-')
+ i = skipChar(data, i, ' ')
+ if i < len(data) && data[i] == '\n' {
+ return 2
+ }
+ return 0
+ }
+
+ return 0
+}
+
+func (p *Markdown) titleBlock(data []byte, doRender bool) int {
+ if data[0] != '%' {
+ return 0
+ }
+ splitData := bytes.Split(data, []byte("\n"))
+ var i int
+ for idx, b := range splitData {
+ if !bytes.HasPrefix(b, []byte("%")) {
+ i = idx // - 1
+ break
+ }
+ }
+
+ data = bytes.Join(splitData[0:i], []byte("\n"))
+ consumed := len(data)
+ data = bytes.TrimPrefix(data, []byte("% "))
+ data = bytes.Replace(data, []byte("\n% "), []byte("\n"), -1)
+ block := p.addBlock(Heading, data)
+ block.Level = 1
+ block.IsTitleblock = true
+
+ return consumed
+}
+
+func (p *Markdown) html(data []byte, doRender bool) int {
+ var i, j int
+
+ // identify the opening tag
+ if data[0] != '<' {
+ return 0
+ }
+ curtag, tagfound := p.htmlFindTag(data[1:])
+
+ // handle special cases
+ if !tagfound {
+ // check for an HTML comment
+ if size := p.htmlComment(data, doRender); size > 0 {
+ return size
+ }
+
+ // check for an
tag
+ if size := p.htmlHr(data, doRender); size > 0 {
+ return size
+ }
+
+ // no special case recognized
+ return 0
+ }
+
+ // look for an unindented matching closing tag
+ // followed by a blank line
+ found := false
+ /*
+ closetag := []byte("\n" + curtag + ">")
+ j = len(curtag) + 1
+ for !found {
+ // scan for a closing tag at the beginning of a line
+ if skip := bytes.Index(data[j:], closetag); skip >= 0 {
+ j += skip + len(closetag)
+ } else {
+ break
+ }
+
+ // see if it is the only thing on the line
+ if skip := p.isEmpty(data[j:]); skip > 0 {
+ // see if it is followed by a blank line/eof
+ j += skip
+ if j >= len(data) {
+ found = true
+ i = j
+ } else {
+ if skip := p.isEmpty(data[j:]); skip > 0 {
+ j += skip
+ found = true
+ i = j
+ }
+ }
+ }
+ }
+ */
+
+ // if not found, try a second pass looking for indented match
+ // but not if tag is "ins" or "del" (following original Markdown.pl)
+ if !found && curtag != "ins" && curtag != "del" {
+ i = 1
+ for i < len(data) {
+ i++
+ for i < len(data) && !(data[i-1] == '<' && data[i] == '/') {
+ i++
+ }
+
+ if i+2+len(curtag) >= len(data) {
+ break
+ }
+
+ j = p.htmlFindEnd(curtag, data[i-1:])
+
+ if j > 0 {
+ i += j - 1
+ found = true
+ break
+ }
+ }
+ }
+
+ if !found {
+ return 0
+ }
+
+ // the end of the block has been found
+ if doRender {
+ // trim newlines
+ end := i
+ for end > 0 && data[end-1] == '\n' {
+ end--
+ }
+ finalizeHTMLBlock(p.addBlock(HTMLBlock, data[:end]))
+ }
+
+ return i
+}
+
+func finalizeHTMLBlock(block *Node) {
+ block.Literal = block.content
+ block.content = nil
+}
+
+// HTML comment, lax form
+func (p *Markdown) htmlComment(data []byte, doRender bool) int {
+ i := p.inlineHTMLComment(data)
+ // needs to end with a blank line
+ if j := p.isEmpty(data[i:]); j > 0 {
+ size := i + j
+ if doRender {
+ // trim trailing newlines
+ end := size
+ for end > 0 && data[end-1] == '\n' {
+ end--
+ }
+ block := p.addBlock(HTMLBlock, data[:end])
+ finalizeHTMLBlock(block)
+ }
+ return size
+ }
+ return 0
+}
+
+// HR, which is the only self-closing block tag considered
+func (p *Markdown) htmlHr(data []byte, doRender bool) int {
+ if len(data) < 4 {
+ return 0
+ }
+ if data[0] != '<' || (data[1] != 'h' && data[1] != 'H') || (data[2] != 'r' && data[2] != 'R') {
+ return 0
+ }
+ if data[3] != ' ' && data[3] != '/' && data[3] != '>' {
+ // not an
tag after all; at least not a valid one
+ return 0
+ }
+ i := 3
+ for i < len(data) && data[i] != '>' && data[i] != '\n' {
+ i++
+ }
+ if i < len(data) && data[i] == '>' {
+ i++
+ if j := p.isEmpty(data[i:]); j > 0 {
+ size := i + j
+ if doRender {
+ // trim newlines
+ end := size
+ for end > 0 && data[end-1] == '\n' {
+ end--
+ }
+ finalizeHTMLBlock(p.addBlock(HTMLBlock, data[:end]))
+ }
+ return size
+ }
+ }
+ return 0
+}
+
+func (p *Markdown) htmlFindTag(data []byte) (string, bool) {
+ i := 0
+ for i < len(data) && isalnum(data[i]) {
+ i++
+ }
+ key := string(data[:i])
+ if _, ok := blockTags[key]; ok {
+ return key, true
+ }
+ return "", false
+}
+
+func (p *Markdown) htmlFindEnd(tag string, data []byte) int {
+ // assume data[0] == '<' && data[1] == '/' already tested
+ if tag == "hr" {
+ return 2
+ }
+ // check if tag is a match
+ closetag := []byte("" + tag + ">")
+ if !bytes.HasPrefix(data, closetag) {
+ return 0
+ }
+ i := len(closetag)
+
+ // check that the rest of the line is blank
+ skip := 0
+ if skip = p.isEmpty(data[i:]); skip == 0 {
+ return 0
+ }
+ i += skip
+ skip = 0
+
+ if i >= len(data) {
+ return i
+ }
+
+ if p.extensions&LaxHTMLBlocks != 0 {
+ return i
+ }
+ if skip = p.isEmpty(data[i:]); skip == 0 {
+ // following line must be blank
+ return 0
+ }
+
+ return i + skip
+}
+
+func (*Markdown) isEmpty(data []byte) int {
+ // it is okay to call isEmpty on an empty buffer
+ if len(data) == 0 {
+ return 0
+ }
+
+ var i int
+ for i = 0; i < len(data) && data[i] != '\n'; i++ {
+ if data[i] != ' ' && data[i] != '\t' {
+ return 0
+ }
+ }
+ if i < len(data) && data[i] == '\n' {
+ i++
+ }
+ return i
+}
+
+func (*Markdown) isHRule(data []byte) bool {
+ i := 0
+
+ // skip up to three spaces
+ for i < 3 && data[i] == ' ' {
+ i++
+ }
+
+ // look at the hrule char
+ if data[i] != '*' && data[i] != '-' && data[i] != '_' {
+ return false
+ }
+ c := data[i]
+
+ // the whole line must be the char or whitespace
+ n := 0
+ for i < len(data) && data[i] != '\n' {
+ switch {
+ case data[i] == c:
+ n++
+ case data[i] != ' ':
+ return false
+ }
+ i++
+ }
+
+ return n >= 3
+}
+
+// isFenceLine checks if there's a fence line (e.g., ``` or ``` go) at the beginning of data,
+// and returns the end index if so, or 0 otherwise. It also returns the marker found.
+// If info is not nil, it gets set to the syntax specified in the fence line.
+func isFenceLine(data []byte, info *string, oldmarker string) (end int, marker string) {
+ i, size := 0, 0
+
+ // skip up to three spaces
+ for i < len(data) && i < 3 && data[i] == ' ' {
+ i++
+ }
+
+ // check for the marker characters: ~ or `
+ if i >= len(data) {
+ return 0, ""
+ }
+ if data[i] != '~' && data[i] != '`' {
+ return 0, ""
+ }
+
+ c := data[i]
+
+ // the whole line must be the same char or whitespace
+ for i < len(data) && data[i] == c {
+ size++
+ i++
+ }
+
+ // the marker char must occur at least 3 times
+ if size < 3 {
+ return 0, ""
+ }
+ marker = string(data[i-size : i])
+
+ // if this is the end marker, it must match the beginning marker
+ if oldmarker != "" && marker != oldmarker {
+ return 0, ""
+ }
+
+ // TODO(shurcooL): It's probably a good idea to simplify the 2 code paths here
+ // into one, always get the info string, and discard it if the caller doesn't care.
+ if info != nil {
+ infoLength := 0
+ i = skipChar(data, i, ' ')
+
+ if i >= len(data) {
+ if i == len(data) {
+ return i, marker
+ }
+ return 0, ""
+ }
+
+ infoStart := i
+
+ if data[i] == '{' {
+ i++
+ infoStart++
+
+ for i < len(data) && data[i] != '}' && data[i] != '\n' {
+ infoLength++
+ i++
+ }
+
+ if i >= len(data) || data[i] != '}' {
+ return 0, ""
+ }
+
+ // strip all whitespace at the beginning and the end
+ // of the {} block
+ for infoLength > 0 && isspace(data[infoStart]) {
+ infoStart++
+ infoLength--
+ }
+
+ for infoLength > 0 && isspace(data[infoStart+infoLength-1]) {
+ infoLength--
+ }
+ i++
+ i = skipChar(data, i, ' ')
+ } else {
+ for i < len(data) && !isverticalspace(data[i]) {
+ infoLength++
+ i++
+ }
+ }
+
+ *info = strings.TrimSpace(string(data[infoStart : infoStart+infoLength]))
+ }
+
+ if i == len(data) {
+ return i, marker
+ }
+ if i > len(data) || data[i] != '\n' {
+ return 0, ""
+ }
+ return i + 1, marker // Take newline into account.
+}
+
+// fencedCodeBlock returns the end index if data contains a fenced code block at the beginning,
+// or 0 otherwise. It writes to out if doRender is true, otherwise it has no side effects.
+// If doRender is true, a final newline is mandatory to recognize the fenced code block.
+func (p *Markdown) fencedCodeBlock(data []byte, doRender bool) int {
+ var info string
+ beg, marker := isFenceLine(data, &info, "")
+ if beg == 0 || beg >= len(data) {
+ return 0
+ }
+
+ var work bytes.Buffer
+ work.Write([]byte(info))
+ work.WriteByte('\n')
+
+ for {
+ // safe to assume beg < len(data)
+
+ // check for the end of the code block
+ fenceEnd, _ := isFenceLine(data[beg:], nil, marker)
+ if fenceEnd != 0 {
+ beg += fenceEnd
+ break
+ }
+
+ // copy the current line
+ end := skipUntilChar(data, beg, '\n') + 1
+
+ // did we reach the end of the buffer without a closing marker?
+ if end >= len(data) {
+ return 0
+ }
+
+ // verbatim copy to the working buffer
+ if doRender {
+ work.Write(data[beg:end])
+ }
+ beg = end
+ }
+
+ if doRender {
+ block := p.addBlock(CodeBlock, work.Bytes()) // TODO: get rid of temp buffer
+ block.IsFenced = true
+ finalizeCodeBlock(block)
+ }
+
+ return beg
+}
+
+func unescapeChar(str []byte) []byte {
+ if str[0] == '\\' {
+ return []byte{str[1]}
+ }
+ return []byte(html.UnescapeString(string(str)))
+}
+
+func unescapeString(str []byte) []byte {
+ if reBackslashOrAmp.Match(str) {
+ return reEntityOrEscapedChar.ReplaceAllFunc(str, unescapeChar)
+ }
+ return str
+}
+
+func finalizeCodeBlock(block *Node) {
+ if block.IsFenced {
+ newlinePos := bytes.IndexByte(block.content, '\n')
+ firstLine := block.content[:newlinePos]
+ rest := block.content[newlinePos+1:]
+ block.Info = unescapeString(bytes.Trim(firstLine, "\n"))
+ block.Literal = rest
+ } else {
+ block.Literal = block.content
+ }
+ block.content = nil
+}
+
+func (p *Markdown) table(data []byte) int {
+ table := p.addBlock(Table, nil)
+ i, columns := p.tableHeader(data)
+ if i == 0 {
+ p.tip = table.Parent
+ table.Unlink()
+ return 0
+ }
+
+ p.addBlock(TableBody, nil)
+
+ for i < len(data) {
+ pipes, rowStart := 0, i
+ for ; i < len(data) && data[i] != '\n'; i++ {
+ if data[i] == '|' {
+ pipes++
+ }
+ }
+
+ if pipes == 0 {
+ i = rowStart
+ break
+ }
+
+ // include the newline in data sent to tableRow
+ if i < len(data) && data[i] == '\n' {
+ i++
+ }
+ p.tableRow(data[rowStart:i], columns, false)
+ }
+
+ return i
+}
+
+// check if the specified position is preceded by an odd number of backslashes
+func isBackslashEscaped(data []byte, i int) bool {
+ backslashes := 0
+ for i-backslashes-1 >= 0 && data[i-backslashes-1] == '\\' {
+ backslashes++
+ }
+ return backslashes&1 == 1
+}
+
+func (p *Markdown) tableHeader(data []byte) (size int, columns []CellAlignFlags) {
+ i := 0
+ colCount := 1
+ for i = 0; i < len(data) && data[i] != '\n'; i++ {
+ if data[i] == '|' && !isBackslashEscaped(data, i) {
+ colCount++
+ }
+ }
+
+ // doesn't look like a table header
+ if colCount == 1 {
+ return
+ }
+
+ // include the newline in the data sent to tableRow
+ j := i
+ if j < len(data) && data[j] == '\n' {
+ j++
+ }
+ header := data[:j]
+
+ // column count ignores pipes at beginning or end of line
+ if data[0] == '|' {
+ colCount--
+ }
+ if i > 2 && data[i-1] == '|' && !isBackslashEscaped(data, i-1) {
+ colCount--
+ }
+
+ columns = make([]CellAlignFlags, colCount)
+
+ // move on to the header underline
+ i++
+ if i >= len(data) {
+ return
+ }
+
+ if data[i] == '|' && !isBackslashEscaped(data, i) {
+ i++
+ }
+ i = skipChar(data, i, ' ')
+
+ // each column header is of form: / *:?-+:? *|/ with # dashes + # colons >= 3
+ // and trailing | optional on last column
+ col := 0
+ for i < len(data) && data[i] != '\n' {
+ dashes := 0
+
+ if data[i] == ':' {
+ i++
+ columns[col] |= TableAlignmentLeft
+ dashes++
+ }
+ for i < len(data) && data[i] == '-' {
+ i++
+ dashes++
+ }
+ if i < len(data) && data[i] == ':' {
+ i++
+ columns[col] |= TableAlignmentRight
+ dashes++
+ }
+ for i < len(data) && data[i] == ' ' {
+ i++
+ }
+ if i == len(data) {
+ return
+ }
+ // end of column test is messy
+ switch {
+ case dashes < 3:
+ // not a valid column
+ return
+
+ case data[i] == '|' && !isBackslashEscaped(data, i):
+ // marker found, now skip past trailing whitespace
+ col++
+ i++
+ for i < len(data) && data[i] == ' ' {
+ i++
+ }
+
+ // trailing junk found after last column
+ if col >= colCount && i < len(data) && data[i] != '\n' {
+ return
+ }
+
+ case (data[i] != '|' || isBackslashEscaped(data, i)) && col+1 < colCount:
+ // something else found where marker was required
+ return
+
+ case data[i] == '\n':
+ // marker is optional for the last column
+ col++
+
+ default:
+ // trailing junk found after last column
+ return
+ }
+ }
+ if col != colCount {
+ return
+ }
+
+ p.addBlock(TableHead, nil)
+ p.tableRow(header, columns, true)
+ size = i
+ if size < len(data) && data[size] == '\n' {
+ size++
+ }
+ return
+}
+
+func (p *Markdown) tableRow(data []byte, columns []CellAlignFlags, header bool) {
+ p.addBlock(TableRow, nil)
+ i, col := 0, 0
+
+ if data[i] == '|' && !isBackslashEscaped(data, i) {
+ i++
+ }
+
+ for col = 0; col < len(columns) && i < len(data); col++ {
+ for i < len(data) && data[i] == ' ' {
+ i++
+ }
+
+ cellStart := i
+
+ for i < len(data) && (data[i] != '|' || isBackslashEscaped(data, i)) && data[i] != '\n' {
+ i++
+ }
+
+ cellEnd := i
+
+ // skip the end-of-cell marker, possibly taking us past end of buffer
+ i++
+
+ for cellEnd > cellStart && cellEnd-1 < len(data) && data[cellEnd-1] == ' ' {
+ cellEnd--
+ }
+
+ cell := p.addBlock(TableCell, data[cellStart:cellEnd])
+ cell.IsHeader = header
+ cell.Align = columns[col]
+ }
+
+ // pad it out with empty columns to get the right number
+ for ; col < len(columns); col++ {
+ cell := p.addBlock(TableCell, nil)
+ cell.IsHeader = header
+ cell.Align = columns[col]
+ }
+
+ // silently ignore rows with too many cells
+}
+
+// returns blockquote prefix length
+func (p *Markdown) quotePrefix(data []byte) int {
+ i := 0
+ for i < 3 && i < len(data) && data[i] == ' ' {
+ i++
+ }
+ if i < len(data) && data[i] == '>' {
+ if i+1 < len(data) && data[i+1] == ' ' {
+ return i + 2
+ }
+ return i + 1
+ }
+ return 0
+}
+
+// blockquote ends with at least one blank line
+// followed by something without a blockquote prefix
+func (p *Markdown) terminateBlockquote(data []byte, beg, end int) bool {
+ if p.isEmpty(data[beg:]) <= 0 {
+ return false
+ }
+ if end >= len(data) {
+ return true
+ }
+ return p.quotePrefix(data[end:]) == 0 && p.isEmpty(data[end:]) == 0
+}
+
+// parse a blockquote fragment
+func (p *Markdown) quote(data []byte) int {
+ block := p.addBlock(BlockQuote, nil)
+ var raw bytes.Buffer
+ beg, end := 0, 0
+ for beg < len(data) {
+ end = beg
+ // Step over whole lines, collecting them. While doing that, check for
+ // fenced code and if one's found, incorporate it altogether,
+ // irregardless of any contents inside it
+ for end < len(data) && data[end] != '\n' {
+ if p.extensions&FencedCode != 0 {
+ if i := p.fencedCodeBlock(data[end:], false); i > 0 {
+ // -1 to compensate for the extra end++ after the loop:
+ end += i - 1
+ break
+ }
+ }
+ end++
+ }
+ if end < len(data) && data[end] == '\n' {
+ end++
+ }
+ if pre := p.quotePrefix(data[beg:]); pre > 0 {
+ // skip the prefix
+ beg += pre
+ } else if p.terminateBlockquote(data, beg, end) {
+ break
+ }
+ // this line is part of the blockquote
+ raw.Write(data[beg:end])
+ beg = end
+ }
+ p.block(raw.Bytes())
+ p.finalize(block)
+ return end
+}
+
+// returns prefix length for block code
+func (p *Markdown) codePrefix(data []byte) int {
+ if len(data) >= 1 && data[0] == '\t' {
+ return 1
+ }
+ if len(data) >= 4 && data[0] == ' ' && data[1] == ' ' && data[2] == ' ' && data[3] == ' ' {
+ return 4
+ }
+ return 0
+}
+
+func (p *Markdown) code(data []byte) int {
+ var work bytes.Buffer
+
+ i := 0
+ for i < len(data) {
+ beg := i
+ for i < len(data) && data[i] != '\n' {
+ i++
+ }
+ if i < len(data) && data[i] == '\n' {
+ i++
+ }
+
+ blankline := p.isEmpty(data[beg:i]) > 0
+ if pre := p.codePrefix(data[beg:i]); pre > 0 {
+ beg += pre
+ } else if !blankline {
+ // non-empty, non-prefixed line breaks the pre
+ i = beg
+ break
+ }
+
+ // verbatim copy to the working buffer
+ if blankline {
+ work.WriteByte('\n')
+ } else {
+ work.Write(data[beg:i])
+ }
+ }
+
+ // trim all the \n off the end of work
+ workbytes := work.Bytes()
+ eol := len(workbytes)
+ for eol > 0 && workbytes[eol-1] == '\n' {
+ eol--
+ }
+ if eol != len(workbytes) {
+ work.Truncate(eol)
+ }
+
+ work.WriteByte('\n')
+
+ block := p.addBlock(CodeBlock, work.Bytes()) // TODO: get rid of temp buffer
+ block.IsFenced = false
+ finalizeCodeBlock(block)
+
+ return i
+}
+
+// returns unordered list item prefix
+func (p *Markdown) uliPrefix(data []byte) int {
+ i := 0
+ // start with up to 3 spaces
+ for i < len(data) && i < 3 && data[i] == ' ' {
+ i++
+ }
+ if i >= len(data)-1 {
+ return 0
+ }
+ // need one of {'*', '+', '-'} followed by a space or a tab
+ if (data[i] != '*' && data[i] != '+' && data[i] != '-') ||
+ (data[i+1] != ' ' && data[i+1] != '\t') {
+ return 0
+ }
+ return i + 2
+}
+
+// returns ordered list item prefix
+func (p *Markdown) oliPrefix(data []byte) int {
+ i := 0
+
+ // start with up to 3 spaces
+ for i < 3 && i < len(data) && data[i] == ' ' {
+ i++
+ }
+
+ // count the digits
+ start := i
+ for i < len(data) && data[i] >= '0' && data[i] <= '9' {
+ i++
+ }
+ if start == i || i >= len(data)-1 {
+ return 0
+ }
+
+ // we need >= 1 digits followed by a dot and a space or a tab
+ if data[i] != '.' || !(data[i+1] == ' ' || data[i+1] == '\t') {
+ return 0
+ }
+ return i + 2
+}
+
+// returns definition list item prefix
+func (p *Markdown) dliPrefix(data []byte) int {
+ if len(data) < 2 {
+ return 0
+ }
+ i := 0
+ // need a ':' followed by a space or a tab
+ if data[i] != ':' || !(data[i+1] == ' ' || data[i+1] == '\t') {
+ return 0
+ }
+ for i < len(data) && data[i] == ' ' {
+ i++
+ }
+ return i + 2
+}
+
+// parse ordered or unordered list block
+func (p *Markdown) list(data []byte, flags ListType) int {
+ i := 0
+ flags |= ListItemBeginningOfList
+ block := p.addBlock(List, nil)
+ block.ListFlags = flags
+ block.Tight = true
+
+ for i < len(data) {
+ skip := p.listItem(data[i:], &flags)
+ if flags&ListItemContainsBlock != 0 {
+ block.ListData.Tight = false
+ }
+ i += skip
+ if skip == 0 || flags&ListItemEndOfList != 0 {
+ break
+ }
+ flags &= ^ListItemBeginningOfList
+ }
+
+ above := block.Parent
+ finalizeList(block)
+ p.tip = above
+ return i
+}
+
+// Returns true if the list item is not the same type as its parent list
+func (p *Markdown) listTypeChanged(data []byte, flags *ListType) bool {
+ if p.dliPrefix(data) > 0 && *flags&ListTypeDefinition == 0 {
+ return true
+ } else if p.oliPrefix(data) > 0 && *flags&ListTypeOrdered == 0 {
+ return true
+ } else if p.uliPrefix(data) > 0 && (*flags&ListTypeOrdered != 0 || *flags&ListTypeDefinition != 0) {
+ return true
+ }
+ return false
+}
+
+// Returns true if block ends with a blank line, descending if needed
+// into lists and sublists.
+func endsWithBlankLine(block *Node) bool {
+ // TODO: figure this out. Always false now.
+ for block != nil {
+ //if block.lastLineBlank {
+ //return true
+ //}
+ t := block.Type
+ if t == List || t == Item {
+ block = block.LastChild
+ } else {
+ break
+ }
+ }
+ return false
+}
+
+func finalizeList(block *Node) {
+ block.open = false
+ item := block.FirstChild
+ for item != nil {
+ // check for non-final list item ending with blank line:
+ if endsWithBlankLine(item) && item.Next != nil {
+ block.ListData.Tight = false
+ break
+ }
+ // recurse into children of list item, to see if there are spaces
+ // between any of them:
+ subItem := item.FirstChild
+ for subItem != nil {
+ if endsWithBlankLine(subItem) && (item.Next != nil || subItem.Next != nil) {
+ block.ListData.Tight = false
+ break
+ }
+ subItem = subItem.Next
+ }
+ item = item.Next
+ }
+}
+
+// Parse a single list item.
+// Assumes initial prefix is already removed if this is a sublist.
+func (p *Markdown) listItem(data []byte, flags *ListType) int {
+ // keep track of the indentation of the first line
+ itemIndent := 0
+ if data[0] == '\t' {
+ itemIndent += 4
+ } else {
+ for itemIndent < 3 && data[itemIndent] == ' ' {
+ itemIndent++
+ }
+ }
+
+ var bulletChar byte = '*'
+ i := p.uliPrefix(data)
+ if i == 0 {
+ i = p.oliPrefix(data)
+ } else {
+ bulletChar = data[i-2]
+ }
+ if i == 0 {
+ i = p.dliPrefix(data)
+ // reset definition term flag
+ if i > 0 {
+ *flags &= ^ListTypeTerm
+ }
+ }
+ if i == 0 {
+ // if in definition list, set term flag and continue
+ if *flags&ListTypeDefinition != 0 {
+ *flags |= ListTypeTerm
+ } else {
+ return 0
+ }
+ }
+
+ // skip leading whitespace on first line
+ for i < len(data) && data[i] == ' ' {
+ i++
+ }
+
+ // find the end of the line
+ line := i
+ for i > 0 && i < len(data) && data[i-1] != '\n' {
+ i++
+ }
+
+ // get working buffer
+ var raw bytes.Buffer
+
+ // put the first line into the working buffer
+ raw.Write(data[line:i])
+ line = i
+
+ // process the following lines
+ containsBlankLine := false
+ sublist := 0
+ codeBlockMarker := ""
+
+gatherlines:
+ for line < len(data) {
+ i++
+
+ // find the end of this line
+ for i < len(data) && data[i-1] != '\n' {
+ i++
+ }
+
+ // if it is an empty line, guess that it is part of this item
+ // and move on to the next line
+ if p.isEmpty(data[line:i]) > 0 {
+ containsBlankLine = true
+ line = i
+ continue
+ }
+
+ // calculate the indentation
+ indent := 0
+ indentIndex := 0
+ if data[line] == '\t' {
+ indentIndex++
+ indent += 4
+ } else {
+ for indent < 4 && line+indent < i && data[line+indent] == ' ' {
+ indent++
+ indentIndex++
+ }
+ }
+
+ chunk := data[line+indentIndex : i]
+
+ if p.extensions&FencedCode != 0 {
+ // determine if in or out of codeblock
+ // if in codeblock, ignore normal list processing
+ _, marker := isFenceLine(chunk, nil, codeBlockMarker)
+ if marker != "" {
+ if codeBlockMarker == "" {
+ // start of codeblock
+ codeBlockMarker = marker
+ } else {
+ // end of codeblock.
+ codeBlockMarker = ""
+ }
+ }
+ // we are in a codeblock, write line, and continue
+ if codeBlockMarker != "" || marker != "" {
+ raw.Write(data[line+indentIndex : i])
+ line = i
+ continue gatherlines
+ }
+ }
+
+ // evaluate how this line fits in
+ switch {
+ // is this a nested list item?
+ case (p.uliPrefix(chunk) > 0 && !p.isHRule(chunk)) ||
+ p.oliPrefix(chunk) > 0 ||
+ p.dliPrefix(chunk) > 0:
+
+ // to be a nested list, it must be indented more
+ // if not, it is either a different kind of list
+ // or the next item in the same list
+ if indent <= itemIndent {
+ if p.listTypeChanged(chunk, flags) {
+ *flags |= ListItemEndOfList
+ } else if containsBlankLine {
+ *flags |= ListItemContainsBlock
+ }
+
+ break gatherlines
+ }
+
+ if containsBlankLine {
+ *flags |= ListItemContainsBlock
+ }
+
+ // is this the first item in the nested list?
+ if sublist == 0 {
+ sublist = raw.Len()
+ }
+
+ // is this a nested prefix heading?
+ case p.isPrefixHeading(chunk):
+ // if the heading is not indented, it is not nested in the list
+ // and thus ends the list
+ if containsBlankLine && indent < 4 {
+ *flags |= ListItemEndOfList
+ break gatherlines
+ }
+ *flags |= ListItemContainsBlock
+
+ // anything following an empty line is only part
+ // of this item if it is indented 4 spaces
+ // (regardless of the indentation of the beginning of the item)
+ case containsBlankLine && indent < 4:
+ if *flags&ListTypeDefinition != 0 && i < len(data)-1 {
+ // is the next item still a part of this list?
+ next := i
+ for next < len(data) && data[next] != '\n' {
+ next++
+ }
+ for next < len(data)-1 && data[next] == '\n' {
+ next++
+ }
+ if i < len(data)-1 && data[i] != ':' && data[next] != ':' {
+ *flags |= ListItemEndOfList
+ }
+ } else {
+ *flags |= ListItemEndOfList
+ }
+ break gatherlines
+
+ // a blank line means this should be parsed as a block
+ case containsBlankLine:
+ raw.WriteByte('\n')
+ *flags |= ListItemContainsBlock
+ }
+
+ // if this line was preceded by one or more blanks,
+ // re-introduce the blank into the buffer
+ if containsBlankLine {
+ containsBlankLine = false
+ raw.WriteByte('\n')
+ }
+
+ // add the line into the working buffer without prefix
+ raw.Write(data[line+indentIndex : i])
+
+ line = i
+ }
+
+ rawBytes := raw.Bytes()
+
+ block := p.addBlock(Item, nil)
+ block.ListFlags = *flags
+ block.Tight = false
+ block.BulletChar = bulletChar
+ block.Delimiter = '.' // Only '.' is possible in Markdown, but ')' will also be possible in CommonMark
+
+ // render the contents of the list item
+ if *flags&ListItemContainsBlock != 0 && *flags&ListTypeTerm == 0 {
+ // intermediate render of block item, except for definition term
+ if sublist > 0 {
+ p.block(rawBytes[:sublist])
+ p.block(rawBytes[sublist:])
+ } else {
+ p.block(rawBytes)
+ }
+ } else {
+ // intermediate render of inline item
+ if sublist > 0 {
+ child := p.addChild(Paragraph, 0)
+ child.content = rawBytes[:sublist]
+ p.block(rawBytes[sublist:])
+ } else {
+ child := p.addChild(Paragraph, 0)
+ child.content = rawBytes
+ }
+ }
+ return line
+}
+
+// render a single paragraph that has already been parsed out
+func (p *Markdown) renderParagraph(data []byte) {
+ if len(data) == 0 {
+ return
+ }
+
+ // trim leading spaces
+ beg := 0
+ for data[beg] == ' ' {
+ beg++
+ }
+
+ end := len(data)
+ // trim trailing newline
+ if data[len(data)-1] == '\n' {
+ end--
+ }
+
+ // trim trailing spaces
+ for end > beg && data[end-1] == ' ' {
+ end--
+ }
+
+ p.addBlock(Paragraph, data[beg:end])
+}
+
+func (p *Markdown) paragraph(data []byte) int {
+ // prev: index of 1st char of previous line
+ // line: index of 1st char of current line
+ // i: index of cursor/end of current line
+ var prev, line, i int
+ tabSize := TabSizeDefault
+ if p.extensions&TabSizeEight != 0 {
+ tabSize = TabSizeDouble
+ }
+ // keep going until we find something to mark the end of the paragraph
+ for i < len(data) {
+ // mark the beginning of the current line
+ prev = line
+ current := data[i:]
+ line = i
+
+ // did we find a reference or a footnote? If so, end a paragraph
+ // preceding it and report that we have consumed up to the end of that
+ // reference:
+ if refEnd := isReference(p, current, tabSize); refEnd > 0 {
+ p.renderParagraph(data[:i])
+ return i + refEnd
+ }
+
+ // did we find a blank line marking the end of the paragraph?
+ if n := p.isEmpty(current); n > 0 {
+ // did this blank line followed by a definition list item?
+ if p.extensions&DefinitionLists != 0 {
+ if i < len(data)-1 && data[i+1] == ':' {
+ return p.list(data[prev:], ListTypeDefinition)
+ }
+ }
+
+ p.renderParagraph(data[:i])
+ return i + n
+ }
+
+ // an underline under some text marks a heading, so our paragraph ended on prev line
+ if i > 0 {
+ if level := p.isUnderlinedHeading(current); level > 0 {
+ // render the paragraph
+ p.renderParagraph(data[:prev])
+
+ // ignore leading and trailing whitespace
+ eol := i - 1
+ for prev < eol && data[prev] == ' ' {
+ prev++
+ }
+ for eol > prev && data[eol-1] == ' ' {
+ eol--
+ }
+
+ id := ""
+ if p.extensions&AutoHeadingIDs != 0 {
+ id = sanitized_anchor_name.Create(string(data[prev:eol]))
+ }
+
+ block := p.addBlock(Heading, data[prev:eol])
+ block.Level = level
+ block.HeadingID = id
+
+ // find the end of the underline
+ for i < len(data) && data[i] != '\n' {
+ i++
+ }
+ return i
+ }
+ }
+
+ // if the next line starts a block of HTML, then the paragraph ends here
+ if p.extensions&LaxHTMLBlocks != 0 {
+ if data[i] == '<' && p.html(current, false) > 0 {
+ // rewind to before the HTML block
+ p.renderParagraph(data[:i])
+ return i
+ }
+ }
+
+ // if there's a prefixed heading or a horizontal rule after this, paragraph is over
+ if p.isPrefixHeading(current) || p.isHRule(current) {
+ p.renderParagraph(data[:i])
+ return i
+ }
+
+ // if there's a fenced code block, paragraph is over
+ if p.extensions&FencedCode != 0 {
+ if p.fencedCodeBlock(current, false) > 0 {
+ p.renderParagraph(data[:i])
+ return i
+ }
+ }
+
+ // if there's a definition list item, prev line is a definition term
+ if p.extensions&DefinitionLists != 0 {
+ if p.dliPrefix(current) != 0 {
+ ret := p.list(data[prev:], ListTypeDefinition)
+ return ret
+ }
+ }
+
+ // if there's a list after this, paragraph is over
+ if p.extensions&NoEmptyLineBeforeBlock != 0 {
+ if p.uliPrefix(current) != 0 ||
+ p.oliPrefix(current) != 0 ||
+ p.quotePrefix(current) != 0 ||
+ p.codePrefix(current) != 0 {
+ p.renderParagraph(data[:i])
+ return i
+ }
+ }
+
+ // otherwise, scan to the beginning of the next line
+ nl := bytes.IndexByte(data[i:], '\n')
+ if nl >= 0 {
+ i += nl + 1
+ } else {
+ i += len(data[i:])
+ }
+ }
+
+ p.renderParagraph(data[:i])
+ return i
+}
+
+func skipChar(data []byte, start int, char byte) int {
+ i := start
+ for i < len(data) && data[i] == char {
+ i++
+ }
+ return i
+}
+
+func skipUntilChar(text []byte, start int, char byte) int {
+ i := start
+ for i < len(text) && text[i] != char {
+ i++
+ }
+ return i
+}
diff --git a/vendor/github.com/russross/blackfriday/v2/doc.go b/vendor/github.com/russross/blackfriday/v2/doc.go
new file mode 100644
index 0000000..5b3fa98
--- /dev/null
+++ b/vendor/github.com/russross/blackfriday/v2/doc.go
@@ -0,0 +1,18 @@
+// Package blackfriday is a markdown processor.
+//
+// It translates plain text with simple formatting rules into an AST, which can
+// then be further processed to HTML (provided by Blackfriday itself) or other
+// formats (provided by the community).
+//
+// The simplest way to invoke Blackfriday is to call the Run function. It will
+// take a text input and produce a text output in HTML (or other format).
+//
+// A slightly more sophisticated way to use Blackfriday is to create a Markdown
+// processor and to call Parse, which returns a syntax tree for the input
+// document. You can leverage Blackfriday's parsing for content extraction from
+// markdown documents. You can assign a custom renderer and set various options
+// to the Markdown processor.
+//
+// If you're interested in calling Blackfriday from command line, see
+// https://github.com/russross/blackfriday-tool.
+package blackfriday
diff --git a/vendor/github.com/russross/blackfriday/v2/esc.go b/vendor/github.com/russross/blackfriday/v2/esc.go
new file mode 100644
index 0000000..6385f27
--- /dev/null
+++ b/vendor/github.com/russross/blackfriday/v2/esc.go
@@ -0,0 +1,34 @@
+package blackfriday
+
+import (
+ "html"
+ "io"
+)
+
+var htmlEscaper = [256][]byte{
+ '&': []byte("&"),
+ '<': []byte("<"),
+ '>': []byte(">"),
+ '"': []byte("""),
+}
+
+func escapeHTML(w io.Writer, s []byte) {
+ var start, end int
+ for end < len(s) {
+ escSeq := htmlEscaper[s[end]]
+ if escSeq != nil {
+ w.Write(s[start:end])
+ w.Write(escSeq)
+ start = end + 1
+ }
+ end++
+ }
+ if start < len(s) && end <= len(s) {
+ w.Write(s[start:end])
+ }
+}
+
+func escLink(w io.Writer, text []byte) {
+ unesc := html.UnescapeString(string(text))
+ escapeHTML(w, []byte(unesc))
+}
diff --git a/vendor/github.com/russross/blackfriday/v2/go.mod b/vendor/github.com/russross/blackfriday/v2/go.mod
new file mode 100644
index 0000000..620b74e
--- /dev/null
+++ b/vendor/github.com/russross/blackfriday/v2/go.mod
@@ -0,0 +1 @@
+module github.com/russross/blackfriday/v2
diff --git a/vendor/github.com/russross/blackfriday/v2/html.go b/vendor/github.com/russross/blackfriday/v2/html.go
new file mode 100644
index 0000000..284c871
--- /dev/null
+++ b/vendor/github.com/russross/blackfriday/v2/html.go
@@ -0,0 +1,949 @@
+//
+// Blackfriday Markdown Processor
+// Available at http://github.com/russross/blackfriday
+//
+// Copyright © 2011 Russ Ross .
+// Distributed under the Simplified BSD License.
+// See README.md for details.
+//
+
+//
+//
+// HTML rendering backend
+//
+//
+
+package blackfriday
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "regexp"
+ "strings"
+)
+
+// HTMLFlags control optional behavior of HTML renderer.
+type HTMLFlags int
+
+// HTML renderer configuration options.
+const (
+ HTMLFlagsNone HTMLFlags = 0
+ SkipHTML HTMLFlags = 1 << iota // Skip preformatted HTML blocks
+ SkipImages // Skip embedded images
+ SkipLinks // Skip all links
+ Safelink // Only link to trusted protocols
+ NofollowLinks // Only link with rel="nofollow"
+ NoreferrerLinks // Only link with rel="noreferrer"
+ NoopenerLinks // Only link with rel="noopener"
+ HrefTargetBlank // Add a blank target
+ CompletePage // Generate a complete HTML page
+ UseXHTML // Generate XHTML output instead of HTML
+ FootnoteReturnLinks // Generate a link at the end of a footnote to return to the source
+ Smartypants // Enable smart punctuation substitutions
+ SmartypantsFractions // Enable smart fractions (with Smartypants)
+ SmartypantsDashes // Enable smart dashes (with Smartypants)
+ SmartypantsLatexDashes // Enable LaTeX-style dashes (with Smartypants)
+ SmartypantsAngledQuotes // Enable angled double quotes (with Smartypants) for double quotes rendering
+ SmartypantsQuotesNBSP // Enable « French guillemets » (with Smartypants)
+ TOC // Generate a table of contents
+)
+
+var (
+ htmlTagRe = regexp.MustCompile("(?i)^" + htmlTag)
+)
+
+const (
+ htmlTag = "(?:" + openTag + "|" + closeTag + "|" + htmlComment + "|" +
+ processingInstruction + "|" + declaration + "|" + cdata + ")"
+ closeTag = "" + tagName + "\\s*[>]"
+ openTag = "<" + tagName + attribute + "*" + "\\s*/?>"
+ attribute = "(?:" + "\\s+" + attributeName + attributeValueSpec + "?)"
+ attributeValue = "(?:" + unquotedValue + "|" + singleQuotedValue + "|" + doubleQuotedValue + ")"
+ attributeValueSpec = "(?:" + "\\s*=" + "\\s*" + attributeValue + ")"
+ attributeName = "[a-zA-Z_:][a-zA-Z0-9:._-]*"
+ cdata = ""
+ declaration = "]*>"
+ doubleQuotedValue = "\"[^\"]*\""
+ htmlComment = "|"
+ processingInstruction = "[<][?].*?[?][>]"
+ singleQuotedValue = "'[^']*'"
+ tagName = "[A-Za-z][A-Za-z0-9-]*"
+ unquotedValue = "[^\"'=<>`\\x00-\\x20]+"
+)
+
+// HTMLRendererParameters is a collection of supplementary parameters tweaking
+// the behavior of various parts of HTML renderer.
+type HTMLRendererParameters struct {
+ // Prepend this text to each relative URL.
+ AbsolutePrefix string
+ // Add this text to each footnote anchor, to ensure uniqueness.
+ FootnoteAnchorPrefix string
+ // Show this text inside the tag for a footnote return link, if the
+ // HTML_FOOTNOTE_RETURN_LINKS flag is enabled. If blank, the string
+ // [return] is used.
+ FootnoteReturnLinkContents string
+ // If set, add this text to the front of each Heading ID, to ensure
+ // uniqueness.
+ HeadingIDPrefix string
+ // If set, add this text to the back of each Heading ID, to ensure uniqueness.
+ HeadingIDSuffix string
+ // Increase heading levels: if the offset is 1, becomes etc.
+ // Negative offset is also valid.
+ // Resulting levels are clipped between 1 and 6.
+ HeadingLevelOffset int
+
+ Title string // Document title (used if CompletePage is set)
+ CSS string // Optional CSS file URL (used if CompletePage is set)
+ Icon string // Optional icon file URL (used if CompletePage is set)
+
+ Flags HTMLFlags // Flags allow customizing this renderer's behavior
+}
+
+// HTMLRenderer is a type that implements the Renderer interface for HTML output.
+//
+// Do not create this directly, instead use the NewHTMLRenderer function.
+type HTMLRenderer struct {
+ HTMLRendererParameters
+
+ closeTag string // how to end singleton tags: either " />" or ">"
+
+ // Track heading IDs to prevent ID collision in a single generation.
+ headingIDs map[string]int
+
+ lastOutputLen int
+ disableTags int
+
+ sr *SPRenderer
+}
+
+const (
+ xhtmlClose = " />"
+ htmlClose = ">"
+)
+
+// NewHTMLRenderer creates and configures an HTMLRenderer object, which
+// satisfies the Renderer interface.
+func NewHTMLRenderer(params HTMLRendererParameters) *HTMLRenderer {
+ // configure the rendering engine
+ closeTag := htmlClose
+ if params.Flags&UseXHTML != 0 {
+ closeTag = xhtmlClose
+ }
+
+ if params.FootnoteReturnLinkContents == "" {
+ params.FootnoteReturnLinkContents = `[return]`
+ }
+
+ return &HTMLRenderer{
+ HTMLRendererParameters: params,
+
+ closeTag: closeTag,
+ headingIDs: make(map[string]int),
+
+ sr: NewSmartypantsRenderer(params.Flags),
+ }
+}
+
+func isHTMLTag(tag []byte, tagname string) bool {
+ found, _ := findHTMLTagPos(tag, tagname)
+ return found
+}
+
+// Look for a character, but ignore it when it's in any kind of quotes, it
+// might be JavaScript
+func skipUntilCharIgnoreQuotes(html []byte, start int, char byte) int {
+ inSingleQuote := false
+ inDoubleQuote := false
+ inGraveQuote := false
+ i := start
+ for i < len(html) {
+ switch {
+ case html[i] == char && !inSingleQuote && !inDoubleQuote && !inGraveQuote:
+ return i
+ case html[i] == '\'':
+ inSingleQuote = !inSingleQuote
+ case html[i] == '"':
+ inDoubleQuote = !inDoubleQuote
+ case html[i] == '`':
+ inGraveQuote = !inGraveQuote
+ }
+ i++
+ }
+ return start
+}
+
+func findHTMLTagPos(tag []byte, tagname string) (bool, int) {
+ i := 0
+ if i < len(tag) && tag[0] != '<' {
+ return false, -1
+ }
+ i++
+ i = skipSpace(tag, i)
+
+ if i < len(tag) && tag[i] == '/' {
+ i++
+ }
+
+ i = skipSpace(tag, i)
+ j := 0
+ for ; i < len(tag); i, j = i+1, j+1 {
+ if j >= len(tagname) {
+ break
+ }
+
+ if strings.ToLower(string(tag[i]))[0] != tagname[j] {
+ return false, -1
+ }
+ }
+
+ if i == len(tag) {
+ return false, -1
+ }
+
+ rightAngle := skipUntilCharIgnoreQuotes(tag, i, '>')
+ if rightAngle >= i {
+ return true, rightAngle
+ }
+
+ return false, -1
+}
+
+func skipSpace(tag []byte, i int) int {
+ for i < len(tag) && isspace(tag[i]) {
+ i++
+ }
+ return i
+}
+
+func isRelativeLink(link []byte) (yes bool) {
+ // a tag begin with '#'
+ if link[0] == '#' {
+ return true
+ }
+
+ // link begin with '/' but not '//', the second maybe a protocol relative link
+ if len(link) >= 2 && link[0] == '/' && link[1] != '/' {
+ return true
+ }
+
+ // only the root '/'
+ if len(link) == 1 && link[0] == '/' {
+ return true
+ }
+
+ // current directory : begin with "./"
+ if bytes.HasPrefix(link, []byte("./")) {
+ return true
+ }
+
+ // parent directory : begin with "../"
+ if bytes.HasPrefix(link, []byte("../")) {
+ return true
+ }
+
+ return false
+}
+
+func (r *HTMLRenderer) ensureUniqueHeadingID(id string) string {
+ for count, found := r.headingIDs[id]; found; count, found = r.headingIDs[id] {
+ tmp := fmt.Sprintf("%s-%d", id, count+1)
+
+ if _, tmpFound := r.headingIDs[tmp]; !tmpFound {
+ r.headingIDs[id] = count + 1
+ id = tmp
+ } else {
+ id = id + "-1"
+ }
+ }
+
+ if _, found := r.headingIDs[id]; !found {
+ r.headingIDs[id] = 0
+ }
+
+ return id
+}
+
+func (r *HTMLRenderer) addAbsPrefix(link []byte) []byte {
+ if r.AbsolutePrefix != "" && isRelativeLink(link) && link[0] != '.' {
+ newDest := r.AbsolutePrefix
+ if link[0] != '/' {
+ newDest += "/"
+ }
+ newDest += string(link)
+ return []byte(newDest)
+ }
+ return link
+}
+
+func appendLinkAttrs(attrs []string, flags HTMLFlags, link []byte) []string {
+ if isRelativeLink(link) {
+ return attrs
+ }
+ val := []string{}
+ if flags&NofollowLinks != 0 {
+ val = append(val, "nofollow")
+ }
+ if flags&NoreferrerLinks != 0 {
+ val = append(val, "noreferrer")
+ }
+ if flags&NoopenerLinks != 0 {
+ val = append(val, "noopener")
+ }
+ if flags&HrefTargetBlank != 0 {
+ attrs = append(attrs, "target=\"_blank\"")
+ }
+ if len(val) == 0 {
+ return attrs
+ }
+ attr := fmt.Sprintf("rel=%q", strings.Join(val, " "))
+ return append(attrs, attr)
+}
+
+func isMailto(link []byte) bool {
+ return bytes.HasPrefix(link, []byte("mailto:"))
+}
+
+func needSkipLink(flags HTMLFlags, dest []byte) bool {
+ if flags&SkipLinks != 0 {
+ return true
+ }
+ return flags&Safelink != 0 && !isSafeLink(dest) && !isMailto(dest)
+}
+
+func isSmartypantable(node *Node) bool {
+ pt := node.Parent.Type
+ return pt != Link && pt != CodeBlock && pt != Code
+}
+
+func appendLanguageAttr(attrs []string, info []byte) []string {
+ if len(info) == 0 {
+ return attrs
+ }
+ endOfLang := bytes.IndexAny(info, "\t ")
+ if endOfLang < 0 {
+ endOfLang = len(info)
+ }
+ return append(attrs, fmt.Sprintf("class=\"language-%s\"", info[:endOfLang]))
+}
+
+func (r *HTMLRenderer) tag(w io.Writer, name []byte, attrs []string) {
+ w.Write(name)
+ if len(attrs) > 0 {
+ w.Write(spaceBytes)
+ w.Write([]byte(strings.Join(attrs, " ")))
+ }
+ w.Write(gtBytes)
+ r.lastOutputLen = 1
+}
+
+func footnoteRef(prefix string, node *Node) []byte {
+ urlFrag := prefix + string(slugify(node.Destination))
+ anchor := fmt.Sprintf(`%d`, urlFrag, node.NoteID)
+ return []byte(fmt.Sprintf(``, urlFrag, anchor))
+}
+
+func footnoteItem(prefix string, slug []byte) []byte {
+ return []byte(fmt.Sprintf(`
`, prefix, slug))
+}
+
+func footnoteReturnLink(prefix, returnLink string, slug []byte) []byte {
+ const format = ` `
+ return []byte(fmt.Sprintf(format, prefix, slug, returnLink))
+}
+
+func itemOpenCR(node *Node) bool {
+ if node.Prev == nil {
+ return false
+ }
+ ld := node.Parent.ListData
+ return !ld.Tight && ld.ListFlags&ListTypeDefinition == 0
+}
+
+func skipParagraphTags(node *Node) bool {
+ grandparent := node.Parent.Parent
+ if grandparent == nil || grandparent.Type != List {
+ return false
+ }
+ tightOrTerm := grandparent.Tight || node.Parent.ListFlags&ListTypeTerm != 0
+ return grandparent.Type == List && tightOrTerm
+}
+
+func cellAlignment(align CellAlignFlags) string {
+ switch align {
+ case TableAlignmentLeft:
+ return "left"
+ case TableAlignmentRight:
+ return "right"
+ case TableAlignmentCenter:
+ return "center"
+ default:
+ return ""
+ }
+}
+
+func (r *HTMLRenderer) out(w io.Writer, text []byte) {
+ if r.disableTags > 0 {
+ w.Write(htmlTagRe.ReplaceAll(text, []byte{}))
+ } else {
+ w.Write(text)
+ }
+ r.lastOutputLen = len(text)
+}
+
+func (r *HTMLRenderer) cr(w io.Writer) {
+ if r.lastOutputLen > 0 {
+ r.out(w, nlBytes)
+ }
+}
+
+var (
+ nlBytes = []byte{'\n'}
+ gtBytes = []byte{'>'}
+ spaceBytes = []byte{' '}
+)
+
+var (
+ brTag = []byte("
")
+ brXHTMLTag = []byte("
")
+ emTag = []byte("")
+ emCloseTag = []byte("")
+ strongTag = []byte("")
+ strongCloseTag = []byte("")
+ delTag = []byte("")
+ delCloseTag = []byte("")
+ ttTag = []byte("")
+ ttCloseTag = []byte("")
+ aTag = []byte("")
+ preTag = []byte("")
+ preCloseTag = []byte("
")
+ codeTag = []byte("")
+ codeCloseTag = []byte("
")
+ pTag = []byte("")
+ pCloseTag = []byte("
")
+ blockquoteTag = []byte("")
+ blockquoteCloseTag = []byte("
")
+ hrTag = []byte("
")
+ hrXHTMLTag = []byte("
")
+ ulTag = []byte("")
+ ulCloseTag = []byte("
")
+ olTag = []byte("")
+ olCloseTag = []byte("
")
+ dlTag = []byte("")
+ dlCloseTag = []byte("
")
+ liTag = []byte("")
+ liCloseTag = []byte("")
+ ddTag = []byte("")
+ ddCloseTag = []byte("")
+ dtTag = []byte("")
+ dtCloseTag = []byte("")
+ tableTag = []byte("")
+ tableCloseTag = []byte("
")
+ tdTag = []byte("")
+ thTag = []byte(" | ")
+ theadTag = []byte("")
+ theadCloseTag = []byte("")
+ tbodyTag = []byte(" | ")
+ tbodyCloseTag = []byte("")
+ trTag = []byte("")
+ trCloseTag = []byte("
")
+ h1Tag = []byte("")
+ h2Tag = []byte("")
+ h3Tag = []byte("")
+ h4Tag = []byte("")
+ h5Tag = []byte("")
+ h6Tag = []byte("")
+
+ footnotesDivBytes = []byte("\n\n")
+)
+
+func headingTagsFromLevel(level int) ([]byte, []byte) {
+ if level <= 1 {
+ return h1Tag, h1CloseTag
+ }
+ switch level {
+ case 2:
+ return h2Tag, h2CloseTag
+ case 3:
+ return h3Tag, h3CloseTag
+ case 4:
+ return h4Tag, h4CloseTag
+ case 5:
+ return h5Tag, h5CloseTag
+ }
+ return h6Tag, h6CloseTag
+}
+
+func (r *HTMLRenderer) outHRTag(w io.Writer) {
+ if r.Flags&UseXHTML == 0 {
+ r.out(w, hrTag)
+ } else {
+ r.out(w, hrXHTMLTag)
+ }
+}
+
+// RenderNode is a default renderer of a single node of a syntax tree. For
+// block nodes it will be called twice: first time with entering=true, second
+// time with entering=false, so that it could know when it's working on an open
+// tag and when on close. It writes the result to w.
+//
+// The return value is a way to tell the calling walker to adjust its walk
+// pattern: e.g. it can terminate the traversal by returning Terminate. Or it
+// can ask the walker to skip a subtree of this node by returning SkipChildren.
+// The typical behavior is to return GoToNext, which asks for the usual
+// traversal to the next node.
+func (r *HTMLRenderer) RenderNode(w io.Writer, node *Node, entering bool) WalkStatus {
+ attrs := []string{}
+ switch node.Type {
+ case Text:
+ if r.Flags&Smartypants != 0 {
+ var tmp bytes.Buffer
+ escapeHTML(&tmp, node.Literal)
+ r.sr.Process(w, tmp.Bytes())
+ } else {
+ if node.Parent.Type == Link {
+ escLink(w, node.Literal)
+ } else {
+ escapeHTML(w, node.Literal)
+ }
+ }
+ case Softbreak:
+ r.cr(w)
+ // TODO: make it configurable via out(renderer.softbreak)
+ case Hardbreak:
+ if r.Flags&UseXHTML == 0 {
+ r.out(w, brTag)
+ } else {
+ r.out(w, brXHTMLTag)
+ }
+ r.cr(w)
+ case Emph:
+ if entering {
+ r.out(w, emTag)
+ } else {
+ r.out(w, emCloseTag)
+ }
+ case Strong:
+ if entering {
+ r.out(w, strongTag)
+ } else {
+ r.out(w, strongCloseTag)
+ }
+ case Del:
+ if entering {
+ r.out(w, delTag)
+ } else {
+ r.out(w, delCloseTag)
+ }
+ case HTMLSpan:
+ if r.Flags&SkipHTML != 0 {
+ break
+ }
+ r.out(w, node.Literal)
+ case Link:
+ // mark it but don't link it if it is not a safe link: no smartypants
+ dest := node.LinkData.Destination
+ if needSkipLink(r.Flags, dest) {
+ if entering {
+ r.out(w, ttTag)
+ } else {
+ r.out(w, ttCloseTag)
+ }
+ } else {
+ if entering {
+ dest = r.addAbsPrefix(dest)
+ var hrefBuf bytes.Buffer
+ hrefBuf.WriteString("href=\"")
+ escLink(&hrefBuf, dest)
+ hrefBuf.WriteByte('"')
+ attrs = append(attrs, hrefBuf.String())
+ if node.NoteID != 0 {
+ r.out(w, footnoteRef(r.FootnoteAnchorPrefix, node))
+ break
+ }
+ attrs = appendLinkAttrs(attrs, r.Flags, dest)
+ if len(node.LinkData.Title) > 0 {
+ var titleBuff bytes.Buffer
+ titleBuff.WriteString("title=\"")
+ escapeHTML(&titleBuff, node.LinkData.Title)
+ titleBuff.WriteByte('"')
+ attrs = append(attrs, titleBuff.String())
+ }
+ r.tag(w, aTag, attrs)
+ } else {
+ if node.NoteID != 0 {
+ break
+ }
+ r.out(w, aCloseTag)
+ }
+ }
+ case Image:
+ if r.Flags&SkipImages != 0 {
+ return SkipChildren
+ }
+ if entering {
+ dest := node.LinkData.Destination
+ dest = r.addAbsPrefix(dest)
+ if r.disableTags == 0 {
+ //if options.safe && potentiallyUnsafe(dest) {
+ //out(w, ``))
+ }
+ }
+ case Code:
+ r.out(w, codeTag)
+ escapeHTML(w, node.Literal)
+ r.out(w, codeCloseTag)
+ case Document:
+ break
+ case Paragraph:
+ if skipParagraphTags(node) {
+ break
+ }
+ if entering {
+ // TODO: untangle this clusterfuck about when the newlines need
+ // to be added and when not.
+ if node.Prev != nil {
+ switch node.Prev.Type {
+ case HTMLBlock, List, Paragraph, Heading, CodeBlock, BlockQuote, HorizontalRule:
+ r.cr(w)
+ }
+ }
+ if node.Parent.Type == BlockQuote && node.Prev == nil {
+ r.cr(w)
+ }
+ r.out(w, pTag)
+ } else {
+ r.out(w, pCloseTag)
+ if !(node.Parent.Type == Item && node.Next == nil) {
+ r.cr(w)
+ }
+ }
+ case BlockQuote:
+ if entering {
+ r.cr(w)
+ r.out(w, blockquoteTag)
+ } else {
+ r.out(w, blockquoteCloseTag)
+ r.cr(w)
+ }
+ case HTMLBlock:
+ if r.Flags&SkipHTML != 0 {
+ break
+ }
+ r.cr(w)
+ r.out(w, node.Literal)
+ r.cr(w)
+ case Heading:
+ headingLevel := r.HTMLRendererParameters.HeadingLevelOffset + node.Level
+ openTag, closeTag := headingTagsFromLevel(headingLevel)
+ if entering {
+ if node.IsTitleblock {
+ attrs = append(attrs, `class="title"`)
+ }
+ if node.HeadingID != "" {
+ id := r.ensureUniqueHeadingID(node.HeadingID)
+ if r.HeadingIDPrefix != "" {
+ id = r.HeadingIDPrefix + id
+ }
+ if r.HeadingIDSuffix != "" {
+ id = id + r.HeadingIDSuffix
+ }
+ attrs = append(attrs, fmt.Sprintf(`id="%s"`, id))
+ }
+ r.cr(w)
+ r.tag(w, openTag, attrs)
+ } else {
+ r.out(w, closeTag)
+ if !(node.Parent.Type == Item && node.Next == nil) {
+ r.cr(w)
+ }
+ }
+ case HorizontalRule:
+ r.cr(w)
+ r.outHRTag(w)
+ r.cr(w)
+ case List:
+ openTag := ulTag
+ closeTag := ulCloseTag
+ if node.ListFlags&ListTypeOrdered != 0 {
+ openTag = olTag
+ closeTag = olCloseTag
+ }
+ if node.ListFlags&ListTypeDefinition != 0 {
+ openTag = dlTag
+ closeTag = dlCloseTag
+ }
+ if entering {
+ if node.IsFootnotesList {
+ r.out(w, footnotesDivBytes)
+ r.outHRTag(w)
+ r.cr(w)
+ }
+ r.cr(w)
+ if node.Parent.Type == Item && node.Parent.Parent.Tight {
+ r.cr(w)
+ }
+ r.tag(w, openTag[:len(openTag)-1], attrs)
+ r.cr(w)
+ } else {
+ r.out(w, closeTag)
+ //cr(w)
+ //if node.parent.Type != Item {
+ // cr(w)
+ //}
+ if node.Parent.Type == Item && node.Next != nil {
+ r.cr(w)
+ }
+ if node.Parent.Type == Document || node.Parent.Type == BlockQuote {
+ r.cr(w)
+ }
+ if node.IsFootnotesList {
+ r.out(w, footnotesCloseDivBytes)
+ }
+ }
+ case Item:
+ openTag := liTag
+ closeTag := liCloseTag
+ if node.ListFlags&ListTypeDefinition != 0 {
+ openTag = ddTag
+ closeTag = ddCloseTag
+ }
+ if node.ListFlags&ListTypeTerm != 0 {
+ openTag = dtTag
+ closeTag = dtCloseTag
+ }
+ if entering {
+ if itemOpenCR(node) {
+ r.cr(w)
+ }
+ if node.ListData.RefLink != nil {
+ slug := slugify(node.ListData.RefLink)
+ r.out(w, footnoteItem(r.FootnoteAnchorPrefix, slug))
+ break
+ }
+ r.out(w, openTag)
+ } else {
+ if node.ListData.RefLink != nil {
+ slug := slugify(node.ListData.RefLink)
+ if r.Flags&FootnoteReturnLinks != 0 {
+ r.out(w, footnoteReturnLink(r.FootnoteAnchorPrefix, r.FootnoteReturnLinkContents, slug))
+ }
+ }
+ r.out(w, closeTag)
+ r.cr(w)
+ }
+ case CodeBlock:
+ attrs = appendLanguageAttr(attrs, node.Info)
+ r.cr(w)
+ r.out(w, preTag)
+ r.tag(w, codeTag[:len(codeTag)-1], attrs)
+ escapeHTML(w, node.Literal)
+ r.out(w, codeCloseTag)
+ r.out(w, preCloseTag)
+ if node.Parent.Type != Item {
+ r.cr(w)
+ }
+ case Table:
+ if entering {
+ r.cr(w)
+ r.out(w, tableTag)
+ } else {
+ r.out(w, tableCloseTag)
+ r.cr(w)
+ }
+ case TableCell:
+ openTag := tdTag
+ closeTag := tdCloseTag
+ if node.IsHeader {
+ openTag = thTag
+ closeTag = thCloseTag
+ }
+ if entering {
+ align := cellAlignment(node.Align)
+ if align != "" {
+ attrs = append(attrs, fmt.Sprintf(`align="%s"`, align))
+ }
+ if node.Prev == nil {
+ r.cr(w)
+ }
+ r.tag(w, openTag, attrs)
+ } else {
+ r.out(w, closeTag)
+ r.cr(w)
+ }
+ case TableHead:
+ if entering {
+ r.cr(w)
+ r.out(w, theadTag)
+ } else {
+ r.out(w, theadCloseTag)
+ r.cr(w)
+ }
+ case TableBody:
+ if entering {
+ r.cr(w)
+ r.out(w, tbodyTag)
+ // XXX: this is to adhere to a rather silly test. Should fix test.
+ if node.FirstChild == nil {
+ r.cr(w)
+ }
+ } else {
+ r.out(w, tbodyCloseTag)
+ r.cr(w)
+ }
+ case TableRow:
+ if entering {
+ r.cr(w)
+ r.out(w, trTag)
+ } else {
+ r.out(w, trCloseTag)
+ r.cr(w)
+ }
+ default:
+ panic("Unknown node type " + node.Type.String())
+ }
+ return GoToNext
+}
+
+// RenderHeader writes HTML document preamble and TOC if requested.
+func (r *HTMLRenderer) RenderHeader(w io.Writer, ast *Node) {
+ r.writeDocumentHeader(w)
+ if r.Flags&TOC != 0 {
+ r.writeTOC(w, ast)
+ }
+}
+
+// RenderFooter writes HTML document footer.
+func (r *HTMLRenderer) RenderFooter(w io.Writer, ast *Node) {
+ if r.Flags&CompletePage == 0 {
+ return
+ }
+ io.WriteString(w, "\n