From a5f56c35d70f8c20d39a3228ca2c511b9c78c43b Mon Sep 17 00:00:00 2001
From: Jacob Brewer
Date: Sat, 18 Jan 2025 09:50:05 +0000
Subject: [PATCH] Adding status cmd
---
cmd_status.go | 35 +
go.mod | 11 +
go.sum | 89 +
main.go | 1 +
pkg/migrations/status.go | 32 +
pkg/migrations/versioning.go | 1 +
vendor/atomicgo.dev/cursor/.gitignore | 31 +
vendor/atomicgo.dev/cursor/.golangci.yml | 99 +
vendor/atomicgo.dev/cursor/CHANGELOG.md | 20 +
vendor/atomicgo.dev/cursor/LICENSE | 21 +
vendor/atomicgo.dev/cursor/README.md | 598 +++
vendor/atomicgo.dev/cursor/area.go | 164 +
vendor/atomicgo.dev/cursor/area_other.go | 13 +
vendor/atomicgo.dev/cursor/area_windows.go | 21 +
vendor/atomicgo.dev/cursor/codecov.yml | 8 +
vendor/atomicgo.dev/cursor/cursor.go | 26 +
vendor/atomicgo.dev/cursor/cursor_other.go | 67 +
.../atomicgo.dev/cursor/cursor_test_linux.go | 130 +
vendor/atomicgo.dev/cursor/cursor_windows.go | 118 +
vendor/atomicgo.dev/cursor/doc.go | 9 +
vendor/atomicgo.dev/cursor/syscall_windows.go | 43 +
vendor/atomicgo.dev/cursor/utils.go | 151 +
vendor/atomicgo.dev/keyboard/.gitignore | 33 +
vendor/atomicgo.dev/keyboard/.golangci.yml | 71 +
vendor/atomicgo.dev/keyboard/LICENSE | 21 +
vendor/atomicgo.dev/keyboard/README.md | 185 +
vendor/atomicgo.dev/keyboard/codecov.yml | 8 +
vendor/atomicgo.dev/keyboard/doc.go | 62 +
vendor/atomicgo.dev/keyboard/input.go | 237 +
vendor/atomicgo.dev/keyboard/internal/keys.go | 38 +
vendor/atomicgo.dev/keyboard/keyboard.go | 179 +
vendor/atomicgo.dev/keyboard/keys/keys.go | 235 +
vendor/atomicgo.dev/keyboard/tty_unix.go | 35 +
vendor/atomicgo.dev/keyboard/tty_windows.go | 47 +
vendor/atomicgo.dev/keyboard/utils.go | 8 +
vendor/atomicgo.dev/keyboard/utils_windows.go | 7 +
vendor/atomicgo.dev/schedule/.gitignore | 40 +
vendor/atomicgo.dev/schedule/.golangci.yml | 99 +
vendor/atomicgo.dev/schedule/LICENSE | 21 +
vendor/atomicgo.dev/schedule/README.md | 281 ++
vendor/atomicgo.dev/schedule/codecov.yml | 8 +
vendor/atomicgo.dev/schedule/doc.go | 6 +
vendor/atomicgo.dev/schedule/schedule.go | 116 +
.../containerd/console/.golangci.yml | 20 +
vendor/github.com/containerd/console/LICENSE | 191 +
.../github.com/containerd/console/README.md | 29 +
.../github.com/containerd/console/console.go | 87 +
.../containerd/console/console_linux.go | 280 ++
.../containerd/console/console_unix.go | 156 +
.../containerd/console/console_windows.go | 216 +
.../containerd/console/console_zos.go | 163 +
.../containerd/console/pty_freebsd_cgo.go | 45 +
.../containerd/console/pty_freebsd_nocgo.go | 36 +
.../github.com/containerd/console/pty_unix.go | 30 +
.../containerd/console/tc_darwin.go | 44 +
.../containerd/console/tc_freebsd_cgo.go | 57 +
.../containerd/console/tc_freebsd_nocgo.go | 55 +
.../github.com/containerd/console/tc_linux.go | 51 +
.../containerd/console/tc_netbsd.go | 45 +
.../containerd/console/tc_openbsd_cgo.go | 51 +
.../containerd/console/tc_openbsd_nocgo.go | 47 +
.../containerd/console/tc_solaris_cgo.go | 51 +
.../containerd/console/tc_solaris_nocgo.go | 47 +
.../github.com/containerd/console/tc_unix.go | 91 +
.../github.com/containerd/console/tc_zos.go | 26 +
vendor/github.com/gookit/color/.gitignore | 20 +
vendor/github.com/gookit/color/.nojekyll | 0
vendor/github.com/gookit/color/LICENSE | 20 +
vendor/github.com/gookit/color/README.md | 580 +++
.../github.com/gookit/color/README.zh-CN.md | 591 +++
vendor/github.com/gookit/color/any.go | 6 +
vendor/github.com/gookit/color/color.go | 251 ++
vendor/github.com/gookit/color/color_16.go | 511 +++
vendor/github.com/gookit/color/color_256.go | 303 ++
vendor/github.com/gookit/color/color_rgb.go | 443 ++
vendor/github.com/gookit/color/color_tag.go | 567 +++
vendor/github.com/gookit/color/convert.go | 966 +++++
vendor/github.com/gookit/color/detect_env.go | 291 ++
.../github.com/gookit/color/detect_nonwin.go | 49 +
.../github.com/gookit/color/detect_windows.go | 250 ++
vendor/github.com/gookit/color/index.html | 25 +
vendor/github.com/gookit/color/printer.go | 133 +
vendor/github.com/gookit/color/quickstart.go | 108 +
vendor/github.com/gookit/color/style.go | 324 ++
vendor/github.com/gookit/color/utils.go | 209 +
.../github.com/lithammer/fuzzysearch/LICENSE | 21 +
.../lithammer/fuzzysearch/fuzzy/fuzzy.go | 292 ++
.../fuzzysearch/fuzzy/levenshtein.go | 45 +
vendor/github.com/mattn/go-runewidth/LICENSE | 21 +
.../github.com/mattn/go-runewidth/README.md | 27 +
.../mattn/go-runewidth/runewidth.go | 358 ++
.../mattn/go-runewidth/runewidth_appengine.go | 9 +
.../mattn/go-runewidth/runewidth_js.go | 9 +
.../mattn/go-runewidth/runewidth_posix.go | 81 +
.../mattn/go-runewidth/runewidth_table.go | 450 ++
.../mattn/go-runewidth/runewidth_windows.go | 28 +
vendor/github.com/pterm/pterm/.gitignore | 22 +
vendor/github.com/pterm/pterm/.golangci.yml | 95 +
.../github.com/pterm/pterm/CODE_OF_CONDUCT.md | 76 +
vendor/github.com/pterm/pterm/CONTRIBUTING.md | 225 +
vendor/github.com/pterm/pterm/LICENSE | 21 +
vendor/github.com/pterm/pterm/README.md | 3814 +++++++++++++++++
vendor/github.com/pterm/pterm/SECURITY.md | 24 +
vendor/github.com/pterm/pterm/area_printer.go | 139 +
vendor/github.com/pterm/pterm/atoms.go | 42 +
vendor/github.com/pterm/pterm/barchart.go | 424 ++
.../pterm/pterm/basic_text_printer.go | 123 +
.../github.com/pterm/pterm/bigtext_printer.go | 551 +++
vendor/github.com/pterm/pterm/box_printer.go | 371 ++
.../pterm/pterm/bulletlist_printer.go | 139 +
.../github.com/pterm/pterm/center_printer.go | 171 +
vendor/github.com/pterm/pterm/codecov.yml | 8 +
vendor/github.com/pterm/pterm/color.go | 383 ++
.../pterm/pterm/conventionalcommit.json | 61 +
vendor/github.com/pterm/pterm/coverage.txt | 1030 +++++
vendor/github.com/pterm/pterm/deprecated.go | 148 +
vendor/github.com/pterm/pterm/errors.go | 14 +
.../github.com/pterm/pterm/header_printer.go | 239 ++
.../github.com/pterm/pterm/heatmap_printer.go | 744 ++++
.../pterm/interactive_confirm_printer.go | 186 +
.../pterm/interactive_continue_printer.go | 197 +
.../pterm/interactive_multiselect_printer.go | 402 ++
.../pterm/pterm/interactive_select_printer.go | 319 ++
.../pterm/interactive_textinput_printer.go | 306 ++
.../pterm/pterm/interface_live_printer.go | 18 +
.../pterm/interface_renderable_printer.go | 11 +
.../pterm/pterm/interface_text_printer.go | 48 +
.../pterm/internal/cancelation_signal.go | 22 +
.../pterm/pterm/internal/center_text.go | 46 +
.../pterm/pterm/internal/collection.go | 7 +
.../github.com/pterm/pterm/internal/exit.go | 14 +
.../pterm/pterm/internal/longest_line.go | 21 +
.../pterm/internal/map_range_to_range.go | 8 +
.../pterm/pterm/internal/max_text_width.go | 21 +
.../pterm/pterm/internal/percentage.go | 13 +
.../pterm/internal/remove_and_count_prefix.go | 11 +
.../pterm/pterm/internal/rgb_complementary.go | 5 +
.../pterm/pterm/internal/title_in_line.go | 28 +
.../github.com/pterm/pterm/internal/utils.go | 8 +
.../pterm/pterm/internal/with_boolean.go | 9 +
vendor/github.com/pterm/pterm/logger.go | 447 ++
.../pterm/pterm/multi_live_printer.go | 124 +
.../github.com/pterm/pterm/panel_printer.go | 190 +
.../pterm/pterm/paragraph_printer.go | 142 +
.../github.com/pterm/pterm/prefix_printer.go | 364 ++
vendor/github.com/pterm/pterm/print.go | 191 +
.../pterm/pterm/progressbar_printer.go | 355 ++
vendor/github.com/pterm/pterm/pterm.go | 72 +
vendor/github.com/pterm/pterm/rgb.go | 298 ++
.../github.com/pterm/pterm/section_printer.go | 175 +
vendor/github.com/pterm/pterm/slog_handler.go | 90 +
.../github.com/pterm/pterm/spinner_printer.go | 277 ++
.../github.com/pterm/pterm/table_printer.go | 306 ++
vendor/github.com/pterm/pterm/terminal.go | 64 +
vendor/github.com/pterm/pterm/theme.go | 259 ++
vendor/github.com/pterm/pterm/tree_printer.go | 161 +
vendor/github.com/rivo/uniseg/LICENSE.txt | 21 +
vendor/github.com/rivo/uniseg/README.md | 157 +
vendor/github.com/rivo/uniseg/doc.go | 108 +
.../github.com/rivo/uniseg/eastasianwidth.go | 2556 +++++++++++
.../rivo/uniseg/emojipresentation.go | 285 ++
.../github.com/rivo/uniseg/gen_breaktest.go | 213 +
.../github.com/rivo/uniseg/gen_properties.go | 256 ++
vendor/github.com/rivo/uniseg/grapheme.go | 334 ++
.../rivo/uniseg/graphemeproperties.go | 1891 ++++++++
.../github.com/rivo/uniseg/graphemerules.go | 138 +
vendor/github.com/rivo/uniseg/line.go | 134 +
.../github.com/rivo/uniseg/lineproperties.go | 3513 +++++++++++++++
vendor/github.com/rivo/uniseg/linerules.go | 470 ++
vendor/github.com/rivo/uniseg/properties.go | 168 +
vendor/github.com/rivo/uniseg/sentence.go | 90 +
.../rivo/uniseg/sentenceproperties.go | 2815 ++++++++++++
.../github.com/rivo/uniseg/sentencerules.go | 205 +
vendor/github.com/rivo/uniseg/step.go | 246 ++
vendor/github.com/rivo/uniseg/width.go | 54 +
vendor/github.com/rivo/uniseg/word.go | 89 +
.../github.com/rivo/uniseg/wordproperties.go | 1848 ++++++++
vendor/github.com/rivo/uniseg/wordrules.go | 246 ++
vendor/github.com/xo/terminfo/.gitignore | 9 +
vendor/github.com/xo/terminfo/LICENSE | 21 +
vendor/github.com/xo/terminfo/README.md | 139 +
vendor/github.com/xo/terminfo/caps.go | 31 +
vendor/github.com/xo/terminfo/capvals.go | 1525 +++++++
vendor/github.com/xo/terminfo/color.go | 88 +
vendor/github.com/xo/terminfo/dec.go | 245 ++
vendor/github.com/xo/terminfo/load.go | 64 +
vendor/github.com/xo/terminfo/param.go | 405 ++
vendor/github.com/xo/terminfo/stack.go | 48 +
vendor/github.com/xo/terminfo/terminfo.go | 479 +++
vendor/golang.org/x/sys/plan9/asm.s | 8 +
vendor/golang.org/x/sys/plan9/asm_plan9_386.s | 30 +
.../golang.org/x/sys/plan9/asm_plan9_amd64.s | 30 +
vendor/golang.org/x/sys/plan9/asm_plan9_arm.s | 25 +
vendor/golang.org/x/sys/plan9/const_plan9.go | 70 +
vendor/golang.org/x/sys/plan9/dir_plan9.go | 212 +
vendor/golang.org/x/sys/plan9/env_plan9.go | 31 +
vendor/golang.org/x/sys/plan9/errors_plan9.go | 50 +
vendor/golang.org/x/sys/plan9/mkall.sh | 150 +
vendor/golang.org/x/sys/plan9/mkerrors.sh | 246 ++
.../golang.org/x/sys/plan9/mksysnum_plan9.sh | 23 +
.../golang.org/x/sys/plan9/pwd_go15_plan9.go | 21 +
vendor/golang.org/x/sys/plan9/pwd_plan9.go | 23 +
vendor/golang.org/x/sys/plan9/race.go | 30 +
vendor/golang.org/x/sys/plan9/race0.go | 25 +
vendor/golang.org/x/sys/plan9/str.go | 22 +
vendor/golang.org/x/sys/plan9/syscall.go | 109 +
.../golang.org/x/sys/plan9/syscall_plan9.go | 361 ++
.../x/sys/plan9/zsyscall_plan9_386.go | 284 ++
.../x/sys/plan9/zsyscall_plan9_amd64.go | 284 ++
.../x/sys/plan9/zsyscall_plan9_arm.go | 284 ++
.../golang.org/x/sys/plan9/zsysnum_plan9.go | 49 +
vendor/golang.org/x/term/CONTRIBUTING.md | 26 +
vendor/golang.org/x/term/LICENSE | 27 +
vendor/golang.org/x/term/PATENTS | 22 +
vendor/golang.org/x/term/README.md | 16 +
vendor/golang.org/x/term/codereview.cfg | 1 +
vendor/golang.org/x/term/term.go | 60 +
vendor/golang.org/x/term/term_plan9.go | 42 +
vendor/golang.org/x/term/term_unix.go | 91 +
vendor/golang.org/x/term/term_unix_bsd.go | 12 +
vendor/golang.org/x/term/term_unix_other.go | 12 +
vendor/golang.org/x/term/term_unsupported.go | 38 +
vendor/golang.org/x/term/term_windows.go | 80 +
vendor/golang.org/x/term/terminal.go | 986 +++++
vendor/golang.org/x/text/cases/cases.go | 162 +
vendor/golang.org/x/text/cases/context.go | 376 ++
vendor/golang.org/x/text/cases/fold.go | 34 +
vendor/golang.org/x/text/cases/icu.go | 61 +
vendor/golang.org/x/text/cases/info.go | 82 +
vendor/golang.org/x/text/cases/map.go | 816 ++++
.../golang.org/x/text/cases/tables10.0.0.go | 2255 ++++++++++
.../golang.org/x/text/cases/tables11.0.0.go | 2316 ++++++++++
.../golang.org/x/text/cases/tables12.0.0.go | 2359 ++++++++++
.../golang.org/x/text/cases/tables13.0.0.go | 2399 +++++++++++
.../golang.org/x/text/cases/tables15.0.0.go | 2527 +++++++++++
vendor/golang.org/x/text/cases/tables9.0.0.go | 2215 ++++++++++
vendor/golang.org/x/text/cases/trieval.go | 217 +
vendor/golang.org/x/text/internal/internal.go | 49 +
.../x/text/internal/language/common.go | 16 +
.../x/text/internal/language/compact.go | 29 +
.../text/internal/language/compact/compact.go | 61 +
.../internal/language/compact/language.go | 260 ++
.../text/internal/language/compact/parents.go | 120 +
.../text/internal/language/compact/tables.go | 1015 +++++
.../x/text/internal/language/compact/tags.go | 91 +
.../x/text/internal/language/compose.go | 167 +
.../x/text/internal/language/coverage.go | 28 +
.../x/text/internal/language/language.go | 627 +++
.../x/text/internal/language/lookup.go | 412 ++
.../x/text/internal/language/match.go | 226 +
.../x/text/internal/language/parse.go | 608 +++
.../x/text/internal/language/tables.go | 3494 +++++++++++++++
.../x/text/internal/language/tags.go | 48 +
vendor/golang.org/x/text/internal/match.go | 67 +
vendor/golang.org/x/text/internal/tag/tag.go | 100 +
vendor/golang.org/x/text/language/coverage.go | 187 +
vendor/golang.org/x/text/language/doc.go | 98 +
vendor/golang.org/x/text/language/language.go | 605 +++
vendor/golang.org/x/text/language/match.go | 735 ++++
vendor/golang.org/x/text/language/parse.go | 256 ++
vendor/golang.org/x/text/language/tables.go | 298 ++
vendor/golang.org/x/text/language/tags.go | 145 +
vendor/modules.txt | 43 +
263 files changed, 74585 insertions(+)
create mode 100644 pkg/migrations/status.go
create mode 100644 vendor/atomicgo.dev/cursor/.gitignore
create mode 100644 vendor/atomicgo.dev/cursor/.golangci.yml
create mode 100644 vendor/atomicgo.dev/cursor/CHANGELOG.md
create mode 100644 vendor/atomicgo.dev/cursor/LICENSE
create mode 100644 vendor/atomicgo.dev/cursor/README.md
create mode 100644 vendor/atomicgo.dev/cursor/area.go
create mode 100644 vendor/atomicgo.dev/cursor/area_other.go
create mode 100644 vendor/atomicgo.dev/cursor/area_windows.go
create mode 100644 vendor/atomicgo.dev/cursor/codecov.yml
create mode 100644 vendor/atomicgo.dev/cursor/cursor.go
create mode 100644 vendor/atomicgo.dev/cursor/cursor_other.go
create mode 100644 vendor/atomicgo.dev/cursor/cursor_test_linux.go
create mode 100644 vendor/atomicgo.dev/cursor/cursor_windows.go
create mode 100644 vendor/atomicgo.dev/cursor/doc.go
create mode 100644 vendor/atomicgo.dev/cursor/syscall_windows.go
create mode 100644 vendor/atomicgo.dev/cursor/utils.go
create mode 100644 vendor/atomicgo.dev/keyboard/.gitignore
create mode 100644 vendor/atomicgo.dev/keyboard/.golangci.yml
create mode 100644 vendor/atomicgo.dev/keyboard/LICENSE
create mode 100644 vendor/atomicgo.dev/keyboard/README.md
create mode 100644 vendor/atomicgo.dev/keyboard/codecov.yml
create mode 100644 vendor/atomicgo.dev/keyboard/doc.go
create mode 100644 vendor/atomicgo.dev/keyboard/input.go
create mode 100644 vendor/atomicgo.dev/keyboard/internal/keys.go
create mode 100644 vendor/atomicgo.dev/keyboard/keyboard.go
create mode 100644 vendor/atomicgo.dev/keyboard/keys/keys.go
create mode 100644 vendor/atomicgo.dev/keyboard/tty_unix.go
create mode 100644 vendor/atomicgo.dev/keyboard/tty_windows.go
create mode 100644 vendor/atomicgo.dev/keyboard/utils.go
create mode 100644 vendor/atomicgo.dev/keyboard/utils_windows.go
create mode 100644 vendor/atomicgo.dev/schedule/.gitignore
create mode 100644 vendor/atomicgo.dev/schedule/.golangci.yml
create mode 100644 vendor/atomicgo.dev/schedule/LICENSE
create mode 100644 vendor/atomicgo.dev/schedule/README.md
create mode 100644 vendor/atomicgo.dev/schedule/codecov.yml
create mode 100644 vendor/atomicgo.dev/schedule/doc.go
create mode 100644 vendor/atomicgo.dev/schedule/schedule.go
create mode 100644 vendor/github.com/containerd/console/.golangci.yml
create mode 100644 vendor/github.com/containerd/console/LICENSE
create mode 100644 vendor/github.com/containerd/console/README.md
create mode 100644 vendor/github.com/containerd/console/console.go
create mode 100644 vendor/github.com/containerd/console/console_linux.go
create mode 100644 vendor/github.com/containerd/console/console_unix.go
create mode 100644 vendor/github.com/containerd/console/console_windows.go
create mode 100644 vendor/github.com/containerd/console/console_zos.go
create mode 100644 vendor/github.com/containerd/console/pty_freebsd_cgo.go
create mode 100644 vendor/github.com/containerd/console/pty_freebsd_nocgo.go
create mode 100644 vendor/github.com/containerd/console/pty_unix.go
create mode 100644 vendor/github.com/containerd/console/tc_darwin.go
create mode 100644 vendor/github.com/containerd/console/tc_freebsd_cgo.go
create mode 100644 vendor/github.com/containerd/console/tc_freebsd_nocgo.go
create mode 100644 vendor/github.com/containerd/console/tc_linux.go
create mode 100644 vendor/github.com/containerd/console/tc_netbsd.go
create mode 100644 vendor/github.com/containerd/console/tc_openbsd_cgo.go
create mode 100644 vendor/github.com/containerd/console/tc_openbsd_nocgo.go
create mode 100644 vendor/github.com/containerd/console/tc_solaris_cgo.go
create mode 100644 vendor/github.com/containerd/console/tc_solaris_nocgo.go
create mode 100644 vendor/github.com/containerd/console/tc_unix.go
create mode 100644 vendor/github.com/containerd/console/tc_zos.go
create mode 100644 vendor/github.com/gookit/color/.gitignore
create mode 100644 vendor/github.com/gookit/color/.nojekyll
create mode 100644 vendor/github.com/gookit/color/LICENSE
create mode 100644 vendor/github.com/gookit/color/README.md
create mode 100644 vendor/github.com/gookit/color/README.zh-CN.md
create mode 100644 vendor/github.com/gookit/color/any.go
create mode 100644 vendor/github.com/gookit/color/color.go
create mode 100644 vendor/github.com/gookit/color/color_16.go
create mode 100644 vendor/github.com/gookit/color/color_256.go
create mode 100644 vendor/github.com/gookit/color/color_rgb.go
create mode 100644 vendor/github.com/gookit/color/color_tag.go
create mode 100644 vendor/github.com/gookit/color/convert.go
create mode 100644 vendor/github.com/gookit/color/detect_env.go
create mode 100644 vendor/github.com/gookit/color/detect_nonwin.go
create mode 100644 vendor/github.com/gookit/color/detect_windows.go
create mode 100644 vendor/github.com/gookit/color/index.html
create mode 100644 vendor/github.com/gookit/color/printer.go
create mode 100644 vendor/github.com/gookit/color/quickstart.go
create mode 100644 vendor/github.com/gookit/color/style.go
create mode 100644 vendor/github.com/gookit/color/utils.go
create mode 100644 vendor/github.com/lithammer/fuzzysearch/LICENSE
create mode 100644 vendor/github.com/lithammer/fuzzysearch/fuzzy/fuzzy.go
create mode 100644 vendor/github.com/lithammer/fuzzysearch/fuzzy/levenshtein.go
create mode 100644 vendor/github.com/mattn/go-runewidth/LICENSE
create mode 100644 vendor/github.com/mattn/go-runewidth/README.md
create mode 100644 vendor/github.com/mattn/go-runewidth/runewidth.go
create mode 100644 vendor/github.com/mattn/go-runewidth/runewidth_appengine.go
create mode 100644 vendor/github.com/mattn/go-runewidth/runewidth_js.go
create mode 100644 vendor/github.com/mattn/go-runewidth/runewidth_posix.go
create mode 100644 vendor/github.com/mattn/go-runewidth/runewidth_table.go
create mode 100644 vendor/github.com/mattn/go-runewidth/runewidth_windows.go
create mode 100644 vendor/github.com/pterm/pterm/.gitignore
create mode 100644 vendor/github.com/pterm/pterm/.golangci.yml
create mode 100644 vendor/github.com/pterm/pterm/CODE_OF_CONDUCT.md
create mode 100644 vendor/github.com/pterm/pterm/CONTRIBUTING.md
create mode 100644 vendor/github.com/pterm/pterm/LICENSE
create mode 100644 vendor/github.com/pterm/pterm/README.md
create mode 100644 vendor/github.com/pterm/pterm/SECURITY.md
create mode 100644 vendor/github.com/pterm/pterm/area_printer.go
create mode 100644 vendor/github.com/pterm/pterm/atoms.go
create mode 100644 vendor/github.com/pterm/pterm/barchart.go
create mode 100644 vendor/github.com/pterm/pterm/basic_text_printer.go
create mode 100644 vendor/github.com/pterm/pterm/bigtext_printer.go
create mode 100644 vendor/github.com/pterm/pterm/box_printer.go
create mode 100644 vendor/github.com/pterm/pterm/bulletlist_printer.go
create mode 100644 vendor/github.com/pterm/pterm/center_printer.go
create mode 100644 vendor/github.com/pterm/pterm/codecov.yml
create mode 100644 vendor/github.com/pterm/pterm/color.go
create mode 100644 vendor/github.com/pterm/pterm/conventionalcommit.json
create mode 100644 vendor/github.com/pterm/pterm/coverage.txt
create mode 100644 vendor/github.com/pterm/pterm/deprecated.go
create mode 100644 vendor/github.com/pterm/pterm/errors.go
create mode 100644 vendor/github.com/pterm/pterm/header_printer.go
create mode 100644 vendor/github.com/pterm/pterm/heatmap_printer.go
create mode 100644 vendor/github.com/pterm/pterm/interactive_confirm_printer.go
create mode 100644 vendor/github.com/pterm/pterm/interactive_continue_printer.go
create mode 100644 vendor/github.com/pterm/pterm/interactive_multiselect_printer.go
create mode 100644 vendor/github.com/pterm/pterm/interactive_select_printer.go
create mode 100644 vendor/github.com/pterm/pterm/interactive_textinput_printer.go
create mode 100644 vendor/github.com/pterm/pterm/interface_live_printer.go
create mode 100644 vendor/github.com/pterm/pterm/interface_renderable_printer.go
create mode 100644 vendor/github.com/pterm/pterm/interface_text_printer.go
create mode 100644 vendor/github.com/pterm/pterm/internal/cancelation_signal.go
create mode 100644 vendor/github.com/pterm/pterm/internal/center_text.go
create mode 100644 vendor/github.com/pterm/pterm/internal/collection.go
create mode 100644 vendor/github.com/pterm/pterm/internal/exit.go
create mode 100644 vendor/github.com/pterm/pterm/internal/longest_line.go
create mode 100644 vendor/github.com/pterm/pterm/internal/map_range_to_range.go
create mode 100644 vendor/github.com/pterm/pterm/internal/max_text_width.go
create mode 100644 vendor/github.com/pterm/pterm/internal/percentage.go
create mode 100644 vendor/github.com/pterm/pterm/internal/remove_and_count_prefix.go
create mode 100644 vendor/github.com/pterm/pterm/internal/rgb_complementary.go
create mode 100644 vendor/github.com/pterm/pterm/internal/title_in_line.go
create mode 100644 vendor/github.com/pterm/pterm/internal/utils.go
create mode 100644 vendor/github.com/pterm/pterm/internal/with_boolean.go
create mode 100644 vendor/github.com/pterm/pterm/logger.go
create mode 100644 vendor/github.com/pterm/pterm/multi_live_printer.go
create mode 100644 vendor/github.com/pterm/pterm/panel_printer.go
create mode 100644 vendor/github.com/pterm/pterm/paragraph_printer.go
create mode 100644 vendor/github.com/pterm/pterm/prefix_printer.go
create mode 100644 vendor/github.com/pterm/pterm/print.go
create mode 100644 vendor/github.com/pterm/pterm/progressbar_printer.go
create mode 100644 vendor/github.com/pterm/pterm/pterm.go
create mode 100644 vendor/github.com/pterm/pterm/rgb.go
create mode 100644 vendor/github.com/pterm/pterm/section_printer.go
create mode 100644 vendor/github.com/pterm/pterm/slog_handler.go
create mode 100644 vendor/github.com/pterm/pterm/spinner_printer.go
create mode 100644 vendor/github.com/pterm/pterm/table_printer.go
create mode 100644 vendor/github.com/pterm/pterm/terminal.go
create mode 100644 vendor/github.com/pterm/pterm/theme.go
create mode 100644 vendor/github.com/pterm/pterm/tree_printer.go
create mode 100644 vendor/github.com/rivo/uniseg/LICENSE.txt
create mode 100644 vendor/github.com/rivo/uniseg/README.md
create mode 100644 vendor/github.com/rivo/uniseg/doc.go
create mode 100644 vendor/github.com/rivo/uniseg/eastasianwidth.go
create mode 100644 vendor/github.com/rivo/uniseg/emojipresentation.go
create mode 100644 vendor/github.com/rivo/uniseg/gen_breaktest.go
create mode 100644 vendor/github.com/rivo/uniseg/gen_properties.go
create mode 100644 vendor/github.com/rivo/uniseg/grapheme.go
create mode 100644 vendor/github.com/rivo/uniseg/graphemeproperties.go
create mode 100644 vendor/github.com/rivo/uniseg/graphemerules.go
create mode 100644 vendor/github.com/rivo/uniseg/line.go
create mode 100644 vendor/github.com/rivo/uniseg/lineproperties.go
create mode 100644 vendor/github.com/rivo/uniseg/linerules.go
create mode 100644 vendor/github.com/rivo/uniseg/properties.go
create mode 100644 vendor/github.com/rivo/uniseg/sentence.go
create mode 100644 vendor/github.com/rivo/uniseg/sentenceproperties.go
create mode 100644 vendor/github.com/rivo/uniseg/sentencerules.go
create mode 100644 vendor/github.com/rivo/uniseg/step.go
create mode 100644 vendor/github.com/rivo/uniseg/width.go
create mode 100644 vendor/github.com/rivo/uniseg/word.go
create mode 100644 vendor/github.com/rivo/uniseg/wordproperties.go
create mode 100644 vendor/github.com/rivo/uniseg/wordrules.go
create mode 100644 vendor/github.com/xo/terminfo/.gitignore
create mode 100644 vendor/github.com/xo/terminfo/LICENSE
create mode 100644 vendor/github.com/xo/terminfo/README.md
create mode 100644 vendor/github.com/xo/terminfo/caps.go
create mode 100644 vendor/github.com/xo/terminfo/capvals.go
create mode 100644 vendor/github.com/xo/terminfo/color.go
create mode 100644 vendor/github.com/xo/terminfo/dec.go
create mode 100644 vendor/github.com/xo/terminfo/load.go
create mode 100644 vendor/github.com/xo/terminfo/param.go
create mode 100644 vendor/github.com/xo/terminfo/stack.go
create mode 100644 vendor/github.com/xo/terminfo/terminfo.go
create mode 100644 vendor/golang.org/x/sys/plan9/asm.s
create mode 100644 vendor/golang.org/x/sys/plan9/asm_plan9_386.s
create mode 100644 vendor/golang.org/x/sys/plan9/asm_plan9_amd64.s
create mode 100644 vendor/golang.org/x/sys/plan9/asm_plan9_arm.s
create mode 100644 vendor/golang.org/x/sys/plan9/const_plan9.go
create mode 100644 vendor/golang.org/x/sys/plan9/dir_plan9.go
create mode 100644 vendor/golang.org/x/sys/plan9/env_plan9.go
create mode 100644 vendor/golang.org/x/sys/plan9/errors_plan9.go
create mode 100644 vendor/golang.org/x/sys/plan9/mkall.sh
create mode 100644 vendor/golang.org/x/sys/plan9/mkerrors.sh
create mode 100644 vendor/golang.org/x/sys/plan9/mksysnum_plan9.sh
create mode 100644 vendor/golang.org/x/sys/plan9/pwd_go15_plan9.go
create mode 100644 vendor/golang.org/x/sys/plan9/pwd_plan9.go
create mode 100644 vendor/golang.org/x/sys/plan9/race.go
create mode 100644 vendor/golang.org/x/sys/plan9/race0.go
create mode 100644 vendor/golang.org/x/sys/plan9/str.go
create mode 100644 vendor/golang.org/x/sys/plan9/syscall.go
create mode 100644 vendor/golang.org/x/sys/plan9/syscall_plan9.go
create mode 100644 vendor/golang.org/x/sys/plan9/zsyscall_plan9_386.go
create mode 100644 vendor/golang.org/x/sys/plan9/zsyscall_plan9_amd64.go
create mode 100644 vendor/golang.org/x/sys/plan9/zsyscall_plan9_arm.go
create mode 100644 vendor/golang.org/x/sys/plan9/zsysnum_plan9.go
create mode 100644 vendor/golang.org/x/term/CONTRIBUTING.md
create mode 100644 vendor/golang.org/x/term/LICENSE
create mode 100644 vendor/golang.org/x/term/PATENTS
create mode 100644 vendor/golang.org/x/term/README.md
create mode 100644 vendor/golang.org/x/term/codereview.cfg
create mode 100644 vendor/golang.org/x/term/term.go
create mode 100644 vendor/golang.org/x/term/term_plan9.go
create mode 100644 vendor/golang.org/x/term/term_unix.go
create mode 100644 vendor/golang.org/x/term/term_unix_bsd.go
create mode 100644 vendor/golang.org/x/term/term_unix_other.go
create mode 100644 vendor/golang.org/x/term/term_unsupported.go
create mode 100644 vendor/golang.org/x/term/term_windows.go
create mode 100644 vendor/golang.org/x/term/terminal.go
create mode 100644 vendor/golang.org/x/text/cases/cases.go
create mode 100644 vendor/golang.org/x/text/cases/context.go
create mode 100644 vendor/golang.org/x/text/cases/fold.go
create mode 100644 vendor/golang.org/x/text/cases/icu.go
create mode 100644 vendor/golang.org/x/text/cases/info.go
create mode 100644 vendor/golang.org/x/text/cases/map.go
create mode 100644 vendor/golang.org/x/text/cases/tables10.0.0.go
create mode 100644 vendor/golang.org/x/text/cases/tables11.0.0.go
create mode 100644 vendor/golang.org/x/text/cases/tables12.0.0.go
create mode 100644 vendor/golang.org/x/text/cases/tables13.0.0.go
create mode 100644 vendor/golang.org/x/text/cases/tables15.0.0.go
create mode 100644 vendor/golang.org/x/text/cases/tables9.0.0.go
create mode 100644 vendor/golang.org/x/text/cases/trieval.go
create mode 100644 vendor/golang.org/x/text/internal/internal.go
create mode 100644 vendor/golang.org/x/text/internal/language/common.go
create mode 100644 vendor/golang.org/x/text/internal/language/compact.go
create mode 100644 vendor/golang.org/x/text/internal/language/compact/compact.go
create mode 100644 vendor/golang.org/x/text/internal/language/compact/language.go
create mode 100644 vendor/golang.org/x/text/internal/language/compact/parents.go
create mode 100644 vendor/golang.org/x/text/internal/language/compact/tables.go
create mode 100644 vendor/golang.org/x/text/internal/language/compact/tags.go
create mode 100644 vendor/golang.org/x/text/internal/language/compose.go
create mode 100644 vendor/golang.org/x/text/internal/language/coverage.go
create mode 100644 vendor/golang.org/x/text/internal/language/language.go
create mode 100644 vendor/golang.org/x/text/internal/language/lookup.go
create mode 100644 vendor/golang.org/x/text/internal/language/match.go
create mode 100644 vendor/golang.org/x/text/internal/language/parse.go
create mode 100644 vendor/golang.org/x/text/internal/language/tables.go
create mode 100644 vendor/golang.org/x/text/internal/language/tags.go
create mode 100644 vendor/golang.org/x/text/internal/match.go
create mode 100644 vendor/golang.org/x/text/internal/tag/tag.go
create mode 100644 vendor/golang.org/x/text/language/coverage.go
create mode 100644 vendor/golang.org/x/text/language/doc.go
create mode 100644 vendor/golang.org/x/text/language/language.go
create mode 100644 vendor/golang.org/x/text/language/match.go
create mode 100644 vendor/golang.org/x/text/language/parse.go
create mode 100644 vendor/golang.org/x/text/language/tables.go
create mode 100644 vendor/golang.org/x/text/language/tags.go
diff --git a/cmd_status.go b/cmd_status.go
index b7eaf8b..1ecba88 100644
--- a/cmd_status.go
+++ b/cmd_status.go
@@ -3,8 +3,13 @@ package main
import (
"context"
"flag"
+ "fmt"
+ "log/slog"
+ "os"
"github.com/google/subcommands"
+ "github.com/jacobbrewer1/goschema/pkg/migrations"
+ "github.com/pterm/pterm"
)
type statusCmd struct{}
@@ -26,5 +31,35 @@ func (c *statusCmd) Usage() string {
func (c *statusCmd) SetFlags(f *flag.FlagSet) {}
func (c *statusCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
+ if e := os.Getenv(migrations.DbEnvVar); e == "" {
+ slog.Error(fmt.Sprintf("Environment variable %s is not set", migrations.DbEnvVar))
+ return subcommands.ExitFailure
+ }
+
+ db, err := migrations.ConnectDB()
+ if err != nil {
+ slog.Error("Error connecting to the database", slog.String("error", err.Error()))
+ return subcommands.ExitFailure
+ }
+
+ versions, err := migrations.NewVersioning(db, "", 0).GetStatus()
+ if err != nil {
+ slog.Error("Error getting the status", slog.String("error", err.Error()))
+ return subcommands.ExitFailure
+ }
+
+ tableDataStr := make([][]string, 0)
+ tableDataStr = append(tableDataStr, []string{"Version", "Current", "Created At"})
+ for _, v := range versions {
+ tableDataStr = append(tableDataStr, []string{v.Version, fmt.Sprintf("%t", v.IsCurrent == 1), v.CreatedAt.String()})
+ }
+
+ var tableData pterm.TableData = tableDataStr
+
+ if err := pterm.DefaultTable.WithHasHeader().WithBoxed().WithData(tableData).Render(); err != nil {
+ slog.Error("Error rendering table", slog.String("error", err.Error()))
+ return subcommands.ExitFailure
+ }
+
return subcommands.ExitSuccess
}
diff --git a/go.mod b/go.mod
index 8a590ad..aad03dc 100644
--- a/go.mod
+++ b/go.mod
@@ -15,19 +15,25 @@ require (
github.com/jmoiron/sqlx v1.4.0
github.com/pingcap/tidb/pkg/parser v0.0.0-20241220080229-acba0cd1e2b0
github.com/prometheus/client_golang v1.20.5
+ github.com/pterm/pterm v0.12.80
github.com/stretchr/testify v1.10.0
)
require (
+ atomicgo.dev/cursor v0.2.0 // indirect
+ atomicgo.dev/keyboard v0.2.9 // indirect
+ atomicgo.dev/schedule v0.1.0 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver v1.5.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
+ github.com/containerd/console v1.0.3 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/go-jose/go-jose/v4 v4.0.1 // indirect
github.com/google/uuid v1.3.1 // indirect
+ github.com/gookit/color v1.5.4 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
@@ -41,6 +47,8 @@ require (
github.com/hashicorp/vault/api/auth/kubernetes v0.8.0 // indirect
github.com/hashicorp/vault/api/auth/userpass v0.8.0 // indirect
github.com/imdario/mergo v0.3.11 // indirect
+ github.com/lithammer/fuzzysearch v1.1.8 // indirect
+ github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
@@ -53,15 +61,18 @@ require (
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
+ github.com/rivo/uniseg v0.4.4 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/ryanuber/go-glob v1.0.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
+ github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/sys v0.28.0 // indirect
+ golang.org/x/term v0.27.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.6.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
diff --git a/go.sum b/go.sum
index 7ed76b4..5641063 100644
--- a/go.sum
+++ b/go.sum
@@ -1,6 +1,23 @@
+atomicgo.dev/assert v0.0.2 h1:FiKeMiZSgRrZsPo9qn/7vmr7mCsh5SZyXY4YGYiYwrg=
+atomicgo.dev/assert v0.0.2/go.mod h1:ut4NcI3QDdJtlmAxQULOmA13Gz6e2DWbSAS8RUOmNYQ=
+atomicgo.dev/cursor v0.2.0 h1:H6XN5alUJ52FZZUkI7AlJbUc1aW38GWZalpYRPpoPOw=
+atomicgo.dev/cursor v0.2.0/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU=
+atomicgo.dev/keyboard v0.2.9 h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8=
+atomicgo.dev/keyboard v0.2.9/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ=
+atomicgo.dev/schedule v0.1.0 h1:nTthAbhZS5YZmgYbb2+DH8uQIZcTlIrd4eYr3UQxEjs=
+atomicgo.dev/schedule v0.1.0/go.mod h1:xeUa3oAkiuHYh8bKiQBRojqAMq3PXXbJujjb0hw8pEU=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+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/go.mod h1:JOIegYyV7rX+7VZ9r77L/eH6CfJHHzXjB69adAhzZkI=
+github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/2oUqKc6bF2c=
+github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE=
+github.com/MarvinJWendt/testza v0.5.2 h1:53KDo64C1z/h/d/stCYCPY69bt/OSwjq5KpFNwi+zB4=
+github.com/MarvinJWendt/testza v0.5.2/go.mod h1:xu53QFE5sCdjtMCKk8YMQ2MnymimEctc4n3EjyIYvEY=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
@@ -8,6 +25,7 @@ github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF0
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
@@ -16,6 +34,8 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
+github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
@@ -35,6 +55,10 @@ github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
+github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
+github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
+github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -78,6 +102,11 @@ github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
+github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
+github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
+github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU=
+github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -87,12 +116,17 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
+github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
+github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
@@ -130,19 +164,38 @@ github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
+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/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8=
+github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s=
+github.com/pterm/pterm v0.12.80 h1:mM55B+GnKUnLMUSqhdINe4s6tOuVQIetQ3my8JGyAIg=
+github.com/pterm/pterm v0.12.80/go.mod h1:c6DeF9bSnOSeFPZlfs4ZRAFcf5SCoTwvwQ5xaKGQlHo=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
+github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
+github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
+github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
+github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
+github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
@@ -159,37 +212,73 @@ go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
+golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
+golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/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/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+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/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
+golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
diff --git a/main.go b/main.go
index 85313d4..f049ff6 100644
--- a/main.go
+++ b/main.go
@@ -20,6 +20,7 @@ func main() {
subcommands.Register(new(generateCmd), "")
subcommands.Register(new(createCmd), "")
subcommands.Register(new(migrateCmd), "")
+ subcommands.Register(new(statusCmd), "")
flag.Parse()
diff --git a/pkg/migrations/status.go b/pkg/migrations/status.go
new file mode 100644
index 0000000..cd87564
--- /dev/null
+++ b/pkg/migrations/status.go
@@ -0,0 +1,32 @@
+package migrations
+
+import (
+ "fmt"
+
+ "github.com/jacobbrewer1/goschema/pkg/models"
+)
+
+func (v *versioning) GetStatus() ([]*models.GoschemaMigrationVersion, error) {
+ sqlStmt := `
+ SELECT version
+ FROM goschema_migration_version
+ ORDER BY created_at DESC;
+ `
+
+ ids := make([]string, 0)
+ if err := v.db.Select(&ids, sqlStmt); err != nil {
+ return nil, fmt.Errorf("get status ids: %w", err)
+ }
+
+ versions := make([]*models.GoschemaMigrationVersion, len(ids))
+ for i, id := range ids {
+ ver, err := models.GoschemaMigrationVersionByVersion(v.db, id)
+ if err != nil {
+ return nil, fmt.Errorf("get status version by version: %w", err)
+ }
+
+ versions[i] = ver
+ }
+
+ return versions, nil
+}
diff --git a/pkg/migrations/versioning.go b/pkg/migrations/versioning.go
index bc1d490..3ed3d2a 100644
--- a/pkg/migrations/versioning.go
+++ b/pkg/migrations/versioning.go
@@ -34,6 +34,7 @@ var (
type Versioning interface {
MigrateUp() error
MigrateDown() error
+ GetStatus() ([]*models.GoschemaMigrationVersion, error)
}
type versioning struct {
diff --git a/vendor/atomicgo.dev/cursor/.gitignore b/vendor/atomicgo.dev/cursor/.gitignore
new file mode 100644
index 0000000..99e2741
--- /dev/null
+++ b/vendor/atomicgo.dev/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/atomicgo.dev/cursor/.golangci.yml b/vendor/atomicgo.dev/cursor/.golangci.yml
new file mode 100644
index 0000000..796ca35
--- /dev/null
+++ b/vendor/atomicgo.dev/cursor/.golangci.yml
@@ -0,0 +1,99 @@
+linters-settings:
+ gocritic:
+ enabled-tags:
+ - diagnostic
+ - experimental
+ - opinionated
+ - performance
+ - style
+ disabled-checks:
+ - dupImport
+ - ifElseChain
+ - octalLiteral
+ - whyNoLint
+ - wrapperFunc
+ - exitAfterDefer
+ - hugeParam
+ - ptrToRefParam
+ - paramTypeCombine
+ - unnamedResult
+linters:
+ disable-all: true
+ enable:
+ # default linters
+ - errcheck
+ - gosimple
+ - govet
+ - ineffassign
+ - staticcheck
+ - typecheck
+ - unused
+ # additional linters
+ - asasalint
+ - asciicheck
+ - bidichk
+ - bodyclose
+ - containedctx
+ - contextcheck
+ - decorder
+ - dupl
+ - durationcheck
+ - errchkjson
+ - errname
+ - errorlint
+ - exhaustive
+ - exhaustruct
+ - exportloopref
+ - forcetypeassert
+ - gocheckcompilerdirectives
+ - gocritic
+ - godot
+ - godox
+ - goerr113
+ - gofmt
+ - goprintffuncname
+ - gosec
+ - gosmopolitan
+ - importas
+ - ireturn
+ - nakedret
+ - nestif
+ - nilerr
+ - nilnil
+ - prealloc
+ - predeclared
+ - revive
+ - rowserrcheck
+ - tagalign
+ - tenv
+ - thelper
+ - tparallel
+ - unconvert
+ - unparam
+ - usestdlibvars
+ - wastedassign
+ - whitespace
+ - wrapcheck
+ - wsl
+ - gocyclo
+ - misspell
+issues:
+ include:
+ - EXC0012
+ - EXC0014
+ exclude-rules:
+ - path: _test\.go
+ linters:
+ - gocyclo
+ - errcheck
+ - dupl
+ - gosec
+ - gocritic
+ - linters:
+ - gocritic
+ text: "unnecessaryDefer:"
+ - linters:
+ - gocritic
+ text: "preferDecodeRune:"
+service:
+ golangci-lint-version: 1.53.x
diff --git a/vendor/atomicgo.dev/cursor/CHANGELOG.md b/vendor/atomicgo.dev/cursor/CHANGELOG.md
new file mode 100644
index 0000000..b565349
--- /dev/null
+++ b/vendor/atomicgo.dev/cursor/CHANGELOG.md
@@ -0,0 +1,20 @@
+
+## [Unreleased]
+
+
+
+## v0.0.1 - 2021-05-09
+### Features
+- implement `Area`
+- add `ClearLinesUp` and `ClearLinesDown`
+- implement cross-platform support
+- implement cursor functions
+
+### Bug Fixes
+- height can no longer be negative on non windows systems
+
+### Code Refactoring
+- remove debug code
+
+
+[Unreleased]: https://github.com/MarvinJWendt/testza/compare/v0.0.1...HEAD
diff --git a/vendor/atomicgo.dev/cursor/LICENSE b/vendor/atomicgo.dev/cursor/LICENSE
new file mode 100644
index 0000000..c78d7a5
--- /dev/null
+++ b/vendor/atomicgo.dev/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/atomicgo.dev/cursor/README.md b/vendor/atomicgo.dev/cursor/README.md
new file mode 100644
index 0000000..0f79974
--- /dev/null
+++ b/vendor/atomicgo.dev/cursor/README.md
@@ -0,0 +1,598 @@
+AtomicGo | cursor
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+---
+
+
+Documentation
+|
+Contributing
+|
+Code of Conduct
+
+
+---
+
+
+
+
+
+
+
+
+go get atomicgo.dev/cursor
+
+
+
+
+
+
+
+
+# cursor
+
+```go
+import "atomicgo.dev/cursor"
+```
+
+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.
+
+Works niceley with https://github.com/atomicgo/keyboard
+
+Special thanks to github.com/k0kubun/go\-ansi which this project is based on.
+
+## Index
+
+- [func Bottom\(\)](<#Bottom>)
+- [func Clear\(\)](<#Clear>)
+- [func ClearLine\(\)](<#ClearLine>)
+- [func ClearLinesDown\(n int\)](<#ClearLinesDown>)
+- [func ClearLinesUp\(n int\)](<#ClearLinesUp>)
+- [func Down\(n int\)](<#Down>)
+- [func DownAndClear\(n int\)](<#DownAndClear>)
+- [func Hide\(\)](<#Hide>)
+- [func HorizontalAbsolute\(n int\)](<#HorizontalAbsolute>)
+- [func Left\(n int\)](<#Left>)
+- [func Move\(x, y int\)](<#Move>)
+- [func Right\(n int\)](<#Right>)
+- [func SetTarget\(w Writer\)](<#SetTarget>)
+- [func Show\(\)](<#Show>)
+- [func StartOfLine\(\)](<#StartOfLine>)
+- [func StartOfLineDown\(n int\)](<#StartOfLineDown>)
+- [func StartOfLineUp\(n int\)](<#StartOfLineUp>)
+- [func TestCustomIOWriter\(t \*testing.T\)](<#TestCustomIOWriter>)
+- [func Up\(n int\)](<#Up>)
+- [func UpAndClear\(n int\)](<#UpAndClear>)
+- [type Area](<#Area>)
+ - [func NewArea\(\) Area](<#NewArea>)
+ - [func \(area \*Area\) Bottom\(\)](<#Area.Bottom>)
+ - [func \(area \*Area\) Clear\(\)](<#Area.Clear>)
+ - [func \(area \*Area\) ClearLinesDown\(n int\)](<#Area.ClearLinesDown>)
+ - [func \(area \*Area\) ClearLinesUp\(n int\)](<#Area.ClearLinesUp>)
+ - [func \(area \*Area\) Down\(n int\)](<#Area.Down>)
+ - [func \(area \*Area\) DownAndClear\(n int\)](<#Area.DownAndClear>)
+ - [func \(area \*Area\) Move\(x, y int\)](<#Area.Move>)
+ - [func \(area \*Area\) StartOfLine\(\)](<#Area.StartOfLine>)
+ - [func \(area \*Area\) StartOfLineDown\(n int\)](<#Area.StartOfLineDown>)
+ - [func \(area \*Area\) StartOfLineUp\(n int\)](<#Area.StartOfLineUp>)
+ - [func \(area \*Area\) Top\(\)](<#Area.Top>)
+ - [func \(area \*Area\) Up\(n int\)](<#Area.Up>)
+ - [func \(area \*Area\) UpAndClear\(n int\)](<#Area.UpAndClear>)
+ - [func \(area \*Area\) Update\(content string\)](<#Area.Update>)
+ - [func \(area Area\) WithWriter\(writer Writer\) Area](<#Area.WithWriter>)
+- [type Cursor](<#Cursor>)
+ - [func NewCursor\(\) \*Cursor](<#NewCursor>)
+ - [func \(c \*Cursor\) Clear\(\)](<#Cursor.Clear>)
+ - [func \(c \*Cursor\) ClearLine\(\)](<#Cursor.ClearLine>)
+ - [func \(c \*Cursor\) Down\(n int\)](<#Cursor.Down>)
+ - [func \(c \*Cursor\) Hide\(\)](<#Cursor.Hide>)
+ - [func \(c \*Cursor\) HorizontalAbsolute\(n int\)](<#Cursor.HorizontalAbsolute>)
+ - [func \(c \*Cursor\) Left\(n int\)](<#Cursor.Left>)
+ - [func \(c \*Cursor\) Right\(n int\)](<#Cursor.Right>)
+ - [func \(c \*Cursor\) Show\(\)](<#Cursor.Show>)
+ - [func \(c \*Cursor\) Up\(n int\)](<#Cursor.Up>)
+ - [func \(c \*Cursor\) WithWriter\(w Writer\) \*Cursor](<#Cursor.WithWriter>)
+- [type Writer](<#Writer>)
+
+
+
+## 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 [Clear]()
+
+```go
+func Clear()
+```
+
+Clear clears the current position and moves the cursor to the left.
+
+
+## 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 they reopen 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 [SetTarget]()
+
+```go
+func SetTarget(w Writer)
+```
+
+SetTarget sets to output target of the default curser to the provided cursor.Writer \(wrapping io.Writer\).
+
+
+## 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 they reopen 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 [TestCustomIOWriter]()
+
+```go
+func TestCustomIOWriter(t *testing.T)
+```
+
+TestCustomIOWriter tests the cursor functions with a custom Writer.
+
+
+## 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]()
+
+Area displays content which can be updated on the fly. You can use this to create live output, charts, dropdowns, etc.
+
+```go
+type Area struct {
+ // contains filtered or unexported fields
+}
+```
+
+
+### func [NewArea]()
+
+```go
+func NewArea() Area
+```
+
+NewArea returns a new Area.
+
+
+### func \(\*Area\) [Bottom]()
+
+```go
+func (area *Area) 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 \(\*Area\) [Clear]()
+
+```go
+func (area *Area) Clear()
+```
+
+Clear clears the content of the Area.
+
+
+### func \(\*Area\) [ClearLinesDown]()
+
+```go
+func (area *Area) ClearLinesDown(n int)
+```
+
+ClearLinesDown clears n lines downwards from the current position and moves the cursor.
+
+
+### func \(\*Area\) [ClearLinesUp]()
+
+```go
+func (area *Area) ClearLinesUp(n int)
+```
+
+ClearLinesUp clears n lines upwards from the current position and moves the cursor.
+
+
+### func \(\*Area\) [Down]()
+
+```go
+func (area *Area) Down(n int)
+```
+
+Down moves the cursor of the area down one line.
+
+
+### func \(\*Area\) [DownAndClear]()
+
+```go
+func (area *Area) DownAndClear(n int)
+```
+
+DownAndClear moves the cursor down by n lines, then clears the line.
+
+
+### func \(\*Area\) [Move]()
+
+```go
+func (area *Area) Move(x, y int)
+```
+
+Move moves the cursor relative by x and y.
+
+
+### func \(\*Area\) [StartOfLine]()
+
+```go
+func (area *Area) StartOfLine()
+```
+
+StartOfLine moves the cursor to the start of the current line.
+
+
+### func \(\*Area\) [StartOfLineDown]()
+
+```go
+func (area *Area) StartOfLineDown(n int)
+```
+
+StartOfLineDown moves the cursor down by n lines, then moves to cursor to the start of the line.
+
+
+### func \(\*Area\) [StartOfLineUp]()
+
+```go
+func (area *Area) StartOfLineUp(n int)
+```
+
+StartOfLineUp moves the cursor up by n lines, then moves to cursor to the start of the line.
+
+
+### func \(\*Area\) [Top]()
+
+```go
+func (area *Area) Top()
+```
+
+Top moves the cursor to the top of the area. This is done by calculating how many lines were moved by Up and Down.
+
+
+### func \(\*Area\) [Up]()
+
+```go
+func (area *Area) Up(n int)
+```
+
+Up moves the cursor of the area up one line.
+
+
+### func \(\*Area\) [UpAndClear]()
+
+```go
+func (area *Area) UpAndClear(n int)
+```
+
+UpAndClear moves the cursor up by n lines, then clears the line.
+
+
+### func \(\*Area\) [Update]()
+
+```go
+func (area *Area) Update(content string)
+```
+
+Update overwrites the content of the Area and adjusts its height based on content.
+
+
+### func \(Area\) [WithWriter]()
+
+```go
+func (area Area) WithWriter(writer Writer) Area
+```
+
+WithWriter sets the custom writer.
+
+
+## type [Cursor]()
+
+Cursor displays content which can be updated on the fly. You can use this to create live output, charts, dropdowns, etc.
+
+```go
+type Cursor struct {
+ // contains filtered or unexported fields
+}
+```
+
+
+### func [NewCursor]()
+
+```go
+func NewCursor() *Cursor
+```
+
+NewCursor creates a new Cursor instance writing to os.Stdout.
+
+
+### func \(\*Cursor\) [Clear]()
+
+```go
+func (c *Cursor) Clear()
+```
+
+Clear clears the current position and moves the cursor to the left.
+
+
+### func \(\*Cursor\) [ClearLine]()
+
+```go
+func (c *Cursor) ClearLine()
+```
+
+ClearLine clears the current line and moves the cursor to it's start position.
+
+
+### func \(\*Cursor\) [Down]()
+
+```go
+func (c *Cursor) Down(n int)
+```
+
+Down moves the cursor n lines down relative to the current position.
+
+
+### func \(\*Cursor\) [Hide]()
+
+```go
+func (c *Cursor) 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 they reopen the terminal.
+
+
+### func \(\*Cursor\) [HorizontalAbsolute]()
+
+```go
+func (c *Cursor) HorizontalAbsolute(n int)
+```
+
+HorizontalAbsolute moves the cursor to n horizontally. The position n is absolute to the start of the line.
+
+
+### func \(\*Cursor\) [Left]()
+
+```go
+func (c *Cursor) Left(n int)
+```
+
+Left moves the cursor n characters to the left relative to the current position.
+
+
+### func \(\*Cursor\) [Right]()
+
+```go
+func (c *Cursor) Right(n int)
+```
+
+Right moves the cursor n characters to the right relative to the current position.
+
+
+### func \(\*Cursor\) [Show]()
+
+```go
+func (c *Cursor) 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 they reopen the terminal.
+
+
+### func \(\*Cursor\) [Up]()
+
+```go
+func (c *Cursor) Up(n int)
+```
+
+Up moves the cursor n lines up relative to the current position.
+
+
+### func \(\*Cursor\) [WithWriter]()
+
+```go
+func (c *Cursor) WithWriter(w Writer) *Cursor
+```
+
+WithWriter allows for any arbitrary Writer to be used for cursor movement abstracted.
+
+
+## type [Writer]()
+
+Writer is an expanded io.Writer interface with a file descriptor.
+
+```go
+type Writer interface {
+ io.Writer
+ Fd() uintptr
+}
+```
+
+Generated by [gomarkdoc]()
+
+
+
+
+---
+
+> [AtomicGo.dev](https://atomicgo.dev) ·
+> with ❤️ by [@MarvinJWendt](https://github.com/MarvinJWendt) |
+> [MarvinJWendt.com](https://marvinjwendt.com)
diff --git a/vendor/atomicgo.dev/cursor/area.go b/vendor/atomicgo.dev/cursor/area.go
new file mode 100644
index 0000000..5b26b5d
--- /dev/null
+++ b/vendor/atomicgo.dev/cursor/area.go
@@ -0,0 +1,164 @@
+package cursor
+
+import (
+ "os"
+ "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
+ writer Writer
+ cursor *Cursor
+ cursorPosY int
+}
+
+// NewArea returns a new Area.
+func NewArea() Area {
+ return Area{
+ height: 0,
+ writer: os.Stdout,
+ cursor: cursor,
+ cursorPosY: 0,
+ }
+}
+
+// WithWriter sets the custom writer.
+func (area Area) WithWriter(writer Writer) Area {
+ area.writer = writer
+ area.cursor = area.cursor.WithWriter(writer)
+
+ return area
+}
+
+// Clear clears the content of the Area.
+func (area *Area) Clear() {
+ // Initialize writer if not done yet
+ if area.writer == nil {
+ area.writer = os.Stdout
+ }
+
+ if area.height > 0 {
+ area.Bottom()
+ area.ClearLinesUp(area.height)
+ area.StartOfLine()
+ } else {
+ area.StartOfLine()
+ area.cursor.ClearLine()
+ }
+}
+
+// Update overwrites the content of the Area and adjusts its height based on content.
+func (area *Area) Update(content string) {
+ area.Clear()
+ area.writeArea(content)
+ area.cursorPosY = 0
+ area.height = strings.Count(content, "\n")
+}
+
+// Up moves the cursor of the area up one line.
+func (area *Area) Up(n int) {
+ if n > 0 {
+ if area.cursorPosY+n > area.height {
+ n = area.height - area.cursorPosY
+ }
+
+ area.cursor.Up(n)
+ area.cursorPosY += n
+ }
+}
+
+// Down moves the cursor of the area down one line.
+func (area *Area) Down(n int) {
+ if n > 0 {
+ if area.cursorPosY-n < 0 {
+ n = area.height - area.cursorPosY
+ }
+
+ area.cursor.Down(n)
+ area.cursorPosY -= n
+ }
+}
+
+// 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 (area *Area) Bottom() {
+ if area.cursorPosY > 0 {
+ area.Down(area.cursorPosY)
+ area.cursorPosY = 0
+ }
+}
+
+// Top moves the cursor to the top of the area.
+// This is done by calculating how many lines were moved by Up and Down.
+func (area *Area) Top() {
+ if area.cursorPosY < area.height {
+ area.Up(area.height - area.cursorPosY)
+ area.cursorPosY = area.height
+ }
+}
+
+// StartOfLine moves the cursor to the start of the current line.
+func (area *Area) StartOfLine() {
+ area.cursor.HorizontalAbsolute(0)
+}
+
+// StartOfLineDown moves the cursor down by n lines, then moves to cursor to the start of the line.
+func (area *Area) StartOfLineDown(n int) {
+ area.Down(n)
+ area.StartOfLine()
+}
+
+// StartOfLineUp moves the cursor up by n lines, then moves to cursor to the start of the line.
+func (area *Area) StartOfLineUp(n int) {
+ area.Up(n)
+ area.StartOfLine()
+}
+
+// UpAndClear moves the cursor up by n lines, then clears the line.
+func (area *Area) UpAndClear(n int) {
+ area.Up(n)
+ area.cursor.ClearLine()
+}
+
+// DownAndClear moves the cursor down by n lines, then clears the line.
+func (area *Area) DownAndClear(n int) {
+ area.Down(n)
+ area.cursor.ClearLine()
+}
+
+// Move moves the cursor relative by x and y.
+func (area *Area) Move(x, y int) {
+ if x > 0 {
+ area.cursor.Right(x)
+ } else if x < 0 {
+ area.cursor.Left(-x)
+ }
+
+ if y > 0 {
+ area.Up(y)
+ } else if y < 0 {
+ area.Down(-y)
+ }
+}
+
+// ClearLinesUp clears n lines upwards from the current position and moves the cursor.
+func (area *Area) ClearLinesUp(n int) {
+ area.StartOfLine()
+ area.cursor.ClearLine()
+
+ for i := 0; i < n; i++ {
+ area.UpAndClear(1)
+ }
+}
+
+// ClearLinesDown clears n lines downwards from the current position and moves the cursor.
+func (area *Area) ClearLinesDown(n int) {
+ area.StartOfLine()
+ area.cursor.ClearLine()
+
+ for i := 0; i < n; i++ {
+ area.DownAndClear(1)
+ }
+}
diff --git a/vendor/atomicgo.dev/cursor/area_other.go b/vendor/atomicgo.dev/cursor/area_other.go
new file mode 100644
index 0000000..b92390d
--- /dev/null
+++ b/vendor/atomicgo.dev/cursor/area_other.go
@@ -0,0 +1,13 @@
+//go:build !windows
+// +build !windows
+
+package cursor
+
+import (
+ "fmt"
+)
+
+// Update overwrites the content of the Area and adjusts its height based on content.
+func (area *Area) writeArea(content string) {
+ fmt.Fprint(area.writer, content)
+}
diff --git a/vendor/atomicgo.dev/cursor/area_windows.go b/vendor/atomicgo.dev/cursor/area_windows.go
new file mode 100644
index 0000000..de7dd29
--- /dev/null
+++ b/vendor/atomicgo.dev/cursor/area_windows.go
@@ -0,0 +1,21 @@
+//go:build windows
+// +build windows
+
+package cursor
+
+import (
+ "fmt"
+)
+
+// writeArea is a helper for platform dependant output.
+// For Windows newlines '\n' in the content are replaced by '\r\n'
+func (area *Area) writeArea(content string) {
+ last := ' '
+ for _, r := range content {
+ if r == '\n' && last != '\r' {
+ fmt.Fprint(area.writer, "\r\n")
+ continue
+ }
+ fmt.Fprint(area.writer, string(r))
+ }
+}
diff --git a/vendor/atomicgo.dev/cursor/codecov.yml b/vendor/atomicgo.dev/cursor/codecov.yml
new file mode 100644
index 0000000..bfdc987
--- /dev/null
+++ b/vendor/atomicgo.dev/cursor/codecov.yml
@@ -0,0 +1,8 @@
+coverage:
+ status:
+ project:
+ default:
+ informational: true
+ patch:
+ default:
+ informational: true
diff --git a/vendor/atomicgo.dev/cursor/cursor.go b/vendor/atomicgo.dev/cursor/cursor.go
new file mode 100644
index 0000000..89a3efc
--- /dev/null
+++ b/vendor/atomicgo.dev/cursor/cursor.go
@@ -0,0 +1,26 @@
+package cursor
+
+import (
+ "os"
+)
+
+// Cursor displays content which can be updated on the fly.
+// You can use this to create live output, charts, dropdowns, etc.
+type Cursor struct {
+ writer Writer
+}
+
+// NewCursor creates a new Cursor instance writing to os.Stdout.
+func NewCursor() *Cursor {
+ return &Cursor{writer: os.Stdout}
+}
+
+// WithWriter allows for any arbitrary Writer to be used
+// for cursor movement abstracted.
+func (c *Cursor) WithWriter(w Writer) *Cursor {
+ if w != nil {
+ c.writer = w
+ }
+
+ return c
+}
diff --git a/vendor/atomicgo.dev/cursor/cursor_other.go b/vendor/atomicgo.dev/cursor/cursor_other.go
new file mode 100644
index 0000000..7c18557
--- /dev/null
+++ b/vendor/atomicgo.dev/cursor/cursor_other.go
@@ -0,0 +1,67 @@
+//go:build !windows
+// +build !windows
+
+package cursor
+
+import (
+ "fmt"
+)
+
+// Up moves the cursor n lines up relative to the current position.
+func (c *Cursor) Up(n int) {
+ if n > 0 {
+ fmt.Fprintf(c.writer, "\x1b[%dA", n)
+ }
+}
+
+// Down moves the cursor n lines down relative to the current position.
+func (c *Cursor) Down(n int) {
+ if n > 0 {
+ fmt.Fprintf(c.writer, "\x1b[%dB", n)
+ }
+}
+
+// Right moves the cursor n characters to the right relative to the current position.
+func (c *Cursor) Right(n int) {
+ if n > 0 {
+ fmt.Fprintf(c.writer, "\x1b[%dC", n)
+ }
+}
+
+// Left moves the cursor n characters to the left relative to the current position.
+func (c *Cursor) Left(n int) {
+ if n > 0 {
+ fmt.Fprintf(c.writer, "\x1b[%dD", n)
+ }
+}
+
+// HorizontalAbsolute moves the cursor to n horizontally.
+// The position n is absolute to the start of the line.
+func (c *Cursor) HorizontalAbsolute(n int) {
+ n++ // Moves the line to the character after n
+ fmt.Fprintf(c.writer, "\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 they reopen the terminal.
+func (c *Cursor) Show() {
+ fmt.Fprint(c.writer, "\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 they reopen the terminal.
+func (c *Cursor) Hide() {
+ fmt.Fprintf(c.writer, "\x1b[?25l")
+}
+
+// ClearLine clears the current line and moves the cursor to it's start position.
+func (c *Cursor) ClearLine() {
+ fmt.Fprintf(c.writer, "\x1b[2K")
+}
+
+// Clear clears the current position and moves the cursor to the left.
+func (c *Cursor) Clear() {
+ fmt.Fprintf(c.writer, "\x1b[K")
+}
diff --git a/vendor/atomicgo.dev/cursor/cursor_test_linux.go b/vendor/atomicgo.dev/cursor/cursor_test_linux.go
new file mode 100644
index 0000000..6a37f40
--- /dev/null
+++ b/vendor/atomicgo.dev/cursor/cursor_test_linux.go
@@ -0,0 +1,130 @@
+package cursor
+
+import (
+ "log"
+ "os"
+ "testing"
+)
+
+// TestCustomIOWriter tests the cursor functions with a custom Writer.
+func TestCustomIOWriter(t *testing.T) {
+ tmpFile, err := os.CreateTemp("", "testingTmpFile-")
+ defer os.Remove(tmpFile.Name())
+
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ w := tmpFile
+ SetTarget(w)
+
+ Up(2)
+
+ expected := "\x1b[2A"
+ actual := getFileContent(t, w.Name())
+
+ if expected != actual {
+ t.Errorf("wanted: %v, got %v", expected, actual)
+ }
+
+ clearFile(t, w)
+ Down(2)
+
+ expected = "\x1b[2B"
+ actual = getFileContent(t, w.Name())
+
+ if expected != actual {
+ t.Errorf("wanted: %v, got %v", expected, actual)
+ }
+
+ clearFile(t, w)
+ Right(2)
+
+ expected = "\x1b[2C"
+ actual = getFileContent(t, w.Name())
+
+ if expected != actual {
+ t.Errorf("wanted: %v, got %v", expected, actual)
+ }
+
+ clearFile(t, w)
+ Left(2)
+
+ expected = "\x1b[2D"
+ actual = getFileContent(t, w.Name())
+
+ if expected != actual {
+ t.Errorf("wanted: %v, got %v", expected, actual)
+ }
+
+ clearFile(t, w)
+ Hide()
+
+ expected = "\x1b[?25l"
+ actual = getFileContent(t, w.Name())
+
+ if expected != actual {
+ t.Errorf("wanted: %v, got %v", expected, actual)
+ }
+
+ clearFile(t, w)
+ Show()
+
+ expected = "\x1b[?25h"
+ actual = getFileContent(t, w.Name())
+
+ if expected != actual {
+ t.Errorf("wanted: %v, got %v", expected, actual)
+ }
+
+ clearFile(t, w)
+ ClearLine()
+
+ expected = "\x1b[2K"
+ actual = getFileContent(t, w.Name())
+
+ if expected != actual {
+ t.Errorf("wanted: %v, got %v", expected, actual)
+ }
+
+ clearFile(t, w)
+ HorizontalAbsolute(3)
+
+ expected = "\x1b[4G"
+ actual = getFileContent(t, w.Name())
+
+ if expected != actual {
+ t.Errorf("wanted: %v, got %v", expected, actual)
+ }
+}
+
+func getFileContent(t *testing.T, fileName string) string {
+ t.Helper()
+
+ content, err := os.ReadFile(fileName)
+ if err != nil {
+ t.Errorf("failed to read file contents: %s", err)
+
+ return ""
+ }
+
+ return string(content)
+}
+
+func clearFile(t *testing.T, file *os.File) {
+ t.Helper()
+
+ err := file.Truncate(0)
+ if err != nil {
+ t.Errorf("failed to clear file")
+
+ return
+ }
+
+ _, err = file.Seek(0, 0)
+ if err != nil {
+ t.Errorf("failed to clear file")
+
+ return
+ }
+}
diff --git a/vendor/atomicgo.dev/cursor/cursor_windows.go b/vendor/atomicgo.dev/cursor/cursor_windows.go
new file mode 100644
index 0000000..ebe2bc5
--- /dev/null
+++ b/vendor/atomicgo.dev/cursor/cursor_windows.go
@@ -0,0 +1,118 @@
+//go:build windows
+// +build windows
+
+package cursor
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+// Up moves the cursor n lines up relative to the current position.
+func (c *Cursor) Up(n int) {
+ c.move(0, -n)
+}
+
+// Down moves the cursor n lines down relative to the current position.
+func (c *Cursor) Down(n int) {
+ c.move(0, n)
+}
+
+// Right moves the cursor n characters to the right relative to the current position.
+func (c *Cursor) Right(n int) {
+ c.move(n, 0)
+}
+
+// Left moves the cursor n characters to the left relative to the current position.
+func (c *Cursor) Left(n int) {
+ c.move(-n, 0)
+}
+
+func (c *Cursor) move(x int, y int) {
+ handle := syscall.Handle(c.writer.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 (c *Cursor) HorizontalAbsolute(n int) {
+ handle := syscall.Handle(c.writer.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 (c *Cursor) Show() {
+ handle := syscall.Handle(c.writer.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 (c *Cursor) Hide() {
+ handle := syscall.Handle(c.writer.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 its start position.
+func (c *Cursor) ClearLine() {
+ handle := syscall.Handle(c.writer.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)))
+}
+
+// Clear clears the current position and moves the cursor to the left.
+func (c *Cursor) Clear() {
+ handle := syscall.Handle(c.writer.Fd())
+
+ var csbi consoleScreenBufferInfo
+ _, _, _ = procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+
+ var w uint32
+ cursor := csbi.cursorPosition
+ _, _, _ = procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(1), uintptr(*(*int32)(unsafe.Pointer(&cursor))), uintptr(unsafe.Pointer(&w)))
+
+ if cursor.x > 0 {
+ cursor.x--
+ }
+ _, _, _ = procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursor))))
+}
diff --git a/vendor/atomicgo.dev/cursor/doc.go b/vendor/atomicgo.dev/cursor/doc.go
new file mode 100644
index 0000000..9c43e8a
--- /dev/null
+++ b/vendor/atomicgo.dev/cursor/doc.go
@@ -0,0 +1,9 @@
+/*
+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.
+
+Works niceley with https://github.com/atomicgo/keyboard
+
+Special thanks to github.com/k0kubun/go-ansi which this project is based on.
+*/
+package cursor
diff --git a/vendor/atomicgo.dev/cursor/syscall_windows.go b/vendor/atomicgo.dev/cursor/syscall_windows.go
new file mode 100644
index 0000000..d4bcdf7
--- /dev/null
+++ b/vendor/atomicgo.dev/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/atomicgo.dev/cursor/utils.go b/vendor/atomicgo.dev/cursor/utils.go
new file mode 100644
index 0000000..4b75f09
--- /dev/null
+++ b/vendor/atomicgo.dev/cursor/utils.go
@@ -0,0 +1,151 @@
+package cursor
+
+import (
+ "io"
+ "os"
+)
+
+//
+// Helpers for global cursor handling on os.Stdout
+//
+
+var autoheight int
+var cursor = &Cursor{writer: os.Stdout}
+
+// Writer is an expanded io.Writer interface with a file descriptor.
+type Writer interface {
+ io.Writer
+ Fd() uintptr
+}
+
+// SetTarget sets to output target of the default curser to the
+// provided cursor.Writer (wrapping io.Writer).
+func SetTarget(w Writer) {
+ cursor = cursor.WithWriter(w)
+}
+
+// Up moves the cursor n lines up relative to the current position.
+func Up(n int) {
+ cursor.Up(n)
+ autoheight += n
+}
+
+// Down moves the cursor n lines down relative to the current position.
+func Down(n int) {
+ cursor.Down(n)
+
+ if autoheight > 0 {
+ autoheight -= n
+ }
+}
+
+// Right moves the cursor n characters to the right relative to the current position.
+func Right(n int) {
+ cursor.Right(n)
+}
+
+// Left moves the cursor n characters to the left relative to the current position.
+func Left(n int) {
+ cursor.Left(n)
+}
+
+// HorizontalAbsolute moves the cursor to n horizontally.
+// The position n is absolute to the start of the line.
+func HorizontalAbsolute(n int) {
+ cursor.HorizontalAbsolute(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 they reopen the terminal.
+func Show() {
+ cursor.Show()
+}
+
+// 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 they reopen the terminal.
+func Hide() {
+ cursor.Hide()
+}
+
+// ClearLine clears the current line and moves the cursor to it's start position.
+func ClearLine() {
+ cursor.ClearLine()
+}
+
+// Clear clears the current position and moves the cursor to the left.
+func Clear() {
+ cursor.Clear()
+}
+
+// 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 autoheight > 0 {
+ Down(autoheight)
+ StartOfLine()
+
+ autoheight = 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/atomicgo.dev/keyboard/.gitignore b/vendor/atomicgo.dev/keyboard/.gitignore
new file mode 100644
index 0000000..32b7c23
--- /dev/null
+++ b/vendor/atomicgo.dev/keyboard/.gitignore
@@ -0,0 +1,33 @@
+### 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 folder
+experimenting
diff --git a/vendor/atomicgo.dev/keyboard/.golangci.yml b/vendor/atomicgo.dev/keyboard/.golangci.yml
new file mode 100644
index 0000000..d18a485
--- /dev/null
+++ b/vendor/atomicgo.dev/keyboard/.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/atomicgo.dev/keyboard/LICENSE b/vendor/atomicgo.dev/keyboard/LICENSE
new file mode 100644
index 0000000..c78d7a5
--- /dev/null
+++ b/vendor/atomicgo.dev/keyboard/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/atomicgo.dev/keyboard/README.md b/vendor/atomicgo.dev/keyboard/README.md
new file mode 100644
index 0000000..73601c3
--- /dev/null
+++ b/vendor/atomicgo.dev/keyboard/README.md
@@ -0,0 +1,185 @@
+AtomicGo | keyboard
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+---
+
+
+Get The Module
+|
+Documentation
+|
+Contributing
+|
+Code of Conduct
+
+
+---
+
+
+
+
+
+
+
+
+
+
+ -----------------------------------------------------------------------------------------------------
+
+
+
+
+
+go get atomicgo.dev/keyboard
+
+
+
+
+
+ -----------------------------------------------------------------------------------------------------
+
+
+
+
+
+
+## Description
+
+Package keyboard can be used to read key presses from the keyboard, while in a
+terminal application. It's crossplatform and keypresses can be combined to check
+for ctrl+c, alt+4, ctrl-shift, alt+ctrl+right, etc. It can also be used to
+simulate (mock) keypresses for CI testing.
+
+Works nicely with https://atomicgo.dev/cursor
+
+## Simple Usage
+
+```go
+keyboard.Listen(func(key keys.Key) (stop bool, err error) {
+ if key.Code == keys.CtrlC {
+ return true, nil // Stop listener by returning true on Ctrl+C
+ }
+
+ fmt.Println("\r" + key.String()) // Print every key press
+ return false, nil // Return false to continue listening
+})
+```
+
+## Advanced Usage
+
+```go
+// Stop keyboard listener on Escape key press or CTRL+C.
+// Exit application on "q" key press.
+// Print every rune key press.
+// Print every other key press.
+keyboard.Listen(func(key keys.Key) (stop bool, err error) {
+ switch key.Code {
+ case keys.CtrlC, keys.Escape:
+ return true, nil // Return true to stop listener
+ case keys.RuneKey: // Check if key is a rune key (a, b, c, 1, 2, 3, ...)
+ if key.String() == "q" { // Check if key is "q"
+ fmt.Println("\rQuitting application")
+ os.Exit(0) // Exit application
+ }
+ fmt.Printf("\rYou pressed the rune key: %s\n", key)
+ default:
+ fmt.Printf("\rYou pressed: %s\n", key)
+ }
+
+ return false, nil // Return false to continue listening
+})
+```
+
+## Simulate Key Presses (for mocking in tests)
+
+```go
+go func() {
+ keyboard.SimulateKeyPress("Hello") // Simulate key press for every letter in string
+ keyboard.SimulateKeyPress(keys.Enter) // Simulate key press for Enter
+ keyboard.SimulateKeyPress(keys.CtrlShiftRight) // Simulate key press for Ctrl+Shift+Right
+ keyboard.SimulateKeyPress('x') // Simulate key press for a single rune
+ keyboard.SimulateKeyPress('x', keys.Down, 'a') // Simulate key presses for multiple inputs
+
+ keyboard.SimulateKeyPress(keys.Escape) // Simulate key press for Escape, which quits the program
+}()
+
+keyboard.Listen(func(key keys.Key) (stop bool, err error) {
+ if key.Code == keys.Escape || key.Code == keys.CtrlC {
+ os.Exit(0) // Exit program on Escape
+ }
+
+ fmt.Println("\r" + key.String()) // Print every key press
+ return false, nil // Return false to continue listening
+})
+```
+
+## Usage
+
+#### func Listen
+
+```go
+func Listen(onKeyPress func(key keys.Key) (stop bool, err error)) error
+```
+Listen calls a callback function when a key is pressed.
+
+Simple example:
+
+ keyboard.Listen(func(key keys.Key) (stop bool, err error) {
+ if key.Code == keys.CtrlC {
+ return true, nil // Stop listener by returning true on Ctrl+C
+ }
+
+ fmt.Println("\r" + key.String()) // Print every key press
+ return false, nil // Return false to continue listening
+ })
+
+#### func SimulateKeyPress
+
+```go
+func SimulateKeyPress(input ...interface{}) error
+```
+SimulateKeyPress simulate a key press. It can be used to mock user input and
+test your application.
+
+Example:
+
+ go func() {
+ keyboard.SimulateKeyPress("Hello") // Simulate key press for every letter in string
+ keyboard.SimulateKeyPress(keys.Enter) // Simulate key press for Enter
+ keyboard.SimulateKeyPress(keys.CtrlShiftRight) // Simulate key press for Ctrl+Shift+Right
+ keyboard.SimulateKeyPress('x') // Simulate key press for a single rune
+ keyboard.SimulateKeyPress('x', keys.Down, 'a') // Simulate key presses for multiple inputs
+ }()
+
+---
+
+> [AtomicGo.dev](https://atomicgo.dev) ·
+> with ❤️ by [@MarvinJWendt](https://github.com/MarvinJWendt) |
+> [MarvinJWendt.com](https://marvinjwendt.com)
diff --git a/vendor/atomicgo.dev/keyboard/codecov.yml b/vendor/atomicgo.dev/keyboard/codecov.yml
new file mode 100644
index 0000000..bfdc987
--- /dev/null
+++ b/vendor/atomicgo.dev/keyboard/codecov.yml
@@ -0,0 +1,8 @@
+coverage:
+ status:
+ project:
+ default:
+ informational: true
+ patch:
+ default:
+ informational: true
diff --git a/vendor/atomicgo.dev/keyboard/doc.go b/vendor/atomicgo.dev/keyboard/doc.go
new file mode 100644
index 0000000..d6557b6
--- /dev/null
+++ b/vendor/atomicgo.dev/keyboard/doc.go
@@ -0,0 +1,62 @@
+/*
+Package keyboard can be used to read key presses from the keyboard, while in a terminal application. It's crossplatform and keypresses can be combined to check for ctrl+c, alt+4, ctrl-shift, alt+ctrl+right, etc.
+It can also be used to simulate (mock) keypresses for CI testing.
+
+Works nicely with https://atomicgo.dev/cursor
+
+## Simple Usage
+
+ keyboard.Listen(func(key keys.Key) (stop bool, err error) {
+ if key.Code == keys.CtrlC {
+ return true, nil // Stop listener by returning true on Ctrl+C
+ }
+
+ fmt.Println("\r" + key.String()) // Print every key press
+ return false, nil // Return false to continue listening
+ })
+
+## Advanced Usage
+
+ // Stop keyboard listener on Escape key press or CTRL+C.
+ // Exit application on "q" key press.
+ // Print every rune key press.
+ // Print every other key press.
+ keyboard.Listen(func(key keys.Key) (stop bool, err error) {
+ switch key.Code {
+ case keys.CtrlC, keys.Escape:
+ return true, nil // Return true to stop listener
+ case keys.RuneKey: // Check if key is a rune key (a, b, c, 1, 2, 3, ...)
+ if key.String() == "q" { // Check if key is "q"
+ fmt.Println("\rQuitting application")
+ os.Exit(0) // Exit application
+ }
+ fmt.Printf("\rYou pressed the rune key: %s\n", key)
+ default:
+ fmt.Printf("\rYou pressed: %s\n", key)
+ }
+
+ return false, nil // Return false to continue listening
+ })
+
+## Simulate Key Presses (for mocking in tests)
+
+ go func() {
+ keyboard.SimulateKeyPress("Hello") // Simulate key press for every letter in string
+ keyboard.SimulateKeyPress(keys.Enter) // Simulate key press for Enter
+ keyboard.SimulateKeyPress(keys.CtrlShiftRight) // Simulate key press for Ctrl+Shift+Right
+ keyboard.SimulateKeyPress('x') // Simulate key press for a single rune
+ keyboard.SimulateKeyPress('x', keys.Down, 'a') // Simulate key presses for multiple inputs
+
+ keyboard.SimulateKeyPress(keys.Escape) // Simulate key press for Escape, which quits the program
+ }()
+
+ keyboard.Listen(func(key keys.Key) (stop bool, err error) {
+ if key.Code == keys.Escape || key.Code == keys.CtrlC {
+ os.Exit(0) // Exit program on Escape
+ }
+
+ fmt.Println("\r" + key.String()) // Print every key press
+ return false, nil // Return false to continue listening
+ })
+*/
+package keyboard
diff --git a/vendor/atomicgo.dev/keyboard/input.go b/vendor/atomicgo.dev/keyboard/input.go
new file mode 100644
index 0000000..21e9c3f
--- /dev/null
+++ b/vendor/atomicgo.dev/keyboard/input.go
@@ -0,0 +1,237 @@
+package keyboard
+
+import (
+ "errors"
+ "fmt"
+ "os"
+ "unicode/utf8"
+
+ "atomicgo.dev/keyboard/internal"
+ "atomicgo.dev/keyboard/keys"
+)
+
+// Sequence mappings.
+var sequences = map[string]keys.Key{
+ // Arrow keys
+ "\x1b[A": {Code: keys.Up},
+ "\x1b[B": {Code: keys.Down},
+ "\x1b[C": {Code: keys.Right},
+ "\x1b[D": {Code: keys.Left},
+ "\x1b[1;2A": {Code: keys.ShiftUp},
+ "\x1b[1;2B": {Code: keys.ShiftDown},
+ "\x1b[1;2C": {Code: keys.ShiftRight},
+ "\x1b[1;2D": {Code: keys.ShiftLeft},
+ "\x1b[OA": {Code: keys.ShiftUp},
+ "\x1b[OB": {Code: keys.ShiftDown},
+ "\x1b[OC": {Code: keys.ShiftRight},
+ "\x1b[OD": {Code: keys.ShiftLeft},
+ "\x1b[a": {Code: keys.ShiftUp},
+ "\x1b[b": {Code: keys.ShiftDown},
+ "\x1b[c": {Code: keys.ShiftRight},
+ "\x1b[d": {Code: keys.ShiftLeft},
+ "\x1b[1;3A": {Code: keys.Up, AltPressed: true},
+ "\x1b[1;3B": {Code: keys.Down, AltPressed: true},
+ "\x1b[1;3C": {Code: keys.Right, AltPressed: true},
+ "\x1b[1;3D": {Code: keys.Left, AltPressed: true},
+ "\x1b\x1b[A": {Code: keys.Up, AltPressed: true},
+ "\x1b\x1b[B": {Code: keys.Down, AltPressed: true},
+ "\x1b\x1b[C": {Code: keys.Right, AltPressed: true},
+ "\x1b\x1b[D": {Code: keys.Left, AltPressed: true},
+ "\x1b[1;4A": {Code: keys.ShiftUp, AltPressed: true},
+ "\x1b[1;4B": {Code: keys.ShiftDown, AltPressed: true},
+ "\x1b[1;4C": {Code: keys.ShiftRight, AltPressed: true},
+ "\x1b[1;4D": {Code: keys.ShiftLeft, AltPressed: true},
+ "\x1b\x1b[a": {Code: keys.ShiftUp, AltPressed: true},
+ "\x1b\x1b[b": {Code: keys.ShiftDown, AltPressed: true},
+ "\x1b\x1b[c": {Code: keys.ShiftRight, AltPressed: true},
+ "\x1b\x1b[d": {Code: keys.ShiftLeft, AltPressed: true},
+ "\x1b[1;5A": {Code: keys.CtrlUp},
+ "\x1b[1;5B": {Code: keys.CtrlDown},
+ "\x1b[1;5C": {Code: keys.CtrlRight},
+ "\x1b[1;5D": {Code: keys.CtrlLeft},
+ "\x1b[Oa": {Code: keys.CtrlUp, AltPressed: true},
+ "\x1b[Ob": {Code: keys.CtrlDown, AltPressed: true},
+ "\x1b[Oc": {Code: keys.CtrlRight, AltPressed: true},
+ "\x1b[Od": {Code: keys.CtrlLeft, AltPressed: true},
+ "\x1b[1;6A": {Code: keys.CtrlShiftUp},
+ "\x1b[1;6B": {Code: keys.CtrlShiftDown},
+ "\x1b[1;6C": {Code: keys.CtrlShiftRight},
+ "\x1b[1;6D": {Code: keys.CtrlShiftLeft},
+ "\x1b[1;7A": {Code: keys.CtrlUp, AltPressed: true},
+ "\x1b[1;7B": {Code: keys.CtrlDown, AltPressed: true},
+ "\x1b[1;7C": {Code: keys.CtrlRight, AltPressed: true},
+ "\x1b[1;7D": {Code: keys.CtrlLeft, AltPressed: true},
+ "\x1b[1;8A": {Code: keys.CtrlShiftUp, AltPressed: true},
+ "\x1b[1;8B": {Code: keys.CtrlShiftDown, AltPressed: true},
+ "\x1b[1;8C": {Code: keys.CtrlShiftRight, AltPressed: true},
+ "\x1b[1;8D": {Code: keys.CtrlShiftLeft, AltPressed: true},
+
+ // Miscellaneous keys
+ "\x1b[Z": {Code: keys.ShiftTab},
+ "\x1b[3~": {Code: keys.Delete},
+ "\x1b[3;3~": {Code: keys.Delete, AltPressed: true},
+ "\x1b[1~": {Code: keys.Home},
+ "\x1b[1;3H~": {Code: keys.Home, AltPressed: true},
+ "\x1b[4~": {Code: keys.End},
+ "\x1b[1;3F~": {Code: keys.End, AltPressed: true},
+ "\x1b[5~": {Code: keys.PgUp},
+ "\x1b[5;3~": {Code: keys.PgUp, AltPressed: true},
+ "\x1b[6~": {Code: keys.PgDown},
+ "\x1b[6;3~": {Code: keys.PgDown, AltPressed: true},
+ "\x1b[7~": {Code: keys.Home},
+ "\x1b[8~": {Code: keys.End},
+ "\x1b\x1b[3~": {Code: keys.Delete, AltPressed: true},
+ "\x1b\x1b[5~": {Code: keys.PgUp, AltPressed: true},
+ "\x1b\x1b[6~": {Code: keys.PgDown, AltPressed: true},
+ "\x1b\x1b[7~": {Code: keys.Home, AltPressed: true},
+ "\x1b\x1b[8~": {Code: keys.End, AltPressed: true},
+
+ // Function keys
+ "\x1bOP": {Code: keys.F1},
+ "\x1bOQ": {Code: keys.F2},
+ "\x1bOR": {Code: keys.F3},
+ "\x1bOS": {Code: keys.F4},
+ "\x1b[15~": {Code: keys.F5},
+ "\x1b[17~": {Code: keys.F6},
+ "\x1b[18~": {Code: keys.F7},
+ "\x1b[19~": {Code: keys.F8},
+ "\x1b[20~": {Code: keys.F9},
+ "\x1b[21~": {Code: keys.F10},
+ "\x1b[23~": {Code: keys.F11},
+ "\x1b[24~": {Code: keys.F12},
+ "\x1b[1;2P": {Code: keys.F13},
+ "\x1b[1;2Q": {Code: keys.F14},
+ "\x1b[1;2R": {Code: keys.F15},
+ "\x1b[1;2S": {Code: keys.F16},
+ "\x1b[15;2~": {Code: keys.F17},
+ "\x1b[17;2~": {Code: keys.F18},
+ "\x1b[18;2~": {Code: keys.F19},
+ "\x1b[19;2~": {Code: keys.F20},
+
+ // Function keys with the alt modifier
+ "\x1b[1;3P": {Code: keys.F1, AltPressed: true},
+ "\x1b[1;3Q": {Code: keys.F2, AltPressed: true},
+ "\x1b[1;3R": {Code: keys.F3, AltPressed: true},
+ "\x1b[1;3S": {Code: keys.F4, AltPressed: true},
+ "\x1b[15;3~": {Code: keys.F5, AltPressed: true},
+ "\x1b[17;3~": {Code: keys.F6, AltPressed: true},
+ "\x1b[18;3~": {Code: keys.F7, AltPressed: true},
+ "\x1b[19;3~": {Code: keys.F8, AltPressed: true},
+ "\x1b[20;3~": {Code: keys.F9, AltPressed: true},
+ "\x1b[21;3~": {Code: keys.F10, AltPressed: true},
+ "\x1b[23;3~": {Code: keys.F11, AltPressed: true},
+ "\x1b[24;3~": {Code: keys.F12, AltPressed: true},
+
+ // Function keys, urxvt
+ "\x1b[11~": {Code: keys.F1},
+ "\x1b[12~": {Code: keys.F2},
+ "\x1b[13~": {Code: keys.F3},
+ "\x1b[14~": {Code: keys.F4},
+ "\x1b[25~": {Code: keys.F13},
+ "\x1b[26~": {Code: keys.F14},
+ "\x1b[28~": {Code: keys.F15},
+ "\x1b[29~": {Code: keys.F16},
+ "\x1b[31~": {Code: keys.F17},
+ "\x1b[32~": {Code: keys.F18},
+ "\x1b[33~": {Code: keys.F19},
+ "\x1b[34~": {Code: keys.F20},
+
+ // Function keys with the alt modifier, urxvt
+ "\x1b\x1b[11~": {Code: keys.F1, AltPressed: true},
+ "\x1b\x1b[12~": {Code: keys.F2, AltPressed: true},
+ "\x1b\x1b[13~": {Code: keys.F3, AltPressed: true},
+ "\x1b\x1b[14~": {Code: keys.F4, AltPressed: true},
+ "\x1b\x1b[25~": {Code: keys.F13, AltPressed: true},
+ "\x1b\x1b[26~": {Code: keys.F14, AltPressed: true},
+ "\x1b\x1b[28~": {Code: keys.F15, AltPressed: true},
+ "\x1b\x1b[29~": {Code: keys.F16, AltPressed: true},
+ "\x1b\x1b[31~": {Code: keys.F17, AltPressed: true},
+ "\x1b\x1b[32~": {Code: keys.F18, AltPressed: true},
+ "\x1b\x1b[33~": {Code: keys.F19, AltPressed: true},
+ "\x1b\x1b[34~": {Code: keys.F20, AltPressed: true},
+}
+
+var hexCodes = map[string]keys.Key{
+ "1b0d": {Code: keys.Enter, AltPressed: true},
+ "1b7f": {Code: keys.Backspace, AltPressed: true},
+ // support other backspace variants
+ "1b08": {Code: keys.Backspace, AltPressed: true},
+ "08": {Code: keys.Backspace},
+
+ // Powershell
+ "1b4f41": {Code: keys.Up, AltPressed: false},
+ "1b4f42": {Code: keys.Down, AltPressed: false},
+ "1b4f43": {Code: keys.Right, AltPressed: false},
+ "1b4f44": {Code: keys.Left, AltPressed: false},
+}
+
+func getKeyPress() (keys.Key, error) {
+ var buf [256]byte
+
+ // Read
+ numBytes, err := inputTTY.Read(buf[:])
+ if err != nil {
+ if errors.Is(err, os.ErrClosed) {
+ return keys.Key{}, nil
+ }
+
+ if err.Error() == "EOF" {
+ return keys.Key{}, nil
+ } else if err.Error() == "invalid argument" {
+ return keys.Key{}, nil
+ }
+
+ return keys.Key{}, nil
+ }
+
+ // Check if it's a sequence
+ if k, ok := sequences[string(buf[:numBytes])]; ok {
+ return k, nil
+ }
+
+ hex := fmt.Sprintf("%x", buf[:numBytes])
+ if k, ok := hexCodes[hex]; ok {
+ return k, nil
+ }
+
+ // Check if the alt key is pressed.
+ if numBytes > 1 && buf[0] == 0x1b {
+ // Remove the initial escape sequence
+ c, _ := utf8.DecodeRune(buf[1:])
+ if c == utf8.RuneError {
+ return keys.Key{}, fmt.Errorf("could not decode rune after removing initial escape sequence")
+ }
+
+ return keys.Key{AltPressed: true, Code: keys.RuneKey, Runes: []rune{c}}, nil
+ }
+
+ var runes []rune
+ b := buf[:numBytes]
+
+ // Translate stdin into runes.
+ for i, w := 0, 0; i < len(b); i += w { //nolint:wastedassign
+ r, width := utf8.DecodeRune(b[i:])
+ if r == utf8.RuneError {
+ return keys.Key{}, fmt.Errorf("could not decode rune: %w", err)
+ }
+ runes = append(runes, r)
+ w = width
+ }
+
+ if len(runes) == 0 {
+ return keys.Key{}, fmt.Errorf("received 0 runes from stdin")
+ } else if len(runes) > 1 {
+ return keys.Key{Code: keys.RuneKey, Runes: runes}, nil
+ }
+
+ r := keys.KeyCode(runes[0])
+ if numBytes == 1 && r <= internal.KeyUnitSeparator || r == internal.KeyDelete {
+ return keys.Key{Code: r}, nil
+ }
+
+ if runes[0] == ' ' {
+ return keys.Key{Code: keys.Space, Runes: runes}, nil
+ }
+
+ return keys.Key{Code: keys.RuneKey, Runes: runes}, nil
+}
diff --git a/vendor/atomicgo.dev/keyboard/internal/keys.go b/vendor/atomicgo.dev/keyboard/internal/keys.go
new file mode 100644
index 0000000..6f73e16
--- /dev/null
+++ b/vendor/atomicgo.dev/keyboard/internal/keys.go
@@ -0,0 +1,38 @@
+package internal
+
+// See: https://en.wikipedia.org/wiki/C0_and_C1_control_codes
+const (
+ KeyNull = 0
+ KeyStartOfHeading = 1
+ KeyStartOfText = 2
+ KeyExit = 3 // ctrl-c
+ KeyEndOfTransimission = 4
+ KeyEnquiry = 5
+ KeyAcknowledge = 6
+ KeyBELL = 7
+ KeyBackspace = 8
+ KeyHorizontalTabulation = 9
+ KeyLineFeed = 10
+ KeyVerticalTabulation = 11
+ KeyFormFeed = 12
+ KeyCarriageReturn = 13
+ KeyShiftOut = 14
+ KeyShiftIn = 15
+ KeyDataLinkEscape = 16
+ KeyDeviceControl1 = 17
+ KeyDeviceControl2 = 18
+ KeyDeviceControl3 = 19
+ KeyDeviceControl4 = 20
+ KeyNegativeAcknowledge = 21
+ KeySynchronousIdle = 22
+ KeyEndOfTransmissionBlock = 23
+ KeyCancel = 24
+ KeyEndOfMedium = 25
+ KeySubstitution = 26
+ KeyEscape = 27
+ KeyFileSeparator = 28
+ KeyGroupSeparator = 29
+ KeyRecordSeparator = 30
+ KeyUnitSeparator = 31
+ KeyDelete = 127
+)
diff --git a/vendor/atomicgo.dev/keyboard/keyboard.go b/vendor/atomicgo.dev/keyboard/keyboard.go
new file mode 100644
index 0000000..0171d22
--- /dev/null
+++ b/vendor/atomicgo.dev/keyboard/keyboard.go
@@ -0,0 +1,179 @@
+package keyboard
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/containerd/console"
+
+ "atomicgo.dev/keyboard/keys"
+)
+
+var windowsStdin *os.File
+var con console.Console
+var stdin = os.Stdin
+var inputTTY *os.File
+var mockChannel = make(chan keys.Key)
+
+var mocking = false
+
+func startListener() error {
+ err := initInput()
+ if err != nil {
+ return err
+ }
+
+ if mocking {
+ return nil
+ }
+
+ if con != nil {
+ err := con.SetRaw()
+ if err != nil {
+ return fmt.Errorf("failed to set raw mode: %w", err)
+ }
+ }
+
+ inputTTY, err = openInputTTY()
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func stopListener() error {
+ if con != nil {
+ err := con.Reset()
+ if err != nil {
+
+ return fmt.Errorf("failed to reset console: %w", err)
+ }
+ }
+
+ return restoreInput()
+}
+
+// Listen calls a callback function when a key is pressed.
+//
+// Simple example:
+//
+// keyboard.Listen(func(key keys.Key) (stop bool, err error) {
+// if key.Code == keys.CtrlC {
+// return true, nil // Stop listener by returning true on Ctrl+C
+// }
+//
+// fmt.Println("\r" + key.String()) // Print every key press
+// return false, nil // Return false to continue listening
+// })
+func Listen(onKeyPress func(key keys.Key) (stop bool, err error)) error {
+ cancel := make(chan bool)
+ stopRoutine := false
+
+ go func() {
+ for {
+ select {
+ case c := <-cancel:
+ if c {
+ return
+ }
+ case keyInfo := <-mockChannel:
+ stopRoutine, _ = onKeyPress(keyInfo)
+ if stopRoutine {
+ closeInput()
+ inputTTY.Close()
+ }
+ }
+ }
+ }()
+
+ err := startListener()
+ if err != nil {
+ if err.Error() != "provided file is not a console" {
+ return err
+ }
+ }
+
+ for !stopRoutine {
+ key, err := getKeyPress()
+ if err != nil {
+ return err
+ }
+
+ // check if returned key is empty
+ // if reflect.DeepEqual(key, keys.Key{}) {
+ // return nil
+ // }
+
+ stop, err := onKeyPress(key)
+ if err != nil {
+ return err
+ }
+
+ if stop {
+ closeInput()
+ inputTTY.Close()
+ break
+ }
+ }
+
+ err = stopListener()
+ if err != nil {
+ return err
+ }
+
+ cancel <- true
+
+ return nil
+}
+
+// SimulateKeyPress simulate a key press. It can be used to mock user stdin and test your application.
+//
+// Example:
+//
+// go func() {
+// keyboard.SimulateKeyPress("Hello") // Simulate key press for every letter in string
+// keyboard.SimulateKeyPress(keys.Enter) // Simulate key press for Enter
+// keyboard.SimulateKeyPress(keys.CtrlShiftRight) // Simulate key press for Ctrl+Shift+Right
+// keyboard.SimulateKeyPress('x') // Simulate key press for a single rune
+// keyboard.SimulateKeyPress('x', keys.Down, 'a') // Simulate key presses for multiple inputs
+// }()
+func SimulateKeyPress(input ...interface{}) error {
+ for _, key := range input {
+ // Check if key is a keys.Key
+ if key, ok := key.(keys.Key); ok {
+ mockChannel <- key
+ return nil
+ }
+
+ // Check if key is a rune
+ if key, ok := key.(rune); ok {
+ mockChannel <- keys.Key{
+ Code: keys.RuneKey,
+ Runes: []rune{key},
+ }
+ return nil
+ }
+
+ // Check if key is a string
+ if key, ok := key.(string); ok {
+ for _, r := range key {
+ mockChannel <- keys.Key{
+ Code: keys.RuneKey,
+ Runes: []rune{r},
+ }
+ }
+ return nil
+ }
+
+ // Check if key is a KeyCode
+ if key, ok := key.(keys.KeyCode); ok {
+ mockChannel <- keys.Key{
+ Code: key,
+ }
+ return nil
+ }
+ }
+
+ return nil
+}
diff --git a/vendor/atomicgo.dev/keyboard/keys/keys.go b/vendor/atomicgo.dev/keyboard/keys/keys.go
new file mode 100644
index 0000000..42b6e71
--- /dev/null
+++ b/vendor/atomicgo.dev/keyboard/keys/keys.go
@@ -0,0 +1,235 @@
+package keys
+
+import "atomicgo.dev/keyboard/internal"
+
+// Key contains information about a keypress.
+type Key struct {
+ Code KeyCode
+ Runes []rune // Runes that the key produced. Most key pressed produce one single rune.
+ AltPressed bool // True when alt is pressed while the key is typed.
+}
+
+// String returns a string representation of the key.
+// (e.g. "a", "B", "alt+a", "enter", "ctrl+c", "shift-down", etc.)
+//
+// Example:
+//
+// k := keys.Key{Code: keys.Enter}
+// fmt.Println(k)
+// // Output: enter
+func (k Key) String() (str string) {
+ if k.AltPressed {
+ str += "alt+"
+ }
+ if k.Code == RuneKey {
+ str += string(k.Runes)
+
+ return str
+ } else if s, ok := keyNames[k.Code]; ok {
+ str += s
+
+ return str
+ }
+
+ return ""
+}
+
+// KeyCode is an integer representation of a non-rune key, such as Escape, Enter, etc.
+// All other keys are represented by a rune and have the KeyCode: RuneKey.
+//
+// Example:
+//
+// k := Key{Code: RuneKey, Runes: []rune{'x'}, AltPressed: true}
+// if k.Code == RuneKey {
+// fmt.Println(k.Runes)
+// // Output: x
+//
+// fmt.Println(k.String())
+// // Output: alt+x
+// }
+type KeyCode int
+
+func (k KeyCode) String() (str string) {
+ if s, ok := keyNames[k]; ok {
+ return s
+ }
+
+ return ""
+}
+
+// All control keys.
+const (
+ Null KeyCode = internal.KeyNull
+ Break KeyCode = internal.KeyExit
+ Enter KeyCode = internal.KeyCarriageReturn
+ Backspace KeyCode = internal.KeyDelete
+ Tab KeyCode = internal.KeyHorizontalTabulation
+ Esc KeyCode = internal.KeyEscape
+ Escape KeyCode = internal.KeyEscape
+
+ CtrlAt KeyCode = internal.KeyNull
+ CtrlA KeyCode = internal.KeyStartOfHeading
+ CtrlB KeyCode = internal.KeyStartOfText
+ CtrlC KeyCode = internal.KeyExit
+ CtrlD KeyCode = internal.KeyEndOfTransimission
+ CtrlE KeyCode = internal.KeyEnquiry
+ CtrlF KeyCode = internal.KeyAcknowledge
+ CtrlG KeyCode = internal.KeyBELL
+ CtrlH KeyCode = internal.KeyBackspace
+ CtrlI KeyCode = internal.KeyHorizontalTabulation
+ CtrlJ KeyCode = internal.KeyLineFeed
+ CtrlK KeyCode = internal.KeyVerticalTabulation
+ CtrlL KeyCode = internal.KeyFormFeed
+ CtrlM KeyCode = internal.KeyCarriageReturn
+ CtrlN KeyCode = internal.KeyShiftOut
+ CtrlO KeyCode = internal.KeyShiftIn
+ CtrlP KeyCode = internal.KeyDataLinkEscape
+ CtrlQ KeyCode = internal.KeyDeviceControl1
+ CtrlR KeyCode = internal.KeyDeviceControl2
+ CtrlS KeyCode = internal.KeyDeviceControl3
+ CtrlT KeyCode = internal.KeyDeviceControl4
+ CtrlU KeyCode = internal.KeyNegativeAcknowledge
+ CtrlV KeyCode = internal.KeySynchronousIdle
+ CtrlW KeyCode = internal.KeyEndOfTransmissionBlock
+ CtrlX KeyCode = internal.KeyCancel
+ CtrlY KeyCode = internal.KeyEndOfMedium
+ CtrlZ KeyCode = internal.KeySubstitution
+
+ CtrlOpenBracket KeyCode = internal.KeyEscape
+ CtrlBackslash KeyCode = internal.KeyFileSeparator
+ CtrlCloseBracket KeyCode = internal.KeyGroupSeparator
+ CtrlCaret KeyCode = internal.KeyRecordSeparator
+ CtrlUnderscore KeyCode = internal.KeyUnitSeparator
+ CtrlQuestionMark KeyCode = internal.KeyDelete
+)
+
+// Other keys.
+const (
+ RuneKey KeyCode = -(iota + 1)
+ Up
+ Down
+ Right
+ Left
+ ShiftTab
+ Home
+ End
+ PgUp
+ PgDown
+ Delete
+ Space
+ CtrlUp
+ CtrlDown
+ CtrlRight
+ CtrlLeft
+ ShiftUp
+ ShiftDown
+ ShiftRight
+ ShiftLeft
+ CtrlShiftUp
+ CtrlShiftDown
+ CtrlShiftLeft
+ CtrlShiftRight
+ F1
+ F2
+ F3
+ F4
+ F5
+ F6
+ F7
+ F8
+ F9
+ F10
+ F11
+ F12
+ F13
+ F14
+ F15
+ F16
+ F17
+ F18
+ F19
+ F20
+)
+
+var keyNames = map[KeyCode]string{
+ // Control keys.
+ internal.KeyNull: "ctrl+@", // also ctrl+backtick
+ internal.KeyStartOfHeading: "ctrl+a",
+ internal.KeyStartOfText: "ctrl+b",
+ internal.KeyExit: "ctrl+c",
+ internal.KeyEndOfTransimission: "ctrl+d",
+ internal.KeyEnquiry: "ctrl+e",
+ internal.KeyAcknowledge: "ctrl+f",
+ internal.KeyBELL: "ctrl+g",
+ internal.KeyBackspace: "ctrl+h",
+ internal.KeyHorizontalTabulation: "tab", // also ctrl+i
+ internal.KeyLineFeed: "ctrl+j",
+ internal.KeyVerticalTabulation: "ctrl+k",
+ internal.KeyFormFeed: "ctrl+l",
+ internal.KeyCarriageReturn: "enter",
+ internal.KeyShiftOut: "ctrl+n",
+ internal.KeyShiftIn: "ctrl+o",
+ internal.KeyDataLinkEscape: "ctrl+p",
+ internal.KeyDeviceControl1: "ctrl+q",
+ internal.KeyDeviceControl2: "ctrl+r",
+ internal.KeyDeviceControl3: "ctrl+s",
+ internal.KeyDeviceControl4: "ctrl+t",
+ internal.KeyNegativeAcknowledge: "ctrl+u",
+ internal.KeySynchronousIdle: "ctrl+v",
+ internal.KeyEndOfTransmissionBlock: "ctrl+w",
+ internal.KeyCancel: "ctrl+x",
+ internal.KeyEndOfMedium: "ctrl+y",
+ internal.KeySubstitution: "ctrl+z",
+ internal.KeyEscape: "esc",
+ internal.KeyFileSeparator: "ctrl+\\",
+ internal.KeyGroupSeparator: "ctrl+]",
+ internal.KeyRecordSeparator: "ctrl+^",
+ internal.KeyUnitSeparator: "ctrl+_",
+ internal.KeyDelete: "backspace",
+
+ // Other keys.
+ RuneKey: "runes",
+ Up: "up",
+ Down: "down",
+ Right: "right",
+ Space: "space",
+ Left: "left",
+ ShiftTab: "shift+tab",
+ Home: "home",
+ End: "end",
+ PgUp: "pgup",
+ PgDown: "pgdown",
+ Delete: "delete",
+ CtrlUp: "ctrl+up",
+ CtrlDown: "ctrl+down",
+ CtrlRight: "ctrl+right",
+ CtrlLeft: "ctrl+left",
+ ShiftUp: "shift+up",
+ ShiftDown: "shift+down",
+ ShiftRight: "shift+right",
+ ShiftLeft: "shift+left",
+ CtrlShiftUp: "ctrl+shift+up",
+ CtrlShiftDown: "ctrl+shift+down",
+ CtrlShiftLeft: "ctrl+shift+left",
+ CtrlShiftRight: "ctrl+shift+right",
+ F1: "f1",
+ F2: "f2",
+ F3: "f3",
+ F4: "f4",
+ F5: "f5",
+ F6: "f6",
+ F7: "f7",
+ F8: "f8",
+ F9: "f9",
+ F10: "f10",
+ F11: "f11",
+ F12: "f12",
+ F13: "f13",
+ F14: "f14",
+ F15: "f15",
+ F16: "f16",
+ F17: "f17",
+ F18: "f18",
+ F19: "f19",
+ F20: "f20",
+}
diff --git a/vendor/atomicgo.dev/keyboard/tty_unix.go b/vendor/atomicgo.dev/keyboard/tty_unix.go
new file mode 100644
index 0000000..b505500
--- /dev/null
+++ b/vendor/atomicgo.dev/keyboard/tty_unix.go
@@ -0,0 +1,35 @@
+//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package keyboard
+
+import (
+ "os"
+
+ "github.com/containerd/console"
+)
+
+func restoreInput() error {
+ if con != nil {
+ return con.Reset()
+ }
+ return nil
+}
+
+func initInput() error {
+ c, err := console.ConsoleFromFile(stdin)
+ if err != nil {
+ return err
+ }
+ con = c
+
+ return nil
+}
+
+func openInputTTY() (*os.File, error) {
+ f, err := os.Open("/dev/tty")
+ if err != nil {
+ return nil, err
+ }
+ return f, nil
+}
diff --git a/vendor/atomicgo.dev/keyboard/tty_windows.go b/vendor/atomicgo.dev/keyboard/tty_windows.go
new file mode 100644
index 0000000..4c334e8
--- /dev/null
+++ b/vendor/atomicgo.dev/keyboard/tty_windows.go
@@ -0,0 +1,47 @@
+//go:build windows
+// +build windows
+
+package keyboard
+
+import (
+ "fmt"
+ "os"
+ "syscall"
+
+ "github.com/containerd/console"
+)
+
+func restoreInput() error {
+ if windowsStdin != nil {
+ os.Stdin = windowsStdin
+ }
+
+ return nil
+}
+
+func initInput() error {
+ windowsStdin = os.Stdin
+
+ os.Stdin = stdin
+
+ var mode uint32
+ err := syscall.GetConsoleMode(syscall.Stdin, &mode)
+
+ if err != nil {
+ mocking = true
+ return nil
+ }
+
+ con = console.Current()
+
+ return nil
+}
+
+func openInputTTY() (*os.File, error) {
+ f, err := os.OpenFile("CONIN$", os.O_RDWR, 0644)
+ if err != nil {
+ return nil, fmt.Errorf("failed to open stdin TTY: %w", err)
+ }
+
+ return f, nil
+}
diff --git a/vendor/atomicgo.dev/keyboard/utils.go b/vendor/atomicgo.dev/keyboard/utils.go
new file mode 100644
index 0000000..9b99626
--- /dev/null
+++ b/vendor/atomicgo.dev/keyboard/utils.go
@@ -0,0 +1,8 @@
+//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package keyboard
+
+func closeInput() {
+
+}
diff --git a/vendor/atomicgo.dev/keyboard/utils_windows.go b/vendor/atomicgo.dev/keyboard/utils_windows.go
new file mode 100644
index 0000000..a85cf43
--- /dev/null
+++ b/vendor/atomicgo.dev/keyboard/utils_windows.go
@@ -0,0 +1,7 @@
+package keyboard
+
+import "syscall"
+
+func closeInput() {
+ syscall.CancelIoEx(syscall.Handle(inputTTY.Fd()), nil)
+}
diff --git a/vendor/atomicgo.dev/schedule/.gitignore b/vendor/atomicgo.dev/schedule/.gitignore
new file mode 100644
index 0000000..7e5f3f4
--- /dev/null
+++ b/vendor/atomicgo.dev/schedule/.gitignore
@@ -0,0 +1,40 @@
+# 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/
+
+# IDEs
+
+## IntelliJ
+.idea
+*.iml
+out
+gen
+
+## Visual Studio Code
+.vscode
+*.code-workspace
+
+# Operating System Files
+
+## macOS
+### General
+.DS_Store
+
+# Other
+
+## Experimenting folder
+experimenting
diff --git a/vendor/atomicgo.dev/schedule/.golangci.yml b/vendor/atomicgo.dev/schedule/.golangci.yml
new file mode 100644
index 0000000..796ca35
--- /dev/null
+++ b/vendor/atomicgo.dev/schedule/.golangci.yml
@@ -0,0 +1,99 @@
+linters-settings:
+ gocritic:
+ enabled-tags:
+ - diagnostic
+ - experimental
+ - opinionated
+ - performance
+ - style
+ disabled-checks:
+ - dupImport
+ - ifElseChain
+ - octalLiteral
+ - whyNoLint
+ - wrapperFunc
+ - exitAfterDefer
+ - hugeParam
+ - ptrToRefParam
+ - paramTypeCombine
+ - unnamedResult
+linters:
+ disable-all: true
+ enable:
+ # default linters
+ - errcheck
+ - gosimple
+ - govet
+ - ineffassign
+ - staticcheck
+ - typecheck
+ - unused
+ # additional linters
+ - asasalint
+ - asciicheck
+ - bidichk
+ - bodyclose
+ - containedctx
+ - contextcheck
+ - decorder
+ - dupl
+ - durationcheck
+ - errchkjson
+ - errname
+ - errorlint
+ - exhaustive
+ - exhaustruct
+ - exportloopref
+ - forcetypeassert
+ - gocheckcompilerdirectives
+ - gocritic
+ - godot
+ - godox
+ - goerr113
+ - gofmt
+ - goprintffuncname
+ - gosec
+ - gosmopolitan
+ - importas
+ - ireturn
+ - nakedret
+ - nestif
+ - nilerr
+ - nilnil
+ - prealloc
+ - predeclared
+ - revive
+ - rowserrcheck
+ - tagalign
+ - tenv
+ - thelper
+ - tparallel
+ - unconvert
+ - unparam
+ - usestdlibvars
+ - wastedassign
+ - whitespace
+ - wrapcheck
+ - wsl
+ - gocyclo
+ - misspell
+issues:
+ include:
+ - EXC0012
+ - EXC0014
+ exclude-rules:
+ - path: _test\.go
+ linters:
+ - gocyclo
+ - errcheck
+ - dupl
+ - gosec
+ - gocritic
+ - linters:
+ - gocritic
+ text: "unnecessaryDefer:"
+ - linters:
+ - gocritic
+ text: "preferDecodeRune:"
+service:
+ golangci-lint-version: 1.53.x
diff --git a/vendor/atomicgo.dev/schedule/LICENSE b/vendor/atomicgo.dev/schedule/LICENSE
new file mode 100644
index 0000000..b42989e
--- /dev/null
+++ b/vendor/atomicgo.dev/schedule/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 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/atomicgo.dev/schedule/README.md b/vendor/atomicgo.dev/schedule/README.md
new file mode 100644
index 0000000..3f7f9a8
--- /dev/null
+++ b/vendor/atomicgo.dev/schedule/README.md
@@ -0,0 +1,281 @@
+AtomicGo | schedule
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+---
+
+
+Documentation
+|
+Contributing
+|
+Code of Conduct
+
+
+---
+
+
+
+
+
+
+
+
+go get atomicgo.dev/schedule
+
+
+
+
+
+
+
+
+# schedule
+
+```go
+import "atomicgo.dev/schedule"
+```
+
+Package schedule provides a simple scheduler for Go.
+
+It can run a function at a given time, in a given duration, or repeatedly at a given interval.
+
+## Index
+
+- [type Task](<#Task>)
+ - [func After\(d time.Duration, task func\(\)\) \*Task](<#After>)
+ - [func At\(t time.Time, task func\(\)\) \*Task](<#At>)
+ - [func Every\(interval time.Duration, task func\(\) bool\) \*Task](<#Every>)
+ - [func \(s \*Task\) ExecutesIn\(\) time.Duration](<#Task.ExecutesIn>)
+ - [func \(s \*Task\) IsActive\(\) bool](<#Task.IsActive>)
+ - [func \(s \*Task\) NextExecutionTime\(\) time.Time](<#Task.NextExecutionTime>)
+ - [func \(s \*Task\) StartedAt\(\) time.Time](<#Task.StartedAt>)
+ - [func \(s \*Task\) Stop\(\)](<#Task.Stop>)
+ - [func \(s \*Task\) Wait\(\)](<#Task.Wait>)
+
+
+
+## type [Task]()
+
+Task holds information about the running task and can be used to stop running tasks.
+
+```go
+type Task struct {
+ // contains filtered or unexported fields
+}
+```
+
+
+### func [After]()
+
+```go
+func After(d time.Duration, task func()) *Task
+```
+
+After executes the task after the given duration. The function is non\-blocking. If you want to wait for the task to be executed, use the Task.Wait method.
+
+Example
+
+
+
+
+```go
+package main
+
+import (
+ "fmt"
+ "time"
+
+ "atomicgo.dev/schedule"
+)
+
+func main() {
+ task := schedule.After(5*time.Second, func() {
+ fmt.Println("5 seconds are over!")
+ })
+
+ fmt.Println("Some stuff happening...")
+
+ task.Wait()
+}
+```
+
+
+
+
+
+### func [At]()
+
+```go
+func At(t time.Time, task func()) *Task
+```
+
+At executes the task at the given time. The function is non\-blocking. If you want to wait for the task to be executed, use the Task.Wait method.
+
+Example
+
+
+
+
+```go
+package main
+
+import (
+ "fmt"
+ "time"
+
+ "atomicgo.dev/schedule"
+)
+
+func main() {
+ task := schedule.At(time.Now().Add(5*time.Second), func() {
+ fmt.Println("5 seconds are over!")
+ })
+
+ fmt.Println("Some stuff happening...")
+
+ task.Wait()
+}
+```
+
+
+
+
+
+### func [Every]()
+
+```go
+func Every(interval time.Duration, task func() bool) *Task
+```
+
+Every executes the task in the given interval, as long as the task function returns true. The function is non\-blocking. If you want to wait for the task to be executed, use the Task.Wait method.
+
+Example
+
+
+
+
+```go
+package main
+
+import (
+ "fmt"
+ "time"
+
+ "atomicgo.dev/schedule"
+)
+
+func main() {
+ task := schedule.Every(time.Second, func() bool {
+ fmt.Println("1 second is over!")
+ return true // return false to stop the task
+ })
+
+ fmt.Println("Some stuff happening...")
+
+ time.Sleep(10 * time.Second)
+
+ task.Stop()
+}
+```
+
+
+
+
+
+### func \(\*Task\) [ExecutesIn]()
+
+```go
+func (s *Task) ExecutesIn() time.Duration
+```
+
+ExecutesIn returns the duration until the next execution.
+
+
+### func \(\*Task\) [IsActive]()
+
+```go
+func (s *Task) IsActive() bool
+```
+
+IsActive returns true if the scheduler is active.
+
+
+### func \(\*Task\) [NextExecutionTime]()
+
+```go
+func (s *Task) NextExecutionTime() time.Time
+```
+
+NextExecutionTime returns the time when the next execution will happen.
+
+
+### func \(\*Task\) [StartedAt]()
+
+```go
+func (s *Task) StartedAt() time.Time
+```
+
+StartedAt returns the time when the scheduler was started.
+
+
+### func \(\*Task\) [Stop]()
+
+```go
+func (s *Task) Stop()
+```
+
+Stop stops the scheduler.
+
+
+### func \(\*Task\) [Wait]()
+
+```go
+func (s *Task) Wait()
+```
+
+Wait blocks until the scheduler is stopped. After and At will stop automatically after the task is executed.
+
+Generated by [gomarkdoc]()
+
+
+
+
+---
+
+> [AtomicGo.dev](https://atomicgo.dev) ·
+> with ❤️ by [@MarvinJWendt](https://github.com/MarvinJWendt) |
+> [MarvinJWendt.com](https://marvinjwendt.com)
diff --git a/vendor/atomicgo.dev/schedule/codecov.yml b/vendor/atomicgo.dev/schedule/codecov.yml
new file mode 100644
index 0000000..bfdc987
--- /dev/null
+++ b/vendor/atomicgo.dev/schedule/codecov.yml
@@ -0,0 +1,8 @@
+coverage:
+ status:
+ project:
+ default:
+ informational: true
+ patch:
+ default:
+ informational: true
diff --git a/vendor/atomicgo.dev/schedule/doc.go b/vendor/atomicgo.dev/schedule/doc.go
new file mode 100644
index 0000000..4801fdb
--- /dev/null
+++ b/vendor/atomicgo.dev/schedule/doc.go
@@ -0,0 +1,6 @@
+/*
+Package schedule provides a simple scheduler for Go.
+
+It can run a function at a given time, in a given duration, or repeatedly at a given interval.
+*/
+package schedule
diff --git a/vendor/atomicgo.dev/schedule/schedule.go b/vendor/atomicgo.dev/schedule/schedule.go
new file mode 100644
index 0000000..635d29d
--- /dev/null
+++ b/vendor/atomicgo.dev/schedule/schedule.go
@@ -0,0 +1,116 @@
+package schedule
+
+import "time"
+
+// Task holds information about the running task and can be used to stop running tasks.
+type Task struct {
+ stop chan struct{}
+ nextExecution time.Time
+ startedAt time.Time
+}
+
+// newTask creates a new Task.
+func newTask() *Task {
+ return &Task{
+ stop: make(chan struct{}),
+ startedAt: time.Now(),
+ }
+}
+
+// StartedAt returns the time when the scheduler was started.
+func (s *Task) StartedAt() time.Time {
+ return s.startedAt
+}
+
+// NextExecutionTime returns the time when the next execution will happen.
+func (s *Task) NextExecutionTime() time.Time {
+ return s.nextExecution
+}
+
+// ExecutesIn returns the duration until the next execution.
+func (s *Task) ExecutesIn() time.Duration {
+ return time.Until(s.nextExecution)
+}
+
+// IsActive returns true if the scheduler is active.
+func (s *Task) IsActive() bool {
+ select {
+ case <-s.stop:
+ return false
+ default:
+ return true
+ }
+}
+
+// Wait blocks until the scheduler is stopped.
+// After and At will stop automatically after the task is executed.
+func (s *Task) Wait() {
+ <-s.stop
+}
+
+// Stop stops the scheduler.
+func (s *Task) Stop() {
+ close(s.stop)
+}
+
+// After executes the task after the given duration.
+// The function is non-blocking. If you want to wait for the task to be executed, use the Task.Wait method.
+func After(d time.Duration, task func()) *Task {
+ scheduler := newTask()
+ scheduler.nextExecution = time.Now().Add(d)
+
+ go func() {
+ select {
+ case <-time.After(d):
+ task()
+ scheduler.Stop()
+ case <-scheduler.stop:
+ return
+ }
+ }()
+
+ return scheduler
+}
+
+// At executes the task at the given time.
+// The function is non-blocking. If you want to wait for the task to be executed, use the Task.Wait method.
+func At(t time.Time, task func()) *Task {
+ scheduler := newTask()
+ scheduler.nextExecution = t
+
+ go func() {
+ select {
+ case <-time.After(time.Until(t)):
+ task()
+ scheduler.Stop()
+ case <-scheduler.stop:
+ return
+ }
+ }()
+
+ return scheduler
+}
+
+// Every executes the task in the given interval, as long as the task function returns true.
+// The function is non-blocking. If you want to wait for the task to be executed, use the Task.Wait method.
+func Every(interval time.Duration, task func() bool) *Task {
+ scheduler := newTask()
+ scheduler.nextExecution = time.Now().Add(interval)
+
+ ticker := time.NewTicker(interval)
+
+ go func() {
+ for {
+ select {
+ case <-ticker.C:
+ task()
+ scheduler.nextExecution = time.Now().Add(interval)
+ case <-scheduler.stop:
+ ticker.Stop()
+ return
+ }
+ }
+ }()
+
+ return scheduler
+}
diff --git a/vendor/github.com/containerd/console/.golangci.yml b/vendor/github.com/containerd/console/.golangci.yml
new file mode 100644
index 0000000..fcba5e8
--- /dev/null
+++ b/vendor/github.com/containerd/console/.golangci.yml
@@ -0,0 +1,20 @@
+linters:
+ enable:
+ - structcheck
+ - varcheck
+ - staticcheck
+ - unconvert
+ - gofmt
+ - goimports
+ - golint
+ - ineffassign
+ - vet
+ - unused
+ - misspell
+ disable:
+ - errcheck
+
+run:
+ timeout: 3m
+ skip-dirs:
+ - vendor
diff --git a/vendor/github.com/containerd/console/LICENSE b/vendor/github.com/containerd/console/LICENSE
new file mode 100644
index 0000000..584149b
--- /dev/null
+++ b/vendor/github.com/containerd/console/LICENSE
@@ -0,0 +1,191 @@
+
+ Apache License
+ Version 2.0, January 2004
+ https://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ Copyright The containerd Authors
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/containerd/console/README.md b/vendor/github.com/containerd/console/README.md
new file mode 100644
index 0000000..580b461
--- /dev/null
+++ b/vendor/github.com/containerd/console/README.md
@@ -0,0 +1,29 @@
+# console
+
+[![PkgGoDev](https://pkg.go.dev/badge/github.com/containerd/console)](https://pkg.go.dev/github.com/containerd/console)
+[![Build Status](https://github.com/containerd/console/workflows/CI/badge.svg)](https://github.com/containerd/console/actions?query=workflow%3ACI)
+[![Go Report Card](https://goreportcard.com/badge/github.com/containerd/console)](https://goreportcard.com/report/github.com/containerd/console)
+
+Golang package for dealing with consoles. Light on deps and a simple API.
+
+## Modifying the current process
+
+```go
+current := console.Current()
+defer current.Reset()
+
+if err := current.SetRaw(); err != nil {
+}
+ws, err := current.Size()
+current.Resize(ws)
+```
+
+## Project details
+
+console is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
+As a containerd sub-project, you will find the:
+ * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md),
+ * [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS),
+ * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md)
+
+information in our [`containerd/project`](https://github.com/containerd/project) repository.
diff --git a/vendor/github.com/containerd/console/console.go b/vendor/github.com/containerd/console/console.go
new file mode 100644
index 0000000..f989d28
--- /dev/null
+++ b/vendor/github.com/containerd/console/console.go
@@ -0,0 +1,87 @@
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package console
+
+import (
+ "errors"
+ "io"
+ "os"
+)
+
+var ErrNotAConsole = errors.New("provided file is not a console")
+
+type File interface {
+ io.ReadWriteCloser
+
+ // Fd returns its file descriptor
+ Fd() uintptr
+ // Name returns its file name
+ Name() string
+}
+
+type Console interface {
+ File
+
+ // Resize resizes the console to the provided window size
+ Resize(WinSize) error
+ // ResizeFrom resizes the calling console to the size of the
+ // provided console
+ ResizeFrom(Console) error
+ // SetRaw sets the console in raw mode
+ SetRaw() error
+ // DisableEcho disables echo on the console
+ DisableEcho() error
+ // Reset restores the console to its orignal state
+ Reset() error
+ // Size returns the window size of the console
+ Size() (WinSize, error)
+}
+
+// WinSize specifies the window size of the console
+type WinSize struct {
+ // Height of the console
+ Height uint16
+ // Width of the console
+ Width uint16
+ x uint16
+ y uint16
+}
+
+// Current returns the current process' console
+func Current() (c Console) {
+ var err error
+ // Usually all three streams (stdin, stdout, and stderr)
+ // are open to the same console, but some might be redirected,
+ // so try all three.
+ for _, s := range []*os.File{os.Stderr, os.Stdout, os.Stdin} {
+ if c, err = ConsoleFromFile(s); err == nil {
+ return c
+ }
+ }
+ // One of the std streams should always be a console
+ // for the design of this function.
+ panic(err)
+}
+
+// ConsoleFromFile returns a console using the provided file
+// nolint:golint
+func ConsoleFromFile(f File) (Console, error) {
+ if err := checkConsole(f); err != nil {
+ return nil, err
+ }
+ return newMaster(f)
+}
diff --git a/vendor/github.com/containerd/console/console_linux.go b/vendor/github.com/containerd/console/console_linux.go
new file mode 100644
index 0000000..c1c839e
--- /dev/null
+++ b/vendor/github.com/containerd/console/console_linux.go
@@ -0,0 +1,280 @@
+// +build linux
+
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package console
+
+import (
+ "io"
+ "os"
+ "sync"
+
+ "golang.org/x/sys/unix"
+)
+
+const (
+ maxEvents = 128
+)
+
+// Epoller manages multiple epoll consoles using edge-triggered epoll api so we
+// dont have to deal with repeated wake-up of EPOLLER or EPOLLHUP.
+// For more details, see:
+// - https://github.com/systemd/systemd/pull/4262
+// - https://github.com/moby/moby/issues/27202
+//
+// Example usage of Epoller and EpollConsole can be as follow:
+//
+// epoller, _ := NewEpoller()
+// epollConsole, _ := epoller.Add(console)
+// go epoller.Wait()
+// var (
+// b bytes.Buffer
+// wg sync.WaitGroup
+// )
+// wg.Add(1)
+// go func() {
+// io.Copy(&b, epollConsole)
+// wg.Done()
+// }()
+// // perform I/O on the console
+// epollConsole.Shutdown(epoller.CloseConsole)
+// wg.Wait()
+// epollConsole.Close()
+type Epoller struct {
+ efd int
+ mu sync.Mutex
+ fdMapping map[int]*EpollConsole
+ closeOnce sync.Once
+}
+
+// NewEpoller returns an instance of epoller with a valid epoll fd.
+func NewEpoller() (*Epoller, error) {
+ efd, err := unix.EpollCreate1(unix.EPOLL_CLOEXEC)
+ if err != nil {
+ return nil, err
+ }
+ return &Epoller{
+ efd: efd,
+ fdMapping: make(map[int]*EpollConsole),
+ }, nil
+}
+
+// Add creates an epoll console based on the provided console. The console will
+// be registered with EPOLLET (i.e. using edge-triggered notification) and its
+// file descriptor will be set to non-blocking mode. After this, user should use
+// the return console to perform I/O.
+func (e *Epoller) Add(console Console) (*EpollConsole, error) {
+ sysfd := int(console.Fd())
+ // Set sysfd to non-blocking mode
+ if err := unix.SetNonblock(sysfd, true); err != nil {
+ return nil, err
+ }
+
+ ev := unix.EpollEvent{
+ Events: unix.EPOLLIN | unix.EPOLLOUT | unix.EPOLLRDHUP | unix.EPOLLET,
+ Fd: int32(sysfd),
+ }
+ if err := unix.EpollCtl(e.efd, unix.EPOLL_CTL_ADD, sysfd, &ev); err != nil {
+ return nil, err
+ }
+ ef := &EpollConsole{
+ Console: console,
+ sysfd: sysfd,
+ readc: sync.NewCond(&sync.Mutex{}),
+ writec: sync.NewCond(&sync.Mutex{}),
+ }
+ e.mu.Lock()
+ e.fdMapping[sysfd] = ef
+ e.mu.Unlock()
+ return ef, nil
+}
+
+// Wait starts the loop to wait for its consoles' notifications and signal
+// appropriate console that it can perform I/O.
+func (e *Epoller) Wait() error {
+ events := make([]unix.EpollEvent, maxEvents)
+ for {
+ n, err := unix.EpollWait(e.efd, events, -1)
+ if err != nil {
+ // EINTR: The call was interrupted by a signal handler before either
+ // any of the requested events occurred or the timeout expired
+ if err == unix.EINTR {
+ continue
+ }
+ return err
+ }
+ for i := 0; i < n; i++ {
+ ev := &events[i]
+ // the console is ready to be read from
+ if ev.Events&(unix.EPOLLIN|unix.EPOLLHUP|unix.EPOLLERR) != 0 {
+ if epfile := e.getConsole(int(ev.Fd)); epfile != nil {
+ epfile.signalRead()
+ }
+ }
+ // the console is ready to be written to
+ if ev.Events&(unix.EPOLLOUT|unix.EPOLLHUP|unix.EPOLLERR) != 0 {
+ if epfile := e.getConsole(int(ev.Fd)); epfile != nil {
+ epfile.signalWrite()
+ }
+ }
+ }
+ }
+}
+
+// CloseConsole unregisters the console's file descriptor from epoll interface
+func (e *Epoller) CloseConsole(fd int) error {
+ e.mu.Lock()
+ defer e.mu.Unlock()
+ delete(e.fdMapping, fd)
+ return unix.EpollCtl(e.efd, unix.EPOLL_CTL_DEL, fd, &unix.EpollEvent{})
+}
+
+func (e *Epoller) getConsole(sysfd int) *EpollConsole {
+ e.mu.Lock()
+ f := e.fdMapping[sysfd]
+ e.mu.Unlock()
+ return f
+}
+
+// Close closes the epoll fd
+func (e *Epoller) Close() error {
+ closeErr := os.ErrClosed // default to "file already closed"
+ e.closeOnce.Do(func() {
+ closeErr = unix.Close(e.efd)
+ })
+ return closeErr
+}
+
+// EpollConsole acts like a console but registers its file descriptor with an
+// epoll fd and uses epoll API to perform I/O.
+type EpollConsole struct {
+ Console
+ readc *sync.Cond
+ writec *sync.Cond
+ sysfd int
+ closed bool
+}
+
+// Read reads up to len(p) bytes into p. It returns the number of bytes read
+// (0 <= n <= len(p)) and any error encountered.
+//
+// If the console's read returns EAGAIN or EIO, we assume that it's a
+// temporary error because the other side went away and wait for the signal
+// generated by epoll event to continue.
+func (ec *EpollConsole) Read(p []byte) (n int, err error) {
+ var read int
+ ec.readc.L.Lock()
+ defer ec.readc.L.Unlock()
+ for {
+ read, err = ec.Console.Read(p[n:])
+ n += read
+ if err != nil {
+ var hangup bool
+ if perr, ok := err.(*os.PathError); ok {
+ hangup = (perr.Err == unix.EAGAIN || perr.Err == unix.EIO)
+ } else {
+ hangup = (err == unix.EAGAIN || err == unix.EIO)
+ }
+ // if the other end disappear, assume this is temporary and wait for the
+ // signal to continue again. Unless we didnt read anything and the
+ // console is already marked as closed then we should exit
+ if hangup && !(n == 0 && len(p) > 0 && ec.closed) {
+ ec.readc.Wait()
+ continue
+ }
+ }
+ break
+ }
+ // if we didnt read anything then return io.EOF to end gracefully
+ if n == 0 && len(p) > 0 && err == nil {
+ err = io.EOF
+ }
+ // signal for others that we finished the read
+ ec.readc.Signal()
+ return n, err
+}
+
+// Writes len(p) bytes from p to the console. It returns the number of bytes
+// written from p (0 <= n <= len(p)) and any error encountered that caused
+// the write to stop early.
+//
+// If writes to the console returns EAGAIN or EIO, we assume that it's a
+// temporary error because the other side went away and wait for the signal
+// generated by epoll event to continue.
+func (ec *EpollConsole) Write(p []byte) (n int, err error) {
+ var written int
+ ec.writec.L.Lock()
+ defer ec.writec.L.Unlock()
+ for {
+ written, err = ec.Console.Write(p[n:])
+ n += written
+ if err != nil {
+ var hangup bool
+ if perr, ok := err.(*os.PathError); ok {
+ hangup = (perr.Err == unix.EAGAIN || perr.Err == unix.EIO)
+ } else {
+ hangup = (err == unix.EAGAIN || err == unix.EIO)
+ }
+ // if the other end disappears, assume this is temporary and wait for the
+ // signal to continue again.
+ if hangup {
+ ec.writec.Wait()
+ continue
+ }
+ }
+ // unrecoverable error, break the loop and return the error
+ break
+ }
+ if n < len(p) && err == nil {
+ err = io.ErrShortWrite
+ }
+ // signal for others that we finished the write
+ ec.writec.Signal()
+ return n, err
+}
+
+// Shutdown closes the file descriptor and signals call waiters for this fd.
+// It accepts a callback which will be called with the console's fd. The
+// callback typically will be used to do further cleanup such as unregister the
+// console's fd from the epoll interface.
+// User should call Shutdown and wait for all I/O operation to be finished
+// before closing the console.
+func (ec *EpollConsole) Shutdown(close func(int) error) error {
+ ec.readc.L.Lock()
+ defer ec.readc.L.Unlock()
+ ec.writec.L.Lock()
+ defer ec.writec.L.Unlock()
+
+ ec.readc.Broadcast()
+ ec.writec.Broadcast()
+ ec.closed = true
+ return close(ec.sysfd)
+}
+
+// signalRead signals that the console is readable.
+func (ec *EpollConsole) signalRead() {
+ ec.readc.L.Lock()
+ ec.readc.Signal()
+ ec.readc.L.Unlock()
+}
+
+// signalWrite signals that the console is writable.
+func (ec *EpollConsole) signalWrite() {
+ ec.writec.L.Lock()
+ ec.writec.Signal()
+ ec.writec.L.Unlock()
+}
diff --git a/vendor/github.com/containerd/console/console_unix.go b/vendor/github.com/containerd/console/console_unix.go
new file mode 100644
index 0000000..a081176
--- /dev/null
+++ b/vendor/github.com/containerd/console/console_unix.go
@@ -0,0 +1,156 @@
+// +build darwin freebsd linux netbsd openbsd solaris
+
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package console
+
+import (
+ "golang.org/x/sys/unix"
+)
+
+// NewPty creates a new pty pair
+// The master is returned as the first console and a string
+// with the path to the pty slave is returned as the second
+func NewPty() (Console, string, error) {
+ f, err := openpt()
+ if err != nil {
+ return nil, "", err
+ }
+ slave, err := ptsname(f)
+ if err != nil {
+ return nil, "", err
+ }
+ if err := unlockpt(f); err != nil {
+ return nil, "", err
+ }
+ m, err := newMaster(f)
+ if err != nil {
+ return nil, "", err
+ }
+ return m, slave, nil
+}
+
+type master struct {
+ f File
+ original *unix.Termios
+}
+
+func (m *master) Read(b []byte) (int, error) {
+ return m.f.Read(b)
+}
+
+func (m *master) Write(b []byte) (int, error) {
+ return m.f.Write(b)
+}
+
+func (m *master) Close() error {
+ return m.f.Close()
+}
+
+func (m *master) Resize(ws WinSize) error {
+ return tcswinsz(m.f.Fd(), ws)
+}
+
+func (m *master) ResizeFrom(c Console) error {
+ ws, err := c.Size()
+ if err != nil {
+ return err
+ }
+ return m.Resize(ws)
+}
+
+func (m *master) Reset() error {
+ if m.original == nil {
+ return nil
+ }
+ return tcset(m.f.Fd(), m.original)
+}
+
+func (m *master) getCurrent() (unix.Termios, error) {
+ var termios unix.Termios
+ if err := tcget(m.f.Fd(), &termios); err != nil {
+ return unix.Termios{}, err
+ }
+ return termios, nil
+}
+
+func (m *master) SetRaw() error {
+ rawState, err := m.getCurrent()
+ if err != nil {
+ return err
+ }
+ rawState = cfmakeraw(rawState)
+ rawState.Oflag = rawState.Oflag | unix.OPOST
+ return tcset(m.f.Fd(), &rawState)
+}
+
+func (m *master) DisableEcho() error {
+ rawState, err := m.getCurrent()
+ if err != nil {
+ return err
+ }
+ rawState.Lflag = rawState.Lflag &^ unix.ECHO
+ return tcset(m.f.Fd(), &rawState)
+}
+
+func (m *master) Size() (WinSize, error) {
+ return tcgwinsz(m.f.Fd())
+}
+
+func (m *master) Fd() uintptr {
+ return m.f.Fd()
+}
+
+func (m *master) Name() string {
+ return m.f.Name()
+}
+
+// checkConsole checks if the provided file is a console
+func checkConsole(f File) error {
+ var termios unix.Termios
+ if tcget(f.Fd(), &termios) != nil {
+ return ErrNotAConsole
+ }
+ return nil
+}
+
+func newMaster(f File) (Console, error) {
+ m := &master{
+ f: f,
+ }
+ t, err := m.getCurrent()
+ if err != nil {
+ return nil, err
+ }
+ m.original = &t
+ return m, nil
+}
+
+// ClearONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair
+// created by us acts normally. In particular, a not-very-well-known default of
+// Linux unix98 ptys is that they have +onlcr by default. While this isn't a
+// problem for terminal emulators, because we relay data from the terminal we
+// also relay that funky line discipline.
+func ClearONLCR(fd uintptr) error {
+ return setONLCR(fd, false)
+}
+
+// SetONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair
+// created by us acts as intended for a terminal emulator.
+func SetONLCR(fd uintptr) error {
+ return setONLCR(fd, true)
+}
diff --git a/vendor/github.com/containerd/console/console_windows.go b/vendor/github.com/containerd/console/console_windows.go
new file mode 100644
index 0000000..787c11f
--- /dev/null
+++ b/vendor/github.com/containerd/console/console_windows.go
@@ -0,0 +1,216 @@
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package console
+
+import (
+ "errors"
+ "fmt"
+ "os"
+
+ "golang.org/x/sys/windows"
+)
+
+var (
+ vtInputSupported bool
+ ErrNotImplemented = errors.New("not implemented")
+)
+
+func (m *master) initStdios() {
+ m.in = windows.Handle(os.Stdin.Fd())
+ if err := windows.GetConsoleMode(m.in, &m.inMode); err == nil {
+ // Validate that windows.ENABLE_VIRTUAL_TERMINAL_INPUT is supported, but do not set it.
+ if err = windows.SetConsoleMode(m.in, m.inMode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT); err == nil {
+ vtInputSupported = true
+ }
+ // Unconditionally set the console mode back even on failure because SetConsoleMode
+ // remembers invalid bits on input handles.
+ windows.SetConsoleMode(m.in, m.inMode)
+ } else {
+ fmt.Printf("failed to get console mode for stdin: %v\n", err)
+ }
+
+ m.out = windows.Handle(os.Stdout.Fd())
+ if err := windows.GetConsoleMode(m.out, &m.outMode); err == nil {
+ if err := windows.SetConsoleMode(m.out, m.outMode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err == nil {
+ m.outMode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
+ } else {
+ windows.SetConsoleMode(m.out, m.outMode)
+ }
+ } else {
+ fmt.Printf("failed to get console mode for stdout: %v\n", err)
+ }
+
+ m.err = windows.Handle(os.Stderr.Fd())
+ if err := windows.GetConsoleMode(m.err, &m.errMode); err == nil {
+ if err := windows.SetConsoleMode(m.err, m.errMode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err == nil {
+ m.errMode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
+ } else {
+ windows.SetConsoleMode(m.err, m.errMode)
+ }
+ } else {
+ fmt.Printf("failed to get console mode for stderr: %v\n", err)
+ }
+}
+
+type master struct {
+ in windows.Handle
+ inMode uint32
+
+ out windows.Handle
+ outMode uint32
+
+ err windows.Handle
+ errMode uint32
+}
+
+func (m *master) SetRaw() error {
+ if err := makeInputRaw(m.in, m.inMode); err != nil {
+ return err
+ }
+
+ // Set StdOut and StdErr to raw mode, we ignore failures since
+ // windows.DISABLE_NEWLINE_AUTO_RETURN might not be supported on this version of
+ // Windows.
+
+ windows.SetConsoleMode(m.out, m.outMode|windows.DISABLE_NEWLINE_AUTO_RETURN)
+
+ windows.SetConsoleMode(m.err, m.errMode|windows.DISABLE_NEWLINE_AUTO_RETURN)
+
+ return nil
+}
+
+func (m *master) Reset() error {
+ for _, s := range []struct {
+ fd windows.Handle
+ mode uint32
+ }{
+ {m.in, m.inMode},
+ {m.out, m.outMode},
+ {m.err, m.errMode},
+ } {
+ if err := windows.SetConsoleMode(s.fd, s.mode); err != nil {
+ return fmt.Errorf("unable to restore console mode: %w", err)
+ }
+ }
+
+ return nil
+}
+
+func (m *master) Size() (WinSize, error) {
+ var info windows.ConsoleScreenBufferInfo
+ err := windows.GetConsoleScreenBufferInfo(m.out, &info)
+ if err != nil {
+ return WinSize{}, fmt.Errorf("unable to get console info: %w", err)
+ }
+
+ winsize := WinSize{
+ Width: uint16(info.Window.Right - info.Window.Left + 1),
+ Height: uint16(info.Window.Bottom - info.Window.Top + 1),
+ }
+
+ return winsize, nil
+}
+
+func (m *master) Resize(ws WinSize) error {
+ return ErrNotImplemented
+}
+
+func (m *master) ResizeFrom(c Console) error {
+ return ErrNotImplemented
+}
+
+func (m *master) DisableEcho() error {
+ mode := m.inMode &^ windows.ENABLE_ECHO_INPUT
+ mode |= windows.ENABLE_PROCESSED_INPUT
+ mode |= windows.ENABLE_LINE_INPUT
+
+ if err := windows.SetConsoleMode(m.in, mode); err != nil {
+ return fmt.Errorf("unable to set console to disable echo: %w", err)
+ }
+
+ return nil
+}
+
+func (m *master) Close() error {
+ return nil
+}
+
+func (m *master) Read(b []byte) (int, error) {
+ return os.Stdin.Read(b)
+}
+
+func (m *master) Write(b []byte) (int, error) {
+ return os.Stdout.Write(b)
+}
+
+func (m *master) Fd() uintptr {
+ return uintptr(m.in)
+}
+
+// on windows, console can only be made from os.Std{in,out,err}, hence there
+// isnt a single name here we can use. Return a dummy "console" value in this
+// case should be sufficient.
+func (m *master) Name() string {
+ return "console"
+}
+
+// makeInputRaw puts the terminal (Windows Console) connected to the given
+// file descriptor into raw mode
+func makeInputRaw(fd windows.Handle, mode uint32) error {
+ // See
+ // -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
+ // -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
+
+ // Disable these modes
+ mode &^= windows.ENABLE_ECHO_INPUT
+ mode &^= windows.ENABLE_LINE_INPUT
+ mode &^= windows.ENABLE_MOUSE_INPUT
+ mode &^= windows.ENABLE_WINDOW_INPUT
+ mode &^= windows.ENABLE_PROCESSED_INPUT
+
+ // Enable these modes
+ mode |= windows.ENABLE_EXTENDED_FLAGS
+ mode |= windows.ENABLE_INSERT_MODE
+ mode |= windows.ENABLE_QUICK_EDIT_MODE
+
+ if vtInputSupported {
+ mode |= windows.ENABLE_VIRTUAL_TERMINAL_INPUT
+ }
+
+ if err := windows.SetConsoleMode(fd, mode); err != nil {
+ return fmt.Errorf("unable to set console to raw mode: %w", err)
+ }
+
+ return nil
+}
+
+func checkConsole(f File) error {
+ var mode uint32
+ if err := windows.GetConsoleMode(windows.Handle(f.Fd()), &mode); err != nil {
+ return err
+ }
+ return nil
+}
+
+func newMaster(f File) (Console, error) {
+ if f != os.Stdin && f != os.Stdout && f != os.Stderr {
+ return nil, errors.New("creating a console from a file is not supported on windows")
+ }
+ m := &master{}
+ m.initStdios()
+ return m, nil
+}
diff --git a/vendor/github.com/containerd/console/console_zos.go b/vendor/github.com/containerd/console/console_zos.go
new file mode 100644
index 0000000..b348a83
--- /dev/null
+++ b/vendor/github.com/containerd/console/console_zos.go
@@ -0,0 +1,163 @@
+// +build zos
+
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package console
+
+import (
+ "fmt"
+ "os"
+
+ "golang.org/x/sys/unix"
+)
+
+// NewPty creates a new pty pair
+// The master is returned as the first console and a string
+// with the path to the pty slave is returned as the second
+func NewPty() (Console, string, error) {
+ var f File
+ var err error
+ var slave string
+ for i := 0;; i++ {
+ ptyp := fmt.Sprintf("/dev/ptyp%04d", i)
+ f, err = os.OpenFile(ptyp, os.O_RDWR, 0600)
+ if err == nil {
+ slave = fmt.Sprintf("/dev/ttyp%04d", i)
+ break
+ }
+ if os.IsNotExist(err) {
+ return nil, "", err
+ }
+ // else probably Resource Busy
+ }
+ m, err := newMaster(f)
+ if err != nil {
+ return nil, "", err
+ }
+ return m, slave, nil
+}
+
+type master struct {
+ f File
+ original *unix.Termios
+}
+
+func (m *master) Read(b []byte) (int, error) {
+ return m.f.Read(b)
+}
+
+func (m *master) Write(b []byte) (int, error) {
+ return m.f.Write(b)
+}
+
+func (m *master) Close() error {
+ return m.f.Close()
+}
+
+func (m *master) Resize(ws WinSize) error {
+ return tcswinsz(m.f.Fd(), ws)
+}
+
+func (m *master) ResizeFrom(c Console) error {
+ ws, err := c.Size()
+ if err != nil {
+ return err
+ }
+ return m.Resize(ws)
+}
+
+func (m *master) Reset() error {
+ if m.original == nil {
+ return nil
+ }
+ return tcset(m.f.Fd(), m.original)
+}
+
+func (m *master) getCurrent() (unix.Termios, error) {
+ var termios unix.Termios
+ if err := tcget(m.f.Fd(), &termios); err != nil {
+ return unix.Termios{}, err
+ }
+ return termios, nil
+}
+
+func (m *master) SetRaw() error {
+ rawState, err := m.getCurrent()
+ if err != nil {
+ return err
+ }
+ rawState = cfmakeraw(rawState)
+ rawState.Oflag = rawState.Oflag | unix.OPOST
+ return tcset(m.f.Fd(), &rawState)
+}
+
+func (m *master) DisableEcho() error {
+ rawState, err := m.getCurrent()
+ if err != nil {
+ return err
+ }
+ rawState.Lflag = rawState.Lflag &^ unix.ECHO
+ return tcset(m.f.Fd(), &rawState)
+}
+
+func (m *master) Size() (WinSize, error) {
+ return tcgwinsz(m.f.Fd())
+}
+
+func (m *master) Fd() uintptr {
+ return m.f.Fd()
+}
+
+func (m *master) Name() string {
+ return m.f.Name()
+}
+
+// checkConsole checks if the provided file is a console
+func checkConsole(f File) error {
+ var termios unix.Termios
+ if tcget(f.Fd(), &termios) != nil {
+ return ErrNotAConsole
+ }
+ return nil
+}
+
+func newMaster(f File) (Console, error) {
+ m := &master{
+ f: f,
+ }
+ t, err := m.getCurrent()
+ if err != nil {
+ return nil, err
+ }
+ m.original = &t
+ return m, nil
+}
+
+// ClearONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair
+// created by us acts normally. In particular, a not-very-well-known default of
+// Linux unix98 ptys is that they have +onlcr by default. While this isn't a
+// problem for terminal emulators, because we relay data from the terminal we
+// also relay that funky line discipline.
+func ClearONLCR(fd uintptr) error {
+ return setONLCR(fd, false)
+}
+
+// SetONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair
+// created by us acts as intended for a terminal emulator.
+func SetONLCR(fd uintptr) error {
+ return setONLCR(fd, true)
+}
diff --git a/vendor/github.com/containerd/console/pty_freebsd_cgo.go b/vendor/github.com/containerd/console/pty_freebsd_cgo.go
new file mode 100644
index 0000000..cbd3cd7
--- /dev/null
+++ b/vendor/github.com/containerd/console/pty_freebsd_cgo.go
@@ -0,0 +1,45 @@
+// +build freebsd,cgo
+
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package console
+
+import (
+ "fmt"
+ "os"
+)
+
+/*
+#include
+#include
+#include
+*/
+import "C"
+
+// openpt allocates a new pseudo-terminal and establishes a connection with its
+// control device.
+func openpt() (*os.File, error) {
+ fd, err := C.posix_openpt(C.O_RDWR)
+ if err != nil {
+ return nil, fmt.Errorf("posix_openpt: %w", err)
+ }
+ if _, err := C.grantpt(fd); err != nil {
+ C.close(fd)
+ return nil, fmt.Errorf("grantpt: %w", err)
+ }
+ return os.NewFile(uintptr(fd), ""), nil
+}
diff --git a/vendor/github.com/containerd/console/pty_freebsd_nocgo.go b/vendor/github.com/containerd/console/pty_freebsd_nocgo.go
new file mode 100644
index 0000000..b5e4318
--- /dev/null
+++ b/vendor/github.com/containerd/console/pty_freebsd_nocgo.go
@@ -0,0 +1,36 @@
+// +build freebsd,!cgo
+
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package console
+
+import (
+ "os"
+)
+
+//
+// Implementing the functions below requires cgo support. Non-cgo stubs
+// versions are defined below to enable cross-compilation of source code
+// that depends on these functions, but the resultant cross-compiled
+// binaries cannot actually be used. If the stub function(s) below are
+// actually invoked they will display an error message and cause the
+// calling process to exit.
+//
+
+func openpt() (*os.File, error) {
+ panic("openpt() support requires cgo.")
+}
diff --git a/vendor/github.com/containerd/console/pty_unix.go b/vendor/github.com/containerd/console/pty_unix.go
new file mode 100644
index 0000000..d5a6bd8
--- /dev/null
+++ b/vendor/github.com/containerd/console/pty_unix.go
@@ -0,0 +1,30 @@
+// +build darwin linux netbsd openbsd solaris
+
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package console
+
+import (
+ "os"
+
+ "golang.org/x/sys/unix"
+)
+
+// openpt allocates a new pseudo-terminal by opening the /dev/ptmx device
+func openpt() (*os.File, error) {
+ return os.OpenFile("/dev/ptmx", unix.O_RDWR|unix.O_NOCTTY|unix.O_CLOEXEC, 0)
+}
diff --git a/vendor/github.com/containerd/console/tc_darwin.go b/vendor/github.com/containerd/console/tc_darwin.go
new file mode 100644
index 0000000..7871545
--- /dev/null
+++ b/vendor/github.com/containerd/console/tc_darwin.go
@@ -0,0 +1,44 @@
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package console
+
+import (
+ "fmt"
+ "os"
+
+ "golang.org/x/sys/unix"
+)
+
+const (
+ cmdTcGet = unix.TIOCGETA
+ cmdTcSet = unix.TIOCSETA
+)
+
+// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
+// unlockpt should be called before opening the slave side of a pty.
+func unlockpt(f *os.File) error {
+ return unix.IoctlSetPointerInt(int(f.Fd()), unix.TIOCPTYUNLK, 0)
+}
+
+// ptsname retrieves the name of the first available pts for the given master.
+func ptsname(f *os.File) (string, error) {
+ n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCPTYGNAME)
+ if err != nil {
+ return "", err
+ }
+ return fmt.Sprintf("/dev/pts/%d", n), nil
+}
diff --git a/vendor/github.com/containerd/console/tc_freebsd_cgo.go b/vendor/github.com/containerd/console/tc_freebsd_cgo.go
new file mode 100644
index 0000000..0f3d272
--- /dev/null
+++ b/vendor/github.com/containerd/console/tc_freebsd_cgo.go
@@ -0,0 +1,57 @@
+// +build freebsd,cgo
+
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package console
+
+import (
+ "fmt"
+ "os"
+
+ "golang.org/x/sys/unix"
+)
+
+/*
+#include
+#include
+*/
+import "C"
+
+const (
+ cmdTcGet = unix.TIOCGETA
+ cmdTcSet = unix.TIOCSETA
+)
+
+// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
+// unlockpt should be called before opening the slave side of a pty.
+func unlockpt(f *os.File) error {
+ fd := C.int(f.Fd())
+ if _, err := C.unlockpt(fd); err != nil {
+ C.close(fd)
+ return fmt.Errorf("unlockpt: %w", err)
+ }
+ return nil
+}
+
+// ptsname retrieves the name of the first available pts for the given master.
+func ptsname(f *os.File) (string, error) {
+ n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCGPTN)
+ if err != nil {
+ return "", err
+ }
+ return fmt.Sprintf("/dev/pts/%d", n), nil
+}
diff --git a/vendor/github.com/containerd/console/tc_freebsd_nocgo.go b/vendor/github.com/containerd/console/tc_freebsd_nocgo.go
new file mode 100644
index 0000000..087fc15
--- /dev/null
+++ b/vendor/github.com/containerd/console/tc_freebsd_nocgo.go
@@ -0,0 +1,55 @@
+// +build freebsd,!cgo
+
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package console
+
+import (
+ "fmt"
+ "os"
+
+ "golang.org/x/sys/unix"
+)
+
+const (
+ cmdTcGet = unix.TIOCGETA
+ cmdTcSet = unix.TIOCSETA
+)
+
+//
+// Implementing the functions below requires cgo support. Non-cgo stubs
+// versions are defined below to enable cross-compilation of source code
+// that depends on these functions, but the resultant cross-compiled
+// binaries cannot actually be used. If the stub function(s) below are
+// actually invoked they will display an error message and cause the
+// calling process to exit.
+//
+
+// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
+// unlockpt should be called before opening the slave side of a pty.
+func unlockpt(f *os.File) error {
+ panic("unlockpt() support requires cgo.")
+}
+
+// ptsname retrieves the name of the first available pts for the given master.
+func ptsname(f *os.File) (string, error) {
+ n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCGPTN)
+ if err != nil {
+ return "", err
+ }
+ return fmt.Sprintf("/dev/pts/%d", n), nil
+}
diff --git a/vendor/github.com/containerd/console/tc_linux.go b/vendor/github.com/containerd/console/tc_linux.go
new file mode 100644
index 0000000..7d552ea
--- /dev/null
+++ b/vendor/github.com/containerd/console/tc_linux.go
@@ -0,0 +1,51 @@
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package console
+
+import (
+ "fmt"
+ "os"
+ "unsafe"
+
+ "golang.org/x/sys/unix"
+)
+
+const (
+ cmdTcGet = unix.TCGETS
+ cmdTcSet = unix.TCSETS
+)
+
+// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
+// unlockpt should be called before opening the slave side of a pty.
+func unlockpt(f *os.File) error {
+ var u int32
+ // XXX do not use unix.IoctlSetPointerInt here, see commit dbd69c59b81.
+ if _, _, err := unix.Syscall(unix.SYS_IOCTL, f.Fd(), unix.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))); err != 0 {
+ return err
+ }
+ return nil
+}
+
+// ptsname retrieves the name of the first available pts for the given master.
+func ptsname(f *os.File) (string, error) {
+ var u uint32
+ // XXX do not use unix.IoctlGetInt here, see commit dbd69c59b81.
+ if _, _, err := unix.Syscall(unix.SYS_IOCTL, f.Fd(), unix.TIOCGPTN, uintptr(unsafe.Pointer(&u))); err != 0 {
+ return "", err
+ }
+ return fmt.Sprintf("/dev/pts/%d", u), nil
+}
diff --git a/vendor/github.com/containerd/console/tc_netbsd.go b/vendor/github.com/containerd/console/tc_netbsd.go
new file mode 100644
index 0000000..71227ae
--- /dev/null
+++ b/vendor/github.com/containerd/console/tc_netbsd.go
@@ -0,0 +1,45 @@
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package console
+
+import (
+ "bytes"
+ "os"
+
+ "golang.org/x/sys/unix"
+)
+
+const (
+ cmdTcGet = unix.TIOCGETA
+ cmdTcSet = unix.TIOCSETA
+)
+
+// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
+// unlockpt should be called before opening the slave side of a pty.
+// This does not exist on NetBSD, it does not allocate controlling terminals on open
+func unlockpt(f *os.File) error {
+ return nil
+}
+
+// ptsname retrieves the name of the first available pts for the given master.
+func ptsname(f *os.File) (string, error) {
+ ptm, err := unix.IoctlGetPtmget(int(f.Fd()), unix.TIOCPTSNAME)
+ if err != nil {
+ return "", err
+ }
+ return string(ptm.Sn[:bytes.IndexByte(ptm.Sn[:], 0)]), nil
+}
diff --git a/vendor/github.com/containerd/console/tc_openbsd_cgo.go b/vendor/github.com/containerd/console/tc_openbsd_cgo.go
new file mode 100644
index 0000000..f0cec06
--- /dev/null
+++ b/vendor/github.com/containerd/console/tc_openbsd_cgo.go
@@ -0,0 +1,51 @@
+// +build openbsd,cgo
+
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package console
+
+import (
+ "os"
+
+ "golang.org/x/sys/unix"
+)
+
+//#include
+import "C"
+
+const (
+ cmdTcGet = unix.TIOCGETA
+ cmdTcSet = unix.TIOCSETA
+)
+
+// ptsname retrieves the name of the first available pts for the given master.
+func ptsname(f *os.File) (string, error) {
+ ptspath, err := C.ptsname(C.int(f.Fd()))
+ if err != nil {
+ return "", err
+ }
+ return C.GoString(ptspath), nil
+}
+
+// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
+// unlockpt should be called before opening the slave side of a pty.
+func unlockpt(f *os.File) error {
+ if _, err := C.grantpt(C.int(f.Fd())); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/vendor/github.com/containerd/console/tc_openbsd_nocgo.go b/vendor/github.com/containerd/console/tc_openbsd_nocgo.go
new file mode 100644
index 0000000..daccce2
--- /dev/null
+++ b/vendor/github.com/containerd/console/tc_openbsd_nocgo.go
@@ -0,0 +1,47 @@
+// +build openbsd,!cgo
+
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+//
+// Implementing the functions below requires cgo support. Non-cgo stubs
+// versions are defined below to enable cross-compilation of source code
+// that depends on these functions, but the resultant cross-compiled
+// binaries cannot actually be used. If the stub function(s) below are
+// actually invoked they will display an error message and cause the
+// calling process to exit.
+//
+
+package console
+
+import (
+ "os"
+
+ "golang.org/x/sys/unix"
+)
+
+const (
+ cmdTcGet = unix.TIOCGETA
+ cmdTcSet = unix.TIOCSETA
+)
+
+func ptsname(f *os.File) (string, error) {
+ panic("ptsname() support requires cgo.")
+}
+
+func unlockpt(f *os.File) error {
+ panic("unlockpt() support requires cgo.")
+}
diff --git a/vendor/github.com/containerd/console/tc_solaris_cgo.go b/vendor/github.com/containerd/console/tc_solaris_cgo.go
new file mode 100644
index 0000000..e36a68e
--- /dev/null
+++ b/vendor/github.com/containerd/console/tc_solaris_cgo.go
@@ -0,0 +1,51 @@
+// +build solaris,cgo
+
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package console
+
+import (
+ "os"
+
+ "golang.org/x/sys/unix"
+)
+
+//#include
+import "C"
+
+const (
+ cmdTcGet = unix.TCGETS
+ cmdTcSet = unix.TCSETS
+)
+
+// ptsname retrieves the name of the first available pts for the given master.
+func ptsname(f *os.File) (string, error) {
+ ptspath, err := C.ptsname(C.int(f.Fd()))
+ if err != nil {
+ return "", err
+ }
+ return C.GoString(ptspath), nil
+}
+
+// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
+// unlockpt should be called before opening the slave side of a pty.
+func unlockpt(f *os.File) error {
+ if _, err := C.grantpt(C.int(f.Fd())); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/vendor/github.com/containerd/console/tc_solaris_nocgo.go b/vendor/github.com/containerd/console/tc_solaris_nocgo.go
new file mode 100644
index 0000000..eb0bd2c
--- /dev/null
+++ b/vendor/github.com/containerd/console/tc_solaris_nocgo.go
@@ -0,0 +1,47 @@
+// +build solaris,!cgo
+
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+//
+// Implementing the functions below requires cgo support. Non-cgo stubs
+// versions are defined below to enable cross-compilation of source code
+// that depends on these functions, but the resultant cross-compiled
+// binaries cannot actually be used. If the stub function(s) below are
+// actually invoked they will display an error message and cause the
+// calling process to exit.
+//
+
+package console
+
+import (
+ "os"
+
+ "golang.org/x/sys/unix"
+)
+
+const (
+ cmdTcGet = unix.TCGETS
+ cmdTcSet = unix.TCSETS
+)
+
+func ptsname(f *os.File) (string, error) {
+ panic("ptsname() support requires cgo.")
+}
+
+func unlockpt(f *os.File) error {
+ panic("unlockpt() support requires cgo.")
+}
diff --git a/vendor/github.com/containerd/console/tc_unix.go b/vendor/github.com/containerd/console/tc_unix.go
new file mode 100644
index 0000000..a6bf01e
--- /dev/null
+++ b/vendor/github.com/containerd/console/tc_unix.go
@@ -0,0 +1,91 @@
+// +build darwin freebsd linux netbsd openbsd solaris zos
+
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package console
+
+import (
+ "golang.org/x/sys/unix"
+)
+
+func tcget(fd uintptr, p *unix.Termios) error {
+ termios, err := unix.IoctlGetTermios(int(fd), cmdTcGet)
+ if err != nil {
+ return err
+ }
+ *p = *termios
+ return nil
+}
+
+func tcset(fd uintptr, p *unix.Termios) error {
+ return unix.IoctlSetTermios(int(fd), cmdTcSet, p)
+}
+
+func tcgwinsz(fd uintptr) (WinSize, error) {
+ var ws WinSize
+
+ uws, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ)
+ if err != nil {
+ return ws, err
+ }
+
+ // Translate from unix.Winsize to console.WinSize
+ ws.Height = uws.Row
+ ws.Width = uws.Col
+ ws.x = uws.Xpixel
+ ws.y = uws.Ypixel
+ return ws, nil
+}
+
+func tcswinsz(fd uintptr, ws WinSize) error {
+ // Translate from console.WinSize to unix.Winsize
+
+ var uws unix.Winsize
+ uws.Row = ws.Height
+ uws.Col = ws.Width
+ uws.Xpixel = ws.x
+ uws.Ypixel = ws.y
+
+ return unix.IoctlSetWinsize(int(fd), unix.TIOCSWINSZ, &uws)
+}
+
+func setONLCR(fd uintptr, enable bool) error {
+ var termios unix.Termios
+ if err := tcget(fd, &termios); err != nil {
+ return err
+ }
+ if enable {
+ // Set +onlcr so we can act like a real terminal
+ termios.Oflag |= unix.ONLCR
+ } else {
+ // Set -onlcr so we don't have to deal with \r.
+ termios.Oflag &^= unix.ONLCR
+ }
+ return tcset(fd, &termios)
+}
+
+func cfmakeraw(t unix.Termios) unix.Termios {
+ t.Iflag &^= (unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON)
+ t.Oflag &^= unix.OPOST
+ t.Lflag &^= (unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN)
+ t.Cflag &^= (unix.CSIZE | unix.PARENB)
+ t.Cflag &^= unix.CS8
+ t.Cc[unix.VMIN] = 1
+ t.Cc[unix.VTIME] = 0
+
+ return t
+}
diff --git a/vendor/github.com/containerd/console/tc_zos.go b/vendor/github.com/containerd/console/tc_zos.go
new file mode 100644
index 0000000..4262eaf
--- /dev/null
+++ b/vendor/github.com/containerd/console/tc_zos.go
@@ -0,0 +1,26 @@
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package console
+
+import (
+ "golang.org/x/sys/unix"
+)
+
+const (
+ cmdTcGet = unix.TCGETS
+ cmdTcSet = unix.TCSETS
+)
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/.nojekyll b/vendor/github.com/gookit/color/.nojekyll
new file mode 100644
index 0000000..e69de29
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..77d50ca
--- /dev/null
+++ b/vendor/github.com/gookit/color/README.md
@@ -0,0 +1,580 @@
+# 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://app.codacy.com/project/badge/Grade/7fef8d74c1d64afc99ce0f2c6d3f8af1)](https://www.codacy.com/gh/gookit/color/dashboard?utm_source=github.com&utm_medium=referral&utm_content=gookit/color&utm_campaign=Badge_Grade)
+[![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 16/256/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
+ - Support converts `HEX` `HSL` value to RGB color
+ - Generic API methods: `Print`, `Printf`, `Println`, `Sprint`, `Sprintf`
+ - Supports HTML tag-style color rendering, such as `message> text>`.
+ - 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.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.Notice.Println("Notice message")
+color.Error.Println("Error 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.Notice.Tips("Notice tips message")
+color.Error.Tips("Error 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.Notice.Prompt("Notice prompt message")
+color.Error.Prompt("Error prompt message")
+// ...
+```
+
+Run demo: `go run ./_examples/theme_prompt.go`
+
+![theme-prompt](_examples/images/theme-prompt.png)
+
+**Block Style**
+
+```go
+color.Danger.Block("Danger block message")
+color.Warn.Block("Warn 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
+
+`Print,Printf,Println` functions support auto parse and render color tags.
+
+```go
+ text := `
+ gookit/color:>
+ A command-line>
+ color library> with 256-color>
+ and True-color> support,
+ universal API> methods
+ and Windows> support.
+`
+ color.Print(text)
+```
+
+Preview, code please see [_examples/demo_tag.go](_examples/demo_tag.go):
+
+![demo_tag](_examples/images/demo_tag.png)
+
+**Tag formats:**
+
+- Use built in tags: `CONTENT>` e.g: `message>`
+- Custom tag attributes: `CONTENT>` e.g: `wel>`
+
+> **Supported** on Windows `cmd.exe` `PowerShell`.
+
+Examples:
+
+```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>")
+```
+
+### Tag attributes
+
+tag attributes format:
+
+```text
+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"
+```
+
+> tag attributes parse please see `func ParseCodeFromAttr()`
+
+### Built-in tags
+
+Built-in tags please see var `colorTags` in [color_tag.go](color_tag.go)
+
+```go
+// use style tag
+color.Print("he>llo>, wel>come>")
+color.Println("hello>")
+color.Println("hello>")
+```
+
+Run demo: `go run ./_examples/color_tag.go`
+
+![color-tags](_examples/images/color-tags.png)
+
+**Use `color.Tag` build message**:
+
+```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")
+```
+
+## 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")
+```
+
+### Convert utils
+
+`color` has many built-in color conversion utility functions.
+
+```go
+func Basic2hex(val uint8) string
+
+func Bg2Fg(val uint8) uint8
+func Fg2Bg(val uint8) uint8
+
+func C256ToRgb(val uint8) (rgb []uint8)
+func C256ToRgbV1(val uint8) (rgb []uint8)
+
+func Hex2basic(hex string, asBg ...bool) uint8
+func Hex2rgb(hex string) []int
+func HexToRGB(hex string) []int
+func HexToRgb(hex string) (rgb []int)
+
+func HslIntToRgb(h, s, l int) (rgb []uint8)
+func HslToRgb(h, s, l float64) (rgb []uint8)
+func HsvToRgb(h, s, v int) (rgb []uint8)
+
+func Rgb2ansi(r, g, b uint8, isBg bool) uint8
+func Rgb2basic(r, g, b uint8, isBg bool) uint8
+func Rgb2hex(rgb []int) string
+func Rgb2short(r, g, b uint8) uint8
+func RgbTo256(r, g, b uint8) uint8
+func RgbTo256Table() map[string]uint8
+func RgbToAnsi(r, g, b uint8, isBg bool) uint8
+func RgbToHex(rgb []int) string
+func RgbToHsl(r, g, b uint8) []float64
+func RgbToHslInt(r, g, b uint8) []int
+```
+
+**Convert to `RGBColor`**:
+
+- `func RGBFromSlice(rgb []uint8, isBg ...bool) RGBColor`
+- `func RGBFromString(rgb string, isBg ...bool) RGBColor`
+- `func HEX(hex string, isBg ...bool) RGBColor`
+- `func HSL(h, s, l float64, isBg ...bool) RGBColor`
+- `func HSLInt(h, s, l int, isBg ...bool) RGBColor`
+
+## Util functions
+
+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
+
+> More useful func please see https://pkg.go.dev/github.com/gookit/color
+
+### Detect color level
+
+`color` automatically checks the color levels supported by the current environment.
+
+```go
+// Level is the color level supported by a terminal.
+type Level = terminfo.ColorLevel
+
+// terminal color available level alias of the terminfo.ColorLevel*
+const (
+ LevelNo = terminfo.ColorLevelNone // not support color.
+ Level16 = terminfo.ColorLevelBasic // basic - 3/4 bit color supported
+ Level256 = terminfo.ColorLevelHundreds // hundreds - 8-bit color supported
+ LevelRgb = terminfo.ColorLevelMillions // millions - (24 bit)true color supported
+)
+```
+
+- `func SupportColor() bool` Whether the current environment supports color output
+- `func Support256Color() bool` Whether the current environment supports 256-color output
+- `func SupportTrueColor() bool` Whether the current environment supports (RGB)True-color output
+- `func TermColorLevel() Level` Get the currently supported color level
+
+
+## Projects using color
+
+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
+- https://github.com/flipped-aurora/gin-vue-admin 基于gin+vue搭建的(中)后台系统框架
+- https://github.com/JanDeDobbeleer/oh-my-posh A prompt theme engine for any shell.
+- https://github.com/jesseduffield/lazygit Simple terminal UI for git commands
+- https://github.com/olivia-ai/olivia 💁♀️Your new best friend powered by an artificial neural network
+- https://github.com/pterm/pterm PTerm is a modern Go module to beautify console output. Featuring charts, progressbars, tables, trees, etc.
+- https://github.com/securego/gosec Golang security checker
+- https://github.com/TNK-Studio/lazykube ⎈ The lazier way to manage kubernetes.
+- [+ See More](https://pkg.go.dev/github.com/gookit/color?tab=importedby)
+
+## 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)
+ - [muesli/termenv](https://github.com/muesli/termenv)
+ - [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..192a89c
--- /dev/null
+++ b/vendor/github.com/gookit/color/README.zh-CN.md
@@ -0,0 +1,591 @@
+# 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://app.codacy.com/project/badge/Grade/7fef8d74c1d64afc99ce0f2c6d3f8af1)](https://www.codacy.com/gh/gookit/color/dashboard?utm_source=github.com&utm_medium=referral&utm_content=gookit/color&utm_campaign=Badge_Grade)
+[![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下的命令行色彩使用库, 拥有丰富的色彩(16/256/True)渲染输出,通用的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色彩的终端
+ - 支持转换 `HEX` `HSL` 等为RGB色彩
+ - 提供通用的API方法:`Print` `Printf` `Println` `Sprint` `Sprintf`
+ - 同时支持html标签式的颜色渲染,除了使用内置标签,同时支持自定义颜色属性
+ - 例如: `this an message> text>` 标签内部文本将会渲染对应色彩
+ - 自定义颜色属性: 支持使用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")
+// ...
+
+// 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")
+// ...
+```
+
+Run demo: `go run ./_examples/theme_basic.go`
+
+![theme-basic](_examples/images/theme-basic.png)
+
+**简约提示风格**
+
+```go
+color.Info.Tips("Info tips message")
+color.Notice.Tips("Notice tips message")
+color.Error.Tips("Error 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.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.Question.Block("Question 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风格
+
+> TIP: 可同时设置前景和背景色
+
+- `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")
+```
+
+## 使用颜色标签
+
+`Print,Printf,Println` 等方法支持自动解析并渲染 HTML 风格的颜色标签
+
+> **支持** 在windows `cmd.exe` `PowerShell` 使用
+
+简单示例:
+
+```go
+ text := `
+ gookit/color:>
+ A command-line>
+ color library> with 256-color>
+ and True-color> support,
+ universal API> methods
+ and Windows> support.
+`
+ color.Print(text)
+```
+
+输出效果, 示例代码请看 [_examples/demo_tag.go](_examples/demo_tag.go):
+
+![demo_tag](_examples/images/demo_tag.png)
+
+**颜色标签格式:**
+
+- 直接使用内置风格标签: `CONTENT>` e.g: `message>`
+- 自定义标签属性: `CONTENT>` e.g: `wel>`
+
+使用内置的颜色标签,可以非常方便简单的构建自己需要的任何格式
+
+> 同时支持自定义颜色属性: 支持使用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>")
+```
+
+### 自定义标签属性
+
+标签属性格式:
+
+```text
+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"
+```
+
+> tag attributes parse please see `func ParseCodeFromAttr()`
+
+### 内置标签
+
+内置标签请参见变量 `colorTags` 定义, 源文件 [color_tag.go](color_tag.go)
+
+```go
+// use style tag
+color.Print("he>llo>, wel>come>")
+color.Println("hello>")
+color.Println("hello>")
+```
+
+> 运行 demo: `go run ./_examples/color_tag.go`
+
+![color-tags](_examples/images/color-tags.png)
+
+**使用 `color.Tag` 包装标签**:
+
+可以使用通用的输出API方法,给后面输出的文本信息加上给定的颜色风格标签
+
+```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")
+```
+
+## 颜色转换
+
+支持 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")
+```
+
+### 颜色转换方法
+
+`color` 内置了许多颜色转换工具方法
+
+```go
+func Basic2hex(val uint8) string
+
+func Bg2Fg(val uint8) uint8
+func Fg2Bg(val uint8) uint8
+
+func C256ToRgb(val uint8) (rgb []uint8)
+func C256ToRgbV1(val uint8) (rgb []uint8)
+
+func Hex2basic(hex string, asBg ...bool) uint8
+func Hex2rgb(hex string) []int
+func HexToRGB(hex string) []int
+func HexToRgb(hex string) (rgb []int)
+
+func HslIntToRgb(h, s, l int) (rgb []uint8)
+func HslToRgb(h, s, l float64) (rgb []uint8)
+func HsvToRgb(h, s, v int) (rgb []uint8)
+
+func Rgb2ansi(r, g, b uint8, isBg bool) uint8
+func Rgb2basic(r, g, b uint8, isBg bool) uint8
+func Rgb2hex(rgb []int) string
+func Rgb2short(r, g, b uint8) uint8
+func RgbTo256(r, g, b uint8) uint8
+func RgbTo256Table() map[string]uint8
+func RgbToAnsi(r, g, b uint8, isBg bool) uint8
+func RgbToHex(rgb []int) string
+func RgbToHsl(r, g, b uint8) []float64
+func RgbToHslInt(r, g, b uint8) []int
+```
+
+**转换为 `RGBColor`**:
+
+- `func RGBFromSlice(rgb []uint8, isBg ...bool) RGBColor`
+- `func RGBFromString(rgb string, isBg ...bool) RGBColor`
+- `func HEX(hex string, isBg ...bool) RGBColor`
+- `func HSL(h, s, l float64, isBg ...bool) RGBColor`
+- `func HSLInt(h, s, l int, isBg ...bool) RGBColor`
+
+## 工具方法参考
+
+一些有用的工具方法参考
+
+- `Disable()` 禁用颜色渲染输出
+- `SetOutput(io.Writer)` 自定义设置渲染后的彩色文本输出位置
+- `ForceOpenColor()` 强制开启颜色渲染
+- `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
+- 更多请查看文档 https://pkg.go.dev/github.com/gookit/color
+
+### 检测支持的颜色级别
+
+`color` 会自动检查当前环境支持的颜色级别
+
+```go
+// Level is the color level supported by a terminal.
+type Level = terminfo.ColorLevel
+
+// terminal color available level alias of the terminfo.ColorLevel*
+const (
+ LevelNo = terminfo.ColorLevelNone // not support color.
+ Level16 = terminfo.ColorLevelBasic // basic - 3/4 bit color supported
+ Level256 = terminfo.ColorLevelHundreds // hundreds - 8-bit color supported
+ LevelRgb = terminfo.ColorLevelMillions // millions - (24 bit)true color supported
+)
+```
+
+- `func SupportColor() bool` 当前环境是否支持色彩输出
+- `func Support256Color() bool` 当前环境是否支持256色彩输出
+- `func SupportTrueColor() bool` 当前环境是否支持(RGB)True色彩输出
+- `func TermColorLevel() Level` 获取当前支持的颜色级别
+
+## 使用Color的项目
+
+看看这些使用了 https://github.com/gookit/color 的项目:
+
+- https://github.com/Delta456/box-cli-maker Make Highly Customized Boxes for your CLI
+- https://github.com/flipped-aurora/gin-vue-admin 基于gin+vue搭建的(中)后台系统框架
+- https://github.com/JanDeDobbeleer/oh-my-posh A prompt theme engine for any shell.
+- https://github.com/jesseduffield/lazygit Simple terminal UI for git commands
+- https://github.com/olivia-ai/olivia 💁♀️Your new best friend powered by an artificial neural network
+- https://github.com/pterm/pterm PTerm is a modern Go module to beautify console output. Featuring charts, progressbars, tables, trees, etc.
+- https://github.com/securego/gosec Golang security checker
+- https://github.com/TNK-Studio/lazykube ⎈ The lazier way to manage kubernetes.
+- [+ See More](https://pkg.go.dev/github.com/gookit/color?tab=importedby)
+
+## 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)
+ - [muesli/termenv](https://github.com/muesli/termenv)
+ - [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/any.go b/vendor/github.com/gookit/color/any.go
new file mode 100644
index 0000000..8bf31c1
--- /dev/null
+++ b/vendor/github.com/gookit/color/any.go
@@ -0,0 +1,6 @@
+//go:build !go1.18
+// +build !go1.18
+
+package color
+
+type any = interface{}
diff --git a/vendor/github.com/gookit/color/color.go b/vendor/github.com/gookit/color/color.go
new file mode 100644
index 0000000..22de1b0
--- /dev/null
+++ b/vendor/github.com/gookit/color/color.go
@@ -0,0 +1,251 @@
+/*
+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"
+ "strings"
+
+ "github.com/xo/terminfo"
+)
+
+// color render templates
+//
+// ESC 操作的表示:
+//
+// "\033"(Octal 8进制) = "\x1b"(Hexadecimal 16进制) = 27 (10进制)
+const (
+ // StartSet chars
+ StartSet = "\x1b["
+ // ResetSet close all properties.
+ ResetSet = "\x1b[0m"
+ // SettingTpl string.
+ SettingTpl = "\x1b[%sm"
+ // FullColorTpl for build color code
+ FullColorTpl = "\x1b[%sm%s\x1b[0m"
+ // CodeSuffix string for color code.
+ CodeSuffix = "[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 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 Get the currently supported color level
+func TermColorLevel() Level {
+ return colorLevel
+}
+
+// SupportColor Whether the current environment supports color output
+func SupportColor() bool {
+ return colorLevel > terminfo.ColorLevelNone
+}
+
+// Support16Color on the current ENV
+// func Support16Color() bool {
+// return colorLevel > terminfo.ColorLevelNone
+// }
+
+// Support256Color Whether the current environment supports 256-color output
+func Support256Color() bool {
+ return colorLevel > terminfo.ColorLevelBasic
+}
+
+// SupportTrueColor Whether the current environment supports (RGB)True-color output
+func SupportTrueColor() bool {
+ return colorLevel > terminfo.ColorLevelHundreds
+}
+
+/*************************************************************
+ * global settings
+ *************************************************************/
+
+// 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
+}
+
+// ForceSetColorLevel 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: please don't use
+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 ...any) 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)
+ return StartSet + code + "m" + message + ResetSet
+}
+
+// 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 ...any) string {
+ msg := formatArgsForPrintln(args)
+ if len(code) == 0 {
+ return msg
+ }
+
+ // disabled OR not support color
+ if !Enable || !SupportColor() {
+ return ClearCode(msg)
+ }
+
+ return StartSet + code + "m" + msg + ResetSet
+}
+
+// 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)
+ return StartSet + code + "m" + str + ResetSet
+}
+
+// ClearCode clear color codes.
+//
+// eg:
+//
+// "\033[36;1mText\x1b[0m" -> "Text"
+func ClearCode(str string) string {
+ if !strings.Contains(str, CodeSuffix) {
+ return str
+ }
+ 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..eda226a
--- /dev/null
+++ b/vendor/github.com/gookit/color/color_16.go
@@ -0,0 +1,511 @@
+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
+ *************************************************************/
+
+const (
+ // OptMax max option value. range: 0 - 9
+ OptMax = 10
+ // DiffFgBg diff foreground and background color
+ DiffFgBg = 10
+)
+
+// Boundary value for foreground/background color 16
+//
+// - base: fg 30~37, bg 40~47
+// - light: fg 90~97, bg 100~107
+const (
+ FgBase uint8 = 30
+ FgMax uint8 = 37
+ BgBase uint8 = 40
+ BgMax uint8 = 47
+
+ HiFgBase uint8 = 90
+ HiFgMax uint8 = 97
+ HiBgBase uint8 = 100
+ HiBgMax uint8 = 107
+)
+
+// 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 (non-standard)
+const (
+ BgDarkGray Color = iota + 100
+ BgLightRed
+ BgLightGreen
+ BgLightYellow
+ BgLightBlue
+ BgLightMagenta
+ BgLightCyan
+ BgLightWhite
+ // BgGray is alias of BgDarkGray
+ BgGray Color = 100
+)
+
+// Option settings. range: 0 - 9
+const (
+ OpReset Color = iota // 0 重置所有设置
+ OpBold // 1 加粗
+ OpFuzzy // 2 模糊(不是所有的终端仿真器都支持)
+ OpItalic // 3 斜体(不是所有的终端仿真器都支持)
+ OpUnderscore // 4 下划线
+ OpBlink // 5 闪烁
+ OpFastBlink // 6 快速闪烁(未广泛支持)
+ 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 a 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 ...any) 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 ...any) string { return RenderWithSpaces(c.String(), a...) }
+
+// Sprint render messages by color setting. is alias of the Render()
+func (c Color) Sprint(a ...any) 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 ...any) 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 ...any) {
+ 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 ...any) {
+ doPrintV2(c.Code(), fmt.Sprintf(format, a...))
+}
+
+// Println messages with new line
+func (c Color) Println(a ...any) { 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 := uint8(c)
+ if val >= 30 && val <= 47 {
+ return Color(val + 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 := uint8(c)
+ if val >= 90 && val <= 107 {
+ return Color(val - 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}
+}
+
+// ToFg always convert fg
+func (c Color) ToFg() Color {
+ val := uint8(c)
+ // option code, don't change
+ if val < 10 {
+ return c
+ }
+ return Color(Bg2Fg(val))
+}
+
+// ToBg always convert bg
+func (c Color) ToBg() Color {
+ val := uint8(c)
+ // option code, don't change
+ if val < 10 {
+ return c
+ }
+ return Color(Fg2Bg(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), c.IsBg())
+}
+
+// Code convert to code string. eg "35"
+func (c Color) Code() string {
+ return strconv.FormatInt(int64(c), 10)
+}
+
+// String convert to code string. eg "35"
+func (c Color) String() string {
+ return strconv.FormatInt(int64(c), 10)
+}
+
+// IsBg check is background color
+func (c Color) IsBg() bool {
+ val := uint8(c)
+ return val >= BgBase && val <= BgMax || val >= HiBgBase && val <= HiBgMax
+}
+
+// IsFg check is foreground color
+func (c Color) IsFg() bool {
+ val := uint8(c)
+ return val >= FgBase && val <= FgMax || val >= HiFgBase && val <= HiFgMax
+}
+
+// IsOption check is option code: 0-9
+func (c Color) IsOption() bool { return uint8(c) < OptMax }
+
+// IsValid color value
+func (c Color) IsValid() bool { return uint8(c) < HiBgMax }
+
+/*************************************************************
+ * 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: 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{}
+ // optionWithAlias = buildOpWithAlias()
+ // 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",
+ }
+)
+
+// Bg2Fg bg color value to fg value
+func Bg2Fg(val uint8) uint8 {
+ if val >= BgBase && val <= 47 { // is bg
+ val = val - 10
+ } else if val >= HiBgBase && val <= 107 { // is hi bg
+ val = val - 10
+ }
+ return val
+}
+
+// Fg2Bg fg color value to bg value
+func Fg2Bg(val uint8) uint8 {
+ if val >= FgBase && val <= 37 { // is fg
+ val = val + 10
+ } else if val >= HiFgBase && val <= 97 { // is hi fg
+ val = val + 10
+ }
+ return val
+}
+
+// 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
+// }
+
+// func buildOpWithAlias() map[string]uint8 {
+// }
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..79ae5f8
--- /dev/null
+++ b/vendor/github.com/gookit/color/color_256.go
@@ -0,0 +1,303 @@
+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.
+// Support 256 color on windows CMD, PowerShell
+//
+// 颜色值使用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]
+//
+// 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 ...any) {
+ doPrintV2(c.String(), fmt.Sprint(a...))
+}
+
+// Printf format and print message
+func (c Color256) Printf(format string, a ...any) {
+ doPrintV2(c.String(), fmt.Sprintf(format, a...))
+}
+
+// Println print message with newline
+func (c Color256) Println(a ...any) {
+ doPrintlnV2(c.String(), a)
+}
+
+// Sprint returns rendered message
+func (c Color256) Sprint(a ...any) string {
+ return RenderCode(c.String(), a...)
+}
+
+// Sprintf returns format and rendered message
+func (c Color256) Sprintf(format string, a ...any) 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 Fg256Pfx + strconv.Itoa(int(c[0]))
+ }
+
+ if c[1] == AsBg { // 1 is Bg
+ 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 {
+ // 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 ...any) {
+ doPrintV2(s.String(), fmt.Sprint(a...))
+}
+
+// Printf format and print message
+func (s *Style256) Printf(format string, a ...any) {
+ doPrintV2(s.String(), fmt.Sprintf(format, a...))
+}
+
+// Println print message with newline
+func (s *Style256) Println(a ...any) {
+ doPrintlnV2(s.String(), a)
+}
+
+// Sprint returns rendered message
+func (s *Style256) Sprint(a ...any) string {
+ return RenderCode(s.Code(), a...)
+}
+
+// Sprintf returns format and rendered message
+func (s *Style256) Sprintf(format string, a ...any) 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, Fg256Pfx+strconv.FormatInt(int64(s.fg[0]), 10))
+ }
+
+ if s.bg[1] > 0 {
+ ss = append(ss, Bg256Pfx+strconv.FormatInt(int64(s.bg[0]), 10))
+ }
+
+ 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..bc129b7
--- /dev/null
+++ b/vendor/github.com/gookit/color/color_rgb.go
@@ -0,0 +1,443 @@
+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
+)
+
+/*************************************************************
+ * RGB Color(Bit24Color, TrueColor)
+ *************************************************************/
+
+// RGBColor definition.
+// Support RGB color on Windows CMD, PowerShell
+//
+// 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}
+type RGBColor [4]uint8
+
+// create an 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...) }
+
+// RgbFromInt create instance from int r,g,b value
+func RgbFromInt(r, g, b int, isBg ...bool) RGBColor {
+ return RGB(uint8(r), uint8(g), uint8(b), isBg...)
+}
+
+// RgbFromInts create instance from []int r,g,b value
+func RgbFromInts(rgb []int, isBg ...bool) RGBColor {
+ return RGB(uint8(rgb[0]), uint8(rgb[1]), uint8(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...) }
+
+// RGBFromHEX quick RGBColor from hex string, alias of HEX()
+func RGBFromHEX(hex string, isBg ...bool) RGBColor { return HEX(hex, isBg...) }
+
+// HSL create RGB color from a hsl value.
+// more see HslToRgb()
+func HSL(h, s, l float64, isBg ...bool) RGBColor {
+ rgb := HslToRgb(h, s, l)
+ return RGB(rgb[0], rgb[1], rgb[2], isBg...)
+}
+
+// Hsl alias of the HSL()
+func Hsl(h, s, l float64, isBg ...bool) RGBColor { return HSL(h, s, l, isBg...) }
+
+// HSLInt create RGB color from a hsl int value.
+// more see HslIntToRgb()
+func HSLInt(h, s, l int, isBg ...bool) RGBColor {
+ rgb := HslIntToRgb(h, s, l)
+ return RGB(rgb[0], rgb[1], rgb[2], isBg...)
+}
+
+// HslInt alias of the HSLInt()
+func HslInt(h, s, l int, isBg ...bool) RGBColor { return HSLInt(h, s, l, isBg...) }
+
+// RGBFromSlice quick RGBColor from slice
+func RGBFromSlice(rgb []uint8, isBg ...bool) RGBColor {
+ return RGB(rgb[0], rgb[1], rgb[2], isBg...)
+}
+
+// RGBFromString create RGB color from a string.
+// Support use color name in the {namedRgbMap}
+//
+// Usage:
+//
+// c := RGBFromString("170,187,204")
+// c.Print("message")
+//
+// c := RGBFromString("brown")
+// c.Print("message with color brown")
+func RGBFromString(rgb string, isBg ...bool) RGBColor {
+ // use color name in the {namedRgbMap}
+ if rgbVal, ok := namedRgbMap[rgb]; ok {
+ rgb = rgbVal
+ }
+
+ // use rgb string.
+ ss := stringToArr(rgb, ",")
+ if len(ss) != 3 {
+ return emptyRGBColor
+ }
+
+ var ar [3]uint8
+ for i, val := range ss {
+ iv, err := strconv.Atoi(val)
+ if err != nil || !isValidUint8(iv) {
+ return emptyRGBColor
+ }
+
+ ar[i] = uint8(iv)
+ }
+
+ return RGB(ar[0], ar[1], 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 ...any) {
+ doPrintV2(c.String(), fmt.Sprint(a...))
+}
+
+// Printf format and print message
+func (c RGBColor) Printf(format string, a ...any) {
+ doPrintV2(c.String(), fmt.Sprintf(format, a...))
+}
+
+// Println print message with newline
+func (c RGBColor) Println(a ...any) {
+ doPrintlnV2(c.String(), a)
+}
+
+// Sprint returns rendered message
+func (c RGBColor) Sprint(a ...any) string {
+ return RenderCode(c.String(), a...)
+}
+
+// Sprintf returns format and rendered message
+func (c RGBColor) Sprintf(format string, a ...any) 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])
+}
+
+// RgbString to color code string without prefix. eg: "204,123,56"
+func (c RGBColor) RgbString() string {
+ return fmt.Sprintf("%d,%d,%d", 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 ""
+}
+
+// ToBg convert to background color
+func (c RGBColor) ToBg() RGBColor {
+ c[3] = AsBg
+ return c
+}
+
+// ToFg convert to foreground color
+func (c RGBColor) ToFg() RGBColor {
+ c[3] = AsFg
+ return c
+}
+
+// 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 supports set foreground and 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 ...any) {
+ doPrintV2(s.String(), fmt.Sprint(a...))
+}
+
+// Printf format and print message
+func (s *RGBStyle) Printf(format string, a ...any) {
+ doPrintV2(s.String(), fmt.Sprintf(format, a...))
+}
+
+// Println print message with newline
+func (s *RGBStyle) Println(a ...any) {
+ doPrintlnV2(s.String(), a)
+}
+
+// Sprint returns rendered message
+func (s *RGBStyle) Sprint(a ...any) string {
+ return RenderCode(s.String(), a...)
+}
+
+// Sprintf returns format and rendered message
+func (s *RGBStyle) Sprintf(format string, a ...any) 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..1d2b9d3
--- /dev/null
+++ b/vendor/github.com/gookit/color/color_tag.go
@@ -0,0 +1,567 @@
+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 fg 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
+ "magenta1": "1;35",
+ "mgb": "1;35",
+ "mga1": "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",
+ "lightMagenta1": "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",
+ "italic": "3",
+ "i": "3", // italic
+ "underscore": "4",
+ "us": "4", // short name for 'underscore'
+ "blink": "5",
+ "fb": "6", // fast blink
+ "reverse": "7",
+ "st": "9", // strikethrough
+
+ // 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
+}
+
+/*************************************************************
+ * internal defined tag attributes
+ *************************************************************/
+
+// built-in attributes for fg,bg 16-colors and op codes.
+var (
+ attrFgs = map[string]string{
+ // basic colors
+
+ "black": FgBlack.Code(),
+ "red": "31",
+ "green": "32",
+ "brown": "33", // #A52A2A
+ "yellow": "33",
+ "ylw": "33",
+ "blue": "34",
+ "cyan": "36",
+ "magenta": "35",
+ "mga": "35",
+ "white": FgWhite.Code(),
+ "default": "39", // no color
+ "normal": "39", // no color
+
+ // light/hi colors
+
+ "darkGray": FgDarkGray.Code(),
+ "dark_gray": "90",
+ "gray": "90",
+ "lightYellow": "93",
+ "light_yellow": "93",
+ "hiYellow": "93",
+ "hi_yellow": "93",
+ "lightMagenta": "95",
+ "light_magenta": "95",
+ "hiMagenta": "95",
+ "hi_magenta": "95",
+ "hi_mga": "95",
+ "lightRed": "91",
+ "light_red": "91",
+ "hiRed": "91",
+ "hi_red": "91",
+ "lightGreen": "92",
+ "light_green": "92",
+ "hiGreen": "92",
+ "hi_green": "92",
+ "lightBlue": "94",
+ "light_blue": "94",
+ "hiBlue": "94",
+ "hi_blue": "94",
+ "lightCyan": "96",
+ "light_cyan": "96",
+ "hiCyan": "96",
+ "hi_cyan": "96",
+ "lightWhite": "97",
+ "light_white": "97",
+ }
+
+ attrBgs = map[string]string{
+ // basic colors
+
+ "black": BgBlack.Code(),
+ "red": "41",
+ "green": "42",
+ "brown": "43", // #A52A2A
+ "yellow": "43",
+ "ylw": "43",
+ "blue": "44",
+ "cyan": "46",
+ "magenta": "45",
+ "mga": "45",
+ "white": FgWhite.Code(),
+ "default": "49", // no color
+ "normal": "49", // no color
+
+ // light/hi colors
+
+ "darkGray": BgDarkGray.Code(),
+ "dark_gray": "100",
+ "gray": "100",
+ "lightYellow": "103",
+ "light_yellow": "103",
+ "hiYellow": "103",
+ "hi_yellow": "103",
+ "lightMagenta": "105",
+ "light_magenta": "105",
+ "hiMagenta": "105",
+ "hi_magenta": "105",
+ "hi_mga": "105",
+ "lightRed": "101",
+ "light_red": "101",
+ "hiRed": "101",
+ "hi_red": "101",
+ "lightGreen": "102",
+ "light_green": "102",
+ "hiGreen": "102",
+ "hi_green": "102",
+ "lightBlue": "104",
+ "light_blue": "104",
+ "hiBlue": "104",
+ "hi_blue": "104",
+ "lightCyan": "106",
+ "light_cyan": "106",
+ "hiCyan": "106",
+ "hi_cyan": "106",
+ "lightWhite": BgLightWhite.Code(),
+ "light_white": "107",
+ }
+
+ attrOpts = map[string]string{
+ "reset": OpReset.Code(),
+ "bold": OpBold.Code(),
+ "b": OpBold.Code(),
+ "fuzzy": OpFuzzy.Code(),
+ "italic": OpItalic.Code(),
+ "i": OpItalic.Code(),
+ "underscore": OpUnderscore.Code(),
+ "us": OpUnderscore.Code(),
+ "u": OpUnderscore.Code(),
+ "blink": OpBlink.Code(),
+ "fastblink": OpFastBlink.Code(),
+ "fb": OpFastBlink.Code(),
+ "reverse": OpReverse.Code(),
+ "concealed": OpConcealed.Code(),
+ "strikethrough": OpStrikethrough.Code(),
+ "st": OpStrikethrough.Code(),
+ }
+)
+
+/*************************************************************
+ * parse color tags
+ *************************************************************/
+
+var (
+ tagParser = TagParser{}
+ // regex for match color 256 code
+ 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 given string, replace color tag and return rendered string
+//
+// Use built in tags:
+//
+// CONTENT>
+// // e.g: `message>`
+//
+// Custom tag attributes:
+//
+// `CONTENT>`
+// // e.g: `wel>`
+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, body := item[0], item[1], item[2]
+
+ // use defined color tag name: "content>" -> tag: "info"
+ if !strings.ContainsRune(tag, '=') {
+ if code := colorTags[tag]; len(code) > 0 {
+ str = strings.Replace(str, full, RenderString(code, body), 1)
+ } else if code, ok := namedRgbMap[tag]; ok {
+ code = strings.Replace(code, ",", ";", -1)
+ now := RenderString(FgRGBPfx+code, body)
+ 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 {
+ str = strings.Replace(str, full, RenderString(code, body), 1)
+ }
+ }
+
+ return str
+}
+
+// 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 code, ok := attrFgs[val]; ok { // attr fg
+ codes = append(codes, code)
+ } else if code := rgbHex256toCode(val, false); code != "" {
+ codes = append(codes, code)
+ }
+ case "bg":
+ if code, ok := attrBgs[val]; ok { // attr bg
+ codes = append(codes, code)
+ } 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 code, ok := attrOpts[n]; ok { // attr ops
+ codes = append(codes, code)
+ }
+ }
+ } else if code, ok := attrOpts[val]; ok {
+ codes = append(codes, code)
+ }
+ }
+ }
+
+ 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 ...any) 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 ...any) {
+ 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 ...any) {
+ 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 ...any) {
+ 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 ...any) string {
+ return RenderCode(GetTagCode(string(tg)), a...)
+}
+
+// Sprintf format and render messages
+func (tg Tag) Sprintf(format string, a ...any) 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..c710353
--- /dev/null
+++ b/vendor/github.com/gookit/color/convert.go
@@ -0,0 +1,966 @@
+package color
+
+import (
+ "fmt"
+ "math"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+// 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}
+// )
+
+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
+ // Tip: only keep foreground color, background color need convert to foreground color for convert to RGB
+ 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
+ // - don't add bg color, convert to fg color for convert to RGB
+ // 40: "000000", // black
+ // 41: "c51e14", // red
+ // 42: "1dc121", // green
+ // 43: "c7c329", // yellow
+ // 44: "0a2fc4", // blue
+ // 45: "c839c5", // magenta
+ // 46: "20c5c6", // cyan
+ // 47: "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
+ // - don't add bg color
+ // 100: "686868", // lightBlack/darkGray
+ // 101: "fd6f6b", // lightRed
+ // 102: "67f86f", // lightGreen
+ // 103: "fffa72", // lightYellow
+ // 104: "6a76fb", // lightBlue
+ // 105: "fd7cfc", // lightMagenta
+ // 106: "68fdfe", // lightCyan
+ // 107: "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
+ *************************************************************/
+
+// BasicToHex convert basic color to hex string.
+func BasicToHex(val uint8) string {
+ val = Bg2Fg(val)
+ return basic2hexMap[val]
+}
+
+// Basic2hex convert basic color to hex string.
+func Basic2hex(val uint8) string {
+ return BasicToHex(val)
+}
+
+// Hex2basic convert hex string to basic color code.
+func Hex2basic(hex string, asBg ...bool) uint8 {
+ val := hex2basicMap[hex]
+
+ if len(asBg) > 0 && asBg[0] {
+ return Fg2Bg(val)
+ }
+ return val
+}
+
+// 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 convert RGB-code to 16-code, 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}
+}
+
+/**************************************************************
+ * HSL color <=> RGB/True color
+ ************************************************************
+ * h,s,l = Hue, Saturation, Lightness
+ *
+ * refers
+ * http://en.wikipedia.org/wiki/HSL_color_space
+ * https://www.w3.org/TR/css-color-3/#hsl-color
+ * https://stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion
+ * https://github.com/less/less.js/blob/master/packages/less/src/less/functions/color.js
+ * https://github.com/d3/d3-color/blob/v3.0.1/README.md#hsl
+ *
+ * examples:
+ * color: hsl(0, 100%, 50%) // red
+ * color: hsl(120, 100%, 50%) // lime
+ * color: hsl(120, 100%, 25%) // dark green
+ * color: hsl(120, 100%, 75%) // light green
+ * color: hsl(120, 75%, 75%) // pastel green, and so on
+ */
+
+// HslIntToRgb Converts an HSL color value to RGB
+// Assumes h: 0-360, s: 0-100, l: 0-100
+// returns r, g, and b in the set [0, 255].
+//
+// Usage:
+//
+// HslIntToRgb(0, 100, 50) // red
+// HslIntToRgb(120, 100, 50) // lime
+// HslIntToRgb(120, 100, 25) // dark green
+// HslIntToRgb(120, 100, 75) // light green
+func HslIntToRgb(h, s, l int) (rgb []uint8) {
+ return HslToRgb(float64(h)/360, float64(s)/100, float64(l)/100)
+}
+
+// HslToRgb Converts an HSL color value to RGB. Conversion formula
+// adapted from http://en.wikipedia.org/wiki/HSL_color_space.
+// Assumes h, s, and l are contained in the set [0, 1]
+// returns r, g, and b in the set [0, 255].
+//
+// Usage:
+//
+// rgbVals := HslToRgb(0, 1, 0.5) // red
+func HslToRgb(h, s, l float64) (rgb []uint8) {
+ var r, g, b float64
+
+ if s == 0 { // achromatic
+ r, g, b = l, l, l
+ } else {
+ var hue2rgb = func(p, q, t float64) float64 {
+ if t < 0.0 {
+ t += 1
+ }
+ if t > 1.0 {
+ t -= 1
+ }
+
+ if t < 1.0/6.0 {
+ return p + (q-p)*6.0*t
+ }
+
+ if t < 1.0/2.0 {
+ return q
+ }
+
+ if t < 2.0/3.0 {
+ return p + (q-p)*(2.0/3.0-t)*6.0
+ }
+ return p
+ }
+
+ // q = l < 0.5 ? l * (1 + s) : l + s - l*s
+ var q float64
+ if l < 0.5 {
+ q = l * (1.0 + s)
+ } else {
+ q = l + s - l*s
+ }
+
+ var p = 2.0*l - q
+
+ r = hue2rgb(p, q, h+1.0/3.0)
+ g = hue2rgb(p, q, h)
+ b = hue2rgb(p, q, h-1.0/3.0)
+ }
+
+ // return []uint8{uint8(r * 255), uint8(g * 255), uint8(b * 255)}
+ return []uint8{
+ uint8(math.Round(r * 255)),
+ uint8(math.Round(g * 255)),
+ uint8(math.Round(b * 255)),
+ }
+}
+
+// RgbToHslInt Converts an RGB color value to HSL. Conversion formula
+// Assumes r, g, and b are contained in the set [0, 255] and
+// returns [h,s,l] h: 0-360, s: 0-100, l: 0-100.
+func RgbToHslInt(r, g, b uint8) []int {
+ f64s := RgbToHsl(r, g, b)
+
+ return []int{int(f64s[0] * 360), int(f64s[1] * 100), int(f64s[2] * 100)}
+}
+
+// RgbToHsl Converts an RGB color value to HSL. Conversion formula
+//
+// adapted from http://en.wikipedia.org/wiki/HSL_color_space.
+//
+// Assumes r, g, and b are contained in the set [0, 255] and
+// returns h, s, and l in the set [0, 1].
+func RgbToHsl(r, g, b uint8) []float64 {
+ // to float64
+ fr, fg, fb := float64(r), float64(g), float64(b)
+ // percentage
+ pr, pg, pb := float64(r)/255.0, float64(g)/255.0, float64(b)/255.0
+
+ ps := []float64{pr, pg, pb}
+ sort.Float64s(ps)
+
+ min, max := ps[0], ps[2]
+ // max := math.Max(math.Max(pr, pg), pb)
+ // min := math.Min(math.Min(pr, pg), pb)
+ mid := (max + min) / 2
+
+ h, s, l := mid, mid, mid
+ if max == min {
+ h, s = 0, 0 // achromatic
+ } else {
+ var d = max - min
+ // s = l > 0.5 ? d / (2 - max - min) : d / (max + min)
+ s = compareF64Val(l > 0.5, d/(2-max-min), d/(max+min))
+
+ switch max {
+ case fr:
+ // h = (g - b) / d + (g < b ? 6 : 0)
+ h = (fg - fb) / d
+ h += compareF64Val(g < b, 6, 0)
+ case fg:
+ h = (fb-fr)/d + 2
+ case fb:
+ h = (fr-fg)/d + 4
+ }
+
+ h /= 6
+ }
+
+ return []float64{h, s, l}
+}
+
+/**************************************************************
+ * HSV color <=> RGB/True color
+ ************************************************************
+ * h,s,l = Hue, Saturation, Value(Brightness)
+ *
+ * refers
+ * https://stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion
+ * https://github.com/less/less.js/blob/master/packages/less/src/less/functions/color.js
+ * https://github.com/d3/d3-color/blob/v3.0.1/README.md#hsl
+ */
+
+// HsvToRgb Converts an HSL color value to RGB. Conversion formula
+// adapted from https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB
+// Assumes h: 0-360, s: 0-100, l: 0-100
+// returns r, g, and b in the set [0, 255].
+func HsvToRgb(h, s, v int) (rgb []uint8) {
+ // TODO ...
+ return
+}
+
+// Named rgb colors
+// https://www.w3.org/TR/css-color-3/#svg-color
+var namedRgbMap = map[string]string{
+ "aliceblue": "240,248,255", // #F0F8FF
+ "antiquewhite": "250,235,215", // #FAEBD7
+ "aqua": "0,255,255", // #00FFFF
+ "aquamarine": "127,255,212", // #7FFFD4
+ "azure": "240,255,255", // #F0FFFF
+ "beige": "245,245,220", // #F5F5DC
+ "bisque": "255,228,196", // #FFE4C4
+ "black": "0,0,0", // #000000
+ "blanchedalmond": "255,235,205", // #FFEBCD
+ "blue": "0,0,255", // #0000FF
+ "blueviolet": "138,43,226", // #8A2BE2
+ "brown": "165,42,42", // #A52A2A
+ "burlywood": "222,184,135", // #DEB887
+ "cadetblue": "95,158,160", // #5F9EA0
+ "chartreuse": "127,255,0", // #7FFF00
+ "chocolate": "210,105,30", // #D2691E
+ "coral": "255,127,80", // #FF7F50
+ "cornflowerblue": "100,149,237", // #6495ED
+ "cornsilk": "255,248,220", // #FFF8DC
+ "crimson": "220,20,60", // #DC143C
+ "cyan": "0,255,255", // #00FFFF
+ "darkblue": "0,0,139", // #00008B
+ "darkcyan": "0,139,139", // #008B8B
+ "darkgoldenrod": "184,134,11", // #B8860B
+ "darkgray": "169,169,169", // #A9A9A9
+ "darkgreen": "0,100,0", // #006400
+ "darkgrey": "169,169,169", // #A9A9A9
+ "darkkhaki": "189,183,107", // #BDB76B
+ "darkmagenta": "139,0,139", // #8B008B
+ "darkolivegreen": "85,107,47", // #556B2F
+ "darkorange": "255,140,0", // #FF8C00
+ "darkorchid": "153,50,204", // #9932CC
+ "darkred": "139,0,0", // #8B0000
+ "darksalmon": "233,150,122", // #E9967A
+ "darkseagreen": "143,188,143", // #8FBC8F
+ "darkslateblue": "72,61,139", // #483D8B
+ "darkslategray": "47,79,79", // #2F4F4F
+ "darkslategrey": "47,79,79", // #2F4F4F
+ "darkturquoise": "0,206,209", // #00CED1
+ "darkviolet": "148,0,211", // #9400D3
+ "deeppink": "255,20,147", // #FF1493
+ "deepskyblue": "0,191,255", // #00BFFF
+ "dimgray": "105,105,105", // #696969
+ "dimgrey": "105,105,105", // #696969
+ "dodgerblue": "30,144,255", // #1E90FF
+ "firebrick": "178,34,34", // #B22222
+ "floralwhite": "255,250,240", // #FFFAF0
+ "forestgreen": "34,139,34", // #228B22
+ "fuchsia": "255,0,255", // #FF00FF
+ "gainsboro": "220,220,220", // #DCDCDC
+ "ghostwhite": "248,248,255", // #F8F8FF
+ "gold": "255,215,0", // #FFD700
+ "goldenrod": "218,165,32", // #DAA520
+ "gray": "128,128,128", // #808080
+ "green": "0,128,0", // #008000
+ "greenyellow": "173,255,47", // #ADFF2F
+ "grey": "128,128,128", // #808080
+ "honeydew": "240,255,240", // #F0FFF0
+ "hotpink": "255,105,180", // #FF69B4
+ "indianred": "205,92,92", // #CD5C5C
+ "indigo": "75,0,130", // #4B0082
+ "ivory": "255,255,240", // #FFFFF0
+ "khaki": "240,230,140", // #F0E68C
+ "lavender": "230,230,250", // #E6E6FA
+ "lavenderblush": "255,240,245", // #FFF0F5
+ "lawngreen": "124,252,0", // #7CFC00
+ "lemonchiffon": "255,250,205", // #FFFACD
+ "lightblue": "173,216,230", // #ADD8E6
+ "lightcoral": "240,128,128", // #F08080
+ "lightcyan": "224,255,255", // #E0FFFF
+ "lightgoldenrodyellow": "250,250,210", // #FAFAD2
+ "lightgray": "211,211,211", // #D3D3D3
+ "lightgreen": "144,238,144", // #90EE90
+ "lightgrey": "211,211,211", // #D3D3D3
+ "lightpink": "255,182,193", // #FFB6C1
+ "lightsalmon": "255,160,122", // #FFA07A
+ "lightseagreen": "32,178,170", // #20B2AA
+ "lightskyblue": "135,206,250", // #87CEFA
+ "lightslategray": "119,136,153", // #778899
+ "lightslategrey": "119,136,153", // #778899
+ "lightsteelblue": "176,196,222", // #B0C4DE
+ "lightyellow": "255,255,224", // #FFFFE0
+ "lime": "0,255,0", // #00FF00
+ "limegreen": "50,205,50", // #32CD32
+ "linen": "250,240,230", // #FAF0E6
+ "magenta": "255,0,255", // #FF00FF
+ "maroon": "128,0,0", // #800000
+ "mediumaquamarine": "102,205,170", // #66CDAA
+ "mediumblue": "0,0,205", // #0000CD
+ "mediumorchid": "186,85,211", // #BA55D3
+ "mediumpurple": "147,112,219", // #9370DB
+ "mediumseagreen": "60,179,113", // #3CB371
+ "mediumslateblue": "123,104,238", // #7B68EE
+ "mediumspringgreen": "0,250,154", // #00FA9A
+ "mediumturquoise": "72,209,204", // #48D1CC
+ "mediumvioletred": "199,21,133", // #C71585
+ "midnightblue": "25,25,112", // #191970
+ "mintcream": "245,255,250", // #F5FFFA
+ "mistyrose": "255,228,225", // #FFE4E1
+ "moccasin": "255,228,181", // #FFE4B5
+ "navajowhite": "255,222,173", // #FFDEAD
+ "navy": "0,0,128", // #000080
+ "oldlace": "253,245,230", // #FDF5E6
+ "olive": "128,128,0", // #808000
+ "olivedrab": "107,142,35", // #6B8E23
+ "orange": "255,165,0", // #FFA500
+ "orangered": "255,69,0", // #FF4500
+ "orchid": "218,112,214", // #DA70D6
+ "palegoldenrod": "238,232,170", // #EEE8AA
+ "palegreen": "152,251,152", // #98FB98
+ "paleturquoise": "175,238,238", // #AFEEEE
+ "palevioletred": "219,112,147", // #DB7093
+ "papayawhip": "255,239,213", // #FFEFD5
+ "peachpuff": "255,218,185", // #FFDAB9
+ "peru": "205,133,63", // #CD853F
+ "pink": "255,192,203", // #FFC0CB
+ "plum": "221,160,221", // #DDA0DD
+ "powderblue": "176,224,230", // #B0E0E6
+ "purple": "128,0,128", // #800080
+ "red": "255,0,0", // #FF0000
+ "rosybrown": "188,143,143", // #BC8F8F
+ "royalblue": "65,105,225", // #4169E1
+ "saddlebrown": "139,69,19", // #8B4513
+ "salmon": "250,128,114", // #FA8072
+ "sandybrown": "244,164,96", // #F4A460
+ "seagreen": "46,139,87", // #2E8B57
+ "seashell": "255,245,238", // #FFF5EE
+ "sienna": "160,82,45", // #A0522D
+ "silver": "192,192,192", // #C0C0C0
+ "skyblue": "135,206,235", // #87CEEB
+ "slateblue": "106,90,205", // #6A5ACD
+ "slategray": "112,128,144", // #708090
+ "slategrey": "112,128,144", // #708090
+ "snow": "255,250,250", // #FFFAFA
+ "springgreen": "0,255,127", // #00FF7F
+ "steelblue": "70,130,180", // #4682B4
+ "tan": "210,180,140", // #D2B48C
+ "teal": "0,128,128", // #008080
+ "thistle": "216,191,216", // #D8BFD8
+ "tomato": "255,99,71", // #FF6347
+ "turquoise": "64,224,208", // #40E0D0
+ "violet": "238,130,238", // #EE82EE
+ "wheat": "245,222,179", // #F5DEB3
+ "white": "255,255,255", // #FFFFFF
+ "whitesmoke": "245,245,245", // #F5F5F5
+ "yellow": "255,255,0", // #FFFF00
+ "yellowgreen": "154,205,50", // #9ACD32
+}
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..7fd8d81
--- /dev/null
+++ b/vendor/github.com/gookit/color/detect_env.go
@@ -0,0 +1,291 @@
+package color
+
+import (
+ "io"
+ "os"
+ "runtime"
+ "strconv"
+ "strings"
+ "syscall"
+
+ "github.com/xo/terminfo"
+)
+
+// Level is the color level supported by a terminal.
+type Level = terminfo.ColorLevel
+
+// terminal color available level alias of the terminfo.ColorLevel*
+const (
+ LevelNo = terminfo.ColorLevelNone // not support color.
+ Level16 = terminfo.ColorLevelBasic // basic - 3/4 bit color supported
+ Level256 = terminfo.ColorLevelHundreds // hundreds - 8-bit color supported
+ LevelRgb = terminfo.ColorLevelMillions // millions - (24 bit)true color supported
+)
+
+/*************************************************************
+ * helper methods for detect color supports
+ *************************************************************/
+
+// DetectColorLevel for current env
+//
+// NOTICE: The method will detect terminal info each times,
+// if only want to get current color level, please direct call SupportColor() or TermColorLevel()
+func DetectColorLevel() Level {
+ level, _ := detectTermColorLevel()
+ return level
+}
+
+// detect terminal color support level
+//
+// refer https://github.com/Delta456/box-cli-maker
+func detectTermColorLevel() (level Level, 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) Level {
+ // 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 {
+ detectedWSL = true
+
+ 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)
+ return strings.Contains(wslContents, "Microsoft")
+ }
+ }
+ return false
+}
+
+/*
+// 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 supports 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"
+ return len(os.Getenv("MSYSTEM")) > 0
+}
+
+// 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()
+}
+
+// IsSupport16Color 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 to 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..26f1090
--- /dev/null
+++ b/vendor/github.com/gookit/color/detect_nonwin.go
@@ -0,0 +1,49 @@
+//go:build !windows
+// +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) (Level, 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..df538b2
--- /dev/null
+++ b/vendor/github.com/gookit/color/detect_windows.go
@@ -0,0 +1,250 @@
+//go:build windows
+// +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 Level, 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/index.html b/vendor/github.com/gookit/color/index.html
new file mode 100644
index 0000000..19e8e9a
--- /dev/null
+++ b/vendor/github.com/gookit/color/index.html
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+ Color - A command-line color library with true color support, universal API methods and Windows support.
+
+
+
+
+
+
+
diff --git a/vendor/github.com/gookit/color/printer.go b/vendor/github.com/gookit/color/printer.go
new file mode 100644
index 0000000..985a0b6
--- /dev/null
+++ b/vendor/github.com/gookit/color/printer.go
@@ -0,0 +1,133 @@
+package color
+
+import "fmt"
+
+/*************************************************************
+ * colored message Printer
+ *************************************************************/
+
+// PrinterFace interface
+type PrinterFace interface {
+ fmt.Stringer
+ Sprint(a ...any) string
+ Sprintf(format string, a ...any) string
+ Print(a ...any)
+ Printf(format string, a ...any)
+ Println(a ...any)
+}
+
+// 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 ...any) string {
+ return RenderCode(p.String(), a...)
+}
+
+// Sprintf returns format and rendering colored messages
+func (p *Printer) Sprintf(format string, a ...any) string {
+ return RenderString(p.String(), fmt.Sprintf(format, a...))
+}
+
+// Print rendering colored messages
+func (p *Printer) Print(a ...any) {
+ doPrintV2(p.String(), fmt.Sprint(a...))
+}
+
+// Printf format and rendering colored messages
+func (p *Printer) Printf(format string, a ...any) {
+ doPrintV2(p.String(), fmt.Sprintf(format, a...))
+}
+
+// Println rendering colored messages with newline
+func (p *Printer) Println(a ...any) {
+ 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 ...any) {
+ Print(v...)
+}
+
+// Printf message
+func (s *SimplePrinter) Printf(format string, v ...any) {
+ Printf(format, v...)
+}
+
+// Println message
+func (s *SimplePrinter) Println(v ...any) {
+ Println(v...)
+}
+
+// Successf message
+func (s *SimplePrinter) Successf(format string, a ...any) {
+ Success.Printf(format, a...)
+}
+
+// Successln message
+func (s *SimplePrinter) Successln(a ...any) {
+ Success.Println(a...)
+}
+
+// Infof message
+func (s *SimplePrinter) Infof(format string, a ...any) {
+ Info.Printf(format, a...)
+}
+
+// Infoln message
+func (s *SimplePrinter) Infoln(a ...any) {
+ Info.Println(a...)
+}
+
+// Warnf message
+func (s *SimplePrinter) Warnf(format string, a ...any) {
+ Warn.Printf(format, a...)
+}
+
+// Warnln message
+func (s *SimplePrinter) Warnln(a ...any) {
+ Warn.Println(a...)
+}
+
+// Errorf message
+func (s *SimplePrinter) Errorf(format string, a ...any) {
+ Error.Printf(format, a...)
+}
+
+// Errorln message
+func (s *SimplePrinter) Errorln(a ...any) {
+ 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..b368b8a
--- /dev/null
+++ b/vendor/github.com/gookit/color/quickstart.go
@@ -0,0 +1,108 @@
+package color
+
+/*************************************************************
+ * quick use color print message
+ *************************************************************/
+
+// Redp print message with Red color
+func Redp(a ...any) { Red.Print(a...) }
+
+// Redf print message with Red color
+func Redf(format string, a ...any) { Red.Printf(format, a...) }
+
+// Redln print message line with Red color
+func Redln(a ...any) { Red.Println(a...) }
+
+// Bluep print message with Blue color
+func Bluep(a ...any) { Blue.Print(a...) }
+
+// Bluef print message with Blue color
+func Bluef(format string, a ...any) { Blue.Printf(format, a...) }
+
+// Blueln print message line with Blue color
+func Blueln(a ...any) { Blue.Println(a...) }
+
+// Cyanp print message with Cyan color
+func Cyanp(a ...any) { Cyan.Print(a...) }
+
+// Cyanf print message with Cyan color
+func Cyanf(format string, a ...any) { Cyan.Printf(format, a...) }
+
+// Cyanln print message line with Cyan color
+func Cyanln(a ...any) { Cyan.Println(a...) }
+
+// Grayp print message with Gray color
+func Grayp(a ...any) { Gray.Print(a...) }
+
+// Grayf print message with Gray color
+func Grayf(format string, a ...any) { Gray.Printf(format, a...) }
+
+// Grayln print message line with Gray color
+func Grayln(a ...any) { Gray.Println(a...) }
+
+// Greenp print message with Green color
+func Greenp(a ...any) { Green.Print(a...) }
+
+// Greenf print message with Green color
+func Greenf(format string, a ...any) { Green.Printf(format, a...) }
+
+// Greenln print message line with Green color
+func Greenln(a ...any) { Green.Println(a...) }
+
+// Yellowp print message with Yellow color
+func Yellowp(a ...any) { Yellow.Print(a...) }
+
+// Yellowf print message with Yellow color
+func Yellowf(format string, a ...any) { Yellow.Printf(format, a...) }
+
+// Yellowln print message line with Yellow color
+func Yellowln(a ...any) { Yellow.Println(a...) }
+
+// Magentap print message with Magenta color
+func Magentap(a ...any) { Magenta.Print(a...) }
+
+// Magentaf print message with Magenta color
+func Magentaf(format string, a ...any) { Magenta.Printf(format, a...) }
+
+// Magentaln print message line with Magenta color
+func Magentaln(a ...any) { Magenta.Println(a...) }
+
+/*************************************************************
+ * quick use style print message
+ *************************************************************/
+
+// Infop print message with Info color
+func Infop(a ...any) { Info.Print(a...) }
+
+// Infof print message with Info style
+func Infof(format string, a ...any) { Info.Printf(format, a...) }
+
+// Infoln print message with Info style
+func Infoln(a ...any) { Info.Println(a...) }
+
+// Successp print message with success color
+func Successp(a ...any) { Success.Print(a...) }
+
+// Successf print message with success style
+func Successf(format string, a ...any) { Success.Printf(format, a...) }
+
+// Successln print message with success style
+func Successln(a ...any) { Success.Println(a...) }
+
+// Errorp print message with Error color
+func Errorp(a ...any) { Error.Print(a...) }
+
+// Errorf print message with Error style
+func Errorf(format string, a ...any) { Error.Printf(format, a...) }
+
+// Errorln print message with Error style
+func Errorln(a ...any) { Error.Println(a...) }
+
+// Warnp print message with Warn color
+func Warnp(a ...any) { Warn.Print(a...) }
+
+// Warnf print message with Warn style
+func Warnf(format string, a ...any) { Warn.Printf(format, a...) }
+
+// Warnln print message with Warn style
+func Warnln(a ...any) { 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..353d39f
--- /dev/null
+++ b/vendor/github.com/gookit/color/style.go
@@ -0,0 +1,324 @@
+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 colored text
+//
+// Usage:
+//
+// color.New(color.FgGreen).Render("text")
+// color.New(color.FgGreen, color.BgBlack, color.OpBold).Render("text")
+func (s Style) Render(a ...any) string {
+ return RenderCode(s.String(), a...)
+}
+
+// Renderln render text with newline.
+// 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 ...any) string {
+ return RenderWithSpaces(s.String(), a...)
+}
+
+// Sprint is alias of the 'Render'
+func (s Style) Sprint(a ...any) string {
+ return RenderCode(s.String(), a...)
+}
+
+// Sprintf format and render message.
+func (s Style) Sprintf(format string, a ...any) string {
+ return RenderString(s.String(), fmt.Sprintf(format, a...))
+}
+
+// Print render and Print text
+func (s Style) Print(a ...any) {
+ doPrintV2(s.String(), fmt.Sprint(a...))
+}
+
+// Printf render and print text
+func (s Style) Printf(format string, a ...any) {
+ doPrintV2(s.Code(), fmt.Sprintf(format, a...))
+}
+
+// Println render and print text line
+func (s Style) Println(a ...any) {
+ 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 ...any) {
+ // 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 ...any) {
+ 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 ...any) {
+ 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 ...any) {
+ s.Styles["info"].Printf(format, a...)
+}
+
+// Infoln message print
+func (s *Scheme) Infoln(v ...any) {
+ s.Styles["info"].Println(v...)
+}
+
+// Warnf message print
+func (s *Scheme) Warnf(format string, a ...any) {
+ s.Styles["warn"].Printf(format, a...)
+}
+
+// Warnln message print
+func (s *Scheme) Warnln(v ...any) {
+ s.Styles["warn"].Println(v...)
+}
+
+// Errorf message print
+func (s *Scheme) Errorf(format string, a ...any) {
+ s.Styles["error"].Printf(format, a...)
+}
+
+// Errorln message print
+func (s *Scheme) Errorln(v ...any) {
+ 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..b6920f6
--- /dev/null
+++ b/vendor/github.com/gookit/color/utils.go
@@ -0,0 +1,209 @@
+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 ...any) {
+ Fprint(output, a...)
+}
+
+// Printf format and print messages
+func Printf(format string, a ...any) {
+ Fprintf(output, format, a...)
+}
+
+// Println messages with new line
+func Println(a ...any) {
+ Fprintln(output, a...)
+}
+
+// Fprint print rendered messages to writer
+//
+// Notice: will ignore print error
+func Fprint(w io.Writer, a ...any) {
+ _, err := fmt.Fprint(w, Render(a...))
+ saveInternalError(err)
+}
+
+// Fprintf print format and rendered messages to writer.
+// Notice: will ignore print error
+func Fprintf(w io.Writer, format string, a ...any) {
+ 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 ...any) {
+ 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 ...any) {
+ l.Print(Render(a...))
+}
+
+// Render parse color tags, return rendered string.
+//
+// Usage:
+//
+// text := Render("hello> world>!")
+// fmt.Println(text)
+func Render(a ...any) string {
+ if len(a) == 0 {
+ return ""
+ }
+ return ReplaceTag(fmt.Sprint(a...))
+}
+
+// Sprint parse color tags, return rendered string
+func Sprint(a ...any) string {
+ if len(a) == 0 {
+ return ""
+ }
+ return ReplaceTag(fmt.Sprint(a...))
+}
+
+// Sprintf format and return rendered string
+func Sprintf(format string, a ...any) 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) }
+
+// Uint8sToInts convert []uint8 to []int
+// func Uint8sToInts(u8s []uint8 ) []int {
+// ints := make([]int, len(u8s))
+// for i, u8 := range u8s {
+// ints[i] = int(u8)
+// }
+// return ints
+// }
+
+/*************************************************************
+ * 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)
+}
+
+// new implementation, support render full color code on pwsh.exe, cmd.exe
+func doPrintlnV2(code string, args []any) {
+ str := formatArgsForPrintln(args)
+ _, err := fmt.Fprintln(output, RenderString(code, str))
+ saveInternalError(err)
+}
+
+// use Println, will add spaces for each arg
+func formatArgsForPrintln(args []any) (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 ...any) {
+ if debugMode {
+ fmt.Print("COLOR_DEBUG: ")
+ fmt.Printf(f, v...)
+ fmt.Println()
+ }
+}
+
+// equals: return ok ? val1 : val2
+func isValidUint8(val int) bool {
+ return val >= 0 && val < 256
+}
+
+// equals: return ok ? val1 : val2
+func compareVal(ok bool, val1, val2 uint8) uint8 {
+ if ok {
+ return val1
+ }
+ return val2
+}
+
+// equals: return ok ? val1 : val2
+func compareF64Val(ok bool, val1, val2 float64) float64 {
+ 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/lithammer/fuzzysearch/LICENSE b/vendor/github.com/lithammer/fuzzysearch/LICENSE
new file mode 100644
index 0000000..dee3d1d
--- /dev/null
+++ b/vendor/github.com/lithammer/fuzzysearch/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2018 Peter Lithammer
+
+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/lithammer/fuzzysearch/fuzzy/fuzzy.go b/vendor/github.com/lithammer/fuzzysearch/fuzzy/fuzzy.go
new file mode 100644
index 0000000..8890877
--- /dev/null
+++ b/vendor/github.com/lithammer/fuzzysearch/fuzzy/fuzzy.go
@@ -0,0 +1,292 @@
+// Fuzzy searching allows for flexibly matching a string with partial input,
+// useful for filtering data very quickly based on lightweight user input.
+package fuzzy
+
+import (
+ "unicode"
+ "unicode/utf8"
+
+ "golang.org/x/text/runes"
+ "golang.org/x/text/transform"
+ "golang.org/x/text/unicode/norm"
+)
+
+func noopTransformer() transform.Transformer {
+ return nopTransformer{}
+}
+
+func foldTransformer() transform.Transformer {
+ return unicodeFoldTransformer{}
+}
+
+func normalizeTransformer() transform.Transformer {
+ return transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC)
+}
+
+func normalizedFoldTransformer() transform.Transformer {
+ return transform.Chain(normalizeTransformer(), foldTransformer())
+}
+
+// Match returns true if source matches target using a fuzzy-searching
+// algorithm. Note that it doesn't implement Levenshtein distance (see
+// RankMatch instead), but rather a simplified version where there's no
+// approximation. The method will return true only if each character in the
+// source can be found in the target and occurs after the preceding matches.
+func Match(source, target string) bool {
+ return match(source, target, noopTransformer())
+}
+
+// MatchFold is a case-insensitive version of Match.
+func MatchFold(source, target string) bool {
+ return match(source, target, foldTransformer())
+}
+
+// MatchNormalized is a unicode-normalized version of Match.
+func MatchNormalized(source, target string) bool {
+ return match(source, target, normalizeTransformer())
+}
+
+// MatchNormalizedFold is a unicode-normalized and case-insensitive version of Match.
+func MatchNormalizedFold(source, target string) bool {
+ return match(source, target, normalizedFoldTransformer())
+}
+
+func match(source, target string, transformer transform.Transformer) bool {
+ sourceT := stringTransform(source, transformer)
+ targetT := stringTransform(target, transformer)
+ return matchTransformed(sourceT, targetT)
+}
+
+func matchTransformed(source, target string) bool {
+ lenDiff := len(target) - len(source)
+
+ if lenDiff < 0 {
+ return false
+ }
+
+ if lenDiff == 0 && source == target {
+ return true
+ }
+
+Outer:
+ for _, r1 := range source {
+ for i, r2 := range target {
+ if r1 == r2 {
+ target = target[i+utf8.RuneLen(r2):]
+ continue Outer
+ }
+ }
+ return false
+ }
+
+ return true
+}
+
+// Find will return a list of strings in targets that fuzzy matches source.
+func Find(source string, targets []string) []string {
+ return find(source, targets, noopTransformer())
+}
+
+// FindFold is a case-insensitive version of Find.
+func FindFold(source string, targets []string) []string {
+ return find(source, targets, foldTransformer())
+}
+
+// FindNormalized is a unicode-normalized version of Find.
+func FindNormalized(source string, targets []string) []string {
+ return find(source, targets, normalizeTransformer())
+}
+
+// FindNormalizedFold is a unicode-normalized and case-insensitive version of Find.
+func FindNormalizedFold(source string, targets []string) []string {
+ return find(source, targets, normalizedFoldTransformer())
+}
+
+func find(source string, targets []string, transformer transform.Transformer) []string {
+ sourceT := stringTransform(source, transformer)
+
+ var matches []string
+
+ for _, target := range targets {
+ targetT := stringTransform(target, transformer)
+ if matchTransformed(sourceT, targetT) {
+ matches = append(matches, target)
+ }
+ }
+
+ return matches
+}
+
+// RankMatch is similar to Match except it will measure the Levenshtein
+// distance between the source and the target and return its result. If there
+// was no match, it will return -1.
+// Given the requirements of match, RankMatch only needs to perform a subset of
+// the Levenshtein calculation, only deletions need be considered, required
+// additions and substitutions would fail the match test.
+func RankMatch(source, target string) int {
+ return rank(source, target, noopTransformer())
+}
+
+// RankMatchFold is a case-insensitive version of RankMatch.
+func RankMatchFold(source, target string) int {
+ return rank(source, target, foldTransformer())
+}
+
+// RankMatchNormalized is a unicode-normalized version of RankMatch.
+func RankMatchNormalized(source, target string) int {
+ return rank(source, target, normalizeTransformer())
+}
+
+// RankMatchNormalizedFold is a unicode-normalized and case-insensitive version of RankMatch.
+func RankMatchNormalizedFold(source, target string) int {
+ return rank(source, target, normalizedFoldTransformer())
+}
+
+func rank(source, target string, transformer transform.Transformer) int {
+ lenDiff := len(target) - len(source)
+
+ if lenDiff < 0 {
+ return -1
+ }
+
+ source = stringTransform(source, transformer)
+ target = stringTransform(target, transformer)
+
+ if lenDiff == 0 && source == target {
+ return 0
+ }
+
+ runeDiff := 0
+
+Outer:
+ for _, r1 := range source {
+ for i, r2 := range target {
+ if r1 == r2 {
+ target = target[i+utf8.RuneLen(r2):]
+ continue Outer
+ } else {
+ runeDiff++
+ }
+ }
+ return -1
+ }
+
+ // Count up remaining char
+ runeDiff += utf8.RuneCountInString(target)
+
+ return runeDiff
+}
+
+// RankFind is similar to Find, except it will also rank all matches using
+// Levenshtein distance.
+func RankFind(source string, targets []string) Ranks {
+ return rankFind(source, targets, noopTransformer())
+}
+
+// RankFindFold is a case-insensitive version of RankFind.
+func RankFindFold(source string, targets []string) Ranks {
+ return rankFind(source, targets, foldTransformer())
+}
+
+// RankFindNormalized is a unicode-normalized version of RankFind.
+func RankFindNormalized(source string, targets []string) Ranks {
+ return rankFind(source, targets, normalizeTransformer())
+}
+
+// RankFindNormalizedFold is a unicode-normalized and case-insensitive version of RankFind.
+func RankFindNormalizedFold(source string, targets []string) Ranks {
+ return rankFind(source, targets, normalizedFoldTransformer())
+}
+
+func rankFind(source string, targets []string, transformer transform.Transformer) Ranks {
+ sourceT := stringTransform(source, transformer)
+
+ var r Ranks
+
+ for index, target := range targets {
+ targetT := stringTransform(target, transformer)
+ if matchTransformed(sourceT, targetT) {
+ distance := LevenshteinDistance(source, target)
+ r = append(r, Rank{source, target, distance, index})
+ }
+ }
+ return r
+}
+
+type Rank struct {
+ // Source is used as the source for matching.
+ Source string
+
+ // Target is the word matched against.
+ Target string
+
+ // Distance is the Levenshtein distance between Source and Target.
+ Distance int
+
+ // Location of Target in original list
+ OriginalIndex int
+}
+
+type Ranks []Rank
+
+func (r Ranks) Len() int {
+ return len(r)
+}
+
+func (r Ranks) Swap(i, j int) {
+ r[i], r[j] = r[j], r[i]
+}
+
+func (r Ranks) Less(i, j int) bool {
+ return r[i].Distance < r[j].Distance
+}
+
+func stringTransform(s string, t transform.Transformer) (transformed string) {
+ // Fast path for the nop transformer to prevent unnecessary allocations.
+ if _, ok := t.(nopTransformer); ok {
+ return s
+ }
+
+ var err error
+ transformed, _, err = transform.String(t, s)
+ if err != nil {
+ transformed = s
+ }
+
+ return
+}
+
+type unicodeFoldTransformer struct{ transform.NopResetter }
+
+func (unicodeFoldTransformer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+ // Converting src to a string allocates.
+ // In theory, it need not; see https://go.dev/issue/27148.
+ // It is possible to write this loop using utf8.DecodeRune
+ // and thereby avoid allocations, but it is noticeably slower.
+ // So just let's wait for the compiler to get smarter.
+ for _, r := range string(src) {
+ if r == utf8.RuneError {
+ // Go spec for ranging over a string says:
+ // If the iteration encounters an invalid UTF-8 sequence,
+ // the second value will be 0xFFFD, the Unicode replacement character,
+ // and the next iteration will advance a single byte in the string.
+ nSrc++
+ } else {
+ nSrc += utf8.RuneLen(r)
+ }
+ r = unicode.ToLower(r)
+ x := utf8.RuneLen(r)
+ if x > len(dst[nDst:]) {
+ err = transform.ErrShortDst
+ break
+ }
+ nDst += utf8.EncodeRune(dst[nDst:], r)
+ }
+ return nDst, nSrc, err
+}
+
+type nopTransformer struct{ transform.NopResetter }
+
+func (nopTransformer) Transform(dst []byte, src []byte, atEOF bool) (int, int, error) {
+ return 0, len(src), nil
+}
diff --git a/vendor/github.com/lithammer/fuzzysearch/fuzzy/levenshtein.go b/vendor/github.com/lithammer/fuzzysearch/fuzzy/levenshtein.go
new file mode 100644
index 0000000..c0fc191
--- /dev/null
+++ b/vendor/github.com/lithammer/fuzzysearch/fuzzy/levenshtein.go
@@ -0,0 +1,45 @@
+package fuzzy
+
+// LevenshteinDistance measures the difference between two strings.
+// The Levenshtein distance between two words is the minimum number of
+// single-character edits (i.e. insertions, deletions or substitutions)
+// required to change one word into the other.
+//
+// This implemention is optimized to use O(min(m,n)) space and is based on the
+// optimized C version found here:
+// http://en.wikibooks.org/wiki/Algorithm_implementation/Strings/Levenshtein_distance#C
+func LevenshteinDistance(s, t string) int {
+ r1, r2 := []rune(s), []rune(t)
+ column := make([]int, 1, 64)
+
+ for y := 1; y <= len(r1); y++ {
+ column = append(column, y)
+ }
+
+ for x := 1; x <= len(r2); x++ {
+ column[0] = x
+
+ for y, lastDiag := 1, x-1; y <= len(r1); y++ {
+ oldDiag := column[y]
+ cost := 0
+ if r1[y-1] != r2[x-1] {
+ cost = 1
+ }
+ column[y] = min(column[y]+1, column[y-1]+1, lastDiag+cost)
+ lastDiag = oldDiag
+ }
+ }
+
+ return column[len(r1)]
+}
+
+func min2(a, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+func min(a, b, c int) int {
+ return min2(min2(a, b), c)
+}
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..5e2cfd9
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/README.md
@@ -0,0 +1,27 @@
+go-runewidth
+============
+
+[![Build Status](https://github.com/mattn/go-runewidth/workflows/test/badge.svg?branch=master)](https://github.com/mattn/go-runewidth/actions?query=workflow%3Atest)
+[![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/runewidth.go b/vendor/github.com/mattn/go-runewidth/runewidth.go
new file mode 100644
index 0000000..7dfbb3b
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/runewidth.go
@@ -0,0 +1,358 @@
+package runewidth
+
+import (
+ "os"
+ "strings"
+
+ "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
+ if DefaultCondition.EastAsianWidth != EastAsianWidth {
+ DefaultCondition.EastAsianWidth = EastAsianWidth
+ if len(DefaultCondition.combinedLut) > 0 {
+ DefaultCondition.combinedLut = DefaultCondition.combinedLut[:0]
+ CreateLUT()
+ }
+ }
+}
+
+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 {
+ combinedLut []byte
+ 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 {
+ if r < 0 || r > 0x10FFFF {
+ return 0
+ }
+ if len(c.combinedLut) > 0 {
+ return int(c.combinedLut[r>>1]>>(uint(r&1)*4)) & 3
+ }
+ // optimized version, verified by TestRuneWidthChecksums()
+ if !c.EastAsianWidth {
+ switch {
+ case r < 0x20:
+ 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 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
+ }
+ }
+}
+
+// CreateLUT will create an in-memory lookup table of 557056 bytes for faster operation.
+// This should not be called concurrently with other operations on c.
+// If options in c is changed, CreateLUT should be called again.
+func (c *Condition) CreateLUT() {
+ const max = 0x110000
+ lut := c.combinedLut
+ if len(c.combinedLut) != 0 {
+ // Remove so we don't use it.
+ c.combinedLut = nil
+ } else {
+ lut = make([]byte, max/2)
+ }
+ for i := range lut {
+ i32 := int32(i * 2)
+ x0 := c.RuneWidth(i32)
+ x1 := c.RuneWidth(i32 + 1)
+ lut[i] = uint8(x0) | uint8(x1)<<4
+ }
+ c.combinedLut = lut
+}
+
+// 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
+}
+
+// TruncateLeft cuts w cells from the beginning of the `s`.
+func (c *Condition) TruncateLeft(s string, w int, prefix string) string {
+ if c.StringWidth(s) <= w {
+ return prefix
+ }
+
+ 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 {
+ if width < w {
+ _, pos = g.Positions()
+ prefix += strings.Repeat(" ", width+chWidth-w)
+ } else {
+ pos, _ = g.Positions()
+ }
+
+ break
+ }
+
+ width += chWidth
+ }
+
+ return prefix + s[pos:]
+}
+
+// Wrap return string wrapped with w cells
+func (c *Condition) Wrap(s string, w int) string {
+ width := 0
+ out := ""
+ for _, r := range 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)
+}
+
+// TruncateLeft cuts w cells from the beginning of the `s`.
+func TruncateLeft(s string, w int, prefix string) string {
+ return DefaultCondition.TruncateLeft(s, w, prefix)
+}
+
+// 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)
+}
+
+// CreateLUT will create an in-memory lookup table of 557055 bytes for faster operation.
+// This should not be called concurrently with other operations.
+func CreateLUT() {
+ if len(DefaultCondition.combinedLut) > 0 {
+ return
+ }
+ DefaultCondition.CreateLUT()
+}
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..84b6528
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/runewidth_appengine.go
@@ -0,0 +1,9 @@
+//go:build appengine
+// +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..c2abbc2
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/runewidth_js.go
@@ -0,0 +1,9 @@
+//go:build js && !appengine
+// +build js,!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..5a31d73
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/runewidth_posix.go
@@ -0,0 +1,81 @@
+//go:build !windows && !js && !appengine
+// +build !windows,!js,!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..ad025ad
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/runewidth_table.go
@@ -0,0 +1,450 @@
+// Code generated by script/generate.go. DO NOT EDIT.
+
+package runewidth
+
+var combining = table{
+ {0x0300, 0x036F}, {0x0483, 0x0489}, {0x07EB, 0x07F3},
+ {0x0C00, 0x0C00}, {0x0C04, 0x0C04}, {0x0CF3, 0x0CF3},
+ {0x0D00, 0x0D01}, {0x135D, 0x135F}, {0x1A7F, 0x1A7F},
+ {0x1AB0, 0x1ACE}, {0x1B6B, 0x1B73}, {0x1DC0, 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}, {0x10F82, 0x10F85},
+ {0x11300, 0x11301}, {0x1133B, 0x1133C}, {0x11366, 0x1136C},
+ {0x11370, 0x11374}, {0x16AF0, 0x16AF4}, {0x1CF00, 0x1CF2D},
+ {0x1CF30, 0x1CF46}, {0x1D165, 0x1D169}, {0x1D16D, 0x1D172},
+ {0x1D17B, 0x1D182}, {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD},
+ {0x1D242, 0x1D244}, {0x1E000, 0x1E006}, {0x1E008, 0x1E018},
+ {0x1E01B, 0x1E021}, {0x1E023, 0x1E024}, {0x1E026, 0x1E02A},
+ {0x1E08F, 0x1E08F}, {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, 0x303E},
+ {0x3041, 0x3096}, {0x3099, 0x30FF}, {0x3105, 0x312F},
+ {0x3131, 0x318E}, {0x3190, 0x31E3}, {0x31EF, 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},
+ {0x1AFF0, 0x1AFF3}, {0x1AFF5, 0x1AFFB}, {0x1AFFD, 0x1AFFE},
+ {0x1B000, 0x1B122}, {0x1B132, 0x1B132}, {0x1B150, 0x1B152},
+ {0x1B155, 0x1B155}, {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}, {0x1F6DC, 0x1F6DF}, {0x1F6EB, 0x1F6EC},
+ {0x1F6F4, 0x1F6FC}, {0x1F7E0, 0x1F7EB}, {0x1F7F0, 0x1F7F0},
+ {0x1F90C, 0x1F93A}, {0x1F93C, 0x1F945}, {0x1F947, 0x1F9FF},
+ {0x1FA70, 0x1FA7C}, {0x1FA80, 0x1FA88}, {0x1FA90, 0x1FABD},
+ {0x1FABF, 0x1FAC5}, {0x1FACE, 0x1FADB}, {0x1FAE0, 0x1FAE8},
+ {0x1FAF0, 0x1FAF8}, {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, 0x070D}, {0x070F, 0x074A}, {0x074D, 0x07B1},
+ {0x07C0, 0x07FA}, {0x07FD, 0x082D}, {0x0830, 0x083E},
+ {0x0840, 0x085B}, {0x085E, 0x085E}, {0x0860, 0x086A},
+ {0x0870, 0x088E}, {0x0890, 0x0891}, {0x0898, 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}, {0x0C3C, 0x0C44},
+ {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56},
+ {0x0C58, 0x0C5A}, {0x0C5D, 0x0C5D}, {0x0C60, 0x0C63},
+ {0x0C66, 0x0C6F}, {0x0C77, 0x0C8C}, {0x0C8E, 0x0C90},
+ {0x0C92, 0x0CA8}, {0x0CAA, 0x0CB3}, {0x0CB5, 0x0CB9},
+ {0x0CBC, 0x0CC4}, {0x0CC6, 0x0CC8}, {0x0CCA, 0x0CCD},
+ {0x0CD5, 0x0CD6}, {0x0CDD, 0x0CDE}, {0x0CE0, 0x0CE3},
+ {0x0CE6, 0x0CEF}, {0x0CF1, 0x0CF3}, {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, 0x0ECE}, {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, 0x1715}, {0x171F, 0x1736}, {0x1740, 0x1753},
+ {0x1760, 0x176C}, {0x176E, 0x1770}, {0x1772, 0x1773},
+ {0x1780, 0x17DD}, {0x17E0, 0x17E9}, {0x17F0, 0x17F9},
+ {0x1800, 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, 0x1ACE}, {0x1B00, 0x1B4C},
+ {0x1B50, 0x1B7E}, {0x1B80, 0x1BF3}, {0x1BFC, 0x1C37},
+ {0x1C3B, 0x1C49}, {0x1C4D, 0x1C88}, {0x1C90, 0x1CBA},
+ {0x1CBD, 0x1CC7}, {0x1CD0, 0x1CFA}, {0x1D00, 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, 0x20C0}, {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, 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, 0x2E5D}, {0x303F, 0x303F},
+ {0x4DC0, 0x4DFF}, {0xA4D0, 0xA62B}, {0xA640, 0xA6F7},
+ {0xA700, 0xA7CA}, {0xA7D0, 0xA7D1}, {0xA7D3, 0xA7D3},
+ {0xA7D5, 0xA7D9}, {0xA7F2, 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, 0xFBC2}, {0xFBD3, 0xFD8F},
+ {0xFD92, 0xFDC7}, {0xFDCF, 0xFDCF}, {0xFDF0, 0xFDFF},
+ {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, 0x1057A}, {0x1057C, 0x1058A}, {0x1058C, 0x10592},
+ {0x10594, 0x10595}, {0x10597, 0x105A1}, {0x105A3, 0x105B1},
+ {0x105B3, 0x105B9}, {0x105BB, 0x105BC}, {0x10600, 0x10736},
+ {0x10740, 0x10755}, {0x10760, 0x10767}, {0x10780, 0x10785},
+ {0x10787, 0x107B0}, {0x107B2, 0x107BA}, {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}, {0x10EFD, 0x10F27}, {0x10F30, 0x10F59},
+ {0x10F70, 0x10F89}, {0x10FB0, 0x10FCB}, {0x10FE0, 0x10FF6},
+ {0x11000, 0x1104D}, {0x11052, 0x11075}, {0x1107F, 0x110C2},
+ {0x110CD, 0x110CD}, {0x110D0, 0x110E8}, {0x110F0, 0x110F9},
+ {0x11100, 0x11134}, {0x11136, 0x11147}, {0x11150, 0x11176},
+ {0x11180, 0x111DF}, {0x111E1, 0x111F4}, {0x11200, 0x11211},
+ {0x11213, 0x11241}, {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, 0x116B9},
+ {0x116C0, 0x116C9}, {0x11700, 0x1171A}, {0x1171D, 0x1172B},
+ {0x11730, 0x11746}, {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}, {0x11AB0, 0x11AF8}, {0x11B00, 0x11B09},
+ {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},
+ {0x11F00, 0x11F10}, {0x11F12, 0x11F3A}, {0x11F3E, 0x11F59},
+ {0x11FB0, 0x11FB0}, {0x11FC0, 0x11FF1}, {0x11FFF, 0x12399},
+ {0x12400, 0x1246E}, {0x12470, 0x12474}, {0x12480, 0x12543},
+ {0x12F90, 0x12FF2}, {0x13000, 0x13455}, {0x14400, 0x14646},
+ {0x16800, 0x16A38}, {0x16A40, 0x16A5E}, {0x16A60, 0x16A69},
+ {0x16A6E, 0x16ABE}, {0x16AC0, 0x16AC9}, {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},
+ {0x1CF00, 0x1CF2D}, {0x1CF30, 0x1CF46}, {0x1CF50, 0x1CFC3},
+ {0x1D000, 0x1D0F5}, {0x1D100, 0x1D126}, {0x1D129, 0x1D1EA},
+ {0x1D200, 0x1D245}, {0x1D2C0, 0x1D2D3}, {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}, {0x1DF00, 0x1DF1E}, {0x1DF25, 0x1DF2A},
+ {0x1E000, 0x1E006}, {0x1E008, 0x1E018}, {0x1E01B, 0x1E021},
+ {0x1E023, 0x1E024}, {0x1E026, 0x1E02A}, {0x1E030, 0x1E06D},
+ {0x1E08F, 0x1E08F}, {0x1E100, 0x1E12C}, {0x1E130, 0x1E13D},
+ {0x1E140, 0x1E149}, {0x1E14E, 0x1E14F}, {0x1E290, 0x1E2AE},
+ {0x1E2C0, 0x1E2F9}, {0x1E2FF, 0x1E2FF}, {0x1E4D0, 0x1E4F9},
+ {0x1E7E0, 0x1E7E6}, {0x1E7E8, 0x1E7EB}, {0x1E7ED, 0x1E7EE},
+ {0x1E7F0, 0x1E7FE}, {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, 0x1F776},
+ {0x1F77B, 0x1F7D9}, {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..5f987a3
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/runewidth_windows.go
@@ -0,0 +1,28 @@
+//go:build windows && !appengine
+// +build windows,!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..dc83dde
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/.gitignore
@@ -0,0 +1,22 @@
+# 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
+/.idea
diff --git a/vendor/github.com/pterm/pterm/.golangci.yml b/vendor/github.com/pterm/pterm/.golangci.yml
new file mode 100644
index 0000000..a964631
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/.golangci.yml
@@ -0,0 +1,95 @@
+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
+ - 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:"
+ - linters:
+ - gocritic
+ text: "preferDecodeRune:"
+service:
+ golangci-lint-version: 1.31.x # use the fixed version to not introduce new linters unexpectedly
+
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..fcde992
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/CONTRIBUTING.md
@@ -0,0 +1,225 @@
+# 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).
+
+## Best practise
+
+We enforce some best practises, especially made for PTerm, to provide a clean and consistent user experience.
+
+### Styles
+
+Styles should always be consumed as pointers. That way, the user can change the style of printers globally.
+
+## 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 ...any) 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 ...any) 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 ...any) 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 ...any) *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 ...any) *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 ...any) *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 strings.Builder
+
+ return ret.String(), 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...any) (*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 any) {
+ p.Print(a)
+ })
+ })
+
+ t.Run("Printf", func(t *testing.T) {
+ testPrintfContains(t, func(w io.Writer, format string, a any) {
+ p.Printf(format, a)
+ })
+ })
+
+ t.Run("Println", func(t *testing.T) {
+ testPrintlnContains(t, func(w io.Writer, a any) {
+ p.Println(a)
+ })
+ })
+
+ t.Run("Sprint", func(t *testing.T) {
+ testSprintContains(t, func(a any) string {
+ return p.Sprint(a)
+ })
+ })
+
+ t.Run("Sprintf", func(t *testing.T) {
+ testSprintfContains(t, func(format string, a any) string {
+ return p.Sprintf(format, a)
+ })
+ })
+
+ t.Run("Sprintln", func(t *testing.T) {
+ testSprintlnContains(t, func(a any) 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..4002a59
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/README.md
@@ -0,0 +1,3814 @@
+
+
+💻 PTerm | Pretty Terminal Printer
+A modern Go framework to make beautiful CLIs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Show Demo Code
+
+
+
+---
+
+
+PTerm.sh
+|
+Installation
+|
+Getting Started
+|
+Documentation
+|
+Examples
+|
+Q&A
+|
+Discord
+
+
+---
+
+## 📦 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
+```
+
+## ⭐ Main Features
+
+| Feature | Description |
+|------------------|-----------------------------------------------------|
+| 🪀 Easy to use | PTerm emphasizes ease of use, with [examples](#-examples) and consistent component design. |
+| 🤹♀️ Cross-Platform | PTerm works on various OS and terminals, including `Windows CMD`, `macOS iTerm2`, and in CI systems like `GitHub Actions`. |
+| 🧪 Well tested | A high test coverage and `28774` automated tests ensure PTerm's reliability. |
+| ✨ Consistent Colors | PTerm uses the [ANSI color scheme](https://en.wikipedia.org/wiki/ANSI_escape_code#3/4_bit) for uniformity and supports `TrueColor` for advanced terminals. |
+| 📚 Component system | PTerm's flexible `Printers` can be used individually or combined to generate beautiful console output. |
+| 🛠 Configurable | PTerm is ready to use without configuration but allows easy customization for unique terminal output. |
+| ✏ Documentation | Access comprehensive docs on [pkg.go.dev](https://pkg.go.dev/github.com/pterm/pterm#section-documentation) and view practical examples in the [examples section](#-examples). |
+
+### Printers (Components)
+
+
+
+
+| Feature | Feature | Feature | Feature | Feature |
+| :-------: | :-------: | :-------: | :-------: | :-------: |
+| Area [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/area) |Barchart [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/barchart) |Basictext [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/basictext) |Bigtext [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/bigtext) |Box [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/box) |
+| Bulletlist [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/bulletlist) |Center [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/center) |Coloring [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/coloring) |Header [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/header) |Heatmap [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/heatmap) |
+| Interactive confirm [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/interactive_confirm) |Interactive continue [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/interactive_continue) |Interactive multiselect [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/interactive_multiselect) |Interactive select [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/interactive_select) |Interactive textinput [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/interactive_textinput) |
+| Logger [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/logger) |Multiple-live-printers [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/multiple-live-printers) |Panel [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/panel) |Paragraph [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/paragraph) |Prefix [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/prefix) |
+| Progressbar [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/progressbar) |Section [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/section) |Slog [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/slog) |Spinner [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/spinner) |Style [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/style) |
+| Table [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/table) |Test.sh [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/test.sh) |Theme [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/theme) |Tree [(Examples)](https://github.com/pterm/pterm/tree/master/_examples/tree) | |
+
+
+
+
+---
+
+
+
+### 🦸♂️ Sponsors
+
+
+
+---
+
+
+
+## 🧪 Examples
+
+
+
+
+
+
+### area/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/area/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "time"
+
+ "github.com/pterm/pterm"
+ "github.com/pterm/pterm/putils"
+)
+
+func main() {
+ // Print an informational message using PTerm's Info printer.
+ // This message will stay in place while the area updates.
+ pterm.Info.Println("The previous text will stay in place, while the area updates.")
+
+ // Print two new lines as spacer.
+ pterm.Print("\n\n")
+
+ // Start the Area printer from PTerm's DefaultArea, with the Center option.
+ // The Area printer allows us to update a specific area of the console output.
+ // The returned 'area' object is used to control the area updates.
+ area, _ := pterm.DefaultArea.WithCenter().Start()
+
+ // Loop 10 times to update the area with the current time.
+ for i := 0; i < 10; i++ {
+ // Get the current time, format it as "15:04:05" (hour:minute:second), and convert it to a string.
+ // Then, create a BigText from the time string using PTerm's DefaultBigText and putils NewLettersFromString.
+ // The Srender() function is used to save the BigText as a string.
+ str, _ := pterm.DefaultBigText.WithLetters(putils.LettersFromString(time.Now().Format("15:04:05"))).Srender()
+
+ // Update the Area contents with the current time string.
+ area.Update(str)
+
+ // Sleep for a second before the next update.
+ time.Sleep(time.Second)
+ }
+
+ // Stop the Area printer after all updates are done.
+ area.Stop()
+}
+
+```
+
+
+
+### area/center
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/area/center/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "time"
+
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Start a new default area in the center of the terminal.
+ // The Start() function returns the created area and an error.
+ area, _ := pterm.DefaultArea.WithCenter().Start()
+
+ // Loop 5 times to simulate a dynamic update.
+ for i := 0; i < 5; i++ {
+ // Update the content of the area with the current count.
+ // The Sprintf function is used to format the string.
+ area.Update(pterm.Sprintf("Current count: %d\nAreas can update their content dynamically!", i))
+
+ // Pause for a second to simulate a time-consuming task.
+ time.Sleep(time.Second)
+ }
+
+ // Stop the area after all updates are done.
+ area.Stop()
+}
+
+```
+
+
+
+### area/default
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/area/default/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "time"
+
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Start a new default area and get a reference to it.
+ // The second return value is an error which is ignored here.
+ area, _ := pterm.DefaultArea.Start()
+
+ // Loop 5 times
+ for i := 0; i < 5; i++ {
+ // Update the content of the area dynamically.
+ // Here we're just displaying the current count.
+ area.Update(pterm.Sprintf("Current count: %d\nAreas can update their content dynamically!", i))
+
+ // Pause for a second before the next update.
+ time.Sleep(time.Second)
+ }
+
+ // Stop the area after all updates are done.
+ // This will clean up and free resources used by the area.
+ area.Stop()
+}
+
+```
+
+
+
+### area/dynamic-chart
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/area/dynamic-chart/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "time"
+
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Start a new fullscreen centered area.
+ // This area will be used to display the bar chart.
+ area, _ := pterm.DefaultArea.WithFullscreen().WithCenter().Start()
+ // Ensure the area stops updating when we're done.
+ defer area.Stop()
+
+ // Loop to update the bar chart 10 times.
+ for i := 0; i < 10; i++ {
+ // Create a new bar chart with dynamic bars.
+ // The bars will change based on the current iteration.
+ barchart := pterm.DefaultBarChart.WithBars(dynamicBars(i))
+ // Render the bar chart to a string.
+ // This string will be used to update the area.
+ content, _ := barchart.Srender()
+ // Update the area with the new bar chart.
+ area.Update(content)
+ // Wait for half a second before the next update.
+ time.Sleep(500 * time.Millisecond)
+ }
+}
+
+// dynamicBars generates a set of bars for the bar chart.
+// The bars will change based on the current iteration.
+func dynamicBars(i int) pterm.Bars {
+ return pterm.Bars{
+ {Label: "A", Value: 10}, // A static bar.
+ {Label: "B", Value: 20 * i}, // A bar that grows with each iteration.
+ {Label: "C", Value: 30}, // Another static bar.
+ {Label: "D", Value: 40 + i}, // A bar that grows slowly with each iteration.
+ }
+}
+
+```
+
+
+
+### area/fullscreen
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/area/fullscreen/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "time"
+
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Start a new fullscreen area. This will return an area instance and an error.
+ // The underscore (_) is used to ignore the error.
+ area, _ := pterm.DefaultArea.WithFullscreen().Start()
+
+ // Loop 5 times to update the area content.
+ for i := 0; i < 5; i++ {
+ // Update the content of the area with the current count.
+ // The Sprintf function is used to format the string.
+ area.Update(pterm.Sprintf("Current count: %d\nAreas can update their content dynamically!", i))
+
+ // Pause for a second before the next update.
+ time.Sleep(time.Second)
+ }
+
+ // Stop the area after all updates are done.
+ area.Stop()
+}
+
+```
+
+
+
+### area/fullscreen-center
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/area/fullscreen-center/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "time"
+
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Initialize a new PTerm area with fullscreen and center options
+ // The Start() function returns the created area and an error (ignored here)
+ area, _ := pterm.DefaultArea.WithFullscreen().WithCenter().Start()
+
+ // Loop 5 times to demonstrate dynamic content update
+ for i := 0; i < 5; i++ {
+ // Update the content of the area with the current count
+ // The Sprintf function is used to format the string with the count
+ area.Update(pterm.Sprintf("Current count: %d\nAreas can update their content dynamically!", i))
+
+ // Pause for a second
+ time.Sleep(time.Second)
+ }
+
+ // Stop the area after all updates are done
+ // This will clear the area and return the terminal to its normal state
+ area.Stop()
+}
+
+```
+
+
+
+### barchart/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/barchart/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Define the bars for the chart
+ bars := []pterm.Bar{
+ {Label: "Bar 1", Value: 5},
+ {Label: "Bar 2", Value: 3},
+ {Label: "Longer Label", Value: 7},
+ }
+
+ // Print an informational message
+ pterm.Info.Println("Chart example with positive only values (bars use 100% of chart area)")
+
+ // Create a bar chart with the defined bars and render it
+ // The DefaultBarChart is used as a base, and the bars are added with the WithBars option
+ // The Render function is then called to display the chart
+ pterm.DefaultBarChart.WithBars(bars).Render()
+
+ // Create a horizontal bar chart with the defined bars and render it
+ // The DefaultBarChart is used as a base, the chart is made horizontal with the WithHorizontal option, and the bars are added with the WithBars option
+ // The Render function is then called to display the chart
+ pterm.DefaultBarChart.WithHorizontal().WithBars(bars).Render()
+}
+
+```
+
+
+
+### barchart/custom-height
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/barchart/custom-height/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Define a slice of Bar structs. Each struct represents a bar in the chart.
+ // The Label field is the name of the bar and the Value field is the height of the bar.
+ bars := []pterm.Bar{
+ {Label: "A", Value: 10},
+ {Label: "B", Value: 20},
+ {Label: "C", Value: 30},
+ {Label: "D", Value: 40},
+ {Label: "E", Value: 50},
+ {Label: "F", Value: 40},
+ {Label: "G", Value: 30},
+ {Label: "H", Value: 20},
+ {Label: "I", Value: 10},
+ }
+
+ // Create and render a bar chart with the defined bars and a height of 5.
+ // The WithBars method is used to set the bars of the chart.
+ // The WithHeight method is used to set the height of the chart.
+ // The Render method is used to display the chart in the terminal.
+ pterm.DefaultBarChart.WithBars(bars).WithHeight(5).Render()
+}
+
+```
+
+
+
+### barchart/custom-width
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/barchart/custom-width/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Define the data for the bar chart
+ barData := []pterm.Bar{
+ {Label: "A", Value: 10},
+ {Label: "B", Value: 20},
+ {Label: "C", Value: 30},
+ {Label: "D", Value: 40},
+ {Label: "E", Value: 50},
+ {Label: "F", Value: 40},
+ {Label: "G", Value: 30},
+ {Label: "H", Value: 20},
+ {Label: "I", Value: 10},
+ }
+
+ // Create a bar chart with the defined data
+ // The chart is horizontal and has a width of 5
+ // The Render() function is called to display the chart
+ pterm.DefaultBarChart.WithBars(barData).WithHorizontal().WithWidth(5).Render()
+}
+
+```
+
+
+
+### barchart/default
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/barchart/default/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Define the data for the bar chart. Each bar is represented by a `pterm.Bar` struct.
+ // The `Label` field represents the label of the bar, and the `Value` field represents the value of the bar.
+ bars := []pterm.Bar{
+ {Label: "A", Value: 10},
+ {Label: "B", Value: 20},
+ {Label: "C", Value: 30},
+ {Label: "D", Value: 40},
+ {Label: "E", Value: 50},
+ {Label: "F", Value: 40},
+ {Label: "G", Value: 30},
+ {Label: "H", Value: 20},
+ {Label: "I", Value: 10},
+ }
+
+ // Use the `DefaultBarChart` from the `pterm` package to create a bar chart.
+ // The `WithBars` method is used to set the bars of the chart.
+ // The `Render` method is used to display the chart.
+ pterm.DefaultBarChart.WithBars(bars).Render()
+}
+
+```
+
+
+
+### barchart/horizontal
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/barchart/horizontal/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Define the data for the bar chart
+ bars := []pterm.Bar{
+ {Label: "A", Value: 10},
+ {Label: "B", Value: 20},
+ {Label: "C", Value: 30},
+ {Label: "D", Value: 40},
+ {Label: "E", Value: 50},
+ {Label: "F", Value: 40},
+ {Label: "G", Value: 30},
+ {Label: "H", Value: 20},
+ {Label: "I", Value: 10},
+ }
+
+ // Create a bar chart with the defined data
+ // The chart is displayed horizontally
+ // The Render() function is called to display the chart
+ pterm.DefaultBarChart.WithBars(bars).WithHorizontal().Render()
+}
+
+```
+
+
+
+### barchart/horizontal-show-value
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/barchart/horizontal-show-value/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Define the data for the bar chart
+ barData := []pterm.Bar{
+ {Label: "A", Value: 10},
+ {Label: "B", Value: 20},
+ {Label: "C", Value: 30},
+ {Label: "D", Value: 40},
+ {Label: "E", Value: 50},
+ {Label: "F", Value: 40},
+ {Label: "G", Value: 30},
+ {Label: "H", Value: 20},
+ {Label: "I", Value: 10},
+ }
+
+ // Create a bar chart with the defined data
+ // The chart is horizontal and displays the value of each bar
+ // The Render() function is called to display the chart
+ pterm.DefaultBarChart.WithBars(barData).WithHorizontal().WithShowValue().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() {
+ // Define a set of bars for the chart.
+ // Each bar has a label and a value.
+ bars := []pterm.Bar{
+ {Label: "Bar 1", Value: 2},
+ {Label: "Bar 2", Value: -3},
+ {Label: "Bar 3", Value: -2},
+ {Label: "Bar 4", Value: 5},
+ {Label: "Longer Label", Value: 7},
+ }
+
+ // Print a section header.
+ // This is useful for separating different parts of the output.
+ 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)")
+
+ // Create a bar chart with the defined bars.
+ // The chart will display the value of each bar.
+ // The Render() function is called to display the chart.
+ pterm.DefaultBarChart.WithBars(bars).WithShowValue().Render()
+
+ // Create a horizontal bar chart with the same bars.
+ // The chart will display the value of each bar.
+ // The Render() function is called to display the chart.
+ pterm.DefaultBarChart.WithHorizontal().WithBars(bars).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() {
+ // Define a set of bars with negative values.
+ // Each bar is represented by a struct with a label and a value.
+ negativeBars := pterm.Bars{
+ {Label: "Bar 1", Value: -5},
+ {Label: "Bar 2", Value: -3},
+ {Label: "Longer Label", Value: -7},
+ }
+
+ // Print an informational message to the console.
+ pterm.Info.Println("Chart example with negative only values (bars use 100% of chart area)")
+
+ // Create a vertical bar chart with the defined bars.
+ // The WithShowValue() option is used to display the value of each bar in the chart.
+ // The Render() method is called to draw the chart.
+ _ = pterm.DefaultBarChart.WithBars(negativeBars).WithShowValue().Render()
+
+ // Create a horizontal bar chart with the same bars.
+ // The WithHorizontal() option is used to orient the chart horizontally.
+ // The WithShowValue() option and Render() method are used in the same way as before.
+ _ = pterm.DefaultBarChart.WithHorizontal().WithBars(negativeBars).WithShowValue().Render()
+}
+
+```
+
+
+
+### barchart/show-value
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/barchart/show-value/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Define a slice of bars for the bar chart. Each bar is represented by a struct
+ // with a Label and a Value. The Label is a string that represents the name of the bar,
+ // and the Value is an integer that represents the height of the bar.
+ bars := []pterm.Bar{
+ {Label: "A", Value: 10},
+ {Label: "B", Value: 20},
+ {Label: "C", Value: 30},
+ {Label: "D", Value: 40},
+ {Label: "E", Value: 50},
+ {Label: "F", Value: 40},
+ {Label: "G", Value: 30},
+ {Label: "H", Value: 20},
+ {Label: "I", Value: 10},
+ }
+
+ // Create a bar chart with the defined bars using the DefaultBarChart object from PTerm.
+ // Chain the WithBars method to set the bars of the chart.
+ // Chain the WithShowValue method to display the value of each bar on the chart.
+ // Finally, call the Render method to display the chart.
+ pterm.DefaultBarChart.WithBars(bars).WithShowValue().Render()
+}
+
+```
+
+
+
+### basictext/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/basictext/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // The DefaultBasicText is a basic text printer provided by PTerm.
+ // It is used to print text without any special formatting.
+ pterm.DefaultBasicText.Println("Default basic text printer.")
+
+ // The DefaultBasicText can be used in any context that requires a TextPrinter.
+ // Here, we're using it with the LightMagenta function to color a portion of the text.
+ pterm.DefaultBasicText.Println("Can be used in any" + pterm.LightMagenta(" TextPrinter ") + "context.")
+
+ // The DefaultBasicText is also useful for resolving progress bars and spinners.
+}
+
+```
+
+
+
+### bigtext/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/bigtext/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+ "github.com/pterm/pterm/putils"
+)
+
+func main() {
+ // Create a large text with the LetterStyle from the standard theme.
+ // This is useful for creating title screens.
+ pterm.DefaultBigText.WithLetters(putils.LettersFromString("PTerm")).Render()
+
+ // Create a large text with differently colored letters.
+ // Here, the first letter 'P' is colored cyan and the rest 'Term' is colored light magenta.
+ // This can be used to highlight specific parts of the text.
+ pterm.DefaultBigText.WithLetters(
+ putils.LettersFromStringWithStyle("P", pterm.FgCyan.ToStyle()),
+ putils.LettersFromStringWithStyle("Term", pterm.FgLightMagenta.ToStyle()),
+ ).Render()
+
+ // Create a large text with a specific RGB color.
+ // This can be used when you need a specific color that is not available in the standard colors.
+ // Here, the color is gold (RGB: 255, 215, 0).
+ pterm.DefaultBigText.WithLetters(
+ putils.LettersFromStringWithRGB("PTerm", pterm.NewRGB(255, 215, 0)),
+ ).Render()
+}
+
+```
+
+
+
+### bigtext/colored
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/bigtext/colored/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+ "github.com/pterm/pterm/putils"
+)
+
+func main() {
+ // Initialize a big text display with the letters "P" and "Term"
+ // "P" is displayed in cyan and "Term" is displayed in light magenta
+ pterm.DefaultBigText.WithLetters(
+ putils.LettersFromStringWithStyle("P", pterm.FgCyan.ToStyle()),
+ putils.LettersFromStringWithStyle("Term", pterm.FgLightMagenta.ToStyle())).
+ Render() // Render the big text to the terminal
+}
+
+```
+
+
+
+### bigtext/default
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/bigtext/default/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+ "github.com/pterm/pterm/putils"
+)
+
+func main() {
+ // Define the text to be rendered
+ var text = "PTerm"
+
+ // Convert the text into a format suitable for PTerm
+ var letters = putils.LettersFromString(text)
+
+ // Render the text using PTerm's default big text style
+ pterm.DefaultBigText.WithLetters(letters).Render()
+}
+
+```
+
+
+
+### box/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/box/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Print an informational message.
+ 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")
+
+ // Create three panels with text, some of them with titles.
+ // The panels are created using the DefaultBox style.
+ 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.")
+
+ // Combine the panels into a layout using the DefaultPanel style.
+ // The layout is a 2D grid, with each row being an array of panels.
+ // In this case, the first row contains panel1 and panel2, and the second row contains only panel3.
+ panels, _ := pterm.DefaultPanel.WithPanels(pterm.Panels{
+ {{Data: panel1}, {Data: panel2}},
+ {{Data: panel3}},
+ }).Srender()
+
+ // Print the panels layout inside a box with a title.
+ // The box is created using the DefaultBox style, with the title positioned at the bottom right.
+ pterm.DefaultBox.WithTitle("Lorem Ipsum").WithTitleBottomRight().WithRightPadding(0).WithBottomPadding(0).Println(panels)
+}
+
+```
+
+
+
+### box/custom-padding
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/box/custom-padding/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Create a default box with custom padding options and print "Hello, World!" inside it.
+ pterm.DefaultBox.WithRightPadding(10).WithLeftPadding(10).WithTopPadding(2).WithBottomPadding(2).Println("Hello, World!")
+}
+
+```
+
+
+
+### box/default
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/box/default/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Create a default box with PTerm and print a message in it.
+ // The DefaultBox.Println method automatically starts, prints the message, and stops the box.
+ pterm.DefaultBox.Println("Hello, World!")
+}
+
+```
+
+
+
+### box/title
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/box/title/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Create a default box with specified padding
+ paddedBox := pterm.DefaultBox.WithLeftPadding(4).WithRightPadding(4).WithTopPadding(1).WithBottomPadding(1)
+
+ // Define a title for the box
+ title := pterm.LightRed("I'm a box!")
+
+ // Create boxes with the title positioned differently and containing different content
+ box1 := paddedBox.WithTitle(title).Sprint("Hello, World!\n 1") // Title at default position (top left)
+ box2 := paddedBox.WithTitle(title).WithTitleTopCenter().Sprint("Hello, World!\n 2") // Title at top center
+ box3 := paddedBox.WithTitle(title).WithTitleTopRight().Sprint("Hello, World!\n 3") // Title at top right
+ box4 := paddedBox.WithTitle(title).WithTitleBottomRight().Sprint("Hello, World!\n 4") // Title at bottom right
+ box5 := paddedBox.WithTitle(title).WithTitleBottomCenter().Sprint("Hello, World!\n 5") // Title at bottom center
+ box6 := paddedBox.WithTitle(title).WithTitleBottomLeft().Sprint("Hello, World!\n 6") // Title at bottom left
+ box7 := paddedBox.WithTitle(title).WithTitleTopLeft().Sprint("Hello, World!\n 7") // Title at top left
+
+ // Render the boxes in a panel layout
+ pterm.DefaultPanel.WithPanels([][]pterm.Panel{
+ {{box1}, {box2}, {box3}},
+ {{box4}, {box5}, {box6}},
+ {{box7}},
+ }).Render()
+}
+
+```
+
+
+
+### bulletlist/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/bulletlist/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+ "github.com/pterm/pterm/putils"
+)
+
+func main() {
+ // Define a list of bullet list items with different levels.
+ bulletListItems := []pterm.BulletListItem{
+ {Level: 0, Text: "Level 0"}, // Level 0 item
+ {Level: 1, Text: "Level 1"}, // Level 1 item
+ {Level: 2, Text: "Level 2"}, // Level 2 item
+ }
+
+ // Use the default bullet list style to render the list items.
+ pterm.DefaultBulletList.WithItems(bulletListItems).Render()
+
+ // Define a string with different levels of indentation.
+ text := `0
+ 1
+ 2
+ 3`
+
+ // Convert the indented string to a bullet list and render it.
+ putils.BulletListFromString(text, " ").Render()
+}
+
+```
+
+
+
+### bulletlist/customized
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/bulletlist/customized/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Define a list of bullet list items with different styles and levels.
+ bulletListItems := []pterm.BulletListItem{
+ {
+ Level: 0, // Level 0 (top level)
+ Text: "Blue", // Text to display
+ TextStyle: pterm.NewStyle(pterm.FgBlue), // Text color
+ BulletStyle: pterm.NewStyle(pterm.FgRed), // Bullet color
+ },
+ {
+ Level: 1, // Level 1 (sub-item)
+ Text: "Green", // Text to display
+ TextStyle: pterm.NewStyle(pterm.FgGreen), // Text color
+ Bullet: "-", // Custom bullet symbol
+ BulletStyle: pterm.NewStyle(pterm.FgLightWhite), // Bullet color
+ },
+ {
+ Level: 2, // Level 2 (sub-sub-item)
+ Text: "Cyan", // Text to display
+ TextStyle: pterm.NewStyle(pterm.FgCyan), // Text color
+ Bullet: ">", // Custom bullet symbol
+ BulletStyle: pterm.NewStyle(pterm.FgYellow), // Bullet color
+ },
+ }
+
+ // Create a bullet list with the defined items and render it.
+ pterm.DefaultBulletList.WithItems(bulletListItems).Render()
+}
+
+```
+
+
+
+### center/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/center/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+ "github.com/pterm/pterm/putils"
+)
+
+func main() {
+ // Print a block of text centered in the terminal
+ pterm.DefaultCenter.Println("This text is centered!\nIt centers the whole block by default.\nIn that way you can do stuff like this:")
+
+ // Generate BigLetters and store in 's'
+ s, _ := pterm.DefaultBigText.WithLetters(putils.LettersFromString("PTerm")).Srender()
+
+ // Print the BigLetters 's' centered in the terminal
+ pterm.DefaultCenter.Println(s)
+
+ // Print each line of the text separately centered in the terminal
+ pterm.DefaultCenter.WithCenterEachLineSeparately().Println("This text is centered!\nBut each line is\ncentered\nseparately")
+}
+
+```
+
+
+
+### coloring/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/coloring/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Create a table with different foreground and background colors.
+ pterm.DefaultTable.WithData([][]string{
+ {pterm.FgBlack.Sprint("Black"), pterm.FgRed.Sprint("Red"), pterm.FgGreen.Sprint("Green"), pterm.FgYellow.Sprint("Yellow")},
+ {"", pterm.FgLightRed.Sprint("Light Red"), pterm.FgLightGreen.Sprint("Light Green"), pterm.FgLightYellow.Sprint("Light Yellow")},
+ {pterm.BgBlack.Sprint("Black"), pterm.BgRed.Sprint("Red"), pterm.BgGreen.Sprint("Green"), pterm.BgYellow.Sprint("Yellow")},
+ {"", pterm.BgLightRed.Sprint("Light Red"), pterm.BgLightGreen.Sprint("Light Green"), pterm.BgLightYellow.Sprint("Light Yellow")},
+ {pterm.FgBlue.Sprint("Blue"), pterm.FgMagenta.Sprint("Magenta"), pterm.FgCyan.Sprint("Cyan"), pterm.FgWhite.Sprint("White")},
+ {pterm.FgLightBlue.Sprint("Light Blue"), pterm.FgLightMagenta.Sprint("Light Magenta"), pterm.FgLightCyan.Sprint("Light Cyan"), pterm.FgLightWhite.Sprint("Light White")},
+ {pterm.BgBlue.Sprint("Blue"), pterm.BgMagenta.Sprint("Magenta"), pterm.BgCyan.Sprint("Cyan"), pterm.BgWhite.Sprint("White")},
+ {pterm.BgLightBlue.Sprint("Light Blue"), pterm.BgLightMagenta.Sprint("Light Magenta"), pterm.BgLightCyan.Sprint("Light Cyan"), pterm.BgLightWhite.Sprint("Light White")},
+ }).Render() // Render the table.
+
+ pterm.Println()
+
+ // Print words in different colors.
+ pterm.Println(pterm.Red("Hello, ") + pterm.Green("World") + pterm.Cyan("!"))
+ pterm.Println(pterm.Red("Even " + pterm.Cyan("nested ") + pterm.Green("colors ") + "are supported!"))
+
+ pterm.Println()
+
+ // Create a new style with a red background, light green foreground, and bold text.
+ style := pterm.NewStyle(pterm.BgRed, pterm.FgLightGreen, pterm.Bold)
+ // Print text using the created style.
+ style.Println("This text uses a style and is bold and light green with a red background!")
+}
+
+```
+
+
+
+### coloring/disable-output
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/coloring/disable-output/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Loop from 0 to 14
+ for i := 0; i < 15; i++ {
+ switch i {
+ case 5:
+ // At the 5th iteration, print a message and disable the output
+ pterm.Info.Println("Disabled Output!")
+ pterm.DisableOutput()
+ case 10:
+ // At the 10th iteration, enable the output and print a message
+ pterm.EnableOutput()
+ pterm.Info.Println("Enabled Output!")
+ }
+
+ // Print a progress message for each iteration
+ pterm.Printf("Printing something... [%d/%d]\n", i, 15)
+ }
+}
+
+```
+
+
+
+### coloring/fade-colors
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/coloring/fade-colors/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Print an informational message.
+ pterm.Info.Println("RGB colors only work in Terminals which support TrueColor.")
+
+ // Define the start and end points for the color gradient.
+ startColor := pterm.NewRGB(0, 255, 255) // Cyan
+ endColor := pterm.NewRGB(255, 0, 255) // Magenta
+
+ // Get the terminal height to determine the gradient range.
+ terminalHeight := pterm.GetTerminalHeight()
+
+ // Loop over the range of the terminal height to create a color gradient.
+ for i := 0; i < terminalHeight-2; i++ {
+ // Calculate the fade factor for the current step in the gradient.
+ fadeFactor := float32(i) / float32(terminalHeight-2)
+
+ // Create a color that represents the current step in the gradient.
+ currentColor := startColor.Fade(0, 1, fadeFactor, endColor)
+
+ // Print a string with the current color.
+ currentColor.Println("Hello, World!")
+ }
+}
+
+```
+
+
+
+### coloring/fade-colors-rgb-style
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/coloring/fade-colors-rgb-style/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "strings"
+
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Define RGB colors
+ white := pterm.NewRGB(255, 255, 255)
+ grey := pterm.NewRGB(128, 128, 128)
+ black := pterm.NewRGB(0, 0, 0)
+ red := pterm.NewRGB(255, 0, 0)
+ purple := pterm.NewRGB(255, 0, 255)
+ green := pterm.NewRGB(0, 255, 0)
+
+ // Define strings to be printed
+ str1 := "RGB colors only work in Terminals which support TrueColor."
+ str2 := "The background and foreground colors can be customized individually."
+ str3 := "Styles can also be applied. For example: Bold or Italic."
+
+ // Print first string with color fading from white to purple
+ printFadedString(str1, white, purple, grey, black)
+
+ // Print second string with color fading from purple to red
+ printFadedString(str2, black, purple, red, red)
+
+ // Print third string with color fading from white to green and style changes
+ printStyledString(str3, white, green, red, black)
+}
+
+// printFadedString prints a string with color fading effect
+func printFadedString(str string, fgStart, fgEnd, bgStart, bgEnd pterm.RGB) {
+ strs := strings.Split(str, "")
+ var result string
+ for i := 0; i < len(str); i++ {
+ // Create a style with color fading effect
+ style := pterm.NewRGBStyle(fgStart.Fade(0, float32(len(str)), float32(i), fgEnd), bgStart.Fade(0, float32(len(str)), float32(i), bgEnd))
+ // Append styled letter to result string
+ result += style.Sprint(strs[i])
+ }
+ pterm.Println(result)
+}
+
+// printStyledString prints a string with color fading and style changes
+func printStyledString(str string, fgStart, fgEnd, bgStart, bgEnd pterm.RGB) {
+ strs := strings.Split(str, "")
+ var result string
+ boldStr := strings.Split("Bold", "")
+ italicStr := strings.Split("Italic", "")
+ bold, italic := 0, 0
+ for i := 0; i < len(str); i++ {
+ // Create a style with color fading effect
+ style := pterm.NewRGBStyle(fgStart.Fade(0, float32(len(str)), float32(i), fgEnd), bgStart.Fade(0, float32(len(str)), float32(i), bgEnd))
+ // Check if the next letters are "Bold" or "Italic" and add the corresponding style
+ if bold < len(boldStr) && i+len(boldStr)-bold <= len(strs) && strings.Join(strs[i:i+len(boldStr)-bold], "") == strings.Join(boldStr[bold:], "") {
+ style = style.AddOptions(pterm.Bold)
+ bold++
+ } else if italic < len(italicStr) && i+len(italicStr)-italic < len(strs) && strings.Join(strs[i:i+len(italicStr)-italic], "") == strings.Join(italicStr[italic:], "") {
+ style = style.AddOptions(pterm.Italic)
+ italic++
+ }
+ // Append styled letter to result string
+ result += style.Sprint(strs[i])
+ }
+ pterm.Println(result)
+}
+
+```
+
+
+
+### coloring/fade-multiple-colors
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/coloring/fade-multiple-colors/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "strings"
+
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Define RGB values for gradient points.
+ startColor := pterm.NewRGB(0, 255, 255)
+ firstPoint := pterm.NewRGB(255, 0, 255)
+ secondPoint := pterm.NewRGB(255, 0, 0)
+ thirdPoint := pterm.NewRGB(0, 255, 0)
+ endColor := pterm.NewRGB(255, 255, 255)
+
+ // Define the string to be printed.
+ str := "RGB colors only work in Terminals which support TrueColor."
+ strs := strings.Split(str, "")
+
+ // Initialize an empty string for the faded info.
+ var fadeInfo string
+
+ // Loop over the string length to create a gradient effect.
+ for i := 0; i < len(str); i++ {
+ // Append each character of the string with a faded color to the info string.
+ fadeInfo += startColor.Fade(0, float32(len(str)), float32(i), firstPoint).Sprint(strs[i])
+ }
+
+ // Print the info string with gradient effect.
+ pterm.Info.Println(fadeInfo)
+
+ // Get the terminal height.
+ terminalHeight := pterm.GetTerminalHeight()
+
+ // Loop over the terminal height to print "Hello, World!" with a gradient effect.
+ for i := 0; i < terminalHeight-2; i++ {
+ // Print the string with a color that fades from startColor to endColor.
+ startColor.Fade(0, float32(terminalHeight-2), float32(i), firstPoint, secondPoint, thirdPoint, endColor).Println("Hello, World!")
+ }
+}
+
+```
+
+
+
+### coloring/override-default-printers
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/coloring/override-default-printers/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Print a default error message with PTerm's built-in Error style.
+ pterm.Error.Println("This is the default Error")
+
+ // Override the default error prefix with a new text and style.
+ pterm.Error.Prefix = pterm.Prefix{Text: "OVERRIDE", Style: pterm.NewStyle(pterm.BgCyan, pterm.FgRed)}
+
+ // Print the error message again, this time with the overridden prefix.
+ pterm.Error.Println("This is the default Error after the prefix was overridden")
+}
+
+```
+
+
+
+### coloring/print-color-rgb
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/coloring/print-color-rgb/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Create a new RGB color with values 178, 44, 199.
+ // This color will be used for the text.
+ pterm.NewRGB(178, 44, 199).Println("This text is printed with a custom RGB!")
+
+ // Create a new RGB color with values 15, 199, 209.
+ // This color will be used for the text.
+ pterm.NewRGB(15, 199, 209).Println("This text is printed with a custom RGB!")
+
+ // Create a new RGB color with values 201, 144, 30.
+ // This color will be used for the background.
+ // The 'true' argument indicates that the color is for the background.
+ pterm.NewRGB(201, 144, 30, true).Println("This text is printed with a custom RGB background!")
+}
+
+```
+
+
+
+### coloring/print-color-rgb-style
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/coloring/print-color-rgb-style/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Define RGB colors for foreground and background.
+ foregroundRGB := pterm.RGB{R: 187, G: 80, B: 0}
+ backgroundRGB := pterm.RGB{R: 0, G: 50, B: 123}
+
+ // Create a new RGB style with the defined foreground and background colors.
+ rgbStyle := pterm.NewRGBStyle(foregroundRGB, backgroundRGB)
+
+ // Print a string with the custom RGB style.
+ rgbStyle.Println("This text is not styled.")
+
+ // Add the 'Bold' option to the RGB style and print a string with this style.
+ rgbStyle.AddOptions(pterm.Bold).Println("This text is bold.")
+
+ // Add the 'Italic' option to the RGB style and print a string with this style.
+ rgbStyle.AddOptions(pterm.Italic).Println("This text is italic.")
+}
+
+```
+
+
+
+### demo/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/demo/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "flag"
+ "math/rand"
+ "reflect"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/pterm/pterm"
+ "github.com/pterm/pterm/putils"
+)
+
+// Speed the demo up, by setting this flag.
+// Usefull for debugging.
+// Example:
+//
+// go run main.go -speedup
+var speedup = flag.Bool("speedup", false, "Speed up the demo")
+var skipIntro = flag.Bool("skip-intro", false, "Skips the intro")
+var second = time.Second
+
+var pseudoProgramList = strings.Split("pseudo-excel pseudo-photoshop pseudo-chrome pseudo-outlook pseudo-explorer "+
+ "pseudo-git pseudo-vsc pseudo-intellij pseudo-minecraft pseudo-scoop pseudo-chocolatey", " ")
+
+func main() {
+ setup() // Setup the demo (flags etc.)
+
+ // Show intro
+ if !*skipIntro {
+ introScreen()
+ clear()
+ }
+
+ showcase("Structured Logging", 5, func() {
+ logger := pterm.DefaultLogger.
+ WithLevel(pterm.LogLevelTrace)
+
+ logger.Trace("Doing not so important stuff", logger.Args("priority", "super low"))
+
+ time.Sleep(time.Second * 3)
+
+ interstingStuff := map[string]any{
+ "when were crayons invented": "1903",
+ "what is the meaning of life": 42,
+ "is this interesting": true,
+ }
+ logger.Debug("This might be interesting", logger.ArgsFromMap(interstingStuff))
+ time.Sleep(time.Second * 3)
+
+ logger.Info("That was actually interesting", logger.Args("such", "wow"))
+ time.Sleep(time.Second * 3)
+ logger.Warn("Oh no, I see an error coming to us!", logger.Args("speed", 88, "measures", "mph"))
+ time.Sleep(time.Second * 3)
+ logger.Error("Damn, here it is!", logger.Args("error", "something went wrong"))
+ time.Sleep(time.Second * 3)
+ logger.Info("But what's really cool is, that you can print very long logs, and PTerm will automatically wrap them for you! Say goodbye to text, that has weird line breaks!", logger.Args("very", "long"))
+ })
+
+ showcase("Progress bar", 2, func() {
+ pb, _ := pterm.DefaultProgressbar.WithTotal(len(pseudoProgramList)).WithTitle("Installing stuff").Start()
+ for i := 0; i < pb.Total; i++ {
+ pb.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])
+ }
+ pb.Increment()
+ time.Sleep(second / 2)
+ }
+ pb.Stop()
+ })
+
+ showcase("Spinner", 2, func() {
+ list := pseudoProgramList[7:]
+ spinner, _ := pterm.DefaultSpinner.Start("Installing stuff")
+ for i := 0; i < len(list); i++ {
+ spinner.UpdateText("Installing " + list[i])
+ if list[i] == "pseudo-minecraft" {
+ pterm.Warning.Println("Could not install pseudo-minecraft\nThe company policy forbids games.")
+ } else {
+ pterm.Success.Println("Installing " + list[i])
+ }
+ time.Sleep(second)
+ }
+ spinner.Success()
+ })
+
+ showcase("Live Output", 2, func() {
+ pterm.Info.Println("You can use an Area to display changing output:")
+ pterm.Println()
+ area, _ := pterm.DefaultArea.WithCenter().Start() // Start the Area printer, with the Center option.
+ for i := 0; i < 10; i++ {
+ str, _ := pterm.DefaultBigText.WithLetters(putils.LettersFromString(time.Now().Format("15:04:05"))).Srender() // Save current time in str.
+ area.Update(str) // Update Area contents.
+ time.Sleep(time.Second)
+ }
+ area.Stop()
+ })
+
+ showcase("Tables", 4, func() {
+ for i := 0; i < 3; i++ {
+ pterm.Println()
+ }
+ td := [][]string{
+ {"Library", "Description"},
+ {"PTerm", "Make beautiful CLIs"},
+ {"Testza", "Programmer friendly test framework"},
+ {"Cursor", "Move the cursor around the terminal"},
+ }
+ table, _ := pterm.DefaultTable.WithHasHeader().WithData(td).Srender()
+ boxedTable, _ := pterm.DefaultTable.WithHasHeader().WithData(td).WithBoxed().Srender()
+ pterm.DefaultCenter.Println(table)
+ pterm.DefaultCenter.Println(boxedTable)
+ })
+
+ showcase("TrueColor Support", 7, func() {
+ 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 :)\n\nLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
+ 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.DefaultCenter.WithCenterEachLineSeparately().Println(fadeInfo)
+ })
+
+ showcase("Fully Customizable", 2, func() {
+ for i := 0; i < 4; i++ {
+ pterm.Println()
+ }
+ text := "All printers are fully customizable!"
+ area := pterm.DefaultArea.WithCenter()
+ area.Update(pterm.DefaultBox.Sprintln(text))
+ time.Sleep(second)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).Sprintln(text))
+ time.Sleep(second / 3)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).Sprintln(text))
+ time.Sleep(second / 3)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).Sprintln(text))
+ time.Sleep(second / 3)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).Sprintln(text))
+ time.Sleep(second / 3)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleTopLeft().Sprintln(text))
+ time.Sleep(second / 3)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleTopCenter().Sprintln(text))
+ time.Sleep(second / 3)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleTopRight().Sprintln(text))
+ time.Sleep(second / 3)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleBottomRight().Sprintln(text))
+ time.Sleep(second / 3)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleBottomCenter().Sprintln(text))
+ time.Sleep(second / 3)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleBottomLeft().Sprintln(text))
+ time.Sleep(second / 3)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithBoxStyle(pterm.NewStyle(pterm.FgCyan)).Sprintln(text))
+ time.Sleep(second / 5)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithBoxStyle(pterm.NewStyle(pterm.FgRed)).Sprintln(text))
+ time.Sleep(second / 5)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithBoxStyle(pterm.NewStyle(pterm.FgGreen)).Sprintln(text))
+ time.Sleep(second / 5)
+ area.Update(pterm.DefaultBox.WithTopPadding(1).
+ WithBottomPadding(1).
+ WithLeftPadding(1).
+ WithRightPadding(1).
+ WithHorizontalString("═").
+ WithVerticalString("║").
+ WithBottomLeftCornerString("╗").
+ WithBottomRightCornerString("╔").
+ WithTopLeftCornerString("╝").
+ WithTopRightCornerString("╚").
+ Sprintln(text))
+ area.Stop()
+ })
+
+ showcase("Themes", 2, func() {
+ pterm.Info.Println("You can change the color theme of PTerm easily to fit your needs!\nThis is the default one:")
+ time.Sleep(second / 2)
+ // 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)
+ }
+ }
+ })
+
+ showcase("And much more!", 3, func() {
+ for i := 0; i < 4; i++ {
+ pterm.Println()
+ }
+ box := pterm.DefaultBox.
+ WithBottomPadding(1).
+ WithTopPadding(1).
+ WithLeftPadding(3).
+ WithRightPadding(3).
+ Sprintf("Have fun exploring %s!", pterm.Cyan("PTerm"))
+ pterm.DefaultCenter.Println(box)
+ })
+}
+
+func setup() {
+ flag.Parse()
+ if *speedup {
+ second = time.Millisecond * 200
+ }
+}
+
+func introScreen() {
+ ptermLogo, _ := pterm.DefaultBigText.WithLetters(
+ putils.LettersFromStringWithStyle("P", pterm.NewStyle(pterm.FgLightCyan)),
+ putils.LettersFromStringWithStyle("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 showcase(title string, seconds int, content func()) {
+ pterm.DefaultHeader.WithBackgroundStyle(pterm.NewStyle(pterm.BgLightBlue)).WithFullWidth().Println(title)
+ pterm.Println()
+ time.Sleep(second / 2)
+ content()
+ time.Sleep(second * time.Duration(seconds))
+ print("\033[H\033[2J")
+}
+
+func randomInt(min, max int) int {
+ rand.Seed(time.Now().UnixNano())
+ return rand.Intn(max-min+1) + min
+}
+
+```
+
+
+
+### header/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/header/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Print a default header.
+ // This uses the default settings of PTerm to print a header.
+ pterm.DefaultHeader.Println("This is the default header!")
+
+ // Print a spacer line for better readability.
+ pterm.Println()
+
+ // Print a full-width header.
+ // This uses the WithFullWidth() option of PTerm to print a header that spans the full width of the terminal.
+ 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() {
+ // Customize the DefaultHeader with a cyan background, black text, and a margin of 15.
+ pterm.DefaultHeader.WithMargin(15).WithBackgroundStyle(pterm.NewStyle(pterm.BgCyan)).WithTextStyle(pterm.NewStyle(pterm.FgBlack)).Println("This is a custom header!")
+
+ // Define a new HeaderPrinter with a red background, black text, and a margin of 20.
+ newHeader := pterm.HeaderPrinter{
+ TextStyle: pterm.NewStyle(pterm.FgBlack),
+ BackgroundStyle: pterm.NewStyle(pterm.BgRed),
+ Margin: 20,
+ }
+
+ // Print the custom header using the new HeaderPrinter.
+ newHeader.Println("This is a custom header!")
+}
+
+```
+
+
+
+### heatmap/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/heatmap/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Define the data for the heatmap. Each sub-array represents a row in the heatmap.
+ data := [][]float32{
+ {0.9, 0.2, -0.7, 0.4, -0.5, 0.6, -0.3, 0.8, -0.1, -1.0, 0.1, -0.8, 0.3},
+ {0.2, -0.7, -0.5, -0.3, -0.1, 0.1, 0.3, 0.5, 0.9, -0.9, -0.7, -0.5, -0.3},
+ {0.4, 0.4, -0.3, -1.0, 0.3, -0.2, -0.9, 0.5, -0.3, -1.0, 0.6, -0.2, -0.9},
+ {0.9, -0.5, -0.1, 0.3, 1, -0.7, -0.3, 0.1, 0.7, -0.9, -0.5, 0.2, 0.6},
+ {0.5, 0.6, 0.1, -0.2, -0.7, 0.8, 0.6, 0.1, -0.5, -0.7, 0.7, 0.3, 0.0},
+ }
+
+ // Define the labels for the X and Y axes of the heatmap.
+ headerData := pterm.HeatmapAxis{
+ XAxis: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"},
+ YAxis: []string{"1", "2", "3", "4", "5"},
+ }
+
+ // Create a heatmap with the defined data and axis labels, and enable RGB colors.
+ // Then render the heatmap.
+ pterm.DefaultHeatmap.WithAxisData(headerData).WithData(data).WithEnableRGB().Render()
+}
+
+```
+
+
+
+### heatmap/custom_colors
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/heatmap/custom_colors/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Define the data for the heatmap
+ data := [][]float32{
+ {0.9, 0.2, -0.7, 0.4, -0.5, 0.6, -0.3, 0.8, -0.1, -1.0, 0.1, -0.8, 0.3},
+ {0.2, -0.7, -0.5, -0.3, -0.1, 0.1, 0.3, 0.5, 0.9, -0.9, -0.7, -0.5, -0.3},
+ {0.4, 0.4, -0.3, -1.0, 0.3, -0.2, -0.9, 0.5, -0.3, -1.0, 0.6, -0.2, -0.9},
+ {0.9, -0.5, -0.1, 0.3, 1, -0.7, -0.3, 0.1, 0.7, -0.9, -0.5, 0.2, 0.6},
+ {0.5, 0.6, 0.1, -0.2, -0.7, 0.8, 0.6, 0.1, -0.5, -0.7, 0.7, 0.3, 0.0},
+ }
+
+ // Define the axis labels for the heatmap
+ headerData := pterm.HeatmapAxis{
+ XAxis: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"},
+ YAxis: []string{"1", "2", "3", "4", "5"},
+ }
+
+ // Print an informational message
+ pterm.Info.Println("The following table has no rgb (supported by every terminal), no axis data and a legend.")
+ pterm.Println()
+
+ // Create the heatmap with the defined data and options, and render it
+ pterm.DefaultHeatmap.
+ WithData(data).
+ WithBoxed(false).
+ WithAxisData(headerData).
+ WithLegend(false).
+ WithColors(pterm.BgBlue, pterm.BgRed, pterm.BgGreen, pterm.BgYellow).
+ WithLegend().
+ Render()
+}
+
+```
+
+
+
+### heatmap/custom_legend
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/heatmap/custom_legend/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Define the data for the heatmap
+ data := [][]float32{
+ {0.9, 0.2, -0.7, 0.4, -0.5, 0.6, -0.3, 0.8, -0.1, -1.0, 0.1, -0.8, 0.3},
+ {0.2, -0.7, -0.5, -0.3, -0.1, 0.1, 0.3, 0.5, 0.9, -0.9, -0.7, -0.5, -0.3},
+ {0.4, 0.4, -0.3, -1.0, 0.3, -0.2, -0.9, 0.5, -0.3, -1.0, 0.6, -0.2, -0.9},
+ {0.9, -0.5, -0.1, 0.3, 1, -0.7, -0.3, 0.1, 0.7, -0.9, -0.5, 0.2, 0.6},
+ {0.5, 0.6, 0.1, -0.2, -0.7, 0.8, 0.6, 0.1, -0.5, -0.7, 0.7, 0.3, 0.0},
+ }
+
+ // Define the header data for the heatmap
+ headerData := pterm.HeatmapAxis{
+ XAxis: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"},
+ YAxis: []string{"1", "2", "3", "4", "5"},
+ }
+
+ // Print an informational message
+ pterm.Info.Println("The following table has rgb (not supported by every terminal), axis data and a custom legend.")
+ pterm.Println()
+
+ // Create the heatmap with the defined data and options
+ // Options are chained in a single line for simplicity
+ pterm.DefaultHeatmap.
+ WithData(data).
+ WithBoxed(false).
+ WithAxisData(headerData).
+ WithEnableRGB().
+ WithLegendLabel("custom").
+ WithLegendOnlyColoredCells().
+ Render() // Render the heatmap
+}
+
+```
+
+
+
+### heatmap/custom_rgb
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/heatmap/custom_rgb/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Define the data for the heatmap.
+ data := [][]float32{
+ {0.9, 0.2, -0.7, 0.4, -0.5, 0.6, -0.3, 0.8, -0.1, -1.0, 0.1, -0.8, 0.3},
+ {0.2, -0.7, -0.5, -0.3, -0.1, 0.1, 0.3, 0.5, 0.9, -0.9, -0.7, -0.5, -0.3},
+ {0.4, 0.4, -0.3, -1.0, 0.3, -0.2, -0.9, 0.5, -0.3, -1.0, 0.6, -0.2, -0.9},
+ {0.9, -0.5, -0.1, 0.3, 1, -0.7, -0.3, 0.1, 0.7, -0.9, -0.5, 0.2, 0.6},
+ {0.5, 0.6, 0.1, -0.2, -0.7, 0.8, 0.6, 0.1, -0.5, -0.7, 0.7, 0.3, 0.0},
+ }
+
+ // Define the axis labels for the heatmap.
+ axisLabels := pterm.HeatmapAxis{
+ XAxis: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"},
+ YAxis: []string{"1", "2", "3", "4", "5"},
+ }
+
+ // Print an informational message.
+ pterm.Info.Println("The following table has rgb (not supported by every terminal), axis data and a legend.")
+ pterm.Println()
+
+ // Define the color range for the heatmap.
+ rgbRange := []pterm.RGB{
+ pterm.NewRGB(0, 0, 255),
+ pterm.NewRGB(255, 0, 0),
+ pterm.NewRGB(0, 255, 0),
+ pterm.NewRGB(255, 255, 0),
+ }
+
+ // Create and render the heatmap.
+ pterm.DefaultHeatmap.
+ WithData(data).
+ WithBoxed(false).
+ WithAxisData(axisLabels).
+ WithEnableRGB().
+ WithRGBRange(rgbRange...).
+ Render()
+}
+
+```
+
+
+
+### heatmap/no_grid
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/heatmap/no_grid/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Define the data for the heatmap.
+ data := [][]float32{
+ {0.9, 0.2, -0.7, 0.4, -0.5, 0.6, -0.3, 0.8, -0.1, -1.0, 0.1, -0.8, 0.3},
+ {0.2, -0.7, -0.5, -0.3, -0.1, 0.1, 0.3, 0.5, 0.9, -0.9, -0.7, -0.5, -0.3},
+ {0.4, 0.4, -0.3, -1.0, 0.3, -0.2, -0.9, 0.5, -0.3, -1.0, 0.6, -0.2, -0.9},
+ {0.9, -0.5, -0.1, 0.3, 1, -0.7, -0.3, 0.1, 0.7, -0.9, -0.5, 0.2, 0.6},
+ {0.5, 0.6, 0.1, -0.2, -0.7, 0.8, 0.6, 0.1, -0.5, -0.7, 0.7, 0.3, 0.0},
+ }
+
+ // Define the axis data for the heatmap.
+ axisData := pterm.HeatmapAxis{
+ XAxis: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"},
+ YAxis: []string{"1", "2", "3", "4", "5"},
+ }
+
+ // Print an informational message.
+ pterm.Info.Println("The following table has rgb (not supported by every terminal), axis data and a legend.")
+ pterm.Println()
+
+ // Create the heatmap with the defined data and options, then render it.
+ pterm.DefaultHeatmap.WithData(data).WithBoxed(false).WithAxisData(axisData).WithEnableRGB().WithLegend().WithGrid(false).Render()
+}
+
+```
+
+
+
+### heatmap/separated
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/heatmap/separated/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Define the data for the heatmap.
+ data := [][]float32{
+ {0.9, 0.2, -0.7, 0.4, -0.5, 0.6, -0.3, 0.8, -0.1, -1.0, 0.1, -0.8, 0.3},
+ {0.2, -0.7, -0.5, -0.3, -0.1, 0.1, 0.3, 0.5, 0.9, -0.9, -0.7, -0.5, -0.3},
+ {0.4, 0.4, -0.3, -1.0, 0.3, -0.2, -0.9, 0.5, -0.3, -1.0, 0.6, -0.2, -0.9},
+ {0.9, -0.5, -0.1, 0.3, 1, -0.7, -0.3, 0.1, 0.7, -0.9, -0.5, 0.2, 0.6},
+ {0.5, 0.6, 0.1, -0.2, -0.7, 0.8, 0.6, 0.1, -0.5, -0.7, 0.7, 0.3, 0.0},
+ }
+
+ // Define the axis labels for the heatmap.
+ headerData := pterm.HeatmapAxis{
+ XAxis: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"},
+ YAxis: []string{"1", "2", "3", "4", "5"},
+ }
+
+ // Print an informational message.
+ pterm.Info.Println("The following table has no rgb (supported by every terminal), no axis data and no legend.")
+ pterm.Println()
+
+ // Create the heatmap with the specified data and options, and render it.
+ pterm.DefaultHeatmap.WithData(data).WithBoxed(false).WithAxisData(headerData).WithLegend(false).Render()
+}
+
+```
+
+
+
+### interactive_confirm/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_confirm/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Show an interactive confirmation dialog and get the result.
+ result, _ := pterm.DefaultInteractiveConfirm.Show()
+
+ // Print a blank line for better readability.
+ pterm.Println()
+
+ // Print the user's answer in a formatted way.
+ pterm.Info.Printfln("You answered: %s", boolToText(result))
+}
+
+// boolToText converts a boolean value to a colored text.
+// If the value is true, it returns a green "Yes".
+// If the value is false, it returns a red "No".
+func boolToText(b bool) string {
+ if b {
+ return pterm.Green("Yes")
+ }
+ return pterm.Red("No")
+}
+
+```
+
+
+
+### interactive_continue/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_continue/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Create an interactive continue prompt with default settings
+ // This will pause the program execution until the user presses enter
+ // The message displayed is "Press 'Enter' to continue..."
+ prompt := pterm.DefaultInteractiveContinue
+
+ // Show the prompt and wait for user input
+ // The returned result is the user's input (should be empty as it's a continue prompt)
+ // The second return value is an error which is ignored here
+ result, _ := prompt.Show()
+
+ // Print a blank line for better readability
+ pterm.Println()
+
+ // Print the user's input with an info prefix
+ // As this is a continue prompt, the input should be empty
+ pterm.Info.Printfln("You answered: %s", result)
+}
+
+```
+
+
+
+### interactive_multiselect/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_multiselect/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "fmt"
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Initialize an empty slice to hold the options.
+ var options []string
+
+ // Populate the options slice with 100 options.
+ for i := 0; i < 100; i++ {
+ options = append(options, fmt.Sprintf("Option %d", i))
+ }
+
+ // Add 5 more options to the slice, indicating the availability of fuzzy searching.
+ for i := 0; i < 5; i++ {
+ options = append(options, fmt.Sprintf("You can use fuzzy searching (%d)", i))
+ }
+
+ // Use PTerm's interactive multiselect to present the options to the user and capture their selections.
+ // The Show() method displays the options and waits for user input.
+ selectedOptions, _ := pterm.DefaultInteractiveMultiselect.WithOptions(options).Show()
+
+ // Print the selected options, highlighted in green.
+ pterm.Info.Printfln("Selected options: %s", pterm.Green(selectedOptions))
+}
+
+```
+
+
+
+### interactive_multiselect/custom-checkmarks
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_multiselect/custom-checkmarks/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "fmt"
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Initialize an empty slice to hold the options
+ var options []string
+
+ // Populate the options slice with 5 options
+ for i := 0; i < 5; i++ {
+ options = append(options, fmt.Sprintf("Option %d", i))
+ }
+
+ // Create a new interactive multiselect printer with the options
+ // Disable the filter and define the checkmark symbols
+ printer := pterm.DefaultInteractiveMultiselect.
+ WithOptions(options).
+ WithFilter(false).
+ WithCheckmark(&pterm.Checkmark{Checked: pterm.Green("+"), Unchecked: pterm.Red("-")})
+
+ // Show the interactive multiselect and get the selected options
+ selectedOptions, _ := printer.Show()
+
+ // Print the selected options
+ pterm.Info.Printfln("Selected options: %s", pterm.Green(selectedOptions))
+}
+
+```
+
+
+
+### interactive_multiselect/custom-keys
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_multiselect/custom-keys/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "atomicgo.dev/keyboard/keys"
+ "fmt"
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Initialize an empty slice to hold the options
+ var options []string
+
+ // Populate the options slice with 5 options
+ for i := 0; i < 5; i++ {
+ options = append(options, fmt.Sprintf("Option %d", i))
+ }
+
+ // Create a new interactive multiselect printer with the options
+ // Disable the filter and set the keys for confirming and selecting options
+ printer := pterm.DefaultInteractiveMultiselect.
+ WithOptions(options).
+ WithFilter(false).
+ WithKeyConfirm(keys.Enter).
+ WithKeySelect(keys.Space)
+
+ // Show the interactive multiselect and get the selected options
+ selectedOptions, _ := printer.Show()
+
+ // Print the selected options
+ pterm.Info.Printfln("Selected options: %s", pterm.Green(selectedOptions))
+}
+
+```
+
+
+
+### interactive_select/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_select/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "fmt"
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Initialize an empty slice to hold the options
+ var options []string
+
+ // Generate 100 options and add them to the options slice
+ for i := 0; i < 100; i++ {
+ options = append(options, fmt.Sprintf("Option %d", i))
+ }
+
+ // Generate 5 additional options with a specific message and add them to the options slice
+ for i := 0; i < 5; i++ {
+ options = append(options, fmt.Sprintf("You can use fuzzy searching (%d)", i))
+ }
+
+ // Use PTerm's interactive select feature to present the options to the user and capture their selection
+ // The Show() method displays the options and waits for the user's input
+ selectedOption, _ := pterm.DefaultInteractiveSelect.WithOptions(options).Show()
+
+ // Display the selected option to the user with a green color for emphasis
+ pterm.Info.Printfln("Selected option: %s", pterm.Green(selectedOption))
+}
+
+```
+
+
+
+### interactive_textinput/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_textinput/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Create an interactive text input with single line input mode and show it
+ result, _ := pterm.DefaultInteractiveTextInput.Show()
+
+ // Print a blank line for better readability
+ pterm.Println()
+
+ // Print the user's answer with an info prefix
+ pterm.Info.Printfln("You answered: %s", result)
+}
+
+```
+
+
+
+### interactive_textinput/default-value
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_textinput/default-value/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Create an interactive text input with single line input mode and show it
+ result, _ := pterm.DefaultInteractiveTextInput.WithDefaultValue("Some default value").Show()
+
+ // Print a blank line for better readability
+ pterm.Println()
+
+ // Print the user's answer with an info prefix
+ pterm.Info.Printfln("You answered: %s", result)
+}
+
+```
+
+
+
+### interactive_textinput/multi-line
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_textinput/multi-line/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Create a default interactive text input with multi-line enabled.
+ // This allows the user to input multiple lines of text.
+ textInput := pterm.DefaultInteractiveTextInput.WithMultiLine()
+
+ // Show the text input to the user and store the result.
+ // The second return value (an error) is ignored with '_'.
+ result, _ := textInput.Show()
+
+ // Print a blank line for better readability in the output.
+ pterm.Println()
+
+ // Print the user's input prefixed with an informational message.
+ // The '%s' placeholder is replaced with the user's input.
+ pterm.Info.Printfln("You answered: %s", result)
+}
+
+```
+
+
+
+### interactive_textinput/password
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_textinput/password/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Create an interactive text input with a mask for password input
+ passwordInput := pterm.DefaultInteractiveTextInput.WithMask("*")
+
+ // Show the password input prompt and store the result
+ result, _ := passwordInput.Show("Enter your password")
+
+ // Get the default logger from PTerm
+ logger := pterm.DefaultLogger
+
+ // Log the received password (masked)
+ // Note: In a real-world application, you should never log passwords
+ logger.Info("Password received", logger.Args("password", result))
+}
+
+```
+
+
+
+### logger/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/logger/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+ "time"
+)
+
+func main() {
+ // Create a logger with trace level
+ logger := pterm.DefaultLogger.WithLevel(pterm.LogLevelTrace)
+
+ // Log a trace level message
+ logger.Trace("Doing not so important stuff", logger.Args("priority", "super low"))
+
+ // Pause for 3 seconds
+ sleep()
+
+ // Define a map with interesting stuff
+ interstingStuff := map[string]any{
+ "when were crayons invented": "1903",
+ "what is the meaning of life": 42,
+ "is this interesting": true,
+ }
+
+ // Log a debug level message with arguments from the map
+ logger.Debug("This might be interesting", logger.ArgsFromMap(interstingStuff))
+
+ // Pause for 3 seconds
+ sleep()
+
+ // Log an info level message
+ logger.Info("That was actually interesting", logger.Args("such", "wow"))
+
+ // Pause for 3 seconds
+ sleep()
+
+ // Log a warning level message
+ logger.Warn("Oh no, I see an error coming to us!", logger.Args("speed", 88, "measures", "mph"))
+
+ // Pause for 3 seconds
+ sleep()
+
+ // Log an error level message
+ logger.Error("Damn, here it is!", logger.Args("error", "something went wrong"))
+
+ // Pause for 3 seconds
+ sleep()
+
+ // Log an info level message with a long text that will be automatically wrapped
+ logger.Info("But what's really cool is, that you can print very long logs, and PTerm will automatically wrap them for you! Say goodbye to text, that has weird line breaks!", logger.Args("very", "long"))
+
+ // Pause for 3 seconds
+ sleep()
+
+ // Log a fatal level message
+ logger.Fatal("Oh no, this process is getting killed!", logger.Args("fatal", true))
+}
+
+// Function to pause the execution for 3 seconds
+func sleep() {
+ time.Sleep(time.Second * 3)
+}
+
+```
+
+
+
+### logger/custom-key-styles
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/logger/custom-key-styles/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Create a logger with a level of Trace or higher.
+ logger := pterm.DefaultLogger.WithLevel(pterm.LogLevelTrace)
+
+ // Define a new style for the "priority" key.
+ priorityStyle := map[string]pterm.Style{
+ "priority": *pterm.NewStyle(pterm.FgRed),
+ }
+
+ // Overwrite all key styles with the new map.
+ logger = logger.WithKeyStyles(priorityStyle)
+
+ // Log an info message. The "priority" key will be displayed in red.
+ logger.Info("The priority key should now be red", logger.Args("priority", "low", "foo", "bar"))
+
+ // Define a new style for the "foo" key.
+ fooStyle := *pterm.NewStyle(pterm.FgBlue)
+
+ // Append the new style to the existing ones.
+ logger.AppendKeyStyle("foo", fooStyle)
+
+ // Log another info message. The "foo" key will be displayed in blue.
+ logger.Info("The foo key should now be blue", logger.Args("priority", "low", "foo", "bar"))
+}
+
+```
+
+
+
+### logger/default
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/logger/default/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+ "time"
+)
+
+func main() {
+ // Create a logger with a level of Trace or higher.
+ logger := pterm.DefaultLogger.WithLevel(pterm.LogLevelTrace)
+
+ // Log a trace message with additional arguments.
+ logger.Trace("Doing not so important stuff", logger.Args("priority", "super low"))
+
+ // Create a map of interesting stuff.
+ interstingStuff := map[string]any{
+ "when were crayons invented": "1903",
+ "what is the meaning of life": 42,
+ "is this interesting": true,
+ }
+
+ // Log a debug message with arguments from a map.
+ logger.Debug("This might be interesting", logger.ArgsFromMap(interstingStuff))
+
+ // Log an info message with additional arguments.
+ logger.Info("That was actually interesting", logger.Args("such", "wow"))
+
+ // Log a warning message with additional arguments.
+ logger.Warn("Oh no, I see an error coming to us!", logger.Args("speed", 88, "measures", "mph"))
+
+ // Log an error message with additional arguments.
+ logger.Error("Damn, here it is!", logger.Args("error", "something went wrong"))
+
+ // Log an info message with additional arguments. PTerm will automatically wrap long logs.
+ logger.Info("But what's really cool is, that you can print very long logs, and PTerm will automatically wrap them for you! Say goodbye to text, that has weird line breaks!", logger.Args("very", "long"))
+
+ // Pause for 2 seconds.
+ time.Sleep(time.Second * 2)
+
+ // Log a fatal message with additional arguments. This will terminate the process.
+ logger.Fatal("Oh no, this process is getting killed!", logger.Args("fatal", true))
+}
+
+```
+
+
+
+### logger/json
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/logger/json/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Create a logger with Trace level and JSON formatter
+ logger := pterm.DefaultLogger.WithLevel(pterm.LogLevelTrace).WithFormatter(pterm.LogFormatterJSON)
+
+ // Log a Trace level message with additional arguments
+ logger.Trace("Doing not so important stuff", logger.Args("priority", "super low"))
+
+ // Create a map of interesting stuff
+ interestingStuff := map[string]any{
+ "when were crayons invented": "1903",
+ "what is the meaning of life": 42,
+ "is this interesting": true,
+ }
+
+ // Log a Debug level message with arguments from the map
+ logger.Debug("This might be interesting", logger.ArgsFromMap(interestingStuff))
+
+ // Log Info, Warn, Error, and Fatal level messages with additional arguments
+ logger.Info("That was actually interesting", logger.Args("such", "wow"))
+ logger.Warn("Oh no, I see an error coming to us!", logger.Args("speed", 88, "measures", "mph"))
+ logger.Error("Damn, here it is!", logger.Args("error", "something went wrong"))
+ logger.Info("But what's really cool is, that you can print very long logs, and PTerm will automatically wrap them for you! Say goodbye to text, that has weird line breaks!", logger.Args("very", "long"))
+ logger.Fatal("Oh no, this process is getting killed!", logger.Args("fatal", true))
+}
+
+```
+
+
+
+### logger/with-caller
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/logger/with-caller/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Create a logger with Trace level and caller information
+ logger := pterm.DefaultLogger.WithLevel(pterm.LogLevelTrace).WithCaller()
+
+ // Log a trace message with additional arguments
+ logger.Trace("Doing not so important stuff", logger.Args("priority", "super low"))
+
+ // Create a map of interesting stuff
+ interestingStuff := map[string]any{
+ "when were crayons invented": "1903",
+ "what is the meaning of life": 42,
+ "is this interesting": true,
+ }
+
+ // Log a debug message with arguments from a map
+ logger.Debug("This might be interesting", logger.ArgsFromMap(interestingStuff))
+
+ // Log an info message with additional arguments
+ logger.Info("That was actually interesting", logger.Args("such", "wow"))
+
+ // Log a warning message with additional arguments
+ logger.Warn("Oh no, I see an error coming to us!", logger.Args("speed", 88, "measures", "mph"))
+
+ // Log an error message with additional arguments
+ logger.Error("Damn, here it is!", logger.Args("error", "something went wrong"))
+
+ // Log an info message with additional arguments. PTerm will automatically wrap long logs.
+ logger.Info("But what's really cool is, that you can print very long logs, and PTerm will automatically wrap them for you! Say goodbye to text, that has weird line breaks!", logger.Args("very", "long"))
+
+ // Log a fatal message with additional arguments. This will terminate the process.
+ logger.Fatal("Oh no, this process is getting killed!", logger.Args("fatal", true))
+}
+
+```
+
+
+
+### multiple-live-printers/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/multiple-live-printers/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "time"
+
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Create a multi printer for managing multiple printers
+ multi := pterm.DefaultMultiPrinter
+
+ // Create two spinners with their own writers
+ spinner1, _ := pterm.DefaultSpinner.WithWriter(multi.NewWriter()).Start("Spinner 1")
+ spinner2, _ := pterm.DefaultSpinner.WithWriter(multi.NewWriter()).Start("Spinner 2")
+
+ // Create five progress bars with their own writers and a total of 100
+ pb1, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 1")
+ pb2, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 2")
+ pb3, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 3")
+ pb4, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 4")
+ pb5, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 5")
+
+ // Start the multi printer
+ multi.Start()
+
+ // Increment progress bars and spinners based on certain conditions
+ for i := 1; i <= 100; i++ {
+ pb1.Increment() // Increment progress bar 1 every iteration
+
+ if i%2 == 0 {
+ pb2.Add(3) // Add 3 to progress bar 2 every even iteration
+ }
+
+ if i%5 == 0 {
+ pb3.Increment() // Increment progress bar 3 every 5th iteration
+ }
+
+ if i%10 == 0 {
+ pb4.Increment() // Increment progress bar 4 every 10th iteration
+ }
+
+ if i%3 == 0 {
+ pb5.Increment() // Increment progress bar 5 every 3rd iteration
+ }
+
+ if i%50 == 0 {
+ spinner1.Success("Spinner 1 is done!") // Mark spinner 1 as successful every 50th iteration
+ }
+
+ if i%60 == 0 {
+ spinner2.Fail("Spinner 2 failed!") // Mark spinner 2 as failed every 60th iteration
+ }
+
+ time.Sleep(time.Millisecond * 50) // Sleep for 50 milliseconds between each iteration
+ }
+
+ // Stop the multi printer
+ multi.Stop()
+}
+
+```
+
+
+
+### panel/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/panel/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Define panels in a 2D 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"},
+ },
+ }
+
+ // Render the panels with a padding of 5
+ _ = pterm.DefaultPanel.WithPanels(panels).WithPadding(5).Render()
+}
+
+```
+
+
+
+### paragraph/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/paragraph/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Using the default paragraph printer to print a long text.
+ // The text is split at the spaces, which is useful for continuous text of all kinds.
+ // The line width can be manually adjusted if needed.
+ 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")
+
+ // Printing a line space for separation.
+ pterm.Println()
+
+ // Printing a long text without using the paragraph printer.
+ // The default Println() function is used here, which does not provide intelligent splitting.
+ 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/customized
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/paragraph/customized/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Define a long text to be printed as a paragraph.
+ longText := "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 the long text as a paragraph with a custom maximal width of 60 characters.
+ pterm.DefaultParagraph.WithMaxWidth(60).Println(longText)
+
+ // Print a line space to separate the paragraph from the following text.
+ pterm.Println()
+
+ // Define another long text to be printed without a paragraph printer.
+ longTextWithoutParagraph := "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"
+
+ // Print the long text without using a paragraph printer.
+ pterm.Println(longTextWithoutParagraph)
+}
+
+```
+
+
+
+### prefix/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/prefix/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Enable debug messages in PTerm.
+ pterm.EnableDebugMessages()
+
+ // Print a debug message with PTerm.
+ pterm.Debug.Println("Hello, World!")
+
+ // Print an informational message with PTerm.
+ pterm.Info.Println("Hello, World!")
+
+ // Print a success message with PTerm.
+ pterm.Success.Println("Hello, World!")
+
+ // Print a warning message with PTerm.
+ pterm.Warning.Println("Hello, World!")
+
+ // Print an error message with PTerm. This will also display the filename and line number in the terminal.
+ pterm.Error.Println("Errors show the filename and linenumber inside the terminal!")
+
+ // Print an informational message with PTerm, with line number.
+ // This demonstrates that other PrefixPrinters can also display line numbers.
+ pterm.Info.WithShowLineNumber().Println("Other PrefixPrinters can do that too!")
+
+ // Temporarily set Fatal to false, so that the CI won't crash.
+ // This will print a fatal message with PTerm, but won't terminate the program.
+ pterm.Fatal.WithFatal(false).Println("Hello, World!")
+}
+
+```
+
+
+
+### progressbar/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/progressbar/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "strings"
+ "time"
+
+ "github.com/pterm/pterm"
+)
+
+// Slice of strings representing names of pseudo applications to be downloaded.
+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 a progressbar with the total steps equal to the number of items in fakeInstallList.
+ // Set the initial title of the progressbar to "Downloading stuff".
+ p, _ := pterm.DefaultProgressbar.WithTotal(len(fakeInstallList)).WithTitle("Downloading stuff").Start()
+
+ // Loop over each item in the fakeInstallList.
+ for i := 0; i < p.Total; i++ {
+ // Simulate a slow download for the 7th item.
+ if i == 6 {
+ time.Sleep(time.Second * 3)
+ }
+
+ // Update the title of the progressbar with the current item being downloaded.
+ p.UpdateTitle("Downloading " + fakeInstallList[i])
+
+ // Print a success message for the current download. This will be printed above the progressbar.
+ pterm.Success.Println("Downloading " + fakeInstallList[i])
+
+ // Increment the progressbar by one to indicate progress.
+ p.Increment()
+
+ // Pause for 350 milliseconds to simulate the time taken for each download.
+ time.Sleep(time.Millisecond * 350)
+ }
+}
+
+```
+
+
+
+### progressbar/multiple
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/progressbar/multiple/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "time"
+
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Create a multi printer instance from the default one
+ multi := pterm.DefaultMultiPrinter
+
+ // Create five progress bars with a total of 100 units each, and assign each a new writer from the multi printer
+ pb1, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 1")
+ pb2, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 2")
+ pb3, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 3")
+ pb4, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 4")
+ pb5, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 5")
+
+ // Start the multi printer
+ multi.Start()
+
+ // Loop to increment progress bars based on certain conditions
+ for i := 1; i <= 100; i++ {
+ pb1.Increment() // Increment the first progress bar at each iteration
+
+ if i%2 == 0 {
+ pb2.Add(3) // Add 3 units to the second progress bar at every even iteration
+ }
+
+ if i%5 == 0 {
+ pb3.Increment() // Increment the third progress bar at every fifth iteration
+ }
+
+ if i%10 == 0 {
+ pb4.Increment() // Increment the fourth progress bar at every tenth iteration
+ }
+
+ if i%3 == 0 {
+ pb5.Increment() // Increment the fifth progress bar at every third iteration
+ }
+
+ time.Sleep(time.Millisecond * 50) // Pause for 50 milliseconds at each iteration
+ }
+
+ // Stop the multi printer
+ multi.Stop()
+}
+
+```
+
+
+
+### section/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/section/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Create a section with level one and print it.
+ pterm.DefaultSection.Println("This is a section!")
+
+ // Print an informational message.
+ pterm.Info.Println("And here is some text.\nThis text could be anything.\nBasically it's just a placeholder")
+
+ // Create a section with level two and print it.
+ pterm.DefaultSection.WithLevel(2).Println("This is another section!")
+
+ // Print another informational message.
+ pterm.Info.Println("And this is\nmore placeholder text")
+}
+
+```
+
+
+
+### slog/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/slog/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "log/slog"
+
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Create a new slog handler with the default PTerm logger
+ handler := pterm.NewSlogHandler(&pterm.DefaultLogger)
+
+ // Create a new slog logger with the handler
+ logger := slog.New(handler)
+
+ // Log a debug message (won't show by default)
+ logger.Debug("This is a debug message that won't show")
+
+ // Change the log level to debug to enable debug messages
+ pterm.DefaultLogger.Level = pterm.LogLevelDebug
+
+ // Log a debug message (will show because debug level is enabled)
+ logger.Debug("This is a debug message", "changedLevel", true)
+
+ // Log an info message
+ logger.Info("This is an info message")
+
+ // Log a warning message
+ logger.Warn("This is a warning message")
+
+ // Log an error message
+ logger.Error("This is an error message")
+}
+
+```
+
+
+
+### spinner/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/spinner/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "time"
+
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Create and start a fork of the default spinner.
+ spinnerInfo, _ := pterm.DefaultSpinner.Start("Some informational action...")
+ time.Sleep(time.Second * 2) // Simulate 3 seconds of processing something.
+ spinnerInfo.Info() // Resolve spinner with information message.
+
+ // 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.
+ spinnerNochange, _ := pterm.DefaultSpinner.Start("Checking something important... (will result in no change)")
+ // Replace the InfoPrinter with a custom "NOCHG" one
+ spinnerNochange.InfoPrinter = &pterm.PrefixPrinter{
+ MessageStyle: &pterm.Style{pterm.FgLightBlue},
+ Prefix: pterm.Prefix{
+ Style: &pterm.Style{pterm.FgBlack, pterm.BgLightBlue},
+ Text: " NOCHG ",
+ },
+ }
+ time.Sleep(time.Second * 2) // Simulate 3 seconds of processing something.
+ spinnerNochange.Info("No change were required") // 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.
+}
+
+```
+
+
+
+### spinner/multiple
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/spinner/multiple/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "time"
+
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Create a multi printer. This allows multiple spinners to print simultaneously.
+ multi := pterm.DefaultMultiPrinter
+
+ // Create and start spinner 1 with a new writer from the multi printer.
+ // The spinner will display the message "Spinner 1".
+ spinner1, _ := pterm.DefaultSpinner.WithWriter(multi.NewWriter()).Start("Spinner 1")
+
+ // Create and start spinner 2 with a new writer from the multi printer.
+ // The spinner will display the message "Spinner 2".
+ spinner2, _ := pterm.DefaultSpinner.WithWriter(multi.NewWriter()).Start("Spinner 2")
+
+ // Create and start spinner 3 with a new writer from the multi printer.
+ // The spinner will display the message "Spinner 3".
+ spinner3, _ := pterm.DefaultSpinner.WithWriter(multi.NewWriter()).Start("Spinner 3")
+
+ // Start the multi printer. This will start printing all the spinners.
+ multi.Start()
+
+ // Wait for 1 second.
+ time.Sleep(time.Millisecond * 1000)
+
+ // Stop spinner 1 with a success message.
+ spinner1.Success("Spinner 1 is done!")
+
+ // Wait for 750 milliseconds.
+ time.Sleep(time.Millisecond * 750)
+
+ // Stop spinner 2 with a failure message.
+ spinner2.Fail("Spinner 2 failed!")
+
+ // Wait for 500 milliseconds.
+ time.Sleep(time.Millisecond * 500)
+
+ // Stop spinner 3 with a warning message.
+ spinner3.Warning("Spinner 3 has a warning!")
+
+ // Stop the multi printer. This will stop printing all the spinners.
+ multi.Stop()
+}
+
+```
+
+
+
+### style/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/style/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Define a primary style with light cyan foreground, gray background, and bold text
+ primary := pterm.NewStyle(pterm.FgLightCyan, pterm.BgGray, pterm.Bold)
+
+ // Define a secondary style with light green foreground, white background, and italic text
+ secondary := pterm.NewStyle(pterm.FgLightGreen, pterm.BgWhite, pterm.Italic)
+
+ // Print "Hello, World!" with the primary style
+ primary.Println("Hello, World!")
+
+ // Print "Hello, World!" with the secondary style
+ secondary.Println("Hello, World!")
+}
+
+```
+
+
+
+### table/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/table/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Define the data for the first table
+ tableData1 := pterm.TableData{
+ {"Firstname", "Lastname", "Email", "Note"},
+ {"Paul", "Dean", "augue@velitAliquam.co.uk", ""},
+ {"Callie", "Mckay", "nunc.sed@est.com", "这是一个测试, haha!"},
+ {"Libby", "Camacho", "lobortis@semper.com", "just a test, hey!"},
+ {"张", "小宝", "zhang@example.com", ""},
+ }
+
+ // Create a table with a header and the defined data, then render it
+ pterm.DefaultTable.WithHasHeader().WithData(tableData1).Render()
+
+ pterm.Println() // Blank line
+
+ // Define the data for the second table
+ tableData2 := pterm.TableData{
+ {"Firstname", "Lastname", "Email"},
+ {"Paul\n\nNewline", "Dean", "augue@velitAliquam.co.uk"},
+ {"Callie", "Mckay", "nunc.sed@est.com\nNewline"},
+ {"Libby", "Camacho", "lobortis@semper.com"},
+ {"张", "小宝", "zhang@example.com"},
+ }
+
+ // Create another table with a header and the defined data, then render it
+ pterm.DefaultTable.WithHasHeader().WithData(tableData2).Render()
+}
+
+```
+
+
+
+### table/alternate-row-style
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/table/alternate-row-style/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Define the data for the table.
+ // Each inner slice represents a row in the table.
+ // The first row is considered as the header of the table.
+ alternateStyle := pterm.NewStyle(pterm.BgDarkGray)
+
+ tableData := pterm.TableData{
+ {"Firstname", "Lastname", "Email", "Note"},
+ {"Paul", "Dean", "augue@velitAliquam.co.uk", ""},
+ {"Callie", "Mckay", "nunc.sed@est.com", "这是一个测试, haha!"},
+ {"Libby", "Camacho", "lobortis@semper.com", "just a test, hey!"},
+ {"张", "小宝", "zhang@example.com", ""},
+ }
+
+ // Create a table with the defined data.
+ // The table has a header and is boxed.
+ // Finally, render the table to print it.
+ pterm.DefaultTable.WithHasHeader().WithBoxed().WithData(tableData).WithAlternateRowStyle(alternateStyle).Render()
+}
+
+```
+
+
+
+### table/boxed
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/table/boxed/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Define the data for the table.
+ // Each inner slice represents a row in the table.
+ // The first row is considered as the header of the table.
+ tableData := pterm.TableData{
+ {"Firstname", "Lastname", "Email", "Note"},
+ {"Paul", "Dean", "augue@velitAliquam.co.uk", ""},
+ {"Callie", "Mckay", "nunc.sed@est.com", "这是一个测试, haha!"},
+ {"Libby", "Camacho", "lobortis@semper.com", "just a test, hey!"},
+ {"张", "小宝", "zhang@example.com", ""},
+ }
+
+ // Create a table with the defined data.
+ // The table has a header and is boxed.
+ // Finally, render the table to print it.
+ pterm.DefaultTable.WithHasHeader().WithBoxed().WithData(tableData).Render()
+}
+
+```
+
+
+
+### table/multiple-lines
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/table/multiple-lines/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Define the data for the table.
+ data := pterm.TableData{
+ {"Firstname", "Lastname", "Email"},
+ {"Paul\n\nNewline", "Dean", "augue@velitAliquam.co.uk"},
+ {"Callie", "Mckay", "nunc.sed@est.com\nNewline"},
+ {"Libby", "Camacho", "lobortis@semper.com"},
+ {"张", "小宝", "zhang@example.com"},
+ }
+
+ // Create and render the table.
+ // The options are chained in a single line for simplicity.
+ // The table has a header, a row separator, and a header row separator.
+ pterm.DefaultTable.WithHasHeader().WithRowSeparator("-").WithHeaderRowSeparator("-").WithData(data).Render()
+}
+
+```
+
+
+
+### table/right-alignment
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/table/right-alignment/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+ // Define the data for the table.
+ // Each inner slice represents a row in the table.
+ // The first row is considered as the header.
+ tableData := pterm.TableData{
+ {"Firstname", "Lastname", "Email", "Note"},
+ {"Paul", "Dean", "augue@velitAliquam.co.uk", ""},
+ {"Callie", "Mckay", "nunc.sed@est.com", "这是一个测试, haha!"},
+ {"Libby", "Camacho", "lobortis@semper.com", "just a test, hey!"},
+ {"张", "小宝", "zhang@example.com", ""},
+ }
+
+ // Create a table with the defined data.
+ // The table has a header and the text in the cells is right-aligned.
+ // The Render() method is used to print the table to the console.
+ pterm.DefaultTable.WithHasHeader().WithRightAlignment().WithData(tableData).Render()
+}
+
+```
+
+
+
+### theme/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/theme/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+ "reflect"
+ "time"
+)
+
+func main() {
+ // Print an informational message about the default theme styles.
+ pterm.Info.Println("These are the default theme styles.\nYou can modify them easily to your personal preference,\nor create new themes from scratch :)")
+
+ // Print a blank line for better readability.
+ pterm.Println()
+
+ // Get the value and type of the default theme.
+ v := reflect.ValueOf(pterm.ThemeDefault)
+ typeOfS := v.Type()
+
+ // Check if the type of the default theme is 'pterm.Theme'.
+ if typeOfS == reflect.TypeOf(pterm.Theme{}) {
+ // Iterate over each field in the default theme.
+ for i := 0; i < v.NumField(); i++ {
+ // Try to convert the field to 'pterm.Style'.
+ field, ok := v.Field(i).Interface().(pterm.Style)
+ if ok {
+ // Print the field name using its own style.
+ field.Println(typeOfS.Field(i).Name)
+ }
+ // Pause for a quarter of a second to make the output easier to read.
+ time.Sleep(time.Millisecond * 250)
+ }
+ }
+}
+
+```
+
+
+
+### tree/demo
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/tree/demo/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+)
+
+func main() {
+ // Define a tree structure using pterm.TreeNode
+ tree := pterm.TreeNode{
+ // The top node of the tree
+ Text: "Top node",
+ // The children of the top node
+ Children: []pterm.TreeNode{{
+ // A child node
+ Text: "Child node",
+ // The children of the child node
+ Children: []pterm.TreeNode{
+ // Grandchildren nodes
+ {Text: "Grandchild node"},
+ {Text: "Grandchild node"},
+ {Text: "Grandchild node"},
+ },
+ }},
+ }
+
+ // Render the tree with the defined structure as the root
+ pterm.DefaultTree.WithRoot(tree).Render()
+}
+
+```
+
+
+
+### tree/from-leveled-list
+
+![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/tree/from-leveled-list/animation.svg)
+
+
+
+SHOW SOURCE
+
+```go
+package main
+
+import (
+ "github.com/pterm/pterm"
+ "github.com/pterm/pterm/putils"
+)
+
+func main() {
+ // Define a leveled list to represent the structure of the directories.
+ leveledList := pterm.LeveledList{
+ {Level: 0, Text: "C:"},
+ {Level: 1, Text: "Users"},
+ {Level: 1, Text: "Windows"},
+ {Level: 1, Text: "Programs"},
+ {Level: 1, Text: "Programs(x86)"},
+ {Level: 1, Text: "dev"},
+ {Level: 0, Text: "D:"},
+ {Level: 0, Text: "E:"},
+ {Level: 1, Text: "Movies"},
+ {Level: 1, Text: "Music"},
+ {Level: 2, Text: "LinkinPark"},
+ {Level: 1, Text: "Games"},
+ {Level: 2, Text: "Shooter"},
+ {Level: 3, Text: "CallOfDuty"},
+ {Level: 3, Text: "CS:GO"},
+ {Level: 3, Text: "Battlefield"},
+ {Level: 4, Text: "Battlefield 1"},
+ {Level: 4, Text: "Battlefield 2"},
+ {Level: 0, Text: "F:"},
+ {Level: 1, Text: "dev"},
+ {Level: 2, Text: "dops"},
+ {Level: 2, Text: "PTerm"},
+ }
+
+ // Convert the leveled list into a tree structure.
+ root := putils.TreeFromLeveledList(leveledList)
+ root.Text = "Computer" // Set the root node text.
+
+ // Render the tree structure using the default tree printer.
+ 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/SECURITY.md b/vendor/github.com/pterm/pterm/SECURITY.md
new file mode 100644
index 0000000..3e4653f
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/SECURITY.md
@@ -0,0 +1,24 @@
+# PTerm Security Policy
+This security policy applies to the PTerm GitHub repository and outlines the process for reporting security issues and handling security incidents. The primary goal of this policy is to ensure the safety and integrity of the PTerm codebase and to minimize the impact of security incidents on our users.
+
+## 1. Overview
+PTerm is a command-line interface (CLI) tool library, and we believe the security risks associated with it are minimal. However, we recognize that vulnerabilities can still arise, and we are committed to addressing them promptly and transparently.
+
+## 2. Reporting Security Issues
+If you discover a security issue in PTerm, please follow these steps:
+
+Open a new issue in the PTerm GitHub repository, describing the security problem in detail.
+
+## 3. Vulnerable Dependencies
+If a dependency of PTerm is found to be vulnerable or infected and requires immediate updates, please follow these steps:
+
+1. Open a new issue in the PTerm GitHub repository, describing the vulnerable dependency and the need for an update.
+2. *Optional: Contact @MarvinJWendt directly via Twitter or Discord to alert them to the issue.*
+
+## 4. Incident Response
+Upon receiving a security report, the PTerm team will:
+
+1. Acknowledge receipt of the report and review the issue.
+2. Investigate the issue and determine the severity and impact.
+3. Develop and implement a fix or mitigation plan, as necessary.
+4. Update the PTerm repository and notify users, if applicable.
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..ce233c0
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/area_printer.go
@@ -0,0 +1,139 @@
+package pterm
+
+import (
+ "io"
+ "strings"
+
+ "atomicgo.dev/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
+}
+
+// SetWriter sets the writer for the AreaPrinter.
+func (p *AreaPrinter) SetWriter(writer io.Writer) {
+
+}
+
+// Update overwrites the content of the AreaPrinter.
+// Can be used live.
+func (p *AreaPrinter) Update(text ...any) {
+ 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 ...any) (*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 {
+ if !p.isActive {
+ return nil
+ }
+ 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
+}
+
+// Clear is a 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..bc11da2
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/atoms.go
@@ -0,0 +1,42 @@
+package pterm
+
+// Checkmark is used in the interactive multiselect printer.
+type Checkmark struct {
+ Checked string
+ Unchecked string
+}
+
+// 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..dd4ba3c
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/barchart.go
@@ -0,0 +1,424 @@
+package pterm
+
+import (
+ "io"
+ "strconv"
+ "strings"
+
+ "github.com/mattn/go-runewidth"
+
+ "github.com/pterm/pterm/internal"
+)
+
+// BarChartPrinter is used to print bar charts.
+type BarChartPrinter struct {
+ Writer io.Writer
+ 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
+}
+
+// WithWriter sets the custom Writer.
+func (p BarChartPrinter) WithWriter(writer io.Writer) *BarChartPrinter {
+ p.Writer = writer
+ 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 strings.Builder
+
+ 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)
+ }
+ }
+ }
+ result, _ := DefaultPanel.WithPanels(panels).Srender()
+ return result, 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.WriteString(barLine)
+ }
+ ret.WriteByte('\n')
+ }
+ }
+
+ return ret.String(), nil
+}
+
+// Render prints the Template to the terminal.
+func (p BarChartPrinter) Render() error {
+ s, _ := p.Srender()
+ Fprintln(p.Writer, 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..a3e5274
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/basic_text_printer.go
@@ -0,0 +1,123 @@
+package pterm
+
+import (
+ "fmt"
+ "io"
+)
+
+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
+ Writer io.Writer
+}
+
+// WithStyle adds a style to the printer.
+func (p BasicTextPrinter) WithStyle(style *Style) *BasicTextPrinter {
+ p.Style = style
+ return &p
+}
+
+func (p BasicTextPrinter) WithWriter(writer io.Writer) *BasicTextPrinter {
+ p.Writer = writer
+ 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 ...any) 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 ...any) 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 ...any) 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 ...any) string {
+ return p.Sprintf(format, a...) + "\n"
+}
+
+// Print formats using the default formats for its operands and writes to provided writer.
+// 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 ...any) *TextPrinter {
+ Fprint(p.Writer, p.Sprint(a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Println formats using the default formats for its operands and writes to provided writer.
+// 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 ...any) *TextPrinter {
+ Fprint(p.Writer, p.Sprintln(a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Printf formats according to a format specifier and writes to provided writer.
+// It returns the number of bytes written and any write error encountered.
+func (p *BasicTextPrinter) Printf(format string, a ...any) *TextPrinter {
+ Fprint(p.Writer, p.Sprintf(format, a...))
+ tp := TextPrinter(p)
+ return &tp
+}
+
+// Printfln formats according to a format specifier and writes to provided writer.
+// 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 ...any) *TextPrinter {
+ Fprint(p.Writer, 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 ...any) *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 ...any) *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..6346b48
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/bigtext_printer.go
@@ -0,0 +1,551 @@
+package pterm
+
+import (
+ "io"
+ "strings"
+
+ "github.com/gookit/color"
+
+ "github.com/mattn/go-runewidth"
+
+ "github.com/pterm/pterm/internal"
+)
+
+// Letters is a slice of Letter.
+type Letters []Letter
+
+// Letter is an object, which holds a string and a specific Style for it.
+type Letter struct {
+ String string
+ Style *Style
+ RGB RGB
+}
+
+// WithStyle returns a new Letter with a specific Style.
+func (l Letter) WithStyle(style *Style) *Letter {
+ l.Style = style
+ return &l
+}
+
+// WithRGB returns a new Letter with a specific RGB color (overwrites style).
+func (l Letter) WithRGB(rgb RGB) *Letter {
+ l.RGB = rgb
+ 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
+ Writer io.Writer
+}
+
+// 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
+}
+
+// WithWriter sets the custom Writer.
+func (p BigTextPrinter) WithWriter(writer io.Writer) *BigTextPrinter {
+ p.Writer = writer
+ return &p
+}
+
+// Srender renders the BigText as a string.
+func (p BigTextPrinter) Srender() (string, error) {
+ var ret strings.Builder
+
+ if RawOutput {
+ for _, letter := range p.Letters {
+ ret.WriteString(letter.String)
+ }
+ return ret.String(), 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,
+ RGB: l.RGB,
+ })
+ }
+ }
+
+ 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)
+ }
+
+ if letter.RGB != (RGB{}) && (color.IsSupportRGBColor() || internal.RunsInCi()) {
+ ret.WriteString(letter.RGB.Sprint(letterLine))
+ } else {
+ ret.WriteString(letter.Style.Sprint(letterLine))
+ }
+ }
+ ret.WriteByte('\n')
+ }
+
+ return ret.String(), nil
+}
+
+// Render prints the BigText to the terminal.
+func (p BigTextPrinter) Render() error {
+ s, _ := p.Srender()
+ Fprintln(p.Writer, 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..8007d9f
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/box_printer.go
@@ -0,0 +1,371 @@
+package pterm
+
+import (
+ "fmt"
+ "io"
+ "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
+ Writer io.Writer
+}
+
+// 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
+}
+
+// WithWriter sets the custom Writer.
+func (p BoxPrinter) WithWriter(writer io.Writer) *BoxPrinter {
+ p.Writer = writer
+ 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 ...any) 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) < internal.GetStringMaxWidth(p.Title) {
+ p.RightPadding = internal.GetStringMaxWidth(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 ...any) 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 ...any) 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 ...any) 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 ...any) *TextPrinter {
+ Fprint(p.Writer, 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 ...any) *TextPrinter {
+ Fprint(p.Writer, 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 ...any) *TextPrinter {
+ Fprint(p.Writer, 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 ...any) *TextPrinter {
+ Fprint(p.Writer, 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 ...any) *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 ...any) *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..de710a6
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/bulletlist_printer.go
@@ -0,0 +1,139 @@
+package pterm
+
+import (
+ "io"
+ "strings"
+)
+
+// 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
+}
+
+// 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
+ Writer io.Writer
+}
+
+// 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
+}
+
+// WithWriter sets the custom Writer.
+func (l BulletListPrinter) WithWriter(writer io.Writer) *BulletListPrinter {
+ l.Writer = writer
+ return &l
+}
+
+// Render prints the list to the terminal.
+func (l BulletListPrinter) Render() error {
+ s, _ := l.Srender()
+ Fprintln(l.Writer, s)
+
+ return nil
+}
+
+// Srender renders the list as a string.
+func (l BulletListPrinter) Srender() (string, error) {
+ var ret strings.Builder
+ 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
+ }
+ }
+
+ split := strings.Split(item.Text, "\n")
+ for i, line := range split {
+ ret.WriteString(strings.Repeat(" ", item.Level))
+ if i == 0 {
+ if item.Bullet == "" {
+ ret.WriteString(item.BulletStyle.Sprint(l.Bullet))
+ } else {
+ ret.WriteString(item.BulletStyle.Sprint(item.Bullet))
+ }
+ ret.WriteByte(' ')
+ } else {
+ ret.WriteString(strings.Repeat(" ", len(item.Bullet)))
+ ret.WriteString(" ")
+ }
+ ret.WriteString(item.TextStyle.Sprint(line))
+ ret.WriteByte('\n')
+ }
+ }
+ return ret.String(), 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..46a87f0
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/center_printer.go
@@ -0,0 +1,171 @@
+package pterm
+
+import (
+ "fmt"
+ "io"
+ "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
+ Writer io.Writer
+}
+
+// WithCenterEachLineSeparately centers each line separately.
+func (p CenterPrinter) WithCenterEachLineSeparately(b ...bool) *CenterPrinter {
+ bt := internal.WithBoolean(b)
+ p.CenterEachLineSeparately = bt
+ return &p
+}
+
+// WithWriter sets the custom Writer.
+func (p CenterPrinter) WithWriter(writer io.Writer) *CenterPrinter {
+ p.Writer = writer
+ 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 ...any) string {
+ if RawOutput {
+ return Sprint(a...)
+ }
+
+ lines := strings.Split(Sprint(a...), "\n")
+
+ var ret strings.Builder
+
+ if p.CenterEachLineSeparately {
+ for _, line := range lines {
+ margin := (GetTerminalWidth() - runewidth.StringWidth(RemoveColorFromString(line))) / 2
+ if margin >= 1 {
+ ret.WriteString(strings.Repeat(" ", margin))
+ }
+ ret.WriteString(line)
+ ret.WriteByte('\n')
+ }
+ return ret.String()
+ }
+
+ 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.WriteString(line)
+ ret.WriteByte('\n')
+ }
+
+ return ret.String()
+ }
+
+ for _, line := range lines {
+ ret.WriteString(strings.Repeat(" ", indent/2))
+ ret.WriteString(line)
+ ret.WriteByte('\n')
+ }
+
+ return ret.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.
+func (p CenterPrinter) Sprintln(a ...any) 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 ...any) 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 ...any) 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 ...any) *TextPrinter {
+ Fprint(p.Writer, 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 ...any) *TextPrinter {
+ Fprint(p.Writer, 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 ...any) *TextPrinter {
+ Fprint(p.Writer, 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 ...any) *TextPrinter {
+ Fprint(p.Writer, 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 ...any) *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 ...any) *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/codecov.yml b/vendor/github.com/pterm/pterm/codecov.yml
new file mode 100644
index 0000000..bfdc987
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/codecov.yml
@@ -0,0 +1,8 @@
+coverage:
+ status:
+ project:
+ default:
+ informational: true
+ patch:
+ default:
+ informational: true
diff --git a/vendor/github.com/pterm/pterm/color.go b/vendor/github.com/pterm/pterm/color.go
new file mode 100644
index 0000000..451b6ec
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/color.go
@@ -0,0 +1,383 @@
+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 ...any) 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 ...any) 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 ...any) 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 ...any) 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 ...any) *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 ...any) *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 ...any) *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 ...any) *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 (c Color) PrintOnError(a ...any) *TextPrinter {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ c.Println(err)
+ }
+ }
+ }
+
+ tp := TextPrinter(c)
+ 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 (c Color) PrintOnErrorf(format string, a ...any) *TextPrinter {
+ for _, arg := range a {
+ if err, ok := arg.(error); ok {
+ if err != nil {
+ c.Println(fmt.Errorf(format, err))
+ }
+ }
+ }
+
+ tp := TextPrinter(c)
+ return &tp
+}
+
+// String converts the color to a string. eg "35".
+func (c Color) String() string {
+ return fmt.Sprintf("%d", c)
+}
+
+// ToStyle converts the color to a style.
+func (c Color) ToStyle() *Style {
+ return &Style{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
+}
+
+// RemoveColor removes the given colors from the Style.
+func (s Style) RemoveColor(colors ...Color) Style {
+ ret := s
+
+ for _, c := range colors {
+ // remove via index
+ for i := 0; i < len(ret); i++ {
+ if ret[i] == c {
+ ret = append(ret[:i], ret[i+1:]...)
+ i--
+ }
+ }
+ }
+
+ 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 ...any) 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 ...any) 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 ...any) 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 ...any) 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 ...any) {
+ 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 ...any) {
+ 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 ...any) {
+ 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 ...any) {
+ 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/coverage.txt b/vendor/github.com/pterm/pterm/coverage.txt
new file mode 100644
index 0000000..330b7db
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/coverage.txt
@@ -0,0 +1,1030 @@
+mode: atomic
+github.com/pterm/pterm/internal/percentage.go:6.49,8.2 1 8
+github.com/pterm/pterm/internal/percentage.go:11.54,13.2 1 4
+github.com/pterm/pterm/internal/remove_and_count_prefix.go:7.66,11.2 3 0
+github.com/pterm/pterm/internal/title_in_line.go:10.71,12.10 2 0
+github.com/pterm/pterm/internal/title_in_line.go:18.2,18.12 1 0
+github.com/pterm/pterm/internal/title_in_line.go:12.10,14.3 1 0
+github.com/pterm/pterm/internal/title_in_line.go:14.8,16.3 1 0
+github.com/pterm/pterm/internal/title_in_line.go:22.66,30.2 5 0
+github.com/pterm/pterm/internal/map_range_to_range.go:3.75,4.26 1 4
+github.com/pterm/pterm/internal/map_range_to_range.go:7.2,7.73 1 4
+github.com/pterm/pterm/internal/map_range_to_range.go:4.26,6.3 1 0
+github.com/pterm/pterm/internal/max_text_width.go:11.38,14.24 3 0
+github.com/pterm/pterm/internal/max_text_width.go:19.2,19.12 1 0
+github.com/pterm/pterm/internal/max_text_width.go:14.24,15.55 1 0
+github.com/pterm/pterm/internal/max_text_width.go:15.55,17.4 1 0
+github.com/pterm/pterm/internal/center_text.go:10.48,13.32 3 2
+github.com/pterm/pterm/internal/center_text.go:36.2,37.26 2 2
+github.com/pterm/pterm/internal/center_text.go:41.2,41.39 1 2
+github.com/pterm/pterm/internal/center_text.go:13.32,14.41 1 4
+github.com/pterm/pterm/internal/center_text.go:14.41,17.32 3 1
+github.com/pterm/pterm/internal/center_text.go:24.4,24.41 1 1
+github.com/pterm/pterm/internal/center_text.go:17.32,18.31 1 11
+github.com/pterm/pterm/internal/center_text.go:22.5,22.52 1 11
+github.com/pterm/pterm/internal/center_text.go:18.31,21.6 2 2
+github.com/pterm/pterm/internal/center_text.go:24.41,28.5 3 3
+github.com/pterm/pterm/internal/center_text.go:29.9,33.4 3 3
+github.com/pterm/pterm/internal/center_text.go:37.26,39.3 1 6
+github.com/pterm/pterm/internal/longest_line.go:11.49,14.29 3 0
+github.com/pterm/pterm/internal/longest_line.go:20.2,20.16 1 0
+github.com/pterm/pterm/internal/longest_line.go:14.29,15.101 1 0
+github.com/pterm/pterm/internal/longest_line.go:15.101,17.4 1 0
+github.com/pterm/pterm/internal/with_boolean.go:4.33,5.17 1 0
+github.com/pterm/pterm/internal/with_boolean.go:8.2,8.13 1 0
+github.com/pterm/pterm/internal/with_boolean.go:5.17,7.3 1 0
+github.com/pterm/pterm/putils/download-with-progressbar.go:20.58,25.2 4 0
+github.com/pterm/pterm/putils/download-with-progressbar.go:29.121,32.16 3 0
+github.com/pterm/pterm/putils/download-with-progressbar.go:36.2,37.16 2 0
+github.com/pterm/pterm/putils/download-with-progressbar.go:41.2,45.16 4 0
+github.com/pterm/pterm/putils/download-with-progressbar.go:49.2,50.73 2 0
+github.com/pterm/pterm/putils/download-with-progressbar.go:55.2,56.16 2 0
+github.com/pterm/pterm/putils/download-with-progressbar.go:60.2,61.12 2 0
+github.com/pterm/pterm/putils/download-with-progressbar.go:32.16,34.3 1 0
+github.com/pterm/pterm/putils/download-with-progressbar.go:37.16,40.3 2 0
+github.com/pterm/pterm/putils/download-with-progressbar.go:45.16,47.3 1 0
+github.com/pterm/pterm/putils/download-with-progressbar.go:50.73,53.3 2 0
+github.com/pterm/pterm/putils/download-with-progressbar.go:56.16,58.3 1 0
+github.com/pterm/pterm/putils/download-with-progressbar.go:66.96,68.2 1 0
+github.com/pterm/pterm/putils/run-with-spinner.go:6.103,8.16 2 0
+github.com/pterm/pterm/putils/run-with-spinner.go:12.2,15.12 3 0
+github.com/pterm/pterm/putils/run-with-spinner.go:8.16,10.3 1 0
+github.com/pterm/pterm/putils/run-with-spinner.go:19.107,21.2 1 0
+github.com/pterm/pterm/putils/stats.go:11.70,13.29 2 0
+github.com/pterm/pterm/putils/stats.go:25.2,29.12 3 0
+github.com/pterm/pterm/putils/stats.go:13.29,18.17 4 0
+github.com/pterm/pterm/putils/stats.go:22.3,22.20 1 0
+github.com/pterm/pterm/putils/stats.go:18.17,20.4 1 0
+github.com/pterm/pterm/putils/tabledata-from-struct-slice.go:13.105,15.32 2 0
+github.com/pterm/pterm/putils/tabledata-from-struct-slice.go:18.2,21.30 3 0
+github.com/pterm/pterm/putils/tabledata-from-struct-slice.go:26.2,26.33 1 0
+github.com/pterm/pterm/putils/tabledata-from-struct-slice.go:30.2,33.33 3 0
+github.com/pterm/pterm/putils/tabledata-from-struct-slice.go:37.2,44.33 4 0
+github.com/pterm/pterm/putils/tabledata-from-struct-slice.go:52.2,52.26 1 0
+github.com/pterm/pterm/putils/tabledata-from-struct-slice.go:61.2,63.22 2 0
+github.com/pterm/pterm/putils/tabledata-from-struct-slice.go:15.32,17.3 1 0
+github.com/pterm/pterm/putils/tabledata-from-struct-slice.go:21.30,24.3 2 0
+github.com/pterm/pterm/putils/tabledata-from-struct-slice.go:26.33,28.3 1 0
+github.com/pterm/pterm/putils/tabledata-from-struct-slice.go:33.33,35.3 1 0
+github.com/pterm/pterm/putils/tabledata-from-struct-slice.go:44.33,45.16 1 0
+github.com/pterm/pterm/putils/tabledata-from-struct-slice.go:45.16,47.4 1 0
+github.com/pterm/pterm/putils/tabledata-from-struct-slice.go:47.9,49.4 1 0
+github.com/pterm/pterm/putils/tabledata-from-struct-slice.go:52.26,55.34 3 0
+github.com/pterm/pterm/putils/tabledata-from-struct-slice.go:59.3,59.36 1 0
+github.com/pterm/pterm/putils/tabledata-from-struct-slice.go:55.34,58.4 2 0
+github.com/pterm/pterm/putils/tabledata-from-struct-slice.go:69.79,71.2 1 0
+github.com/pterm/pterm/putils/tabledata_from_csv.go:11.56,13.2 1 1
+github.com/pterm/pterm/putils/tabledata_from_separated_values.go:13.99,14.57 1 3
+github.com/pterm/pterm/putils/tabledata_from_separated_values.go:18.2,18.8 1 3
+github.com/pterm/pterm/putils/tabledata_from_separated_values.go:14.57,16.3 1 6
+github.com/pterm/pterm/putils/tabledata_from_tsv.go:11.56,13.2 1 1
+github.com/pterm/pterm/rgb.go:23.42,25.2 1 14316
+github.com/pterm/pterm/rgb.go:28.32,30.2 1 28640
+github.com/pterm/pterm/rgb.go:33.45,38.19 4 12
+github.com/pterm/pterm/rgb.go:41.2,41.19 1 12
+github.com/pterm/pterm/rgb.go:45.2,46.16 2 8
+github.com/pterm/pterm/rgb.go:49.2,55.8 2 7
+github.com/pterm/pterm/rgb.go:38.19,40.3 1 4
+github.com/pterm/pterm/rgb.go:41.19,43.3 1 4
+github.com/pterm/pterm/rgb.go:46.16,48.3 1 1
+github.com/pterm/pterm/rgb.go:59.62,60.13 1 14416
+github.com/pterm/pterm/rgb.go:65.2,65.19 1 14416
+github.com/pterm/pterm/rgb.go:85.2,85.10 1 1
+github.com/pterm/pterm/rgb.go:60.13,64.3 3 2
+github.com/pterm/pterm/rgb.go:65.19,71.3 1 14411
+github.com/pterm/pterm/rgb.go:71.8,71.25 1 5
+github.com/pterm/pterm/rgb.go:71.25,74.18 3 4
+github.com/pterm/pterm/rgb.go:74.18,76.4 1 1
+github.com/pterm/pterm/rgb.go:76.9,77.36 1 3
+github.com/pterm/pterm/rgb.go:77.36,79.24 2 3
+github.com/pterm/pterm/rgb.go:79.24,81.6 1 3
+github.com/pterm/pterm/rgb.go:90.46,92.2 1 4224
+github.com/pterm/pterm/rgb.go:96.48,98.2 1 1950
+github.com/pterm/pterm/rgb.go:101.62,103.2 1 2052
+github.com/pterm/pterm/rgb.go:107.64,109.2 1 1944
+github.com/pterm/pterm/rgb.go:114.51,118.2 3 54
+github.com/pterm/pterm/rgb.go:123.53,127.2 3 978
+github.com/pterm/pterm/rgb.go:131.67,135.2 3 54
+github.com/pterm/pterm/rgb.go:140.69,144.2 3 972
+github.com/pterm/pterm/rgb.go:149.58,150.24 1 6
+github.com/pterm/pterm/rgb.go:158.2,159.12 2 6
+github.com/pterm/pterm/rgb.go:150.24,151.33 1 6
+github.com/pterm/pterm/rgb.go:151.33,152.18 1 3
+github.com/pterm/pterm/rgb.go:152.18,154.5 1 3
+github.com/pterm/pterm/rgb.go:165.74,166.24 1 6
+github.com/pterm/pterm/rgb.go:174.2,175.12 2 6
+github.com/pterm/pterm/rgb.go:166.24,167.33 1 6
+github.com/pterm/pterm/rgb.go:167.33,168.18 1 3
+github.com/pterm/pterm/rgb.go:168.18,170.5 1 3
+github.com/pterm/pterm/bigtext_printer.go:17.48,19.2 1 3
+github.com/pterm/pterm/bigtext_printer.go:22.71,26.23 3 6
+github.com/pterm/pterm/bigtext_printer.go:33.2,33.10 1 6
+github.com/pterm/pterm/bigtext_printer.go:26.23,31.3 1 19
+github.com/pterm/pterm/bigtext_printer.go:37.64,41.23 3 2
+github.com/pterm/pterm/bigtext_printer.go:49.2,49.10 1 2
+github.com/pterm/pterm/bigtext_printer.go:41.23,47.3 1 7
+github.com/pterm/pterm/bigtext_printer.go:60.49,63.2 2 1
+github.com/pterm/pterm/bigtext_printer.go:66.42,69.2 2 1
+github.com/pterm/pterm/bigtext_printer.go:72.46,75.2 2 1
+github.com/pterm/pterm/bigtext_printer.go:87.84,90.2 2 1
+github.com/pterm/pterm/bigtext_printer.go:93.73,95.33 2 5
+github.com/pterm/pterm/bigtext_printer.go:98.2,99.11 2 5
+github.com/pterm/pterm/bigtext_printer.go:95.33,97.3 1 6
+github.com/pterm/pterm/bigtext_printer.go:103.76,106.2 2 0
+github.com/pterm/pterm/bigtext_printer.go:109.51,112.15 2 8
+github.com/pterm/pterm/bigtext_printer.go:119.2,120.30 2 5
+github.com/pterm/pterm/bigtext_printer.go:130.2,132.31 2 5
+github.com/pterm/pterm/bigtext_printer.go:139.2,139.34 1 5
+github.com/pterm/pterm/bigtext_printer.go:161.2,161.17 1 5
+github.com/pterm/pterm/bigtext_printer.go:112.15,113.36 1 3
+github.com/pterm/pterm/bigtext_printer.go:116.3,116.18 1 3
+github.com/pterm/pterm/bigtext_printer.go:113.36,115.4 1 15
+github.com/pterm/pterm/bigtext_printer.go:120.30,121.47 1 20
+github.com/pterm/pterm/bigtext_printer.go:121.47,127.4 1 20
+github.com/pterm/pterm/bigtext_printer.go:132.31,134.20 2 20
+github.com/pterm/pterm/bigtext_printer.go:134.20,136.4 1 4
+github.com/pterm/pterm/bigtext_printer.go:139.34,140.37 1 21
+github.com/pterm/pterm/bigtext_printer.go:158.3,158.14 1 21
+github.com/pterm/pterm/bigtext_printer.go:140.37,144.28 4 100
+github.com/pterm/pterm/bigtext_printer.go:147.4,148.41 2 100
+github.com/pterm/pterm/bigtext_printer.go:152.4,152.29 1 100
+github.com/pterm/pterm/bigtext_printer.go:144.28,146.5 1 100
+github.com/pterm/pterm/bigtext_printer.go:148.41,150.5 1 7
+github.com/pterm/pterm/bigtext_printer.go:152.29,154.5 1 25
+github.com/pterm/pterm/bigtext_printer.go:154.10,156.5 1 75
+github.com/pterm/pterm/bigtext_printer.go:165.40,170.2 3 7
+github.com/pterm/pterm/panel_printer.go:36.63,39.2 2 96
+github.com/pterm/pterm/panel_printer.go:42.62,43.17 1 2
+github.com/pterm/pterm/panel_printer.go:46.2,47.11 2 2
+github.com/pterm/pterm/panel_printer.go:43.17,45.3 1 1
+github.com/pterm/pterm/panel_printer.go:51.74,52.23 1 20
+github.com/pterm/pterm/panel_printer.go:55.2,56.11 2 20
+github.com/pterm/pterm/panel_printer.go:52.23,54.3 1 1
+github.com/pterm/pterm/panel_printer.go:60.68,64.2 3 19
+github.com/pterm/pterm/panel_printer.go:67.75,70.2 2 19
+github.com/pterm/pterm/panel_printer.go:73.72,76.2 2 0
+github.com/pterm/pterm/panel_printer.go:78.45,80.33 2 45
+github.com/pterm/pterm/panel_printer.go:86.2,86.12 1 45
+github.com/pterm/pterm/panel_printer.go:80.33,81.32 1 99
+github.com/pterm/pterm/panel_printer.go:84.3,84.14 1 99
+github.com/pterm/pterm/panel_printer.go:81.32,83.4 1 117
+github.com/pterm/pterm/panel_printer.go:90.49,93.15 2 96
+github.com/pterm/pterm/panel_printer.go:97.2,97.26 1 51
+github.com/pterm/pterm/panel_printer.go:103.2,103.36 1 51
+github.com/pterm/pterm/panel_printer.go:111.2,111.26 1 51
+github.com/pterm/pterm/panel_printer.go:119.2,121.23 2 51
+github.com/pterm/pterm/panel_printer.go:131.2,131.35 1 51
+github.com/pterm/pterm/panel_printer.go:181.2,181.17 1 51
+github.com/pterm/pterm/panel_printer.go:93.15,95.3 1 45
+github.com/pterm/pterm/panel_printer.go:97.26,98.31 1 104
+github.com/pterm/pterm/panel_printer.go:98.31,100.4 1 126
+github.com/pterm/pterm/panel_printer.go:103.36,104.27 1 9
+github.com/pterm/pterm/panel_printer.go:104.27,105.32 1 18
+github.com/pterm/pterm/panel_printer.go:105.32,107.5 1 27
+github.com/pterm/pterm/panel_printer.go:111.26,112.27 1 104
+github.com/pterm/pterm/panel_printer.go:112.27,113.32 1 54
+github.com/pterm/pterm/panel_printer.go:113.32,115.5 1 72
+github.com/pterm/pterm/panel_printer.go:121.23,122.34 1 9
+github.com/pterm/pterm/panel_printer.go:122.34,123.29 1 27
+github.com/pterm/pterm/panel_printer.go:123.29,124.68 1 27
+github.com/pterm/pterm/panel_printer.go:124.68,126.6 1 21
+github.com/pterm/pterm/panel_printer.go:131.35,136.31 3 104
+github.com/pterm/pterm/panel_printer.go:140.3,140.40 1 104
+github.com/pterm/pterm/panel_printer.go:144.3,144.38 1 104
+github.com/pterm/pterm/panel_printer.go:151.3,151.34 1 104
+github.com/pterm/pterm/panel_printer.go:136.31,138.4 1 126
+github.com/pterm/pterm/panel_printer.go:140.40,142.4 1 126
+github.com/pterm/pterm/panel_printer.go:144.38,146.26 2 126
+github.com/pterm/pterm/panel_printer.go:146.26,148.5 1 104
+github.com/pterm/pterm/panel_printer.go:151.34,152.22 1 215
+github.com/pterm/pterm/panel_printer.go:152.22,153.43 1 215
+github.com/pterm/pterm/panel_printer.go:176.5,176.16 1 215
+github.com/pterm/pterm/panel_printer.go:153.43,157.28 4 312
+github.com/pterm/pterm/panel_printer.go:160.6,160.30 1 312
+github.com/pterm/pterm/panel_printer.go:163.6,164.28 2 312
+github.com/pterm/pterm/panel_printer.go:173.6,174.23 2 312
+github.com/pterm/pterm/panel_printer.go:157.28,159.7 1 285
+github.com/pterm/pterm/panel_printer.go:160.30,162.7 1 276
+github.com/pterm/pterm/panel_printer.go:164.28,165.44 1 285
+github.com/pterm/pterm/panel_printer.go:165.44,167.8 1 87
+github.com/pterm/pterm/panel_printer.go:168.12,169.51 1 27
+github.com/pterm/pterm/panel_printer.go:169.51,171.8 1 17
+github.com/pterm/pterm/panel_printer.go:185.38,190.2 3 92
+github.com/pterm/pterm/tree_printer.go:51.63,54.2 2 1
+github.com/pterm/pterm/tree_printer.go:57.63,60.2 2 1
+github.com/pterm/pterm/tree_printer.go:63.70,66.2 2 1
+github.com/pterm/pterm/tree_printer.go:69.75,72.2 2 1
+github.com/pterm/pterm/tree_printer.go:75.66,78.2 2 1
+github.com/pterm/pterm/tree_printer.go:81.64,84.2 2 1
+github.com/pterm/pterm/tree_printer.go:87.59,90.2 2 8
+github.com/pterm/pterm/tree_printer.go:94.58,95.16 1 2
+github.com/pterm/pterm/tree_printer.go:98.2,99.11 2 2
+github.com/pterm/pterm/tree_printer.go:95.16,97.3 1 1
+github.com/pterm/pterm/tree_printer.go:103.70,106.2 2 0
+github.com/pterm/pterm/tree_printer.go:109.37,114.2 3 3
+github.com/pterm/pterm/tree_printer.go:117.48,118.24 1 4
+github.com/pterm/pterm/tree_printer.go:121.2,121.24 1 4
+github.com/pterm/pterm/tree_printer.go:125.2,125.50 1 4
+github.com/pterm/pterm/tree_printer.go:118.24,120.3 1 2
+github.com/pterm/pterm/tree_printer.go:121.24,123.3 1 2
+github.com/pterm/pterm/tree_printer.go:131.73,133.28 2 12
+github.com/pterm/pterm/tree_printer.go:154.2,154.12 1 12
+github.com/pterm/pterm/tree_printer.go:133.28,134.22 1 32
+github.com/pterm/pterm/tree_printer.go:134.22,135.31 1 21
+github.com/pterm/pterm/tree_printer.go:135.31,138.5 1 17
+github.com/pterm/pterm/tree_printer.go:138.10,142.5 2 4
+github.com/pterm/pterm/tree_printer.go:143.9,143.30 1 11
+github.com/pterm/pterm/tree_printer.go:143.30,144.31 1 11
+github.com/pterm/pterm/tree_printer.go:144.31,147.5 1 7
+github.com/pterm/pterm/tree_printer.go:147.10,151.5 2 4
+github.com/pterm/pterm/tree_printer.go:158.68,159.32 1 11
+github.com/pterm/pterm/tree_printer.go:163.2,168.42 2 9
+github.com/pterm/pterm/tree_printer.go:192.2,192.14 1 9
+github.com/pterm/pterm/tree_printer.go:159.32,161.3 1 2
+github.com/pterm/pterm/tree_printer.go:168.42,171.23 2 86
+github.com/pterm/pterm/tree_printer.go:176.3,176.35 1 86
+github.com/pterm/pterm/tree_printer.go:182.3,182.37 1 86
+github.com/pterm/pterm/tree_printer.go:186.3,189.5 1 86
+github.com/pterm/pterm/tree_printer.go:171.23,174.4 2 1
+github.com/pterm/pterm/tree_printer.go:176.35,177.52 1 77
+github.com/pterm/pterm/tree_printer.go:177.52,179.5 1 1
+github.com/pterm/pterm/tree_printer.go:182.37,185.4 2 97
+github.com/pterm/pterm/basic_text_printer.go:21.69,24.2 2 1
+github.com/pterm/pterm/basic_text_printer.go:26.80,29.2 2 0
+github.com/pterm/pterm/basic_text_printer.go:33.59,34.20 1 1371
+github.com/pterm/pterm/basic_text_printer.go:37.2,37.29 1 1371
+github.com/pterm/pterm/basic_text_printer.go:34.20,36.3 1 1371
+github.com/pterm/pterm/basic_text_printer.go:42.61,45.2 2 651
+github.com/pterm/pterm/basic_text_printer.go:48.75,50.2 1 684
+github.com/pterm/pterm/basic_text_printer.go:54.77,56.2 1 648
+github.com/pterm/pterm/basic_text_printer.go:61.65,65.2 3 18
+github.com/pterm/pterm/basic_text_printer.go:70.67,74.2 3 327
+github.com/pterm/pterm/basic_text_printer.go:78.81,82.2 3 18
+github.com/pterm/pterm/basic_text_printer.go:87.83,91.2 3 324
+github.com/pterm/pterm/basic_text_printer.go:96.72,97.24 1 2
+github.com/pterm/pterm/basic_text_printer.go:105.2,106.12 2 2
+github.com/pterm/pterm/basic_text_printer.go:97.24,98.33 1 2
+github.com/pterm/pterm/basic_text_printer.go:98.33,99.18 1 1
+github.com/pterm/pterm/basic_text_printer.go:99.18,101.5 1 1
+github.com/pterm/pterm/basic_text_printer.go:112.88,113.24 1 2
+github.com/pterm/pterm/basic_text_printer.go:121.2,122.12 2 2
+github.com/pterm/pterm/basic_text_printer.go:113.24,114.33 1 2
+github.com/pterm/pterm/basic_text_printer.go:114.33,115.18 1 1
+github.com/pterm/pterm/basic_text_printer.go:115.18,117.5 1 1
+github.com/pterm/pterm/print.go:12.36,14.2 1 13790
+github.com/pterm/pterm/print.go:18.38,20.2 1 253647
+github.com/pterm/pterm/print.go:23.54,25.2 1 139826
+github.com/pterm/pterm/print.go:29.56,31.2 1 30
+github.com/pterm/pterm/print.go:34.40,37.2 2 6291
+github.com/pterm/pterm/print.go:40.39,42.2 1 29128
+github.com/pterm/pterm/print.go:47.30,49.2 1 3576
+github.com/pterm/pterm/print.go:54.32,56.2 1 432
+github.com/pterm/pterm/print.go:60.46,62.2 1 14
+github.com/pterm/pterm/print.go:67.48,69.2 1 14
+github.com/pterm/pterm/print.go:74.37,75.24 1 2
+github.com/pterm/pterm/print.go:75.24,76.33 1 2
+github.com/pterm/pterm/print.go:76.33,77.18 1 1
+github.com/pterm/pterm/print.go:77.18,79.5 1 1
+github.com/pterm/pterm/print.go:87.53,88.24 1 2
+github.com/pterm/pterm/print.go:88.24,89.33 1 2
+github.com/pterm/pterm/print.go:89.33,90.18 1 1
+github.com/pterm/pterm/print.go:90.18,92.5 1 1
+github.com/pterm/pterm/print.go:100.49,101.13 1 13753
+github.com/pterm/pterm/print.go:105.2,108.48 3 13715
+github.com/pterm/pterm/print.go:116.2,116.48 1 13715
+github.com/pterm/pterm/print.go:124.2,124.14 1 13715
+github.com/pterm/pterm/print.go:128.2,131.48 2 13715
+github.com/pterm/pterm/print.go:101.13,103.3 1 38
+github.com/pterm/pterm/print.go:108.48,109.19 1 19966
+github.com/pterm/pterm/print.go:109.19,113.4 3 14278
+github.com/pterm/pterm/print.go:116.48,117.23 1 3131
+github.com/pterm/pterm/print.go:117.23,121.4 3 283
+github.com/pterm/pterm/print.go:124.14,126.3 1 10861
+github.com/pterm/pterm/print.go:131.48,132.19 1 19966
+github.com/pterm/pterm/print.go:132.19,134.4 1 14278
+github.com/pterm/pterm/print.go:141.51,144.2 1 173
+github.com/pterm/pterm/print.go:152.31,153.13 1 12
+github.com/pterm/pterm/print.go:157.2,157.34 1 6
+github.com/pterm/pterm/print.go:153.13,155.3 1 6
+github.com/pterm/pterm/print.go:161.45,162.13 1 7041
+github.com/pterm/pterm/print.go:166.2,166.37 1 7035
+github.com/pterm/pterm/print.go:162.13,164.3 1 6
+github.com/pterm/pterm/print.go:170.53,172.2 1 36443
+github.com/pterm/pterm/print.go:174.35,176.2 1 76
+github.com/pterm/pterm/print.go:178.26,180.2 1 14561
+github.com/pterm/pterm/progressbar_printer.go:63.72,66.2 2 3
+github.com/pterm/pterm/progressbar_printer.go:71.76,74.2 2 1
+github.com/pterm/pterm/progressbar_printer.go:77.70,80.2 2 9
+github.com/pterm/pterm/progressbar_printer.go:83.74,86.2 2 1
+github.com/pterm/pterm/progressbar_printer.go:89.79,92.2 2 1
+github.com/pterm/pterm/progressbar_printer.go:95.80,98.2 2 1
+github.com/pterm/pterm/progressbar_printer.go:101.103,104.2 2 1
+github.com/pterm/pterm/progressbar_printer.go:107.80,110.2 2 1
+github.com/pterm/pterm/progressbar_printer.go:113.74,116.2 2 1
+github.com/pterm/pterm/progressbar_printer.go:119.74,122.2 2 1
+github.com/pterm/pterm/progressbar_printer.go:125.79,128.2 2 1
+github.com/pterm/pterm/progressbar_printer.go:131.78,134.2 2 1
+github.com/pterm/pterm/progressbar_printer.go:137.76,140.2 2 1
+github.com/pterm/pterm/progressbar_printer.go:143.79,146.2 2 2
+github.com/pterm/pterm/progressbar_printer.go:149.76,152.2 2 1
+github.com/pterm/pterm/progressbar_printer.go:155.84,158.2 2 0
+github.com/pterm/pterm/progressbar_printer.go:161.62,164.2 2 12
+github.com/pterm/pterm/progressbar_printer.go:167.76,171.2 3 14291
+github.com/pterm/pterm/progressbar_printer.go:174.67,175.25 1 14315
+github.com/pterm/pterm/progressbar_printer.go:178.2,178.23 1 14315
+github.com/pterm/pterm/progressbar_printer.go:181.2,181.18 1 14315
+github.com/pterm/pterm/progressbar_printer.go:185.2,189.21 4 14314
+github.com/pterm/pterm/progressbar_printer.go:197.2,206.17 5 14314
+github.com/pterm/pterm/progressbar_printer.go:209.2,209.17 1 14314
+github.com/pterm/pterm/progressbar_printer.go:213.2,215.22 2 14314
+github.com/pterm/pterm/progressbar_printer.go:218.2,218.23 1 14314
+github.com/pterm/pterm/progressbar_printer.go:222.2,226.39 4 14314
+github.com/pterm/pterm/progressbar_printer.go:230.2,231.26 2 14314
+github.com/pterm/pterm/progressbar_printer.go:237.2,237.16 1 14314
+github.com/pterm/pterm/progressbar_printer.go:240.2,240.10 1 14314
+github.com/pterm/pterm/progressbar_printer.go:175.25,177.3 1 2
+github.com/pterm/pterm/progressbar_printer.go:178.23,180.3 1 2
+github.com/pterm/pterm/progressbar_printer.go:181.18,183.3 1 1
+github.com/pterm/pterm/progressbar_printer.go:189.21,191.3 1 1
+github.com/pterm/pterm/progressbar_printer.go:191.8,191.44 1 14313
+github.com/pterm/pterm/progressbar_printer.go:191.44,193.3 1 1
+github.com/pterm/pterm/progressbar_printer.go:193.8,195.3 1 14312
+github.com/pterm/pterm/progressbar_printer.go:206.17,208.3 1 14313
+github.com/pterm/pterm/progressbar_printer.go:209.17,211.3 1 14313
+github.com/pterm/pterm/progressbar_printer.go:215.22,217.3 1 14313
+github.com/pterm/pterm/progressbar_printer.go:218.23,220.3 1 14313
+github.com/pterm/pterm/progressbar_printer.go:226.39,228.3 1 14312
+github.com/pterm/pterm/progressbar_printer.go:231.26,233.3 1 37
+github.com/pterm/pterm/progressbar_printer.go:233.8,235.3 1 14277
+github.com/pterm/pterm/progressbar_printer.go:237.16,239.3 1 6871
+github.com/pterm/pterm/progressbar_printer.go:244.65,245.18 1 18
+github.com/pterm/pterm/progressbar_printer.go:249.2,252.26 3 17
+github.com/pterm/pterm/progressbar_printer.go:255.2,255.10 1 17
+github.com/pterm/pterm/progressbar_printer.go:245.18,247.3 1 1
+github.com/pterm/pterm/progressbar_printer.go:252.26,254.3 1 1
+github.com/pterm/pterm/progressbar_printer.go:259.66,260.30 1 7
+github.com/pterm/pterm/progressbar_printer.go:263.2,269.16 5 7
+github.com/pterm/pterm/progressbar_printer.go:260.30,262.3 1 1
+github.com/pterm/pterm/progressbar_printer.go:273.66,274.17 1 10
+github.com/pterm/pterm/progressbar_printer.go:277.2,278.22 2 3
+github.com/pterm/pterm/progressbar_printer.go:284.2,284.15 1 3
+github.com/pterm/pterm/progressbar_printer.go:274.17,276.3 1 7
+github.com/pterm/pterm/progressbar_printer.go:278.22,281.3 2 1
+github.com/pterm/pterm/progressbar_printer.go:281.8,283.3 1 2
+github.com/pterm/pterm/progressbar_printer.go:290.66,294.2 3 2
+github.com/pterm/pterm/progressbar_printer.go:299.65,303.2 3 1
+github.com/pterm/pterm/progressbar_printer.go:306.61,308.2 1 14314
+github.com/pterm/pterm/progressbar_printer.go:310.56,313.2 2 14313
+github.com/pterm/pterm/prefix_printer.go:101.65,104.2 2 10
+github.com/pterm/pterm/prefix_printer.go:107.62,110.2 2 100
+github.com/pterm/pterm/prefix_printer.go:113.70,116.2 2 5
+github.com/pterm/pterm/prefix_printer.go:122.60,125.2 2 11
+github.com/pterm/pterm/prefix_printer.go:128.69,131.2 2 95
+github.com/pterm/pterm/prefix_printer.go:136.63,139.2 2 75
+github.com/pterm/pterm/prefix_printer.go:144.72,147.2 2 5
+github.com/pterm/pterm/prefix_printer.go:150.74,153.2 2 0
+github.com/pterm/pterm/prefix_printer.go:157.57,159.39 2 10852
+github.com/pterm/pterm/prefix_printer.go:163.2,163.15 1 10762
+github.com/pterm/pterm/prefix_printer.go:171.2,171.27 1 5110
+github.com/pterm/pterm/prefix_printer.go:174.2,174.26 1 5110
+github.com/pterm/pterm/prefix_printer.go:177.2,177.27 1 5110
+github.com/pterm/pterm/prefix_printer.go:181.2,184.32 3 5110
+github.com/pterm/pterm/prefix_printer.go:189.2,190.33 2 5110
+github.com/pterm/pterm/prefix_printer.go:202.2,204.22 2 5110
+github.com/pterm/pterm/prefix_printer.go:209.2,209.13 1 5110
+github.com/pterm/pterm/prefix_printer.go:213.2,213.20 1 5110
+github.com/pterm/pterm/prefix_printer.go:159.39,161.3 1 90
+github.com/pterm/pterm/prefix_printer.go:163.15,164.26 1 5652
+github.com/pterm/pterm/prefix_printer.go:164.26,166.4 1 5607
+github.com/pterm/pterm/prefix_printer.go:166.9,168.4 1 45
+github.com/pterm/pterm/prefix_printer.go:171.27,173.3 1 1
+github.com/pterm/pterm/prefix_printer.go:174.26,176.3 1 1663
+github.com/pterm/pterm/prefix_printer.go:177.27,179.3 1 1
+github.com/pterm/pterm/prefix_printer.go:184.32,187.3 2 3095
+github.com/pterm/pterm/prefix_printer.go:190.33,191.13 1 5133
+github.com/pterm/pterm/prefix_printer.go:191.13,193.26 2 5110
+github.com/pterm/pterm/prefix_printer.go:196.4,196.35 1 5110
+github.com/pterm/pterm/prefix_printer.go:193.26,195.5 1 50
+github.com/pterm/pterm/prefix_printer.go:197.9,199.4 1 23
+github.com/pterm/pterm/prefix_printer.go:204.22,207.3 2 45
+github.com/pterm/pterm/prefix_printer.go:209.13,211.3 1 3095
+github.com/pterm/pterm/prefix_printer.go:218.58,219.39 1 6600
+github.com/pterm/pterm/prefix_printer.go:222.2,223.22 2 6510
+github.com/pterm/pterm/prefix_printer.go:219.39,221.3 1 90
+github.com/pterm/pterm/prefix_printer.go:227.72,228.39 1 3695
+github.com/pterm/pterm/prefix_printer.go:231.2,231.40 1 3605
+github.com/pterm/pterm/prefix_printer.go:228.39,230.3 1 90
+github.com/pterm/pterm/prefix_printer.go:236.74,237.39 1 3330
+github.com/pterm/pterm/prefix_printer.go:240.2,240.39 1 3240
+github.com/pterm/pterm/prefix_printer.go:237.39,239.3 1 90
+github.com/pterm/pterm/prefix_printer.go:246.62,248.39 2 420
+github.com/pterm/pterm/prefix_printer.go:251.2,253.12 3 410
+github.com/pterm/pterm/prefix_printer.go:248.39,250.3 1 10
+github.com/pterm/pterm/prefix_printer.go:259.64,261.39 2 3280
+github.com/pterm/pterm/prefix_printer.go:264.2,266.12 3 3270
+github.com/pterm/pterm/prefix_printer.go:261.39,263.3 1 10
+github.com/pterm/pterm/prefix_printer.go:271.78,273.39 2 190
+github.com/pterm/pterm/prefix_printer.go:276.2,278.12 3 180
+github.com/pterm/pterm/prefix_printer.go:273.39,275.3 1 10
+github.com/pterm/pterm/prefix_printer.go:284.80,286.39 2 1630
+github.com/pterm/pterm/prefix_printer.go:289.2,291.12 3 1620
+github.com/pterm/pterm/prefix_printer.go:286.39,288.3 1 10
+github.com/pterm/pterm/prefix_printer.go:299.69,300.24 1 10
+github.com/pterm/pterm/prefix_printer.go:308.2,309.12 2 10
+github.com/pterm/pterm/prefix_printer.go:300.24,301.33 1 10
+github.com/pterm/pterm/prefix_printer.go:301.33,302.18 1 5
+github.com/pterm/pterm/prefix_printer.go:302.18,304.5 1 5
+github.com/pterm/pterm/prefix_printer.go:315.85,316.24 1 10
+github.com/pterm/pterm/prefix_printer.go:324.2,325.12 2 10
+github.com/pterm/pterm/prefix_printer.go:316.24,317.33 1 10
+github.com/pterm/pterm/prefix_printer.go:317.33,318.18 1 5
+github.com/pterm/pterm/prefix_printer.go:318.18,320.5 1 5
+github.com/pterm/pterm/prefix_printer.go:329.52,331.2 1 5115
+github.com/pterm/pterm/prefix_printer.go:346.35,347.13 1 5480
+github.com/pterm/pterm/prefix_printer.go:347.13,348.12 1 5
+github.com/pterm/pterm/area_printer.go:28.43,30.2 1 9
+github.com/pterm/pterm/area_printer.go:33.65,36.2 2 3
+github.com/pterm/pterm/area_printer.go:39.61,42.2 2 2
+github.com/pterm/pterm/area_printer.go:45.57,48.2 2 1
+github.com/pterm/pterm/area_printer.go:52.51,53.19 1 18
+github.com/pterm/pterm/area_printer.go:57.2,60.14 3 18
+github.com/pterm/pterm/area_printer.go:64.2,64.18 1 18
+github.com/pterm/pterm/area_printer.go:82.2,82.20 1 18
+github.com/pterm/pterm/area_printer.go:53.19,56.3 2 2
+github.com/pterm/pterm/area_printer.go:60.14,62.3 1 2
+github.com/pterm/pterm/area_printer.go:64.18,72.15 6 2
+github.com/pterm/pterm/area_printer.go:77.3,77.29 1 2
+github.com/pterm/pterm/area_printer.go:72.15,75.4 2 2
+github.com/pterm/pterm/area_printer.go:77.29,80.4 2 2
+github.com/pterm/pterm/area_printer.go:86.72,95.2 6 5
+github.com/pterm/pterm/area_printer.go:99.36,101.22 2 4
+github.com/pterm/pterm/area_printer.go:104.2,104.12 1 4
+github.com/pterm/pterm/area_printer.go:101.22,103.3 1 2
+github.com/pterm/pterm/area_printer.go:110.60,114.2 3 2
+github.com/pterm/pterm/area_printer.go:119.59,123.2 3 1
+github.com/pterm/pterm/area_printer.go:128.31,130.2 1 3
+github.com/pterm/pterm/bulletlist_printer.go:11.77,13.25 2 2
+github.com/pterm/pterm/bulletlist_printer.go:16.2,16.42 1 2
+github.com/pterm/pterm/bulletlist_printer.go:13.25,15.3 1 8
+github.com/pterm/pterm/bulletlist_printer.go:20.78,26.2 2 8
+github.com/pterm/pterm/bulletlist_printer.go:38.62,41.2 2 1
+github.com/pterm/pterm/bulletlist_printer.go:44.63,47.2 2 1
+github.com/pterm/pterm/bulletlist_printer.go:50.69,53.2 2 1
+github.com/pterm/pterm/bulletlist_printer.go:56.67,59.2 2 1
+github.com/pterm/pterm/bulletlist_printer.go:62.71,65.2 2 1
+github.com/pterm/pterm/bulletlist_printer.go:68.74,70.2 1 2
+github.com/pterm/pterm/bulletlist_printer.go:89.81,92.2 2 76
+github.com/pterm/pterm/bulletlist_printer.go:95.75,98.2 2 1
+github.com/pterm/pterm/bulletlist_printer.go:101.73,104.2 2 1
+github.com/pterm/pterm/bulletlist_printer.go:107.77,110.2 2 1
+github.com/pterm/pterm/bulletlist_printer.go:113.82,116.2 2 0
+github.com/pterm/pterm/bulletlist_printer.go:119.43,124.2 3 56
+github.com/pterm/pterm/bulletlist_printer.go:127.54,129.31 2 74
+github.com/pterm/pterm/bulletlist_printer.go:150.2,150.17 1 74
+github.com/pterm/pterm/bulletlist_printer.go:129.31,130.28 1 74
+github.com/pterm/pterm/bulletlist_printer.go:137.3,137.30 1 74
+github.com/pterm/pterm/bulletlist_printer.go:144.3,144.24 1 74
+github.com/pterm/pterm/bulletlist_printer.go:130.28,131.26 1 74
+github.com/pterm/pterm/bulletlist_printer.go:131.26,133.5 1 18
+github.com/pterm/pterm/bulletlist_printer.go:133.10,135.5 1 56
+github.com/pterm/pterm/bulletlist_printer.go:137.30,138.28 1 74
+github.com/pterm/pterm/bulletlist_printer.go:138.28,140.5 1 18
+github.com/pterm/pterm/bulletlist_printer.go:140.10,142.5 1 56
+github.com/pterm/pterm/bulletlist_printer.go:144.24,146.4 1 56
+github.com/pterm/pterm/bulletlist_printer.go:146.9,148.4 1 18
+github.com/pterm/pterm/header_printer.go:35.67,38.2 2 1
+github.com/pterm/pterm/header_printer.go:41.73,44.2 2 3
+github.com/pterm/pterm/header_printer.go:47.62,50.2 2 3
+github.com/pterm/pterm/header_printer.go:53.64,56.2 2 21
+github.com/pterm/pterm/header_printer.go:59.74,62.2 2 0
+github.com/pterm/pterm/header_printer.go:66.56,67.15 1 1393
+github.com/pterm/pterm/header_printer.go:71.2,71.24 1 664
+github.com/pterm/pterm/header_printer.go:74.2,74.30 1 664
+github.com/pterm/pterm/header_printer.go:78.2,85.17 5 664
+github.com/pterm/pterm/header_printer.go:98.2,101.17 3 664
+github.com/pterm/pterm/header_printer.go:108.2,109.49 2 664
+github.com/pterm/pterm/header_printer.go:117.2,119.12 2 664
+github.com/pterm/pterm/header_printer.go:67.15,69.3 1 729
+github.com/pterm/pterm/header_printer.go:71.24,73.3 1 3
+github.com/pterm/pterm/header_printer.go:74.30,76.3 1 3
+github.com/pterm/pterm/header_printer.go:85.17,88.3 2 11
+github.com/pterm/pterm/header_printer.go:88.8,89.42 1 653
+github.com/pterm/pterm/header_printer.go:89.42,92.4 2 1
+github.com/pterm/pterm/header_printer.go:92.9,95.4 2 652
+github.com/pterm/pterm/header_printer.go:101.17,104.3 2 11
+github.com/pterm/pterm/header_printer.go:104.8,106.3 1 653
+github.com/pterm/pterm/header_printer.go:109.49,112.69 3 666
+github.com/pterm/pterm/header_printer.go:115.3,115.67 1 666
+github.com/pterm/pterm/header_printer.go:112.69,114.4 1 8
+github.com/pterm/pterm/header_printer.go:122.47,125.32 3 664
+github.com/pterm/pterm/header_printer.go:146.2,147.26 2 664
+github.com/pterm/pterm/header_printer.go:151.2,151.39 1 664
+github.com/pterm/pterm/header_printer.go:125.32,126.65 1 664
+github.com/pterm/pterm/header_printer.go:126.65,129.32 3 2
+github.com/pterm/pterm/header_printer.go:136.4,136.41 1 2
+github.com/pterm/pterm/header_printer.go:129.32,130.31 1 272
+github.com/pterm/pterm/header_printer.go:134.5,134.52 1 272
+github.com/pterm/pterm/header_printer.go:130.31,133.6 2 2
+github.com/pterm/pterm/header_printer.go:136.41,139.5 2 4
+github.com/pterm/pterm/header_printer.go:140.9,143.4 2 662
+github.com/pterm/pterm/header_printer.go:147.26,149.3 1 666
+github.com/pterm/pterm/header_printer.go:156.58,158.2 1 652
+github.com/pterm/pterm/header_printer.go:161.72,163.2 1 684
+github.com/pterm/pterm/header_printer.go:167.74,169.2 1 648
+github.com/pterm/pterm/header_printer.go:174.62,178.2 3 36
+github.com/pterm/pterm/header_printer.go:183.64,187.2 3 328
+github.com/pterm/pterm/header_printer.go:191.78,195.2 3 18
+github.com/pterm/pterm/header_printer.go:200.80,204.2 3 324
+github.com/pterm/pterm/header_printer.go:209.69,210.24 1 2
+github.com/pterm/pterm/header_printer.go:218.2,219.12 2 2
+github.com/pterm/pterm/header_printer.go:210.24,211.33 1 2
+github.com/pterm/pterm/header_printer.go:211.33,212.18 1 1
+github.com/pterm/pterm/header_printer.go:212.18,214.5 1 1
+github.com/pterm/pterm/header_printer.go:225.85,226.24 1 2
+github.com/pterm/pterm/header_printer.go:234.2,235.12 2 2
+github.com/pterm/pterm/header_printer.go:226.24,227.33 1 2
+github.com/pterm/pterm/header_printer.go:227.33,228.18 1 1
+github.com/pterm/pterm/header_printer.go:228.18,230.5 1 1
+github.com/pterm/pterm/center_printer.go:25.79,29.2 3 3
+github.com/pterm/pterm/center_printer.go:32.74,35.2 2 0
+github.com/pterm/pterm/center_printer.go:39.56,40.15 1 2096
+github.com/pterm/pterm/center_printer.go:44.2,48.32 3 998
+github.com/pterm/pterm/center_printer.go:60.2,62.29 2 655
+github.com/pterm/pterm/center_printer.go:69.2,71.18 2 655
+github.com/pterm/pterm/center_printer.go:79.2,79.29 1 653
+github.com/pterm/pterm/center_printer.go:83.2,83.12 1 653
+github.com/pterm/pterm/center_printer.go:40.15,42.3 1 1098
+github.com/pterm/pterm/center_printer.go:48.32,49.30 1 343
+github.com/pterm/pterm/center_printer.go:57.3,57.13 1 343
+github.com/pterm/pterm/center_printer.go:49.30,51.18 2 649
+github.com/pterm/pterm/center_printer.go:51.18,53.5 1 1
+github.com/pterm/pterm/center_printer.go:53.10,55.5 1 648
+github.com/pterm/pterm/center_printer.go:62.29,64.32 2 971
+github.com/pterm/pterm/center_printer.go:64.32,66.4 1 654
+github.com/pterm/pterm/center_printer.go:71.18,72.30 1 2
+github.com/pterm/pterm/center_printer.go:76.3,76.13 1 2
+github.com/pterm/pterm/center_printer.go:72.30,74.4 1 5
+github.com/pterm/pterm/center_printer.go:79.29,81.3 1 966
+github.com/pterm/pterm/center_printer.go:88.58,90.2 1 1298
+github.com/pterm/pterm/center_printer.go:93.72,95.2 1 720
+github.com/pterm/pterm/center_printer.go:99.74,101.2 1 648
+github.com/pterm/pterm/center_printer.go:106.61,110.2 3 38
+github.com/pterm/pterm/center_printer.go:115.63,119.2 3 650
+github.com/pterm/pterm/center_printer.go:123.77,127.2 3 36
+github.com/pterm/pterm/center_printer.go:132.79,136.2 3 324
+github.com/pterm/pterm/center_printer.go:141.68,142.24 1 2
+github.com/pterm/pterm/center_printer.go:150.2,151.12 2 2
+github.com/pterm/pterm/center_printer.go:142.24,143.33 1 2
+github.com/pterm/pterm/center_printer.go:143.33,144.18 1 1
+github.com/pterm/pterm/center_printer.go:144.18,146.5 1 1
+github.com/pterm/pterm/center_printer.go:157.84,158.24 1 2
+github.com/pterm/pterm/center_printer.go:166.2,167.12 2 2
+github.com/pterm/pterm/center_printer.go:158.24,159.33 1 2
+github.com/pterm/pterm/center_printer.go:159.33,160.18 1 1
+github.com/pterm/pterm/center_printer.go:160.18,162.5 1 1
+github.com/pterm/pterm/table_printer.go:48.61,51.2 2 1
+github.com/pterm/pterm/table_printer.go:54.62,57.2 2 9
+github.com/pterm/pterm/table_printer.go:60.67,63.2 2 1
+github.com/pterm/pterm/table_printer.go:66.78,69.2 2 4
+github.com/pterm/pterm/table_printer.go:72.79,75.2 2 1
+github.com/pterm/pterm/table_printer.go:78.69,81.2 2 1
+github.com/pterm/pterm/table_printer.go:84.70,87.2 2 1
+github.com/pterm/pterm/table_printer.go:90.72,93.2 2 3
+github.com/pterm/pterm/table_printer.go:96.73,99.2 2 1
+github.com/pterm/pterm/table_printer.go:102.63,105.2 2 9
+github.com/pterm/pterm/table_printer.go:108.71,109.50 1 1
+github.com/pterm/pterm/table_printer.go:112.2,112.11 1 1
+github.com/pterm/pterm/table_printer.go:109.50,111.3 1 1
+github.com/pterm/pterm/table_printer.go:116.58,119.2 2 1
+github.com/pterm/pterm/table_printer.go:122.66,127.2 4 2
+github.com/pterm/pterm/table_printer.go:130.67,135.2 4 2
+github.com/pterm/pterm/table_printer.go:138.72,141.2 2 0
+github.com/pterm/pterm/table_printer.go:144.49,145.20 1 10
+github.com/pterm/pterm/table_printer.go:148.2,148.29 1 10
+github.com/pterm/pterm/table_printer.go:151.2,151.26 1 10
+github.com/pterm/pterm/table_printer.go:154.2,154.38 1 10
+github.com/pterm/pterm/table_printer.go:157.2,157.32 1 10
+github.com/pterm/pterm/table_printer.go:161.2,164.29 3 10
+github.com/pterm/pterm/table_printer.go:173.2,173.30 1 10
+github.com/pterm/pterm/table_printer.go:202.2,204.13 2 10
+github.com/pterm/pterm/table_printer.go:208.2,208.17 1 10
+github.com/pterm/pterm/table_printer.go:145.20,147.3 1 1
+github.com/pterm/pterm/table_printer.go:148.29,150.3 1 1
+github.com/pterm/pterm/table_printer.go:151.26,153.3 1 1
+github.com/pterm/pterm/table_printer.go:154.38,156.3 1 1
+github.com/pterm/pterm/table_printer.go:157.32,159.3 1 1
+github.com/pterm/pterm/table_printer.go:164.29,165.31 1 41
+github.com/pterm/pterm/table_printer.go:165.31,167.41 2 123
+github.com/pterm/pterm/table_printer.go:167.41,169.5 1 33
+github.com/pterm/pterm/table_printer.go:173.30,175.31 2 41
+github.com/pterm/pterm/table_printer.go:191.3,191.59 1 41
+github.com/pterm/pterm/table_printer.go:195.3,195.61 1 41
+github.com/pterm/pterm/table_printer.go:199.3,199.14 1 41
+github.com/pterm/pterm/table_printer.go:175.31,179.33 3 123
+github.com/pterm/pterm/table_printer.go:184.4,184.30 1 123
+github.com/pterm/pterm/table_printer.go:179.33,182.5 2 82
+github.com/pterm/pterm/table_printer.go:184.30,186.5 1 24
+github.com/pterm/pterm/table_printer.go:186.10,188.5 1 99
+github.com/pterm/pterm/table_printer.go:191.59,193.4 1 3
+github.com/pterm/pterm/table_printer.go:195.61,197.4 1 4
+github.com/pterm/pterm/table_printer.go:204.13,206.3 1 1
+github.com/pterm/pterm/table_printer.go:211.82,213.22 2 123
+github.com/pterm/pterm/table_printer.go:216.2,216.64 1 111
+github.com/pterm/pterm/table_printer.go:213.22,215.3 1 12
+github.com/pterm/pterm/table_printer.go:219.75,221.2 1 3
+github.com/pterm/pterm/table_printer.go:223.69,225.2 1 4
+github.com/pterm/pterm/table_printer.go:228.38,233.2 3 9
+github.com/pterm/pterm/barchart.go:44.63,47.2 2 14
+github.com/pterm/pterm/barchart.go:50.81,53.2 2 1
+github.com/pterm/pterm/barchart.go:56.83,59.2 2 1
+github.com/pterm/pterm/barchart.go:62.69,66.2 3 5
+github.com/pterm/pterm/barchart.go:69.65,72.2 2 1
+github.com/pterm/pterm/barchart.go:75.64,78.2 2 1
+github.com/pterm/pterm/barchart.go:81.68,84.2 2 11
+github.com/pterm/pterm/barchart.go:87.78,90.2 2 0
+github.com/pterm/pterm/barchart.go:92.48,95.29 2 1
+github.com/pterm/pterm/barchart.go:99.2,99.12 1 1
+github.com/pterm/pterm/barchart.go:95.29,97.3 1 6
+github.com/pterm/pterm/barchart.go:103.52,104.50 1 15
+github.com/pterm/pterm/barchart.go:122.2,122.29 1 15
+github.com/pterm/pterm/barchart.go:131.2,144.82 2 15
+github.com/pterm/pterm/barchart.go:168.2,168.82 1 15
+github.com/pterm/pterm/barchart.go:183.2,183.84 1 15
+github.com/pterm/pterm/barchart.go:207.2,207.84 1 15
+github.com/pterm/pterm/barchart.go:248.2,248.15 1 15
+github.com/pterm/pterm/barchart.go:251.2,251.29 1 14
+github.com/pterm/pterm/barchart.go:263.2,271.29 7 14
+github.com/pterm/pterm/barchart.go:284.2,286.18 2 14
+github.com/pterm/pterm/barchart.go:415.2,415.17 1 10
+github.com/pterm/pterm/barchart.go:104.50,108.22 3 14
+github.com/pterm/pterm/barchart.go:113.3,115.28 2 14
+github.com/pterm/pterm/barchart.go:119.3,119.16 1 14
+github.com/pterm/pterm/barchart.go:108.22,111.4 2 11
+github.com/pterm/pterm/barchart.go:115.28,117.4 1 4
+github.com/pterm/pterm/barchart.go:122.29,123.16 1 4
+github.com/pterm/pterm/barchart.go:127.3,127.15 1 2
+github.com/pterm/pterm/barchart.go:123.16,125.4 1 2
+github.com/pterm/pterm/barchart.go:144.82,145.24 1 16
+github.com/pterm/pterm/barchart.go:149.3,149.56 1 16
+github.com/pterm/pterm/barchart.go:161.3,161.21 1 16
+github.com/pterm/pterm/barchart.go:145.24,147.4 1 9
+github.com/pterm/pterm/barchart.go:149.56,150.31 1 560
+github.com/pterm/pterm/barchart.go:150.31,152.5 1 180
+github.com/pterm/pterm/barchart.go:152.10,154.5 1 380
+github.com/pterm/pterm/barchart.go:161.21,162.58 1 4
+github.com/pterm/pterm/barchart.go:162.58,164.5 1 60
+github.com/pterm/pterm/barchart.go:168.82,169.57 1 14
+github.com/pterm/pterm/barchart.go:177.3,177.24 1 14
+github.com/pterm/pterm/barchart.go:169.57,170.31 1 508
+github.com/pterm/pterm/barchart.go:170.31,172.5 1 393
+github.com/pterm/pterm/barchart.go:172.10,174.5 1 115
+github.com/pterm/pterm/barchart.go:177.24,179.4 1 12
+github.com/pterm/pterm/barchart.go:183.84,184.24 1 11
+github.com/pterm/pterm/barchart.go:190.3,190.55 1 11
+github.com/pterm/pterm/barchart.go:198.3,198.24 1 11
+github.com/pterm/pterm/barchart.go:184.24,185.56 1 3
+github.com/pterm/pterm/barchart.go:185.56,187.5 1 45
+github.com/pterm/pterm/barchart.go:190.55,191.31 1 502
+github.com/pterm/pterm/barchart.go:191.31,193.5 1 243
+github.com/pterm/pterm/barchart.go:193.10,195.5 1 259
+github.com/pterm/pterm/barchart.go:198.24,204.4 2 11
+github.com/pterm/pterm/barchart.go:207.84,208.56 1 10
+github.com/pterm/pterm/barchart.go:218.3,218.41 1 10
+github.com/pterm/pterm/barchart.go:224.3,224.24 1 10
+github.com/pterm/pterm/barchart.go:208.56,209.31 1 454
+github.com/pterm/pterm/barchart.go:209.31,211.5 1 310
+github.com/pterm/pterm/barchart.go:211.10,213.5 1 144
+github.com/pterm/pterm/barchart.go:218.41,219.56 1 2
+github.com/pterm/pterm/barchart.go:219.56,221.5 1 52
+github.com/pterm/pterm/barchart.go:224.24,239.32 1 10
+github.com/pterm/pterm/barchart.go:243.4,243.60 1 10
+github.com/pterm/pterm/barchart.go:239.32,241.5 1 2
+github.com/pterm/pterm/barchart.go:248.15,250.3 1 1
+github.com/pterm/pterm/barchart.go:251.29,252.23 1 51
+github.com/pterm/pterm/barchart.go:256.3,256.28 1 51
+github.com/pterm/pterm/barchart.go:260.3,260.59 1 51
+github.com/pterm/pterm/barchart.go:252.23,254.4 1 3
+github.com/pterm/pterm/barchart.go:256.28,258.4 1 48
+github.com/pterm/pterm/barchart.go:271.29,272.30 1 51
+github.com/pterm/pterm/barchart.go:275.3,275.30 1 51
+github.com/pterm/pterm/barchart.go:278.3,279.35 2 51
+github.com/pterm/pterm/barchart.go:272.30,274.4 1 13
+github.com/pterm/pterm/barchart.go:275.30,277.4 1 8
+github.com/pterm/pterm/barchart.go:279.35,281.4 1 15
+github.com/pterm/pterm/barchart.go:286.18,294.41 5 4
+github.com/pterm/pterm/barchart.go:299.3,299.30 1 4
+github.com/pterm/pterm/barchart.go:331.3,332.18 2 4
+github.com/pterm/pterm/barchart.go:294.41,297.4 2 1
+github.com/pterm/pterm/barchart.go:299.30,304.24 4 21
+github.com/pterm/pterm/barchart.go:304.24,310.5 3 8
+github.com/pterm/pterm/barchart.go:310.10,310.31 1 13
+github.com/pterm/pterm/barchart.go:310.31,316.5 3 8
+github.com/pterm/pterm/barchart.go:316.10,320.23 2 5
+github.com/pterm/pterm/barchart.go:326.5,326.22 1 5
+github.com/pterm/pterm/barchart.go:320.23,324.6 2 3
+github.com/pterm/pterm/barchart.go:326.22,328.6 1 2
+github.com/pterm/pterm/barchart.go:333.8,341.41 5 10
+github.com/pterm/pterm/barchart.go:346.3,346.30 1 10
+github.com/pterm/pterm/barchart.go:381.3,383.36 2 10
+github.com/pterm/pterm/barchart.go:390.3,390.36 1 10
+github.com/pterm/pterm/barchart.go:397.3,397.38 1 10
+github.com/pterm/pterm/barchart.go:341.41,344.4 2 1
+github.com/pterm/pterm/barchart.go:346.30,351.24 4 30
+github.com/pterm/pterm/barchart.go:377.4,378.102 2 30
+github.com/pterm/pterm/barchart.go:351.24,357.5 3 12
+github.com/pterm/pterm/barchart.go:357.10,357.31 1 18
+github.com/pterm/pterm/barchart.go:357.31,362.5 2 12
+github.com/pterm/pterm/barchart.go:362.10,366.23 2 6
+github.com/pterm/pterm/barchart.go:372.5,372.22 1 6
+github.com/pterm/pterm/barchart.go:366.23,370.6 2 4
+github.com/pterm/pterm/barchart.go:372.22,374.6 1 2
+github.com/pterm/pterm/barchart.go:383.36,385.37 2 30
+github.com/pterm/pterm/barchart.go:385.37,387.5 1 9
+github.com/pterm/pterm/barchart.go:390.36,392.37 2 30
+github.com/pterm/pterm/barchart.go:392.37,394.5 1 2
+github.com/pterm/pterm/barchart.go:397.38,398.43 1 383
+github.com/pterm/pterm/barchart.go:411.4,411.15 1 383
+github.com/pterm/pterm/barchart.go:398.43,402.29 4 1257
+github.com/pterm/pterm/barchart.go:405.5,406.39 2 1257
+github.com/pterm/pterm/barchart.go:409.5,409.19 1 1257
+github.com/pterm/pterm/barchart.go:402.29,404.6 1 1227
+github.com/pterm/pterm/barchart.go:406.39,408.6 1 712
+github.com/pterm/pterm/barchart.go:419.41,424.2 3 14
+github.com/pterm/pterm/pterm.go:22.13,24.2 1 1
+github.com/pterm/pterm/pterm.go:27.21,29.2 1 1
+github.com/pterm/pterm/pterm.go:32.22,34.2 1 2
+github.com/pterm/pterm/pterm.go:37.28,39.2 1 31
+github.com/pterm/pterm/pterm.go:42.29,44.2 1 36
+github.com/pterm/pterm/pterm.go:48.22,51.2 2 14223
+github.com/pterm/pterm/pterm.go:56.23,59.2 2 14223
+github.com/pterm/pterm/pterm.go:62.32,67.2 3 10
+github.com/pterm/pterm/terminal.go:24.29,25.29 1 30970
+github.com/pterm/pterm/terminal.go:28.2,29.14 2 7
+github.com/pterm/pterm/terminal.go:25.29,27.3 1 30963
+github.com/pterm/pterm/terminal.go:33.30,34.30 1 17
+github.com/pterm/pterm/terminal.go:37.2,38.15 2 4
+github.com/pterm/pterm/terminal.go:34.30,36.3 1 13
+github.com/pterm/pterm/terminal.go:42.55,43.57 1 13
+github.com/pterm/pterm/terminal.go:46.2,47.12 2 12
+github.com/pterm/pterm/terminal.go:50.2,50.12 1 12
+github.com/pterm/pterm/terminal.go:53.2,53.16 1 12
+github.com/pterm/pterm/terminal.go:56.2,56.18 1 12
+github.com/pterm/pterm/terminal.go:43.57,45.3 1 1
+github.com/pterm/pterm/terminal.go:47.12,49.3 1 12
+github.com/pterm/pterm/terminal.go:50.12,52.3 1 12
+github.com/pterm/pterm/terminal.go:53.16,55.3 1 12
+github.com/pterm/pterm/terminal.go:60.51,64.2 3 10
+github.com/pterm/pterm/paragraph_printer.go:23.69,26.2 2 1
+github.com/pterm/pterm/paragraph_printer.go:29.80,32.2 2 0
+github.com/pterm/pterm/paragraph_printer.go:36.59,37.15 1 1373
+github.com/pterm/pterm/paragraph_printer.go:41.2,42.21 2 653
+github.com/pterm/pterm/paragraph_printer.go:45.2,47.33 3 652
+github.com/pterm/pterm/paragraph_printer.go:57.2,57.16 1 652
+github.com/pterm/pterm/paragraph_printer.go:37.15,39.3 1 720
+github.com/pterm/pterm/paragraph_printer.go:42.21,44.3 1 1
+github.com/pterm/pterm/paragraph_printer.go:47.33,48.30 1 405
+github.com/pterm/pterm/paragraph_printer.go:48.30,51.4 2 3
+github.com/pterm/pterm/paragraph_printer.go:51.9,54.4 2 402
+github.com/pterm/pterm/paragraph_printer.go:62.61,64.2 1 651
+github.com/pterm/pterm/paragraph_printer.go:67.75,69.2 1 684
+github.com/pterm/pterm/paragraph_printer.go:73.77,75.2 1 648
+github.com/pterm/pterm/paragraph_printer.go:80.65,84.2 3 20
+github.com/pterm/pterm/paragraph_printer.go:89.67,93.2 3 327
+github.com/pterm/pterm/paragraph_printer.go:97.81,101.2 3 18
+github.com/pterm/pterm/paragraph_printer.go:106.83,110.2 3 324
+github.com/pterm/pterm/paragraph_printer.go:115.72,116.24 1 2
+github.com/pterm/pterm/paragraph_printer.go:124.2,125.12 2 2
+github.com/pterm/pterm/paragraph_printer.go:116.24,117.33 1 2
+github.com/pterm/pterm/paragraph_printer.go:117.33,118.18 1 1
+github.com/pterm/pterm/paragraph_printer.go:118.18,120.5 1 1
+github.com/pterm/pterm/paragraph_printer.go:131.88,132.24 1 2
+github.com/pterm/pterm/paragraph_printer.go:140.2,141.12 2 2
+github.com/pterm/pterm/paragraph_printer.go:132.24,133.33 1 2
+github.com/pterm/pterm/paragraph_printer.go:133.33,134.18 1 1
+github.com/pterm/pterm/paragraph_printer.go:134.18,136.5 1 1
+github.com/pterm/pterm/section_printer.go:30.65,33.2 2 2
+github.com/pterm/pterm/section_printer.go:36.62,39.2 2 4
+github.com/pterm/pterm/section_printer.go:42.74,45.2 2 1
+github.com/pterm/pterm/section_printer.go:48.69,51.2 2 2
+github.com/pterm/pterm/section_printer.go:54.72,57.2 2 2
+github.com/pterm/pterm/section_printer.go:60.76,63.2 2 0
+github.com/pterm/pterm/section_printer.go:67.57,68.20 1 1379
+github.com/pterm/pterm/section_printer.go:72.2,74.36 2 1379
+github.com/pterm/pterm/section_printer.go:78.2,78.17 1 1379
+github.com/pterm/pterm/section_printer.go:82.2,84.39 2 1379
+github.com/pterm/pterm/section_printer.go:88.2,88.12 1 1379
+github.com/pterm/pterm/section_printer.go:68.20,70.3 1 1
+github.com/pterm/pterm/section_printer.go:74.36,76.3 1 1375
+github.com/pterm/pterm/section_printer.go:78.17,80.3 1 1378
+github.com/pterm/pterm/section_printer.go:84.39,86.3 1 1375
+github.com/pterm/pterm/section_printer.go:93.59,96.2 2 657
+github.com/pterm/pterm/section_printer.go:99.73,101.2 1 686
+github.com/pterm/pterm/section_printer.go:105.75,107.2 1 650
+github.com/pterm/pterm/section_printer.go:112.63,116.2 3 18
+github.com/pterm/pterm/section_printer.go:121.65,125.2 3 333
+github.com/pterm/pterm/section_printer.go:129.79,133.2 3 18
+github.com/pterm/pterm/section_printer.go:138.81,142.2 3 326
+github.com/pterm/pterm/section_printer.go:147.70,148.24 1 2
+github.com/pterm/pterm/section_printer.go:156.2,157.12 2 2
+github.com/pterm/pterm/section_printer.go:148.24,149.33 1 2
+github.com/pterm/pterm/section_printer.go:149.33,150.18 1 1
+github.com/pterm/pterm/section_printer.go:150.18,152.5 1 1
+github.com/pterm/pterm/section_printer.go:163.86,164.24 1 2
+github.com/pterm/pterm/section_printer.go:172.2,173.12 2 2
+github.com/pterm/pterm/section_printer.go:164.24,165.33 1 2
+github.com/pterm/pterm/section_printer.go:165.33,166.18 1 1
+github.com/pterm/pterm/section_printer.go:166.18,168.5 1 1
+github.com/pterm/pterm/color.go:14.20,17.2 2 14224
+github.com/pterm/pterm/color.go:20.21,23.2 2 14225
+github.com/pterm/pterm/color.go:142.50,145.2 2 650
+github.com/pterm/pterm/color.go:150.48,153.36 3 73138
+github.com/pterm/pterm/color.go:156.2,157.16 2 73138
+github.com/pterm/pterm/color.go:153.36,155.3 1 74532
+github.com/pterm/pterm/color.go:162.64,164.2 1 36
+github.com/pterm/pterm/color.go:169.66,171.2 1 648
+github.com/pterm/pterm/color.go:177.55,181.2 3 326
+github.com/pterm/pterm/color.go:187.53,191.2 3 18
+github.com/pterm/pterm/color.go:196.69,200.2 3 18
+github.com/pterm/pterm/color.go:206.71,210.2 3 324
+github.com/pterm/pterm/color.go:215.60,216.24 1 2
+github.com/pterm/pterm/color.go:224.2,225.12 2 2
+github.com/pterm/pterm/color.go:216.24,217.33 1 2
+github.com/pterm/pterm/color.go:217.33,218.18 1 1
+github.com/pterm/pterm/color.go:218.18,220.5 1 1
+github.com/pterm/pterm/color.go:231.76,232.24 1 2
+github.com/pterm/pterm/color.go:240.2,241.12 2 2
+github.com/pterm/pterm/color.go:232.24,233.33 1 2
+github.com/pterm/pterm/color.go:233.33,234.18 1 1
+github.com/pterm/pterm/color.go:234.18,236.5 1 1
+github.com/pterm/pterm/color.go:245.32,247.2 1 327052
+github.com/pterm/pterm/color.go:255.39,257.27 2 3313
+github.com/pterm/pterm/color.go:260.2,260.13 1 3313
+github.com/pterm/pterm/color.go:257.27,259.3 1 726
+github.com/pterm/pterm/color.go:264.43,267.28 2 5
+github.com/pterm/pterm/color.go:271.2,271.12 1 5
+github.com/pterm/pterm/color.go:267.28,269.3 1 6
+github.com/pterm/pterm/color.go:277.48,280.36 3 46526
+github.com/pterm/pterm/color.go:283.2,284.46 2 46526
+github.com/pterm/pterm/color.go:280.36,282.3 1 48484
+github.com/pterm/pterm/color.go:290.50,292.2 1 324
+github.com/pterm/pterm/color.go:296.64,298.2 1 36
+github.com/pterm/pterm/color.go:303.66,305.2 1 648
+github.com/pterm/pterm/color.go:311.40,313.2 1 18
+github.com/pterm/pterm/color.go:319.42,321.2 1 324
+github.com/pterm/pterm/color.go:326.56,328.2 1 18
+github.com/pterm/pterm/color.go:334.58,336.2 1 324
+github.com/pterm/pterm/color.go:339.30,341.2 1 1
+github.com/pterm/pterm/color.go:344.32,346.2 1 143496
+github.com/pterm/pterm/color.go:350.42,351.22 1 143496
+github.com/pterm/pterm/color.go:355.2,356.27 2 138007
+github.com/pterm/pterm/color.go:360.2,360.33 1 138007
+github.com/pterm/pterm/color.go:351.22,353.3 1 5489
+github.com/pterm/pterm/color.go:356.27,358.3 1 177988
+github.com/pterm/pterm/theme.go:93.52,96.2 2 1
+github.com/pterm/pterm/theme.go:99.54,102.2 2 1
+github.com/pterm/pterm/theme.go:105.54,108.2 2 1
+github.com/pterm/pterm/theme.go:111.56,114.2 2 1
+github.com/pterm/pterm/theme.go:117.55,120.2 2 1
+github.com/pterm/pterm/theme.go:123.59,126.2 2 1
+github.com/pterm/pterm/theme.go:129.58,132.2 2 1
+github.com/pterm/pterm/theme.go:135.59,138.2 2 1
+github.com/pterm/pterm/theme.go:141.58,144.2 2 1
+github.com/pterm/pterm/theme.go:147.57,150.2 2 1
+github.com/pterm/pterm/theme.go:153.56,156.2 2 1
+github.com/pterm/pterm/theme.go:159.57,162.2 2 1
+github.com/pterm/pterm/theme.go:165.56,168.2 2 1
+github.com/pterm/pterm/theme.go:171.63,174.2 2 1
+github.com/pterm/pterm/theme.go:177.62,180.2 2 1
+github.com/pterm/pterm/theme.go:183.59,186.2 2 1
+github.com/pterm/pterm/theme.go:189.61,192.2 2 1
+github.com/pterm/pterm/theme.go:195.51,198.2 2 1
+github.com/pterm/pterm/theme.go:201.57,204.2 2 1
+github.com/pterm/pterm/theme.go:207.56,210.2 2 1
+github.com/pterm/pterm/theme.go:213.49,216.2 2 1
+github.com/pterm/pterm/theme.go:219.53,222.2 2 1
+github.com/pterm/pterm/theme.go:225.48,228.2 2 1
+github.com/pterm/pterm/theme.go:231.52,234.2 2 1
+github.com/pterm/pterm/theme.go:237.53,240.2 2 1
+github.com/pterm/pterm/theme.go:243.48,246.2 2 1
+github.com/pterm/pterm/atoms.go:15.39,18.2 2 1
+github.com/pterm/pterm/atoms.go:21.48,24.2 2 1
+github.com/pterm/pterm/atoms.go:27.40,30.2 2 1
+github.com/pterm/pterm/atoms.go:33.43,36.2 2 1
+github.com/pterm/pterm/box_printer.go:55.55,58.2 2 25
+github.com/pterm/pterm/box_printer.go:61.61,70.2 8 2
+github.com/pterm/pterm/box_printer.go:73.62,82.2 8 2
+github.com/pterm/pterm/box_printer.go:85.63,94.2 8 2
+github.com/pterm/pterm/box_printer.go:97.64,106.2 8 2
+github.com/pterm/pterm/box_printer.go:109.65,118.2 8 2
+github.com/pterm/pterm/box_printer.go:121.66,130.2 8 2
+github.com/pterm/pterm/box_printer.go:133.60,136.2 2 1
+github.com/pterm/pterm/box_printer.go:139.61,142.2 2 1
+github.com/pterm/pterm/box_printer.go:145.70,148.2 2 1
+github.com/pterm/pterm/box_printer.go:151.69,154.2 2 1
+github.com/pterm/pterm/box_printer.go:157.73,160.2 2 1
+github.com/pterm/pterm/box_printer.go:163.72,166.2 2 1
+github.com/pterm/pterm/box_printer.go:169.64,172.2 2 1
+github.com/pterm/pterm/box_printer.go:175.66,178.2 2 1
+github.com/pterm/pterm/box_printer.go:181.61,182.17 1 2
+github.com/pterm/pterm/box_printer.go:185.2,186.11 2 2
+github.com/pterm/pterm/box_printer.go:182.17,184.3 1 1
+github.com/pterm/pterm/box_printer.go:190.64,191.17 1 2
+github.com/pterm/pterm/box_printer.go:194.2,195.11 2 2
+github.com/pterm/pterm/box_printer.go:191.17,193.3 1 1
+github.com/pterm/pterm/box_printer.go:199.63,200.17 1 2
+github.com/pterm/pterm/box_printer.go:203.2,204.11 2 2
+github.com/pterm/pterm/box_printer.go:200.17,202.3 1 1
+github.com/pterm/pterm/box_printer.go:208.62,209.17 1 2
+github.com/pterm/pterm/box_printer.go:212.2,213.11 2 2
+github.com/pterm/pterm/box_printer.go:209.17,211.3 1 1
+github.com/pterm/pterm/box_printer.go:217.68,220.2 2 0
+github.com/pterm/pterm/box_printer.go:224.53,225.23 1 1441
+github.com/pterm/pterm/box_printer.go:228.2,228.24 1 1441
+github.com/pterm/pterm/box_printer.go:231.2,236.19 4 1441
+github.com/pterm/pterm/box_printer.go:273.2,276.24 3 1441
+github.com/pterm/pterm/box_printer.go:286.2,286.68 1 1441
+github.com/pterm/pterm/box_printer.go:225.23,227.3 1 7
+github.com/pterm/pterm/box_printer.go:228.24,230.3 1 7
+github.com/pterm/pterm/box_printer.go:236.19,241.3 2 1417
+github.com/pterm/pterm/box_printer.go:241.8,243.92 2 24
+github.com/pterm/pterm/box_printer.go:246.3,246.21 1 24
+github.com/pterm/pterm/box_printer.go:243.92,245.4 1 6
+github.com/pterm/pterm/box_printer.go:246.21,250.4 2 19
+github.com/pterm/pterm/box_printer.go:250.9,250.29 1 5
+github.com/pterm/pterm/box_printer.go:250.29,254.4 2 1
+github.com/pterm/pterm/box_printer.go:254.9,254.30 1 4
+github.com/pterm/pterm/box_printer.go:254.30,258.4 2 1
+github.com/pterm/pterm/box_printer.go:258.9,258.31 1 3
+github.com/pterm/pterm/box_printer.go:258.31,262.4 2 1
+github.com/pterm/pterm/box_printer.go:262.9,262.32 1 2
+github.com/pterm/pterm/box_printer.go:262.32,266.4 2 1
+github.com/pterm/pterm/box_printer.go:266.9,266.33 1 1
+github.com/pterm/pterm/box_printer.go:266.33,270.4 2 1
+github.com/pterm/pterm/box_printer.go:276.24,277.66 1 1477
+github.com/pterm/pterm/box_printer.go:277.66,281.4 1 36
+github.com/pterm/pterm/box_printer.go:281.9,284.4 1 1441
+github.com/pterm/pterm/box_printer.go:291.55,293.2 1 651
+github.com/pterm/pterm/box_printer.go:296.69,298.2 1 684
+github.com/pterm/pterm/box_printer.go:302.71,304.2 1 648
+github.com/pterm/pterm/box_printer.go:309.58,313.2 3 18
+github.com/pterm/pterm/box_printer.go:318.60,322.2 3 327
+github.com/pterm/pterm/box_printer.go:326.74,330.2 3 18
+github.com/pterm/pterm/box_printer.go:335.76,339.2 3 324
+github.com/pterm/pterm/box_printer.go:344.65,345.24 1 2
+github.com/pterm/pterm/box_printer.go:353.2,354.12 2 2
+github.com/pterm/pterm/box_printer.go:345.24,346.33 1 2
+github.com/pterm/pterm/box_printer.go:346.33,347.18 1 1
+github.com/pterm/pterm/box_printer.go:347.18,349.5 1 1
+github.com/pterm/pterm/box_printer.go:360.81,361.24 1 2
+github.com/pterm/pterm/box_printer.go:369.2,370.12 2 2
+github.com/pterm/pterm/box_printer.go:361.24,362.33 1 2
+github.com/pterm/pterm/box_printer.go:362.33,363.18 1 1
+github.com/pterm/pterm/box_printer.go:363.18,365.5 1 1
+github.com/pterm/pterm/spinner_printer.go:51.63,54.2 2 1
+github.com/pterm/pterm/spinner_printer.go:57.74,60.2 2 1
+github.com/pterm/pterm/spinner_printer.go:63.65,66.2 2 1
+github.com/pterm/pterm/spinner_printer.go:69.72,72.2 2 2
+github.com/pterm/pterm/spinner_printer.go:75.72,78.2 2 1
+github.com/pterm/pterm/spinner_printer.go:81.71,84.2 2 2
+github.com/pterm/pterm/spinner_printer.go:87.66,90.2 2 2
+github.com/pterm/pterm/spinner_printer.go:93.87,96.2 2 1
+github.com/pterm/pterm/spinner_printer.go:99.70,102.2 2 1
+github.com/pterm/pterm/spinner_printer.go:105.76,108.2 2 0
+github.com/pterm/pterm/spinner_printer.go:112.50,114.16 2 17
+github.com/pterm/pterm/spinner_printer.go:118.2,118.15 1 17
+github.com/pterm/pterm/spinner_printer.go:114.16,117.3 2 16
+github.com/pterm/pterm/spinner_printer.go:118.15,120.3 1 1
+github.com/pterm/pterm/spinner_printer.go:124.77,129.20 4 10
+github.com/pterm/pterm/spinner_printer.go:133.2,133.15 1 10
+github.com/pterm/pterm/spinner_printer.go:137.2,137.12 1 10
+github.com/pterm/pterm/spinner_printer.go:154.2,154.16 1 10
+github.com/pterm/pterm/spinner_printer.go:129.20,131.3 1 5
+github.com/pterm/pterm/spinner_printer.go:133.15,135.3 1 6
+github.com/pterm/pterm/spinner_printer.go:137.12,138.18 1 10
+github.com/pterm/pterm/spinner_printer.go:138.18,139.35 1 536530
+github.com/pterm/pterm/spinner_printer.go:139.35,140.33 1 93756
+github.com/pterm/pterm/spinner_printer.go:144.5,145.20 2 6
+github.com/pterm/pterm/spinner_printer.go:148.5,150.24 3 6
+github.com/pterm/pterm/spinner_printer.go:140.33,141.14 1 93898
+github.com/pterm/pterm/spinner_printer.go:145.20,147.6 1 5
+github.com/pterm/pterm/spinner_printer.go:159.39,161.22 2 65
+github.com/pterm/pterm/spinner_printer.go:167.2,167.12 1 65
+github.com/pterm/pterm/spinner_printer.go:161.22,164.3 2 2
+github.com/pterm/pterm/spinner_printer.go:164.8,166.3 1 63
+github.com/pterm/pterm/spinner_printer.go:173.63,177.2 3 2
+github.com/pterm/pterm/spinner_printer.go:182.62,186.2 3 3
+github.com/pterm/pterm/spinner_printer.go:190.58,191.29 1 19
+github.com/pterm/pterm/spinner_printer.go:195.2,195.23 1 19
+github.com/pterm/pterm/spinner_printer.go:198.2,200.14 3 19
+github.com/pterm/pterm/spinner_printer.go:191.29,193.3 1 1
+github.com/pterm/pterm/spinner_printer.go:195.23,197.3 1 1
+github.com/pterm/pterm/spinner_printer.go:205.55,206.26 1 19
+github.com/pterm/pterm/spinner_printer.go:210.2,210.23 1 19
+github.com/pterm/pterm/spinner_printer.go:213.2,215.14 3 19
+github.com/pterm/pterm/spinner_printer.go:206.26,208.3 1 1
+github.com/pterm/pterm/spinner_printer.go:210.23,212.3 1 1
+github.com/pterm/pterm/spinner_printer.go:220.58,221.29 1 19
+github.com/pterm/pterm/spinner_printer.go:225.2,225.23 1 19
+github.com/pterm/pterm/spinner_printer.go:228.2,230.14 3 19
+github.com/pterm/pterm/spinner_printer.go:221.29,223.3 1 1
+github.com/pterm/pterm/spinner_printer.go:225.23,227.3 1 1
diff --git a/vendor/github.com/pterm/pterm/deprecated.go b/vendor/github.com/pterm/pterm/deprecated.go
new file mode 100644
index 0000000..9a6d9d0
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/deprecated.go
@@ -0,0 +1,148 @@
+package pterm
+
+import (
+ "strconv"
+ "strings"
+
+ "github.com/pterm/pterm/internal"
+)
+
+// 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.
+//
+// Deprecated: use putils.LettersFromString instead.
+func NewLettersFromString(text string) Letters {
+ return NewLettersFromStringWithStyle(text, &ThemeDefault.LetterStyle)
+}
+
+// NewLettersFromStringWithStyle creates a Letters object from a string and applies a Style to it.
+//
+// Deprecated: use putils.LettersFromStringWithStyle instead.
+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
+}
+
+// NewLettersFromStringWithRGB creates a Letters object from a string and applies an RGB color to it (overwrites style).
+//
+// Deprecated: use putils.LettersFromStringWithRGB instead.
+func NewLettersFromStringWithRGB(text string, rgb RGB) Letters {
+ s := strings.Split(text, "")
+ l := Letters{}
+
+ for _, s2 := range s {
+ l = append(l, Letter{
+ String: s2,
+ Style: &Style{},
+ RGB: rgb,
+ })
+ }
+
+ return l
+}
+
+// NewBulletListFromStrings returns a BulletListPrinter with Text using the NewTreeListItemFromString method.
+//
+// Deprecated: use putils.BulletListFromStrings instead.
+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.
+//
+// Deprecated: use putils.BulletListItemFromString instead.
+func NewBulletListItemFromString(text string, padding string) BulletListItem {
+ s, l := internal.RemoveAndCountPrefix(text, padding)
+ return BulletListItem{
+ Level: l,
+ Text: s,
+ }
+}
+
+// NewBulletListFromString returns a BulletListPrinter with Text using the NewTreeListItemFromString method, splitting after return (\n).
+//
+// Deprecated: use putils.BulletListFromString instead.
+func NewBulletListFromString(s string, padding string) BulletListPrinter {
+ return NewBulletListFromStrings(strings.Split(s, "\n"), padding)
+}
+
+// NewTreeFromLeveledList converts a TreeItems list to a TreeNode and returns it.
+//
+// Deprecated: use putils.TreeFromLeveledList instead.
+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
+}
+
+// NewRGBFromHEX converts a HEX and returns a new RGB.
+//
+// Deprecated: use putils.RGBFromHEX instead.
+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)
+ // #nosec G115
+ return RGB{
+ R: uint8(c >> 16), //nolint:gosec
+ G: uint8((c & 0x00FF00) >> 8), //nolint:gosec
+ B: uint8(c & 0x0000FF), //nolint:gosec
+ }, nil
+}
diff --git a/vendor/github.com/pterm/pterm/errors.go b/vendor/github.com/pterm/pterm/errors.go
new file mode 100644
index 0000000..9260ab6
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/errors.go
@@ -0,0 +1,14 @@
+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")
+
+ // ErrKeyWithoutValue - an odd number of arguments was passed to a pterm Logger's Args method.
+ ErrKeyWithoutValue = "ERROR: key_without_value"
+)
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..e038ef6
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/header_printer.go
@@ -0,0 +1,239 @@
+package pterm
+
+import (
+ "fmt"
+ "io"
+ "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
+ Writer io.Writer
+}
+
+// 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
+}
+
+// WithWriter sets the custom Writer.
+func (p HeaderPrinter) WithWriter(writer io.Writer) *HeaderPrinter {
+ p.Writer = writer
+ 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 ...any) 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 strings.Builder
+
+ if p.FullWidth {
+ longestLineLen = runewidth.StringWidth(RemoveColorFromString(internal.ReturnLongestLine(text, "\n")))
+ marginString = strings.Repeat(" ", (GetTerminalWidth()-longestLineLen)/2)
+ } else {
+ marginString = strings.Repeat(" ", p.Margin)
+ }
+
+ ret.WriteString(p.BackgroundStyle.Sprint(blankLine))
+ ret.WriteByte('\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.WriteString(p.BackgroundStyle.Sprint(p.TextStyle.Sprint(line)))
+ ret.WriteByte('\n')
+ }
+ ret.WriteString(p.BackgroundStyle.Sprint(blankLine))
+ ret.WriteByte('\n')
+
+ return ret.String()
+}
+
+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 ...any) 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 ...any) 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 ...any) 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 ...any) *TextPrinter {
+ Fprint(p.Writer, 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 ...any) *TextPrinter {
+ Fprint(p.Writer, 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 ...any) *TextPrinter {
+ Fprint(p.Writer, 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 ...any) *TextPrinter {
+ Fprint(p.Writer, 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 ...any) *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 ...any) *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/heatmap_printer.go b/vendor/github.com/pterm/pterm/heatmap_printer.go
new file mode 100644
index 0000000..f0765e5
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/heatmap_printer.go
@@ -0,0 +1,744 @@
+package pterm
+
+import (
+ "bytes"
+ "errors"
+ "io"
+ "math"
+ "strings"
+
+ "github.com/pterm/pterm/internal"
+)
+
+// DefaultHeatmap contains standards, which can be used to print a HeatmapPrinter.
+var DefaultHeatmap = HeatmapPrinter{
+ AxisStyle: &ThemeDefault.HeatmapHeaderStyle,
+ SeparatorStyle: &ThemeDefault.HeatmapSeparatorStyle,
+ VerticalSeparator: "│",
+ TopRightCornerSeparator: "└",
+ TopLeftCornerSeparator: "┘",
+ BottomLeftCornerSeparator: "┐",
+ BottomRightCornerSeparator: "┌",
+ HorizontalSeparator: "─",
+ TSeparator: "┬",
+ TReverseSeparator: "┴",
+ LSeparator: "├",
+ LReverseSeparator: "┤",
+ TCrossSeparator: "┼",
+ LegendLabel: "Legend",
+ Boxed: true,
+ Grid: true,
+ Legend: true,
+ TextRGB: RGB{0, 0, 0, false},
+ RGBRange: []RGB{{R: 255, G: 0, B: 0, Background: true}, {R: 255, G: 165, B: 0, Background: true}, {R: 0, G: 255, B: 0, Background: true}},
+ TextColor: FgBlack,
+ Colors: []Color{BgRed, BgLightRed, BgYellow, BgLightYellow, BgLightGreen, BgGreen},
+
+ EnableRGB: false,
+}
+
+// HeatmapData is the type that contains the data of a HeatmapPrinter.
+type HeatmapData [][]float32
+
+type HeatmapAxis struct {
+ XAxis []string
+ YAxis []string
+}
+
+// HeatmapPrinter is able to render tables.
+type HeatmapPrinter struct {
+ HasHeader bool
+ AxisStyle *Style
+ VerticalSeparator string
+ TopRightCornerSeparator string
+ TopLeftCornerSeparator string
+ BottomLeftCornerSeparator string
+ BottomRightCornerSeparator string
+ HorizontalSeparator string
+ TSeparator string
+ TReverseSeparator string
+ LSeparator string
+ LReverseSeparator string
+ TCrossSeparator string
+ LegendLabel string
+ SeparatorStyle *Style
+ Data HeatmapData
+ Axis HeatmapAxis
+ Boxed bool
+ Grid bool
+ OnlyColoredCells bool
+ LegendOnlyColoredCells bool
+ EnableComplementaryColor bool
+ Legend bool
+ CellSize int
+ Colors []Color
+ TextColor Color
+ EnableRGB bool
+ RGBRange []RGB
+ TextRGB RGB
+ Writer io.Writer
+
+ minValue float32
+ maxValue float32
+
+ rgbLegendValue int
+}
+
+var complementaryColors = map[Color]Color{
+ BgBlack: FgLightWhite,
+ BgRed: FgCyan,
+ BgGreen: FgMagenta,
+ BgYellow: FgBlue,
+ BgBlue: FgYellow,
+ BgMagenta: FgGreen,
+ BgCyan: FgRed,
+ BgWhite: FgBlack,
+ BgDefault: FgBlack,
+ BgDarkGray: FgLightWhite,
+ BgLightRed: FgLightCyan,
+ BgLightGreen: FgLightMagenta,
+ BgLightYellow: FgLightBlue,
+ BgLightBlue: FgLightYellow,
+ BgLightMagenta: FgLightGreen,
+ BgLightCyan: FgLightRed,
+ BgLightWhite: FgBlack,
+}
+
+// WithAxisData returns a new HeatmapPrinter, where the first line and row are headers.
+func (p HeatmapPrinter) WithAxisData(hd HeatmapAxis) *HeatmapPrinter {
+ p.HasHeader = true
+ p.Axis = hd
+ return &p
+}
+
+// WithAxisStyle returns a new HeatmapPrinter with a specific AxisStyle.
+func (p HeatmapPrinter) WithAxisStyle(style *Style) *HeatmapPrinter {
+ p.AxisStyle = style
+ return &p
+}
+
+// WithSeparatorStyle returns a new HeatmapPrinter with a specific SeparatorStyle.
+func (p HeatmapPrinter) WithSeparatorStyle(style *Style) *HeatmapPrinter {
+ p.SeparatorStyle = style
+ return &p
+}
+
+// WithData returns a new HeatmapPrinter with specific Data.
+func (p HeatmapPrinter) WithData(data [][]float32) *HeatmapPrinter {
+ p.Data = data
+ return &p
+}
+
+// WithTextColor returns a new HeatmapPrinter with a specific TextColor.
+// This sets EnableComplementaryColor to false.
+func (p HeatmapPrinter) WithTextColor(color Color) *HeatmapPrinter {
+ p.TextColor = color
+ p.EnableComplementaryColor = false
+ return &p
+}
+
+// WithTextRGB returns a new HeatmapPrinter with a specific TextRGB.
+// This sets EnableComplementaryColor to false.
+func (p HeatmapPrinter) WithTextRGB(rgb RGB) *HeatmapPrinter {
+ p.TextRGB = rgb
+ p.EnableComplementaryColor = false
+ return &p
+}
+
+// WithBoxed returns a new HeatmapPrinter with a box around the table.
+// If set to true, Grid will be set to true too.
+func (p HeatmapPrinter) WithBoxed(b ...bool) *HeatmapPrinter {
+ p.Boxed = internal.WithBoolean(b)
+ if p.Boxed && !p.Grid {
+ p.Grid = true
+ }
+ return &p
+}
+
+// WithGrid returns a new HeatmapPrinter with a grid.
+// If set to false, Boxed will be set to false too.
+func (p HeatmapPrinter) WithGrid(b ...bool) *HeatmapPrinter {
+ b2 := internal.WithBoolean(b)
+ p.Grid = b2
+ if !b2 && p.Boxed {
+ p.Boxed = false
+ }
+ return &p
+}
+
+// WithEnableRGB returns a new HeatmapPrinter with RGB colors.
+func (p HeatmapPrinter) WithEnableRGB(b ...bool) *HeatmapPrinter {
+ p.EnableRGB = internal.WithBoolean(b)
+ return &p
+}
+
+// WithOnlyColoredCells returns a new HeatmapPrinter with only colored cells.
+func (p HeatmapPrinter) WithOnlyColoredCells(b ...bool) *HeatmapPrinter {
+ b2 := internal.WithBoolean(b)
+ p.OnlyColoredCells = b2
+ return &p
+}
+
+// WithLegendOnlyColoredCells returns a new HeatmapPrinter with legend with only colored cells.
+// This sets the Legend to true.
+func (p HeatmapPrinter) WithLegendOnlyColoredCells(b ...bool) *HeatmapPrinter {
+ b2 := internal.WithBoolean(b)
+ p.LegendOnlyColoredCells = b2
+ if b2 {
+ p.Legend = true
+ }
+ return &p
+}
+
+// WithEnableComplementaryColor returns a new HeatmapPrinter with complement color.
+func (p HeatmapPrinter) WithEnableComplementaryColor(b ...bool) *HeatmapPrinter {
+ p.EnableComplementaryColor = internal.WithBoolean(b)
+ return &p
+}
+
+// WithLegend returns a new HeatmapPrinter with a legend.
+func (p HeatmapPrinter) WithLegend(b ...bool) *HeatmapPrinter {
+ p.Legend = internal.WithBoolean(b)
+ return &p
+}
+
+// WithCellSize returns a new HeatmapPrinter with a specific cell size.
+// This only works if there is no header and OnlyColoredCells == true!
+func (p HeatmapPrinter) WithCellSize(i int) *HeatmapPrinter {
+ p.CellSize = i
+ return &p
+}
+
+// WithLegendLabel returns a new HeatmapPrinter with a specific legend tag.
+// This sets the Legend to true.
+func (p HeatmapPrinter) WithLegendLabel(s string) *HeatmapPrinter {
+ p.LegendLabel = s
+ p.Legend = true
+ return &p
+}
+
+// WithRGBRange returns a new HeatmapPrinter with a specific RGBRange.
+func (p HeatmapPrinter) WithRGBRange(rgb ...RGB) *HeatmapPrinter {
+ p.RGBRange = rgb
+ return &p
+}
+
+// WithColors returns a new HeatmapPrinter with a specific Colors.
+func (p HeatmapPrinter) WithColors(colors ...Color) *HeatmapPrinter {
+ p.Colors = colors
+ return &p
+}
+
+// WithWriter sets the Writer.
+func (p HeatmapPrinter) WithWriter(writer io.Writer) *HeatmapPrinter {
+ p.Writer = writer
+ return &p
+}
+
+// Srender renders the HeatmapPrinter as a string.
+func (p HeatmapPrinter) Srender() (string, error) {
+ if err := p.errCheck(); err != nil {
+ return "", err
+ }
+
+ if p.SeparatorStyle == nil {
+ p.SeparatorStyle = DefaultHeatmap.SeparatorStyle
+ }
+ if p.AxisStyle == nil {
+ p.AxisStyle = DefaultHeatmap.AxisStyle
+ }
+
+ if RawOutput {
+ p.Legend = false
+ }
+
+ buffer := bytes.NewBufferString("")
+ xAmount := len(p.Data[0]) - 1
+ yAmount := len(p.Data) - 1
+ p.minValue, p.maxValue = minMaxFloat32(p.Data)
+
+ var data string
+ for _, datum := range p.Data {
+ for _, f := range datum {
+ data += Sprintf("%v\n", f)
+ }
+ }
+
+ if p.HasHeader {
+ data, xAmount, yAmount = p.computeAxisData(data, xAmount, yAmount)
+ }
+
+ colWidth := internal.GetStringMaxWidth(data)
+ legendColWidth := colWidth + 2
+
+ if p.OnlyColoredCells && (p.CellSize > colWidth || !p.HasHeader) {
+ colWidth = p.CellSize
+ }
+
+ if p.Boxed {
+ p.renderSeparatorRow(buffer, colWidth, xAmount, true)
+ }
+
+ p.renderData(buffer, colWidth, xAmount, yAmount)
+
+ if p.HasHeader {
+ p.renderHeader(buffer, colWidth, xAmount)
+ }
+
+ if p.Boxed {
+ p.renderSeparatorRow(buffer, colWidth, xAmount, false)
+ }
+
+ if p.Legend {
+ p.renderLegend(buffer, legendColWidth)
+ }
+
+ buffer.WriteString("\n")
+
+ return buffer.String(), nil
+}
+
+func (p HeatmapPrinter) computeAxisData(data string, xAmount, yAmount int) (string, int, int) {
+ var header string
+ for _, h := range p.Axis.XAxis {
+ header += h + "\n"
+ }
+ for _, h := range p.Axis.YAxis {
+ header += h + "\n"
+ }
+
+ if p.OnlyColoredCells {
+ data = header
+ } else {
+ data += header
+ }
+ xAmount++
+ yAmount++
+
+ p.Axis.YAxis = append(p.Axis.YAxis, "")
+
+ return data, xAmount, yAmount
+}
+
+func (p HeatmapPrinter) renderSeparatorRow(buffer *bytes.Buffer, colWidth, xAmount int, top bool) {
+ tSep := p.TReverseSeparator
+ rightSep := p.TopRightCornerSeparator
+ leftSep := p.TopLeftCornerSeparator
+
+ if top {
+ tSep = p.TSeparator
+ rightSep = p.BottomRightCornerSeparator
+ leftSep = p.BottomLeftCornerSeparator
+ } else {
+ buffer.WriteString("\n")
+ }
+ buffer.WriteString(p.SeparatorStyle.Sprint(rightSep))
+ for i := 0; i < xAmount+1; i++ {
+ buffer.WriteString(strings.Repeat(p.SeparatorStyle.Sprint(p.HorizontalSeparator), colWidth))
+ if i < xAmount {
+ buffer.WriteString(p.SeparatorStyle.Sprint(tSep))
+ }
+ }
+ buffer.WriteString(p.SeparatorStyle.Sprint(leftSep))
+
+ if top {
+ buffer.WriteString("\n")
+ }
+}
+
+func (p HeatmapPrinter) renderLegend(buffer *bytes.Buffer, legendColWidth int) {
+ buffer.WriteString("\n")
+ buffer.WriteString("\n")
+ if p.Boxed {
+ p.boxLegend(buffer, p.LegendLabel, legendColWidth)
+ } else {
+ p.generateLegend(buffer, p.LegendLabel, legendColWidth)
+ }
+}
+
+func (p HeatmapPrinter) renderHeader(buffer *bytes.Buffer, colWidth int, xAmount int) {
+ buffer.WriteString("\n")
+ if p.Boxed {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.LSeparator))
+ }
+ if p.Grid {
+ for i := 0; i < xAmount+1; i++ {
+ buffer.WriteString(strings.Repeat(p.SeparatorStyle.Sprint(p.HorizontalSeparator), colWidth))
+ if i < xAmount {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.TCrossSeparator))
+ }
+ }
+ }
+ if p.Boxed {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.LReverseSeparator))
+ }
+ if p.Grid {
+ buffer.WriteString("\n")
+ }
+ for j, f := range p.Axis.XAxis {
+ if j == 0 {
+ if p.Boxed {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.VerticalSeparator))
+ }
+ ct := internal.CenterText(" ", colWidth)
+ if len(ct) < colWidth {
+ ct += strings.Repeat(" ", colWidth-len(ct))
+ }
+ buffer.WriteString(p.AxisStyle.Sprint(ct))
+ if p.Grid {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.VerticalSeparator))
+ }
+ }
+ var ct string
+ ct = internal.CenterText(Sprintf("%v", f), colWidth)
+ if len(ct) < colWidth {
+ ct += strings.Repeat(" ", colWidth-len(ct))
+ }
+ buffer.WriteString(p.AxisStyle.Sprint(ct))
+
+ if j < xAmount {
+ if !p.Boxed && j == xAmount-1 {
+ continue
+ }
+ if p.Grid {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.VerticalSeparator))
+ }
+ }
+ }
+}
+
+func (p HeatmapPrinter) renderData(buffer *bytes.Buffer, colWidth int, xAmount int, yAmount int) {
+ for i, datum := range p.Data {
+ if p.Boxed {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.VerticalSeparator))
+ }
+ for j, f := range datum {
+ if j == 0 && p.HasHeader {
+ ct := internal.CenterText(p.Axis.YAxis[i], colWidth)
+ if len(ct) < colWidth {
+ ct += strings.Repeat(" ", colWidth-len(ct))
+ }
+ buffer.WriteString(p.AxisStyle.Sprint(ct))
+ if p.Grid {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.VerticalSeparator))
+ }
+ }
+ var ct string
+ if p.OnlyColoredCells {
+ ct = internal.CenterText(" ", colWidth)
+ } else {
+ ct = internal.CenterText(Sprintf("%v", f), colWidth)
+ }
+ if len(ct) < colWidth {
+ if len(Sprintf("%v", f)) == 1 {
+ ct += strings.Repeat(" ", colWidth-len(ct))
+ } else {
+ ct = strings.Repeat(" ", colWidth-len(ct)) + ct
+ }
+ }
+ if p.EnableRGB {
+ rgb := p.RGBRange[0].Fade(p.minValue, p.maxValue, f, p.RGBRange[1:]...)
+ rgbStyle := NewRGBStyle(p.TextRGB, rgb)
+ if p.EnableComplementaryColor {
+ complimentary := NewRGB(internal.Complementary(rgb.R, rgb.G, rgb.B))
+ rgbStyle = NewRGBStyle(complimentary, rgb)
+ }
+ buffer.WriteString(rgbStyle.Sprint(ct))
+ } else {
+ color := getColor(p.minValue, p.maxValue, f, p.Colors...)
+ fgColor := p.TextColor
+ if p.EnableComplementaryColor {
+ fgColor = complementaryColors[color]
+ }
+ buffer.WriteString(fgColor.Sprint(color.Sprintf("%s", ct)))
+ }
+ if j < xAmount {
+ if !p.Boxed && p.HasHeader && j == xAmount-1 {
+ continue
+ }
+ if p.Grid {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.VerticalSeparator))
+ }
+ }
+ if p.Boxed && !p.HasHeader && j == xAmount {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.VerticalSeparator))
+ }
+ }
+
+ if i < yAmount {
+ if p.HasHeader && i == yAmount-1 {
+ continue
+ }
+ buffer.WriteString("\n")
+ if p.Boxed {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.LSeparator))
+ }
+ if p.Grid {
+ for i := 0; i < xAmount+1; i++ {
+ buffer.WriteString(strings.Repeat(p.SeparatorStyle.Sprint(p.HorizontalSeparator), colWidth))
+ if i < xAmount {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.TCrossSeparator))
+ }
+ }
+ }
+ if p.Boxed {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.LReverseSeparator))
+ }
+ if p.Grid {
+ buffer.WriteString("\n")
+ }
+ }
+ }
+}
+
+func (p HeatmapPrinter) generateLegend(buffer *bytes.Buffer, legend string, legendColWidth int) {
+ buffer.WriteString(p.AxisStyle.Sprint(legend))
+ if p.Grid {
+ buffer.WriteString(p.SeparatorStyle.Sprintf("%s", p.VerticalSeparator))
+ } else {
+ buffer.WriteString(" ")
+ }
+ if p.EnableRGB {
+ p.generateRGBLegend(buffer, legendColWidth)
+ } else {
+ p.generateColorLegend(buffer, legendColWidth)
+ }
+}
+
+func (p HeatmapPrinter) generateColorLegend(buffer *bytes.Buffer, legendColWidth int) {
+ for i, color := range p.Colors {
+ // the first color is the min value and the last color is the max value
+ var f float32
+ if i == 0 {
+ f = p.minValue
+ } else if i == len(p.Colors)-1 {
+ f = p.maxValue
+ } else {
+ f = p.minValue + (p.maxValue-p.minValue)*float32(i)/float32(len(p.Colors)-1)
+ }
+ fgColor := p.TextColor
+ if p.EnableComplementaryColor {
+ fgColor = complementaryColors[color]
+ }
+ buffer.WriteString(fgColor.Sprint(color.Sprint(centerAndShorten(f, legendColWidth, p.LegendOnlyColoredCells))))
+ if p.Grid && i < len(p.Colors)-1 && !p.LegendOnlyColoredCells {
+ buffer.WriteString(p.SeparatorStyle.Sprintf("%s", p.VerticalSeparator))
+ }
+ }
+}
+
+func (p HeatmapPrinter) generateRGBLegend(buffer *bytes.Buffer, legendColWidth int) {
+ p.rgbLegendValue = 10
+ steps := len(p.RGBRange)
+ if steps < p.rgbLegendValue {
+ steps = p.rgbLegendValue
+ }
+ if p.LegendOnlyColoredCells {
+ steps *= 3
+ }
+ for i := 0; i < steps; i++ {
+ // the first color is the min value and the last color is the max value
+ var f float32
+ if i == 0 {
+ f = p.minValue
+ } else if i == steps-1 {
+ f = p.maxValue
+ } else {
+ f = p.minValue + (p.maxValue-p.minValue)*float32(i)/float32(steps-1)
+ }
+ rgb := p.RGBRange[0].Fade(p.minValue, p.maxValue, f, p.RGBRange[1:]...)
+ rgbStyle := NewRGBStyle(p.TextRGB, rgb)
+ if p.EnableComplementaryColor {
+ complimentary := NewRGB(internal.Complementary(rgb.R, rgb.G, rgb.B))
+ rgbStyle = NewRGBStyle(complimentary, rgb)
+ }
+ if p.LegendOnlyColoredCells {
+ buffer.WriteString(rgbStyle.Sprint(centerAndShorten(f, 1, p.LegendOnlyColoredCells)))
+ } else {
+ buffer.WriteString(rgbStyle.Sprint(centerAndShorten(f, legendColWidth, p.LegendOnlyColoredCells)))
+ }
+ if p.Grid && i < steps-1 && !p.LegendOnlyColoredCells {
+ buffer.WriteString(p.SeparatorStyle.Sprintf("%s", p.VerticalSeparator))
+ }
+ }
+}
+
+func (p HeatmapPrinter) boxLegend(buffer *bytes.Buffer, legend string, legendColWidth int) {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.BottomRightCornerSeparator))
+
+ p.generateSeparatorRow(buffer, legend, legendColWidth, true)
+
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.BottomLeftCornerSeparator))
+ buffer.WriteString("\n")
+ buffer.WriteString(p.SeparatorStyle.Sprintf("%s", p.VerticalSeparator))
+
+ p.generateLegend(buffer, legend, legendColWidth)
+
+ buffer.WriteString(p.SeparatorStyle.Sprintf("%s", p.VerticalSeparator))
+ buffer.WriteString("\n")
+
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.TopRightCornerSeparator))
+
+ p.generateSeparatorRow(buffer, legend, legendColWidth, false)
+
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.TopLeftCornerSeparator))
+}
+
+func (p HeatmapPrinter) generateSeparatorRow(buffer *bytes.Buffer, legend string, legendColWidth int, top bool) {
+ p.rgbLegendValue = 10
+ steps := len(p.RGBRange)
+ if steps < p.rgbLegendValue {
+ steps = p.rgbLegendValue
+ }
+ if p.LegendOnlyColoredCells {
+ steps *= 3
+ }
+
+ var xValue int
+ if p.EnableRGB {
+ xValue = len(p.RGBRange)
+ if xValue < p.rgbLegendValue {
+ xValue = p.rgbLegendValue
+ }
+ } else {
+ xValue = len(p.Colors)
+ }
+
+ for i := 0; i < xValue+1; i++ {
+ if i == 0 {
+ firstLength := len(legend)
+ buffer.WriteString(strings.Repeat(p.SeparatorStyle.Sprint(p.HorizontalSeparator), firstLength))
+ } else {
+ if p.LegendOnlyColoredCells {
+ if p.EnableRGB {
+ buffer.WriteString(strings.Repeat(p.SeparatorStyle.Sprint(p.HorizontalSeparator), steps/(xValue)))
+ } else {
+ buffer.WriteString(strings.Repeat(p.SeparatorStyle.Sprint(p.HorizontalSeparator), legendColWidth))
+ }
+ } else {
+ buffer.WriteString(strings.Repeat(p.SeparatorStyle.Sprint(p.HorizontalSeparator), legendColWidth))
+ }
+ }
+ if i < xValue && !p.LegendOnlyColoredCells || i == 0 {
+ if top {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.TSeparator))
+ } else {
+ buffer.WriteString(p.SeparatorStyle.Sprint(p.TReverseSeparator))
+ }
+ }
+ }
+}
+
+func centerAndShorten(f float32, lineLength int, onlyColor bool) string {
+ value := ""
+ if !onlyColor {
+ value = Sprintf("%.2v", f)
+ }
+ if len(value) > lineLength {
+ value = value[:lineLength]
+ if strings.HasSuffix(value, ".") {
+ value = Sprintf("%.1v", f)
+ lineLength = len(value)
+ }
+ }
+ ct := internal.CenterText(value, lineLength)
+ if len(ct) < lineLength {
+ if len(Sprintf("%v", f)) == 1 {
+ ct += strings.Repeat(" ", lineLength-len(ct))
+ } else {
+ ct = strings.Repeat(" ", lineLength-len(ct)) + ct
+ }
+ }
+
+ return ct
+}
+
+func getColor(minStep float32, maxStep float32, current float32, colors ...Color) Color {
+ // split the range into equal parts
+ // and assign a color to each part
+ // the last color is assigned to the max value
+ // and the first color to the min value
+ // the rest of the colors are assigned to the
+ // middle values
+ step := (maxStep - minStep) / float32(len(colors))
+ for i := range colors {
+ if current >= minStep+float32(i)*step && current < minStep+float32(i+1)*step {
+ return colors[i]
+ }
+ }
+ return colors[len(colors)-1]
+}
+
+// Render prints the HeatmapPrinter to the terminal.
+func (p HeatmapPrinter) Render() error {
+ s, err := p.Srender()
+ if err != nil {
+ return err
+ }
+ Fprintln(p.Writer, s)
+
+ return nil
+}
+
+func (p HeatmapPrinter) errCheck() error {
+ if p.HasHeader {
+ if p.Axis.XAxis == nil {
+ return errors.New("x axis is nil")
+ }
+ if p.Axis.YAxis == nil {
+ return errors.New("y axis is nil")
+ }
+
+ if len(p.Axis.XAxis) == 0 {
+ return errors.New("x axis is empty")
+ }
+ if len(p.Axis.YAxis) == 0 {
+ return errors.New("y axis is empty")
+ }
+
+ for i := 1; i < len(p.Data); i++ {
+ if len(p.Data[i]) != len(p.Axis.XAxis) {
+ return errors.New("x axis length does not match data")
+ }
+ }
+ if len(p.Axis.YAxis) != len(p.Data) {
+ return errors.New("y axis length does not match data")
+ }
+ }
+
+ if p.Data == nil {
+ return errors.New("data is nil")
+ }
+
+ if len(p.Data) == 0 {
+ return errors.New("data is empty")
+ }
+
+ // check if p.Data[n] has the same length
+ for i := 1; i < len(p.Data); i++ {
+ if len(p.Data[i]) != len(p.Data[0]) {
+ return errors.New("data is not rectangular")
+ }
+ }
+
+ return nil
+}
+
+// return min and max value of a slice
+func minMaxFloat32(s [][]float32) (float32, float32) {
+ var minslice, maxslice float32
+ minslice = math.MaxFloat32
+ maxslice = -math.MaxFloat32
+
+ for _, r := range s {
+ for _, c := range r {
+ if c < minslice {
+ minslice = c
+ }
+ if c > maxslice {
+ maxslice = c
+ }
+ }
+ }
+ return minslice, maxslice
+}
diff --git a/vendor/github.com/pterm/pterm/interactive_confirm_printer.go b/vendor/github.com/pterm/pterm/interactive_confirm_printer.go
new file mode 100644
index 0000000..a94cc5d
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/interactive_confirm_printer.go
@@ -0,0 +1,186 @@
+package pterm
+
+import (
+ "fmt"
+ "strings"
+
+ "atomicgo.dev/cursor"
+ "atomicgo.dev/keyboard"
+ "atomicgo.dev/keyboard/keys"
+
+ "github.com/pterm/pterm/internal"
+)
+
+// DefaultInteractiveConfirm is the default InteractiveConfirm printer.
+// Pressing "y" will return true, "n" will return false.
+// Pressing enter without typing "y" or "n" will return the configured default value (by default set to "no").
+var DefaultInteractiveConfirm = InteractiveConfirmPrinter{
+ DefaultValue: false,
+ DefaultText: "Please confirm",
+ TextStyle: &ThemeDefault.PrimaryStyle,
+ ConfirmText: "Yes",
+ ConfirmStyle: &ThemeDefault.SuccessMessageStyle,
+ RejectText: "No",
+ RejectStyle: &ThemeDefault.ErrorMessageStyle,
+ SuffixStyle: &ThemeDefault.SecondaryStyle,
+ Delimiter: ": ",
+}
+
+// InteractiveConfirmPrinter is a printer for interactive confirm prompts.
+type InteractiveConfirmPrinter struct {
+ DefaultValue bool
+ DefaultText string
+ Delimiter string
+ TextStyle *Style
+ ConfirmText string
+ ConfirmStyle *Style
+ RejectText string
+ RejectStyle *Style
+ SuffixStyle *Style
+ OnInterruptFunc func()
+}
+
+// WithDefaultText sets the default text.
+func (p InteractiveConfirmPrinter) WithDefaultText(text string) *InteractiveConfirmPrinter {
+ p.DefaultText = text
+ return &p
+}
+
+// WithDefaultValue sets the default value, which will be returned when the user presses enter without typing "y" or "n".
+func (p InteractiveConfirmPrinter) WithDefaultValue(value bool) *InteractiveConfirmPrinter {
+ p.DefaultValue = value
+ return &p
+}
+
+// WithTextStyle sets the text style.
+func (p InteractiveConfirmPrinter) WithTextStyle(style *Style) *InteractiveConfirmPrinter {
+ p.TextStyle = style
+ return &p
+}
+
+// WithConfirmText sets the confirm text.
+func (p InteractiveConfirmPrinter) WithConfirmText(text string) *InteractiveConfirmPrinter {
+ p.ConfirmText = text
+ return &p
+}
+
+// WithConfirmStyle sets the confirm style.
+func (p InteractiveConfirmPrinter) WithConfirmStyle(style *Style) *InteractiveConfirmPrinter {
+ p.ConfirmStyle = style
+ return &p
+}
+
+// WithRejectText sets the reject text.
+func (p InteractiveConfirmPrinter) WithRejectText(text string) *InteractiveConfirmPrinter {
+ p.RejectText = text
+ return &p
+}
+
+// WithRejectStyle sets the reject style.
+func (p InteractiveConfirmPrinter) WithRejectStyle(style *Style) *InteractiveConfirmPrinter {
+ p.RejectStyle = style
+ return &p
+}
+
+// WithSuffixStyle sets the suffix style.
+func (p InteractiveConfirmPrinter) WithSuffixStyle(style *Style) *InteractiveConfirmPrinter {
+ p.SuffixStyle = style
+ return &p
+}
+
+// OnInterrupt sets the function to execute on exit of the input reader
+func (p InteractiveConfirmPrinter) WithOnInterruptFunc(exitFunc func()) *InteractiveConfirmPrinter {
+ p.OnInterruptFunc = exitFunc
+ return &p
+}
+
+// WithDelimiter sets the delimiter between the message and the input.
+func (p InteractiveConfirmPrinter) WithDelimiter(delimiter string) *InteractiveConfirmPrinter {
+ p.Delimiter = delimiter
+ return &p
+}
+
+// Show shows the confirm prompt.
+//
+// Example:
+//
+// result, _ := pterm.DefaultInteractiveConfirm.Show("Are you sure?")
+// pterm.Println(result)
+func (p InteractiveConfirmPrinter) Show(text ...string) (bool, error) {
+ // should be the first defer statement to make sure it is executed last
+ // and all the needed cleanup can be done before
+ cancel, exit := internal.NewCancelationSignal(p.OnInterruptFunc)
+ defer exit()
+
+ var result bool
+
+ if len(text) == 0 || text[0] == "" {
+ text = []string{p.DefaultText}
+ }
+
+ p.TextStyle.Print(text[0] + " " + p.getSuffix() + p.Delimiter)
+ y, n := p.getShortHandles()
+
+ var interrupted bool
+ err := keyboard.Listen(func(keyInfo keys.Key) (stop bool, err error) {
+ key := keyInfo.Code
+ char := strings.ToLower(keyInfo.String())
+ if err != nil {
+ return false, fmt.Errorf("failed to get key: %w", err)
+ }
+
+ switch key {
+ case keys.RuneKey:
+ switch char {
+ case y:
+ p.ConfirmStyle.Print(p.ConfirmText)
+ Println()
+ result = true
+ return true, nil
+ case n:
+ p.RejectStyle.Print(p.RejectText)
+ Println()
+ result = false
+ return true, nil
+ }
+ case keys.Enter:
+ if p.DefaultValue {
+ p.ConfirmStyle.Print(p.ConfirmText)
+ } else {
+ p.RejectStyle.Print(p.RejectText)
+ }
+ Println()
+ result = p.DefaultValue
+ return true, nil
+ case keys.CtrlC:
+ cancel()
+ interrupted = true
+ return true, nil
+ }
+ return false, nil
+ })
+ if !interrupted {
+ cursor.StartOfLine()
+ }
+ return result, err
+}
+
+// getShortHandles returns the short hand answers for the confirmation prompt
+func (p InteractiveConfirmPrinter) getShortHandles() (string, string) {
+ y := strings.ToLower(string([]rune(p.ConfirmText)[0]))
+ n := strings.ToLower(string([]rune(p.RejectText)[0]))
+
+ return y, n
+}
+
+// getSuffix returns the confirmation prompt suffix
+func (p InteractiveConfirmPrinter) getSuffix() string {
+ y, n := p.getShortHandles()
+ if p.DefaultValue {
+ y = strings.ToUpper(y)
+ } else {
+ n = strings.ToUpper(n)
+ }
+
+ return p.SuffixStyle.Sprintf("[%s/%s]", y, n)
+}
diff --git a/vendor/github.com/pterm/pterm/interactive_continue_printer.go b/vendor/github.com/pterm/pterm/interactive_continue_printer.go
new file mode 100644
index 0000000..a6c23ff
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/interactive_continue_printer.go
@@ -0,0 +1,197 @@
+package pterm
+
+import (
+ "fmt"
+ "strings"
+
+ "atomicgo.dev/cursor"
+ "atomicgo.dev/keyboard"
+ "atomicgo.dev/keyboard/keys"
+ "golang.org/x/text/cases"
+ "golang.org/x/text/language"
+
+ "github.com/pterm/pterm/internal"
+)
+
+// DefaultInteractiveContinue is the default InteractiveContinue printer.
+// Pressing "y" will return yes, "n" will return no, "a" returns all and "s" returns stop.
+// Pressing enter without typing any letter will return the configured default value (by default set to "yes", the fisrt option).
+var DefaultInteractiveContinue = InteractiveContinuePrinter{
+ DefaultValueIndex: 0,
+ DefaultText: "Do you want to continue",
+ TextStyle: &ThemeDefault.PrimaryStyle,
+ Options: []string{"yes", "no", "all", "cancel"},
+ OptionsStyle: &ThemeDefault.SuccessMessageStyle,
+ SuffixStyle: &ThemeDefault.SecondaryStyle,
+ Delimiter: ": ",
+}
+
+// InteractiveContinuePrinter is a printer for interactive continue prompts.
+type InteractiveContinuePrinter struct {
+ DefaultValueIndex int
+ DefaultText string
+ Delimiter string
+ TextStyle *Style
+ Options []string
+ OptionsStyle *Style
+ Handles []string
+ ShowShortHandles bool
+ SuffixStyle *Style
+}
+
+// WithDefaultText sets the default text.
+func (p InteractiveContinuePrinter) WithDefaultText(text string) *InteractiveContinuePrinter {
+ p.DefaultText = text
+ return &p
+}
+
+// WithDefaultValueIndex sets the default value, which will be returned when the user presses enter without typing any letter.
+func (p InteractiveContinuePrinter) WithDefaultValueIndex(value int) *InteractiveContinuePrinter {
+ if value >= len(p.Options) {
+ panic("Index out of range")
+ }
+ p.DefaultValueIndex = value
+ return &p
+}
+
+// WithDefaultValue sets the default value, which will be returned when the user presses enter without typing any letter.
+func (p InteractiveContinuePrinter) WithDefaultValue(value string) *InteractiveContinuePrinter {
+ for i, o := range p.Options {
+ if o == value {
+ p.DefaultValueIndex = i
+ break
+ }
+ }
+ return &p
+}
+
+// WithTextStyle sets the text style.
+func (p InteractiveContinuePrinter) WithTextStyle(style *Style) *InteractiveContinuePrinter {
+ p.TextStyle = style
+ return &p
+}
+
+// WithOptions sets the options.
+func (p InteractiveContinuePrinter) WithOptions(options []string) *InteractiveContinuePrinter {
+ p.Options = options
+ return &p
+}
+
+// WithHandles allows you to customize the short handles for the answers.
+func (p InteractiveContinuePrinter) WithHandles(handles []string) *InteractiveContinuePrinter {
+ if len(handles) != len(p.Options) {
+ Warning.Printf("%v is not a valid set of handles", handles)
+ p.setDefaultHandles()
+ return &p
+ }
+ p.Handles = handles
+ return &p
+}
+
+// WithShowShortHandles will set ShowShortHandles to true
+// this makes the printer display the shorthand options instead their shorthand version.
+func (p InteractiveContinuePrinter) WithShowShortHandles(b ...bool) *InteractiveContinuePrinter {
+ p.ShowShortHandles = internal.WithBoolean(b)
+ return &p
+}
+
+// WithOptionsStyle sets the continue style.
+func (p InteractiveContinuePrinter) WithOptionsStyle(style *Style) *InteractiveContinuePrinter {
+ p.OptionsStyle = style
+ return &p
+}
+
+// WithSuffixStyle sets the suffix style.
+func (p InteractiveContinuePrinter) WithSuffixStyle(style *Style) *InteractiveContinuePrinter {
+ p.SuffixStyle = style
+ return &p
+}
+
+// WithDelimiter sets the delimiter between the message and the input.
+func (p InteractiveContinuePrinter) WithDelimiter(delimiter string) *InteractiveContinuePrinter {
+ p.Delimiter = delimiter
+ return &p
+}
+
+// Show shows the continue prompt.
+//
+// Example:
+//
+// result, _ := pterm.DefaultInteractiveContinue.Show("Do you want to apply the changes?")
+// pterm.Println(result)
+func (p InteractiveContinuePrinter) Show(text ...string) (string, error) {
+ var result string
+
+ if len(text) == 0 || text[0] == "" {
+ text = []string{p.DefaultText}
+ }
+
+ p.TextStyle.Print(text[0] + " " + p.getSuffix() + p.Delimiter)
+
+ err := keyboard.Listen(func(keyInfo keys.Key) (stop bool, err error) {
+ if err != nil {
+ return false, fmt.Errorf("failed to get key: %w", err)
+ }
+ key := keyInfo.Code
+ char := keyInfo.String()
+
+ switch key {
+ case keys.RuneKey:
+ for i, c := range p.Handles {
+ if !p.ShowShortHandles {
+ c = string([]rune(c)[0])
+ }
+ if char == c || (i == p.DefaultValueIndex && strings.EqualFold(c, char)) {
+ p.OptionsStyle.Print(p.Options[i])
+ Println()
+ result = p.Options[i]
+ return true, nil
+ }
+ }
+ case keys.Enter:
+ p.OptionsStyle.Print(p.Options[p.DefaultValueIndex])
+ Println()
+ result = p.Options[p.DefaultValueIndex]
+ return true, nil
+ case keys.CtrlC:
+ internal.Exit(1)
+ return true, nil
+ }
+ return false, nil
+ })
+ cursor.StartOfLine()
+ return result, err
+}
+
+// getShortHandles returns the short hand answers for the continueation prompt
+func (p InteractiveContinuePrinter) getShortHandles() []string {
+ var handles []string
+ for _, option := range p.Options {
+ handles = append(handles, strings.ToLower(string([]rune(option)[0])))
+ }
+ handles[p.DefaultValueIndex] = strings.ToUpper(handles[p.DefaultValueIndex])
+
+ return handles
+}
+
+// setDefaultHandles initialises the handles
+func (p *InteractiveContinuePrinter) setDefaultHandles() {
+ if p.ShowShortHandles {
+ p.Handles = p.getShortHandles()
+ }
+
+ if len(p.Handles) == 0 {
+ p.Handles = make([]string, len(p.Options))
+ copy(p.Handles, p.Options)
+ p.Handles[p.DefaultValueIndex] = cases.Title(language.Und, cases.Compact).String(p.Handles[p.DefaultValueIndex])
+ }
+}
+
+// getSuffix returns the continuation prompt suffix
+func (p *InteractiveContinuePrinter) getSuffix() string {
+ if p.Handles == nil || len(p.Handles) != len(p.Options) {
+ p.setDefaultHandles()
+ }
+
+ return p.SuffixStyle.Sprintf("[%s]", strings.Join(p.Handles, "/"))
+}
diff --git a/vendor/github.com/pterm/pterm/interactive_multiselect_printer.go b/vendor/github.com/pterm/pterm/interactive_multiselect_printer.go
new file mode 100644
index 0000000..83c1756
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/interactive_multiselect_printer.go
@@ -0,0 +1,402 @@
+package pterm
+
+import (
+ "fmt"
+ "sort"
+ "strings"
+
+ "atomicgo.dev/cursor"
+ "atomicgo.dev/keyboard"
+ "atomicgo.dev/keyboard/keys"
+ "github.com/lithammer/fuzzysearch/fuzzy"
+
+ "github.com/pterm/pterm/internal"
+)
+
+var (
+ // DefaultInteractiveMultiselect is the default InteractiveMultiselect printer.
+ DefaultInteractiveMultiselect = InteractiveMultiselectPrinter{
+ TextStyle: &ThemeDefault.PrimaryStyle,
+ DefaultText: "Please select your options",
+ Options: []string{},
+ OptionStyle: &ThemeDefault.DefaultText,
+ DefaultOptions: []string{},
+ MaxHeight: 5,
+ Selector: ">",
+ SelectorStyle: &ThemeDefault.SecondaryStyle,
+ Filter: true,
+ KeySelect: keys.Enter,
+ KeyConfirm: keys.Tab,
+ Checkmark: &ThemeDefault.Checkmark,
+ }
+)
+
+// InteractiveMultiselectPrinter is a printer for interactive multiselect menus.
+type InteractiveMultiselectPrinter struct {
+ DefaultText string
+ TextStyle *Style
+ Options []string
+ OptionStyle *Style
+ DefaultOptions []string
+ MaxHeight int
+ Selector string
+ SelectorStyle *Style
+ Filter bool
+ Checkmark *Checkmark
+ OnInterruptFunc func()
+
+ selectedOption int
+ selectedOptions []int
+ text string
+ fuzzySearchString string
+ fuzzySearchMatches []string
+ displayedOptions []string
+ displayedOptionsStart int
+ displayedOptionsEnd int
+
+ // KeySelect is the select key. It cannot be keys.Space when Filter is enabled.
+ KeySelect keys.KeyCode
+
+ // KeyConfirm is the confirm key. It cannot be keys.Space when Filter is enabled.
+ KeyConfirm keys.KeyCode
+}
+
+// WithOptions sets the options.
+func (p InteractiveMultiselectPrinter) WithOptions(options []string) *InteractiveMultiselectPrinter {
+ p.Options = options
+ return &p
+}
+
+// WithDefaultOptions sets the default options.
+func (p InteractiveMultiselectPrinter) WithDefaultOptions(options []string) *InteractiveMultiselectPrinter {
+ p.DefaultOptions = options
+ return &p
+}
+
+// WithDefaultText sets the default text.
+func (p InteractiveMultiselectPrinter) WithDefaultText(text string) *InteractiveMultiselectPrinter {
+ p.DefaultText = text
+ return &p
+}
+
+// WithMaxHeight sets the maximum height of the select menu.
+func (p InteractiveMultiselectPrinter) WithMaxHeight(maxHeight int) *InteractiveMultiselectPrinter {
+ p.MaxHeight = maxHeight
+ return &p
+}
+
+// WithFilter sets the Filter option
+func (p InteractiveMultiselectPrinter) WithFilter(b ...bool) *InteractiveMultiselectPrinter {
+ p.Filter = internal.WithBoolean(b)
+ return &p
+}
+
+// WithKeySelect sets the confirm key
+// It cannot be keys.Space when Filter is enabled.
+func (p InteractiveMultiselectPrinter) WithKeySelect(keySelect keys.KeyCode) *InteractiveMultiselectPrinter {
+ p.KeySelect = keySelect
+ return &p
+}
+
+// WithKeyConfirm sets the confirm key
+// It cannot be keys.Space when Filter is enabled.
+func (p InteractiveMultiselectPrinter) WithKeyConfirm(keyConfirm keys.KeyCode) *InteractiveMultiselectPrinter {
+ p.KeyConfirm = keyConfirm
+ return &p
+}
+
+// WithCheckmark sets the checkmark
+func (p InteractiveMultiselectPrinter) WithCheckmark(checkmark *Checkmark) *InteractiveMultiselectPrinter {
+ p.Checkmark = checkmark
+ return &p
+}
+
+// OnInterrupt sets the function to execute on exit of the input reader
+func (p InteractiveMultiselectPrinter) WithOnInterruptFunc(exitFunc func()) *InteractiveMultiselectPrinter {
+ p.OnInterruptFunc = exitFunc
+ return &p
+}
+
+// Show shows the interactive multiselect menu and returns the selected entry.
+func (p *InteractiveMultiselectPrinter) Show(text ...string) ([]string, error) {
+ // should be the first defer statement to make sure it is executed last
+ // and all the needed cleanup can be done before
+ cancel, exit := internal.NewCancelationSignal(p.OnInterruptFunc)
+ defer exit()
+
+ if len(text) == 0 || Sprint(text[0]) == "" {
+ text = []string{p.DefaultText}
+ }
+
+ p.text = p.TextStyle.Sprint(text[0])
+ p.fuzzySearchMatches = append([]string{}, p.Options...)
+
+ if p.MaxHeight == 0 {
+ p.MaxHeight = DefaultInteractiveMultiselect.MaxHeight
+ }
+
+ maxHeight := p.MaxHeight
+ if maxHeight > len(p.fuzzySearchMatches) {
+ maxHeight = len(p.fuzzySearchMatches)
+ }
+
+ if len(p.Options) == 0 {
+ return nil, fmt.Errorf("no options provided")
+ }
+
+ p.displayedOptions = append([]string{}, p.fuzzySearchMatches[:maxHeight]...)
+ p.displayedOptionsStart = 0
+ p.displayedOptionsEnd = maxHeight
+
+ for _, option := range p.DefaultOptions {
+ p.selectOption(option)
+ }
+
+ area, err := DefaultArea.Start(p.renderSelectMenu())
+ defer area.Stop()
+ if err != nil {
+ return nil, fmt.Errorf("could not start area: %w", err)
+ }
+
+ if p.Filter && (p.KeyConfirm == keys.Space || p.KeySelect == keys.Space) {
+ return nil, fmt.Errorf("if filter/search is active, keys.Space can not be used for KeySelect or KeyConfirm")
+ }
+
+ area.Update(p.renderSelectMenu())
+
+ cursor.Hide()
+ defer cursor.Show()
+ err = keyboard.Listen(func(keyInfo keys.Key) (stop bool, err error) {
+ key := keyInfo.Code
+
+ if p.MaxHeight > len(p.fuzzySearchMatches) {
+ maxHeight = len(p.fuzzySearchMatches)
+ } else {
+ maxHeight = p.MaxHeight
+ }
+
+ switch key {
+ case p.KeyConfirm:
+ if len(p.fuzzySearchMatches) == 0 {
+ return false, nil
+ }
+ area.Update(p.renderFinishedMenu())
+ return true, nil
+ case p.KeySelect:
+ if len(p.fuzzySearchMatches) > 0 {
+ // Select option if not already selected
+ p.selectOption(p.fuzzySearchMatches[p.selectedOption])
+ }
+ area.Update(p.renderSelectMenu())
+ case keys.RuneKey:
+ if p.Filter {
+ // Fuzzy search for options
+ // append to fuzzy search string
+ p.fuzzySearchString += keyInfo.String()
+ p.selectedOption = 0
+ p.displayedOptionsStart = 0
+ p.displayedOptionsEnd = maxHeight
+ p.displayedOptions = append([]string{}, p.fuzzySearchMatches[:maxHeight]...)
+ }
+ area.Update(p.renderSelectMenu())
+ case keys.Space:
+ if p.Filter {
+ p.fuzzySearchString += " "
+ p.selectedOption = 0
+ area.Update(p.renderSelectMenu())
+ }
+ case keys.Backspace:
+ // Remove last character from fuzzy search string
+ if p.fuzzySearchString != "" {
+ // Handle UTF-8 characters
+ p.fuzzySearchString = string([]rune(p.fuzzySearchString)[:len([]rune(p.fuzzySearchString))-1])
+ }
+
+ if p.fuzzySearchString == "" {
+ p.fuzzySearchMatches = append([]string{}, p.Options...)
+ }
+
+ p.renderSelectMenu()
+
+ if len(p.fuzzySearchMatches) > p.MaxHeight {
+ maxHeight = p.MaxHeight
+ } else {
+ maxHeight = len(p.fuzzySearchMatches)
+ }
+
+ p.selectedOption = 0
+ p.displayedOptionsStart = 0
+ p.displayedOptionsEnd = maxHeight
+ p.displayedOptions = append([]string{}, p.fuzzySearchMatches[p.displayedOptionsStart:p.displayedOptionsEnd]...)
+
+ area.Update(p.renderSelectMenu())
+ case keys.Left:
+ // Unselect all options
+ p.selectedOptions = []int{}
+ area.Update(p.renderSelectMenu())
+ case keys.Right:
+ // Select all options
+ p.selectedOptions = []int{}
+ for i := 0; i < len(p.Options); i++ {
+ p.selectedOptions = append(p.selectedOptions, i)
+ }
+ area.Update(p.renderSelectMenu())
+ case keys.Up, keys.CtrlP:
+ if len(p.fuzzySearchMatches) == 0 {
+ return false, nil
+ }
+ if p.selectedOption > 0 {
+ p.selectedOption--
+ if p.selectedOption < p.displayedOptionsStart {
+ p.displayedOptionsStart--
+ p.displayedOptionsEnd--
+ if p.displayedOptionsStart < 0 {
+ p.displayedOptionsStart = 0
+ p.displayedOptionsEnd = maxHeight
+ }
+ p.displayedOptions = append([]string{}, p.fuzzySearchMatches[p.displayedOptionsStart:p.displayedOptionsEnd]...)
+ }
+ } else {
+ p.selectedOption = len(p.fuzzySearchMatches) - 1
+ p.displayedOptionsStart = len(p.fuzzySearchMatches) - maxHeight
+ p.displayedOptionsEnd = len(p.fuzzySearchMatches)
+ p.displayedOptions = append([]string{}, p.fuzzySearchMatches[p.displayedOptionsStart:p.displayedOptionsEnd]...)
+ }
+
+ area.Update(p.renderSelectMenu())
+ case keys.Down, keys.CtrlN:
+ if len(p.fuzzySearchMatches) == 0 {
+ return false, nil
+ }
+ p.displayedOptions = p.fuzzySearchMatches[:maxHeight]
+ if p.selectedOption < len(p.fuzzySearchMatches)-1 {
+ p.selectedOption++
+ if p.selectedOption >= p.displayedOptionsEnd {
+ p.displayedOptionsStart++
+ p.displayedOptionsEnd++
+ p.displayedOptions = append([]string{}, p.fuzzySearchMatches[p.displayedOptionsStart:p.displayedOptionsEnd]...)
+ }
+ } else {
+ p.selectedOption = 0
+ p.displayedOptionsStart = 0
+ p.displayedOptionsEnd = maxHeight
+ p.displayedOptions = append([]string{}, p.fuzzySearchMatches[p.displayedOptionsStart:p.displayedOptionsEnd]...)
+ }
+
+ area.Update(p.renderSelectMenu())
+ case keys.CtrlC:
+ cancel()
+ return true, nil
+ }
+
+ return false, nil
+ })
+ if err != nil {
+ Error.Println(err)
+ return nil, fmt.Errorf("failed to start keyboard listener: %w", err)
+ }
+
+ var result []string
+ for _, selectedOption := range p.selectedOptions {
+ result = append(result, p.Options[selectedOption])
+ }
+
+ return result, nil
+}
+
+func (p InteractiveMultiselectPrinter) findOptionByText(text string) int {
+ for i, option := range p.Options {
+ if option == text {
+ return i
+ }
+ }
+ return -1
+}
+
+func (p *InteractiveMultiselectPrinter) isSelected(optionText string) bool {
+ for _, selectedOption := range p.selectedOptions {
+ if p.Options[selectedOption] == optionText {
+ return true
+ }
+ }
+
+ return false
+}
+
+func (p *InteractiveMultiselectPrinter) selectOption(optionText string) {
+ if p.isSelected(optionText) {
+ // Remove from selected options
+ for i, selectedOption := range p.selectedOptions {
+ if p.Options[selectedOption] == optionText {
+ p.selectedOptions = append(p.selectedOptions[:i], p.selectedOptions[i+1:]...)
+ break
+ }
+ }
+ } else {
+ // Add to selected options
+ p.selectedOptions = append(p.selectedOptions, p.findOptionByText(optionText))
+ }
+}
+
+func (p *InteractiveMultiselectPrinter) renderSelectMenu() string {
+ var content strings.Builder
+ content.WriteString(Sprintf("%s: %s\n", p.text, p.fuzzySearchString))
+
+ // find options that match fuzzy search string
+ rankedResults := fuzzy.RankFindFold(p.fuzzySearchString, p.Options)
+ // map rankedResults to fuzzySearchMatches
+ p.fuzzySearchMatches = []string{}
+ if len(rankedResults) != len(p.Options) {
+ sort.Sort(rankedResults)
+ }
+ for _, result := range rankedResults {
+ p.fuzzySearchMatches = append(p.fuzzySearchMatches, result.Target)
+ }
+
+ indexMapper := make([]string, len(p.fuzzySearchMatches))
+ for i := 0; i < len(p.fuzzySearchMatches); i++ {
+ // if in displayed options range
+ if i >= p.displayedOptionsStart && i < p.displayedOptionsEnd {
+ indexMapper[i] = p.fuzzySearchMatches[i]
+ }
+ }
+
+ for i, option := range indexMapper {
+ if option == "" {
+ continue
+ }
+ var checkmark string
+ if p.isSelected(option) {
+ checkmark = fmt.Sprintf("[%s]", p.Checkmark.Checked)
+ } else {
+ checkmark = fmt.Sprintf("[%s]", p.Checkmark.Unchecked)
+ }
+ if i == p.selectedOption {
+ content.WriteString(Sprintf("%s %s %s\n", p.renderSelector(), checkmark, option))
+ } else {
+ content.WriteString(Sprintf(" %s %s\n", checkmark, option))
+ }
+ }
+
+ help := fmt.Sprintf("%s: %s | %s: %s | left: %s | right: %s", p.KeySelect, Bold.Sprint("select"), p.KeyConfirm, Bold.Sprint("confirm"), Bold.Sprint("none"), Bold.Sprint("all"))
+ if p.Filter {
+ help += fmt.Sprintf("| type to %s", Bold.Sprint("filter"))
+ }
+ content.WriteString(ThemeDefault.SecondaryStyle.Sprintfln("%s", help))
+
+ return content.String()
+}
+
+func (p InteractiveMultiselectPrinter) renderFinishedMenu() string {
+ var content string
+ content += Sprintf("%s: %s\n", p.text, p.fuzzySearchString)
+ for _, option := range p.selectedOptions {
+ content += Sprintf(" %s %s\n", p.renderSelector(), p.Options[option])
+ }
+
+ return content
+}
+
+func (p InteractiveMultiselectPrinter) renderSelector() string {
+ return p.SelectorStyle.Sprint(p.Selector)
+}
diff --git a/vendor/github.com/pterm/pterm/interactive_select_printer.go b/vendor/github.com/pterm/pterm/interactive_select_printer.go
new file mode 100644
index 0000000..71e810c
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/interactive_select_printer.go
@@ -0,0 +1,319 @@
+package pterm
+
+import (
+ "fmt"
+ "math"
+ "sort"
+ "strings"
+
+ "atomicgo.dev/cursor"
+ "atomicgo.dev/keyboard"
+ "atomicgo.dev/keyboard/keys"
+ "github.com/lithammer/fuzzysearch/fuzzy"
+ "github.com/pterm/pterm/internal"
+)
+
+var (
+ // DefaultInteractiveSelect is the default InteractiveSelect printer.
+ DefaultInteractiveSelect = InteractiveSelectPrinter{
+ TextStyle: &ThemeDefault.PrimaryStyle,
+ DefaultText: "Please select an option",
+ Options: []string{},
+ OptionStyle: &ThemeDefault.DefaultText,
+ DefaultOption: "",
+ MaxHeight: 5,
+ Selector: ">",
+ SelectorStyle: &ThemeDefault.SecondaryStyle,
+ Filter: true,
+ }
+)
+
+// InteractiveSelectPrinter is a printer for interactive select menus.
+type InteractiveSelectPrinter struct {
+ TextStyle *Style
+ DefaultText string
+ Options []string
+ OptionStyle *Style
+ DefaultOption string
+ MaxHeight int
+ Selector string
+ SelectorStyle *Style
+ OnInterruptFunc func()
+ Filter bool
+
+ selectedOption int
+ result string
+ text string
+ fuzzySearchString string
+ fuzzySearchMatches []string
+ displayedOptions []string
+ displayedOptionsStart int
+ displayedOptionsEnd int
+}
+
+// WithDefaultText sets the default text.
+func (p InteractiveSelectPrinter) WithDefaultText(text string) *InteractiveSelectPrinter {
+ p.DefaultText = text
+ return &p
+}
+
+// WithOptions sets the options.
+func (p InteractiveSelectPrinter) WithOptions(options []string) *InteractiveSelectPrinter {
+ p.Options = options
+ return &p
+}
+
+// WithDefaultOption sets the default options.
+func (p InteractiveSelectPrinter) WithDefaultOption(option string) *InteractiveSelectPrinter {
+ p.DefaultOption = option
+ return &p
+}
+
+// WithMaxHeight sets the maximum height of the select menu.
+func (p InteractiveSelectPrinter) WithMaxHeight(maxHeight int) *InteractiveSelectPrinter {
+ p.MaxHeight = maxHeight
+ return &p
+}
+
+// OnInterrupt sets the function to execute on exit of the input reader
+func (p InteractiveSelectPrinter) WithOnInterruptFunc(exitFunc func()) *InteractiveSelectPrinter {
+ p.OnInterruptFunc = exitFunc
+ return &p
+}
+
+// WithFilter sets the Filter option
+func (p InteractiveSelectPrinter) WithFilter(b ...bool) *InteractiveSelectPrinter {
+ p.Filter = internal.WithBoolean(b)
+ return &p
+}
+
+// Show shows the interactive select menu and returns the selected entry.
+func (p *InteractiveSelectPrinter) Show(text ...string) (string, error) {
+ // should be the first defer statement to make sure it is executed last
+ // and all the needed cleanup can be done before
+ cancel, exit := internal.NewCancelationSignal(p.OnInterruptFunc)
+ defer exit()
+
+ if len(text) == 0 || Sprint(text[0]) == "" {
+ text = []string{p.DefaultText}
+ }
+
+ p.text = p.TextStyle.Sprint(text[0])
+ p.fuzzySearchMatches = append([]string{}, p.Options...)
+
+ if p.MaxHeight == 0 {
+ p.MaxHeight = DefaultInteractiveSelect.MaxHeight
+ }
+
+ maxHeight := p.MaxHeight
+ if maxHeight > len(p.fuzzySearchMatches) {
+ maxHeight = len(p.fuzzySearchMatches)
+ }
+
+ if len(p.Options) == 0 {
+ return "", fmt.Errorf("no options provided")
+ }
+
+ p.displayedOptions = append([]string{}, p.fuzzySearchMatches[:maxHeight]...)
+ p.displayedOptionsStart = 0
+ p.displayedOptionsEnd = maxHeight
+
+ // Get index of default option
+ if p.DefaultOption != "" {
+ for i, option := range p.Options {
+ if option == p.DefaultOption {
+ p.selectedOption = i
+ if i > 0 && len(p.Options) > maxHeight {
+ p.displayedOptionsEnd = int(math.Min(float64(i-1+maxHeight), float64(len(p.Options))))
+ p.displayedOptionsStart = p.displayedOptionsEnd - maxHeight
+ } else {
+ p.displayedOptionsStart = 0
+ p.displayedOptionsEnd = maxHeight
+ }
+ p.displayedOptions = p.Options[p.displayedOptionsStart:p.displayedOptionsEnd]
+ break
+ }
+ }
+ }
+
+ area, err := DefaultArea.Start(p.renderSelectMenu())
+ defer area.Stop()
+ if err != nil {
+ return "", fmt.Errorf("could not start area: %w", err)
+ }
+
+ area.Update(p.renderSelectMenu())
+
+ cursor.Hide()
+ defer cursor.Show()
+
+ err = keyboard.Listen(func(keyInfo keys.Key) (stop bool, err error) {
+ key := keyInfo.Code
+
+ if p.MaxHeight > len(p.fuzzySearchMatches) {
+ maxHeight = len(p.fuzzySearchMatches)
+ } else {
+ maxHeight = p.MaxHeight
+ }
+
+ switch key {
+ case keys.RuneKey:
+ if p.Filter {
+ // Fuzzy search for options
+ // append to fuzzy search string
+ p.fuzzySearchString += keyInfo.String()
+ p.selectedOption = 0
+ p.displayedOptionsStart = 0
+ p.displayedOptionsEnd = maxHeight
+ p.displayedOptions = append([]string{}, p.fuzzySearchMatches[:maxHeight]...)
+ area.Update(p.renderSelectMenu())
+ }
+ case keys.Space:
+ p.fuzzySearchString += " "
+ p.selectedOption = 0
+ area.Update(p.renderSelectMenu())
+ case keys.Backspace:
+ // Remove last character from fuzzy search string
+ if p.fuzzySearchString != "" {
+ // Handle UTF-8 characters
+ p.fuzzySearchString = string([]rune(p.fuzzySearchString)[:len([]rune(p.fuzzySearchString))-1])
+ }
+
+ if p.fuzzySearchString == "" {
+ p.fuzzySearchMatches = append([]string{}, p.Options...)
+ }
+
+ p.renderSelectMenu()
+
+ if len(p.fuzzySearchMatches) > p.MaxHeight {
+ maxHeight = p.MaxHeight
+ } else {
+ maxHeight = len(p.fuzzySearchMatches)
+ }
+
+ p.selectedOption = 0
+ p.displayedOptionsStart = 0
+ p.displayedOptionsEnd = maxHeight
+ p.displayedOptions = append([]string{}, p.fuzzySearchMatches[p.displayedOptionsStart:p.displayedOptionsEnd]...)
+
+ area.Update(p.renderSelectMenu())
+ case keys.Up, keys.CtrlP:
+ if len(p.fuzzySearchMatches) == 0 {
+ return false, nil
+ }
+ if p.selectedOption > 0 {
+ p.selectedOption--
+ if p.selectedOption < p.displayedOptionsStart {
+ p.displayedOptionsStart--
+ p.displayedOptionsEnd--
+ if p.displayedOptionsStart < 0 {
+ p.displayedOptionsStart = 0
+ p.displayedOptionsEnd = maxHeight
+ }
+ p.displayedOptions = append([]string{}, p.fuzzySearchMatches[p.displayedOptionsStart:p.displayedOptionsEnd]...)
+ }
+ } else {
+ p.selectedOption = len(p.fuzzySearchMatches) - 1
+ p.displayedOptionsStart = len(p.fuzzySearchMatches) - maxHeight
+ p.displayedOptionsEnd = len(p.fuzzySearchMatches)
+ p.displayedOptions = append([]string{}, p.fuzzySearchMatches[p.displayedOptionsStart:p.displayedOptionsEnd]...)
+ }
+
+ area.Update(p.renderSelectMenu())
+ case keys.Down, keys.CtrlN:
+ if len(p.fuzzySearchMatches) == 0 {
+ return false, nil
+ }
+ p.displayedOptions = p.fuzzySearchMatches[:maxHeight]
+ if p.selectedOption < len(p.fuzzySearchMatches)-1 {
+ p.selectedOption++
+ if p.selectedOption >= p.displayedOptionsEnd {
+ p.displayedOptionsStart++
+ p.displayedOptionsEnd++
+ p.displayedOptions = append([]string{}, p.fuzzySearchMatches[p.displayedOptionsStart:p.displayedOptionsEnd]...)
+ }
+ } else {
+ p.selectedOption = 0
+ p.displayedOptionsStart = 0
+ p.displayedOptionsEnd = maxHeight
+ p.displayedOptions = append([]string{}, p.fuzzySearchMatches[p.displayedOptionsStart:p.displayedOptionsEnd]...)
+ }
+
+ area.Update(p.renderSelectMenu())
+ case keys.CtrlC:
+ cancel()
+ return true, nil
+ case keys.Enter:
+ if len(p.fuzzySearchMatches) == 0 {
+ return false, nil
+ }
+ area.Update(p.renderFinishedMenu())
+ return true, nil
+ }
+
+ return false, nil
+ })
+ if err != nil {
+ Error.Println(err)
+ return "", fmt.Errorf("failed to start keyboard listener: %w", err)
+ }
+
+ return p.result, nil
+}
+
+func (p *InteractiveSelectPrinter) renderSelectMenu() string {
+ var content strings.Builder
+ if p.Filter {
+ content.WriteString(Sprintf("%s %s: %s\n", p.text, p.SelectorStyle.Sprint("[type to search]"), p.fuzzySearchString))
+ } else {
+ content.WriteString(Sprintf("%s:\n", p.text))
+ }
+
+ // find options that match fuzzy search string
+ rankedResults := fuzzy.RankFindFold(p.fuzzySearchString, p.Options)
+ // map rankedResults to fuzzySearchMatches
+ p.fuzzySearchMatches = []string{}
+ if len(rankedResults) != len(p.Options) {
+ sort.Sort(rankedResults)
+ }
+ for _, result := range rankedResults {
+ p.fuzzySearchMatches = append(p.fuzzySearchMatches, result.Target)
+ }
+
+ if len(p.fuzzySearchMatches) != 0 {
+ p.result = p.fuzzySearchMatches[p.selectedOption]
+ }
+
+ indexMapper := make([]string, len(p.fuzzySearchMatches))
+ for i := 0; i < len(p.fuzzySearchMatches); i++ {
+ // if in displayed options range
+ if i >= p.displayedOptionsStart && i < p.displayedOptionsEnd {
+ indexMapper[i] = p.fuzzySearchMatches[i]
+ }
+ }
+
+ for i, option := range indexMapper {
+ if option == "" {
+ continue
+ }
+ if i == p.selectedOption {
+ content.WriteString(Sprintf("%s %s\n", p.renderSelector(), p.OptionStyle.Sprint(option)))
+ } else {
+ content.WriteString(Sprintf(" %s\n", p.OptionStyle.Sprint(option)))
+ }
+ }
+
+ return content.String()
+}
+
+func (p InteractiveSelectPrinter) renderFinishedMenu() string {
+ var content string
+ content += Sprintf("%s: %s\n", p.text, p.fuzzySearchString)
+ content += Sprintf(" %s %s\n", p.renderSelector(), p.result)
+
+ return content
+}
+
+func (p InteractiveSelectPrinter) renderSelector() string {
+ return p.SelectorStyle.Sprint(p.Selector)
+}
diff --git a/vendor/github.com/pterm/pterm/interactive_textinput_printer.go b/vendor/github.com/pterm/pterm/interactive_textinput_printer.go
new file mode 100644
index 0000000..f649cf8
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/interactive_textinput_printer.go
@@ -0,0 +1,306 @@
+package pterm
+
+import (
+ "strings"
+
+ "atomicgo.dev/cursor"
+ "atomicgo.dev/keyboard"
+ "atomicgo.dev/keyboard/keys"
+ "github.com/mattn/go-runewidth"
+
+ "github.com/pterm/pterm/internal"
+)
+
+// DefaultInteractiveTextInput is the default InteractiveTextInput printer.
+var DefaultInteractiveTextInput = InteractiveTextInputPrinter{
+ DefaultText: "Input text",
+ Delimiter: ": ",
+ TextStyle: &ThemeDefault.PrimaryStyle,
+ Mask: "",
+}
+
+// InteractiveTextInputPrinter is a printer for interactive select menus.
+type InteractiveTextInputPrinter struct {
+ TextStyle *Style
+ DefaultText string
+ DefaultValue string
+ Delimiter string
+ MultiLine bool
+ Mask string
+ OnInterruptFunc func()
+
+ input []string
+ cursorXPos int
+ cursorYPos int
+ text string
+ startedTyping bool
+ valueStyle *Style
+}
+
+// WithDefaultText sets the default text.
+func (p InteractiveTextInputPrinter) WithDefaultText(text string) *InteractiveTextInputPrinter {
+ p.DefaultText = text
+ return &p
+}
+
+// WithDefaultValue sets the default value.
+func (p InteractiveTextInputPrinter) WithDefaultValue(value string) *InteractiveTextInputPrinter {
+ p.DefaultValue = value
+ return &p
+}
+
+// WithTextStyle sets the text style.
+func (p InteractiveTextInputPrinter) WithTextStyle(style *Style) *InteractiveTextInputPrinter {
+ p.TextStyle = style
+ return &p
+}
+
+// WithMultiLine sets the multi line flag.
+func (p InteractiveTextInputPrinter) WithMultiLine(multiLine ...bool) *InteractiveTextInputPrinter {
+ p.MultiLine = internal.WithBoolean(multiLine)
+ return &p
+}
+
+// WithMask sets the mask.
+func (p InteractiveTextInputPrinter) WithMask(mask string) *InteractiveTextInputPrinter {
+ p.Mask = mask
+ return &p
+}
+
+// WithOnInterruptFunc sets the function to execute on exit of the input reader
+func (p InteractiveTextInputPrinter) WithOnInterruptFunc(exitFunc func()) *InteractiveTextInputPrinter {
+ p.OnInterruptFunc = exitFunc
+ return &p
+}
+
+// WithDelimiter sets the delimiter between the message and the input.
+func (p InteractiveTextInputPrinter) WithDelimiter(delimiter string) *InteractiveTextInputPrinter {
+ p.Delimiter = delimiter
+ return &p
+}
+
+// Show shows the interactive select menu and returns the selected entry.
+func (p InteractiveTextInputPrinter) Show(text ...string) (string, error) {
+ // should be the first defer statement to make sure it is executed last
+ // and all the needed cleanup can be done before
+ cancel, exit := internal.NewCancelationSignal(p.OnInterruptFunc)
+ defer exit()
+
+ var areaText string
+
+ if len(text) == 0 || text[0] == "" {
+ text = []string{p.DefaultText}
+ }
+
+ if p.MultiLine {
+ areaText = p.TextStyle.Sprintfln("%s %s %s", text[0], ThemeDefault.SecondaryStyle.Sprint("[Press tab to submit]"), p.Delimiter)
+ } else {
+ areaText = p.TextStyle.Sprintf("%s%s", text[0], p.Delimiter)
+ }
+
+ p.text = areaText
+ area := cursor.NewArea()
+ area.Update(areaText)
+ area.StartOfLine()
+
+ if !p.MultiLine {
+ cursor.Right(runewidth.StringWidth(RemoveColorFromString(areaText)))
+ }
+
+ if p.DefaultValue != "" {
+ p.input = append(p.input, p.DefaultValue)
+ p.updateArea(&area)
+ }
+
+ err := keyboard.Listen(func(key keys.Key) (stop bool, err error) {
+ if !p.MultiLine {
+ p.cursorYPos = 0
+ }
+ if len(p.input) == 0 {
+ p.input = append(p.input, "")
+ }
+
+ switch key.Code {
+ case keys.Tab:
+ if p.MultiLine {
+ area.Bottom()
+ return true, nil
+ }
+ case keys.Enter:
+ if p.DefaultValue != "" && !p.startedTyping {
+ for i := range p.input {
+ p.input[i] = RemoveColorFromString(p.input[i])
+ }
+
+ if p.MultiLine {
+ area.Bottom()
+ }
+ return true, nil
+ }
+
+ if p.MultiLine {
+ if key.AltPressed {
+ p.cursorXPos = 0
+ }
+ appendAfterY := append([]string{}, p.input[p.cursorYPos+1:]...)
+ appendAfterX := string(append([]rune{}, []rune(p.input[p.cursorYPos])[len([]rune(p.input[p.cursorYPos]))+p.cursorXPos:]...))
+ p.input[p.cursorYPos] = string(append([]rune{}, []rune(p.input[p.cursorYPos])[:len([]rune(p.input[p.cursorYPos]))+p.cursorXPos]...))
+ p.input = append(p.input[:p.cursorYPos+1], appendAfterX)
+ p.input = append(p.input, appendAfterY...)
+ p.cursorYPos++
+ p.cursorXPos = -internal.GetStringMaxWidth(p.input[p.cursorYPos])
+ cursor.StartOfLine()
+ } else {
+ return true, nil
+ }
+ case keys.RuneKey:
+ if !p.startedTyping {
+ p.startedTyping = true
+ }
+ p.input[p.cursorYPos] = string(append([]rune(p.input[p.cursorYPos])[:len([]rune(p.input[p.cursorYPos]))+p.cursorXPos], append([]rune(key.String()), []rune(p.input[p.cursorYPos])[len([]rune(p.input[p.cursorYPos]))+p.cursorXPos:]...)...))
+ case keys.Space:
+ if !p.startedTyping {
+ p.startedTyping = true
+ }
+ p.input[p.cursorYPos] = string(append([]rune(p.input[p.cursorYPos])[:len([]rune(p.input[p.cursorYPos]))+p.cursorXPos], append([]rune(" "), []rune(p.input[p.cursorYPos])[len([]rune(p.input[p.cursorYPos]))+p.cursorXPos:]...)...))
+ case keys.Backspace:
+ if !p.startedTyping {
+ p.startedTyping = true
+ }
+ if len([]rune(p.input[p.cursorYPos]))+p.cursorXPos > 0 {
+ p.input[p.cursorYPos] = string(append([]rune(p.input[p.cursorYPos])[:len([]rune(p.input[p.cursorYPos]))-1+p.cursorXPos], []rune(p.input[p.cursorYPos])[len([]rune(p.input[p.cursorYPos]))+p.cursorXPos:]...))
+ } else if p.cursorYPos > 0 {
+ p.input[p.cursorYPos-1] += p.input[p.cursorYPos]
+ appendAfterY := append([]string{}, p.input[p.cursorYPos+1:]...)
+ p.input = append(p.input[:p.cursorYPos], appendAfterY...)
+ p.cursorXPos = 0
+ p.cursorYPos--
+ }
+ case keys.Delete:
+ if !p.startedTyping {
+ p.input = []string{""}
+ p.startedTyping = true
+ return false, nil
+ }
+ if len([]rune(p.input[p.cursorYPos]))+p.cursorXPos < len([]rune(p.input[p.cursorYPos])) {
+ p.input[p.cursorYPos] = string(append([]rune(p.input[p.cursorYPos])[:len([]rune(p.input[p.cursorYPos]))+p.cursorXPos], []rune(p.input[p.cursorYPos])[len([]rune(p.input[p.cursorYPos]))+p.cursorXPos+1:]...))
+ p.cursorXPos++
+ } else if p.cursorYPos < len(p.input)-1 {
+ p.input[p.cursorYPos] += p.input[p.cursorYPos+1]
+ appendAfterY := append([]string{}, p.input[p.cursorYPos+2:]...)
+ p.input = append(p.input[:p.cursorYPos+1], appendAfterY...)
+ p.cursorXPos = 0
+ }
+ case keys.CtrlC:
+ cancel()
+ return true, nil
+ case keys.Down:
+ if !p.MultiLine {
+ return false, nil
+ }
+ if !p.startedTyping {
+ p.input = []string{""}
+ p.startedTyping = true
+ }
+ if p.cursorYPos+1 < len(p.input) {
+ p.cursorXPos = (internal.GetStringMaxWidth(p.input[p.cursorYPos]) + p.cursorXPos) - internal.GetStringMaxWidth(p.input[p.cursorYPos+1])
+ if p.cursorXPos > 0 {
+ p.cursorXPos = 0
+ }
+ p.cursorYPos++
+ }
+ case keys.Up:
+ if !p.MultiLine {
+ return false, nil
+ }
+ if !p.startedTyping {
+ p.input = []string{""}
+ p.startedTyping = true
+ }
+ if p.cursorYPos > 0 {
+ p.cursorXPos = (internal.GetStringMaxWidth(p.input[p.cursorYPos]) + p.cursorXPos) - internal.GetStringMaxWidth(p.input[p.cursorYPos-1])
+ if p.cursorXPos > 0 {
+ p.cursorXPos = 0
+ }
+ p.cursorYPos--
+ }
+ }
+
+ if internal.GetStringMaxWidth(p.input[p.cursorYPos]) > 0 {
+ switch key.Code {
+ case keys.Right:
+ if p.cursorXPos < 0 {
+ p.cursorXPos++
+ } else if p.cursorYPos < len(p.input)-1 {
+ p.cursorYPos++
+ p.cursorXPos = -internal.GetStringMaxWidth(p.input[p.cursorYPos])
+ }
+ case keys.Left:
+ if p.cursorXPos+internal.GetStringMaxWidth(p.input[p.cursorYPos]) > 0 {
+ p.cursorXPos--
+ } else if p.cursorYPos > 0 {
+ p.cursorYPos--
+ p.cursorXPos = 0
+ }
+ }
+ }
+
+ p.updateArea(&area)
+
+ return false, nil
+ })
+ if err != nil {
+ return "", err
+ }
+
+ // Add new line
+ Println()
+
+ for i, s := range p.input {
+ if i < len(p.input)-1 {
+ areaText += s + "\n"
+ } else {
+ areaText += s
+ }
+ }
+
+ if !p.startedTyping {
+ return p.DefaultValue, nil
+ }
+
+ return strings.ReplaceAll(areaText, p.text, ""), nil
+}
+
+func (p InteractiveTextInputPrinter) updateArea(area *cursor.Area) string {
+ if !p.MultiLine {
+ p.cursorYPos = 0
+ }
+ areaText := p.text
+
+ for i, s := range p.input {
+ if i < len(p.input)-1 {
+ areaText += s + "\n"
+ } else {
+ areaText += s
+ }
+ }
+
+ if p.Mask != "" {
+ areaText = p.text + strings.Repeat(p.Mask, internal.GetStringMaxWidth(areaText)-internal.GetStringMaxWidth(p.text))
+ }
+
+ if p.cursorXPos+internal.GetStringMaxWidth(p.input[p.cursorYPos]) < 1 {
+ p.cursorXPos = -internal.GetStringMaxWidth(p.input[p.cursorYPos])
+ }
+
+ area.Update(Gray(areaText))
+ area.Top()
+ area.Down(p.cursorYPos + 1)
+ area.StartOfLine()
+ if p.MultiLine {
+ cursor.Right(internal.GetStringMaxWidth(p.input[p.cursorYPos]) + p.cursorXPos)
+ } else {
+ cursor.Right(internal.GetStringMaxWidth(areaText) + p.cursorXPos)
+ }
+ return areaText
+}
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..69dce34
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/interface_live_printer.go
@@ -0,0 +1,18 @@
+package pterm
+
+import "io"
+
+// 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)
+
+ SetWriter(writer io.Writer)
+}
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..4603807
--- /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 ...any) 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 ...any) string
+
+ // Sprintf formats according to a format specifier and returns the resulting string.
+ Sprintf(format string, a ...any) 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 ...any) 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 ...any) *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 ...any) *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 ...any) *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 ...any) *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 ...any) *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 ...any) *TextPrinter
+}
diff --git a/vendor/github.com/pterm/pterm/internal/cancelation_signal.go b/vendor/github.com/pterm/pterm/internal/cancelation_signal.go
new file mode 100644
index 0000000..33f17cc
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/internal/cancelation_signal.go
@@ -0,0 +1,22 @@
+package internal
+
+// NewCancelationSignal for keeping track of a cancelation
+func NewCancelationSignal(interruptFunc func()) (func(), func()) {
+ canceled := false
+
+ cancel := func() {
+ canceled = true
+ }
+
+ exit := func() {
+ if canceled {
+ if interruptFunc != nil {
+ interruptFunc()
+ } else {
+ Exit(1)
+ }
+ }
+ }
+
+ return cancel, exit
+}
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..658224a
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/internal/center_text.go
@@ -0,0 +1,46 @@
+package internal
+
+import (
+ "strings"
+
+ "github.com/gookit/color"
+)
+
+// CenterText returns a centered string with a padding left and right
+// If width is 0, it will be calculated automatically
+func CenterText(text string, width int) string {
+ var lines []string
+ if width == 0 {
+ width = GetStringMaxWidth(text)
+ }
+ 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/exit.go b/vendor/github.com/pterm/pterm/internal/exit.go
new file mode 100644
index 0000000..f07a004
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/internal/exit.go
@@ -0,0 +1,14 @@
+package internal
+
+import "os"
+
+// ExitFuncType is the type of function used to exit the program.
+type ExitFuncType func(int)
+
+// DefaultExitFunc is the default function used to exit the program.
+var DefaultExitFunc ExitFuncType = os.Exit
+
+// Exit calls the current exit function.
+func Exit(code int) {
+ DefaultExitFunc(code)
+}
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..9612fcf
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/internal/max_text_width.go
@@ -0,0 +1,21 @@
+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 maxString int
+ ss := strings.Split(s, "\n")
+ for _, s2 := range ss {
+ s2WithoutColor := color.ClearCode(s2)
+ if runewidth.StringWidth(s2WithoutColor) > maxString {
+ maxString = runewidth.StringWidth(s2WithoutColor)
+ }
+ }
+ return maxString
+}
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/rgb_complementary.go b/vendor/github.com/pterm/pterm/internal/rgb_complementary.go
new file mode 100644
index 0000000..71520b3
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/internal/rgb_complementary.go
@@ -0,0 +1,5 @@
+package internal
+
+func Complementary(r, g, b uint8) (uint8, uint8, uint8) {
+ return 255 - r, 255 - g, 255 - b
+}
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..68e28ec
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/internal/title_in_line.go
@@ -0,0 +1,28 @@
+package internal
+
+import (
+ "strings"
+)
+
+// 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+GetStringMaxWidth(title)))
+ } else {
+ ret += strings.Repeat(line, length-(4+GetStringMaxWidth(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 + GetStringMaxWidth(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/utils.go b/vendor/github.com/pterm/pterm/internal/utils.go
new file mode 100644
index 0000000..ca74cfd
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/internal/utils.go
@@ -0,0 +1,8 @@
+package internal
+
+import "os"
+
+// RunsInCi returns true if the current build is running on a CI server.
+func RunsInCi() bool {
+ return os.Getenv("CI") != ""
+}
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/logger.go b/vendor/github.com/pterm/pterm/logger.go
new file mode 100644
index 0000000..407f4d5
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/logger.go
@@ -0,0 +1,447 @@
+package pterm
+
+import (
+ "encoding/json"
+ "io"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/pterm/pterm/internal"
+)
+
+type LogLevel int
+
+// Style returns the style of the log level.
+func (l LogLevel) Style() Style {
+ baseStyle := NewStyle(Bold)
+ switch l {
+ case LogLevelTrace:
+ return baseStyle.Add(*FgCyan.ToStyle())
+ case LogLevelDebug:
+ return baseStyle.Add(*FgBlue.ToStyle())
+ case LogLevelInfo:
+ return baseStyle.Add(*FgGreen.ToStyle())
+ case LogLevelWarn:
+ return baseStyle.Add(*FgYellow.ToStyle())
+ case LogLevelError:
+ return baseStyle.Add(*FgRed.ToStyle())
+ case LogLevelFatal:
+ return baseStyle.Add(*FgRed.ToStyle())
+ case LogLevelPrint:
+ return baseStyle.Add(*FgWhite.ToStyle())
+ }
+
+ return baseStyle.Add(*FgWhite.ToStyle())
+}
+
+func (l LogLevel) String() string {
+ switch l {
+ case LogLevelDisabled:
+ return ""
+ case LogLevelTrace:
+ return "TRACE"
+ case LogLevelDebug:
+ return "DEBUG"
+ case LogLevelInfo:
+ return "INFO"
+ case LogLevelWarn:
+ return "WARN"
+ case LogLevelError:
+ return "ERROR"
+ case LogLevelFatal:
+ return "FATAL"
+ case LogLevelPrint:
+ return "PRINT"
+ }
+ return "Unknown"
+}
+
+const (
+ // LogLevelDisabled does never print.
+ LogLevelDisabled LogLevel = iota
+ // LogLevelTrace is the log level for traces.
+ LogLevelTrace
+ // LogLevelDebug is the log level for debug.
+ LogLevelDebug
+ // LogLevelInfo is the log level for info.
+ LogLevelInfo
+ // LogLevelWarn is the log level for warnings.
+ LogLevelWarn
+ // LogLevelError is the log level for errors.
+ LogLevelError
+ // LogLevelFatal is the log level for fatal errors.
+ LogLevelFatal
+ // LogLevelPrint is the log level for printing.
+ LogLevelPrint
+)
+
+// LogFormatter is the log formatter.
+// Can be either LogFormatterColorful or LogFormatterJSON.
+type LogFormatter int
+
+const (
+ // LogFormatterColorful is a colorful log formatter.
+ LogFormatterColorful LogFormatter = iota
+ // LogFormatterJSON is a JSON log formatter.
+ LogFormatterJSON
+)
+
+// DefaultLogger is the default logger.
+var DefaultLogger = Logger{
+ Formatter: LogFormatterColorful,
+ Writer: os.Stdout,
+ Level: LogLevelInfo,
+ ShowTime: true,
+ TimeFormat: "2006-01-02 15:04:05",
+ MaxWidth: 80,
+ KeyStyles: map[string]Style{
+ "error": *NewStyle(FgRed, Bold),
+ "err": *NewStyle(FgRed, Bold),
+ "caller": *NewStyle(FgGray, Bold),
+ },
+}
+
+// loggerMutex syncs all loggers, so that they don't print at the exact same time.
+var loggerMutex sync.Mutex
+
+type Logger struct {
+ // Formatter is the log formatter of the logger.
+ Formatter LogFormatter
+ // Writer is the writer of the logger.
+ Writer io.Writer
+ // Level is the log level of the logger.
+ Level LogLevel
+ // ShowCaller defines if the logger should print the caller.
+ ShowCaller bool
+ // CallerOffset defines the offset of the caller.
+ CallerOffset int
+ // ShowTime defines if the logger should print a timestamp.
+ ShowTime bool
+ // TimestampLayout defines the layout of the timestamp.
+ TimeFormat string
+ // KeyStyles defines the styles for specific keys.
+ KeyStyles map[string]Style
+ // MaxWidth defines the maximum width of the logger.
+ // If the text (including the arguments) is longer than the max width, it will be split into multiple lines.
+ MaxWidth int
+}
+
+// WithFormatter sets the log formatter of the logger.
+func (l Logger) WithFormatter(formatter LogFormatter) *Logger {
+ l.Formatter = formatter
+ return &l
+}
+
+// WithWriter sets the writer of the logger.
+func (l Logger) WithWriter(writer io.Writer) *Logger {
+ l.Writer = writer
+ return &l
+}
+
+// WithLevel sets the log level of the logger.
+func (l Logger) WithLevel(level LogLevel) *Logger {
+ l.Level = level
+ return &l
+}
+
+// WithCaller enables or disables the caller.
+func (l Logger) WithCaller(b ...bool) *Logger {
+ l.ShowCaller = internal.WithBoolean(b)
+ return &l
+}
+
+// WithCallerOffset sets the caller offset.
+func (l Logger) WithCallerOffset(offset int) *Logger {
+ l.CallerOffset = offset
+ return &l
+}
+
+// WithTime enables or disables the timestamp.
+func (l Logger) WithTime(b ...bool) *Logger {
+ l.ShowTime = internal.WithBoolean(b)
+ return &l
+}
+
+// WithTimeFormat sets the timestamp layout.
+func (l Logger) WithTimeFormat(format string) *Logger {
+ l.TimeFormat = format
+ return &l
+}
+
+// WithKeyStyles sets the style for a specific key.
+func (l Logger) WithKeyStyles(styles map[string]Style) *Logger {
+ l.KeyStyles = styles
+ return &l
+}
+
+// WithMaxWidth sets the maximum width of the logger.
+func (l Logger) WithMaxWidth(width int) *Logger {
+ l.MaxWidth = width
+ return &l
+}
+
+// AppendKeyStyles appends a style for a specific key.
+func (l Logger) AppendKeyStyles(styles map[string]Style) *Logger {
+ for k, v := range styles {
+ l.KeyStyles[k] = v
+ }
+ return &l
+}
+
+// AppendKeyStyle appends a style for a specific key.
+func (l Logger) AppendKeyStyle(key string, style Style) *Logger {
+ l.KeyStyles[key] = style
+ return &l
+}
+
+// CanPrint checks if the logger can print a specific log level.
+func (l Logger) CanPrint(level LogLevel) bool {
+ if l.Level == LogLevelDisabled {
+ return false
+ }
+ return l.Level <= level
+}
+
+// Args converts any arguments to a slice of LoggerArgument.
+func (l Logger) Args(args ...any) []LoggerArgument {
+ var loggerArgs []LoggerArgument
+
+ // args are in the format of: key, value, key, value, key, value, ...
+ args = l.sanitizeArgs(args)
+
+ for i := 0; i < len(args); i += 2 {
+ key := Sprint(args[i])
+ value := args[i+1]
+
+ loggerArgs = append(loggerArgs, LoggerArgument{
+ Key: key,
+ Value: value,
+ })
+ }
+
+ return loggerArgs
+}
+
+// ArgsFromMap converts a map to a slice of LoggerArgument.
+func (l Logger) ArgsFromMap(m map[string]any) []LoggerArgument {
+ var loggerArgs []LoggerArgument
+
+ for k, v := range m {
+ loggerArgs = append(loggerArgs, LoggerArgument{
+ Key: k,
+ Value: v,
+ })
+ }
+
+ return loggerArgs
+}
+
+// sanitizeArgs inserts an error message into an args slice if an odd number of arguments is provided.
+func (l Logger) sanitizeArgs(args []any) []any {
+ numArgs := len(args)
+ if numArgs > 0 && numArgs%2 != 0 {
+ if numArgs > 1 {
+ lastArg := args[numArgs-1]
+ args = append(args[:numArgs-1], []any{ErrKeyWithoutValue, lastArg}...)
+ } else {
+ args = []any{ErrKeyWithoutValue, args[0]}
+ }
+ }
+ return args
+}
+
+func (l Logger) getCallerInfo() (path string, line int) {
+ if !l.ShowCaller {
+ return
+ }
+
+ _, path, line, _ = runtime.Caller(l.CallerOffset + 4)
+ _, callerBase, _, _ := runtime.Caller(0)
+ basepath := filepath.Dir(callerBase)
+ basepath = strings.ReplaceAll(basepath, "\\", "/")
+
+ path = strings.TrimPrefix(path, basepath)
+
+ return
+}
+
+func (l Logger) combineArgs(args ...[]LoggerArgument) []LoggerArgument {
+ var result []LoggerArgument
+
+ for _, arg := range args {
+ result = append(result, arg...)
+ }
+
+ return result
+}
+
+func (l Logger) print(level LogLevel, msg string, args []LoggerArgument) {
+ if !l.CanPrint(level) {
+ return
+ }
+
+ var line string
+
+ switch l.Formatter {
+ case LogFormatterColorful:
+ line = l.renderColorful(level, msg, args)
+ case LogFormatterJSON:
+ line = l.renderJSON(level, msg, args)
+ }
+
+ loggerMutex.Lock()
+ defer loggerMutex.Unlock()
+
+ Fprintln(l.Writer, line)
+}
+
+func (l Logger) renderColorful(level LogLevel, msg string, args []LoggerArgument) (result string) {
+ if l.ShowTime {
+ result += Gray(time.Now().Format(l.TimeFormat)) + " "
+ }
+
+ if GetTerminalWidth() > 0 && GetTerminalWidth() < l.MaxWidth {
+ l.MaxWidth = GetTerminalWidth()
+ }
+
+ var argumentsInNewLine bool
+
+ result += level.Style().Sprintf("%-5s", level.String()) + " "
+
+ // if msg is too long, wrap it to multiple lines with the same length
+ remainingWidth := l.MaxWidth - internal.GetStringMaxWidth(result)
+ if internal.GetStringMaxWidth(msg) > remainingWidth {
+ argumentsInNewLine = true
+ msg = DefaultParagraph.WithMaxWidth(remainingWidth).Sprint(msg)
+ padding := len(time.Now().Format(l.TimeFormat) + " ")
+ msg = strings.ReplaceAll(msg, "\n", "\n"+strings.Repeat(" ", padding)+" │ ")
+ }
+
+ result += msg
+
+ if l.ShowCaller {
+ path, line := l.getCallerInfo()
+ args = append(args, LoggerArgument{
+ Key: "caller",
+ Value: FgGray.Sprintf("%s:%d", path, line),
+ })
+ }
+
+ arguments := make([]string, len(args))
+
+ // add arguments
+ if len(args) > 0 {
+ for i, arg := range args {
+ if style, ok := l.KeyStyles[arg.Key]; ok {
+ arguments[i] = style.Sprintf("%s: ", arg.Key)
+ } else {
+ arguments[i] = level.Style().Sprintf("%s: ", arg.Key)
+ }
+
+ arguments[i] += Sprintf("%s", Sprint(arg.Value))
+ }
+ }
+
+ fullLine := result + " " + strings.Join(arguments, " ")
+
+ // if the full line is too long, wrap the arguments to multiple lines
+ if internal.GetStringMaxWidth(fullLine) > l.MaxWidth {
+ argumentsInNewLine = true
+ }
+
+ if !argumentsInNewLine {
+ result = fullLine
+ } else {
+ padding := 4
+ if l.ShowTime {
+ padding = len(time.Time{}.Format(l.TimeFormat)) + 3
+ }
+
+ for i, argument := range arguments {
+ var pipe string
+ if i < len(arguments)-1 {
+ pipe = "├"
+ } else {
+ pipe = "└"
+ }
+ result += "\n" + strings.Repeat(" ", padding) + pipe + " " + argument
+ }
+ }
+
+ return
+}
+
+func (l Logger) renderJSON(level LogLevel, msg string, args []LoggerArgument) string {
+ m := l.argsToMap(args)
+
+ m["level"] = level.String()
+ m["timestamp"] = time.Now().Format(l.TimeFormat)
+ m["msg"] = msg
+
+ if file, line := l.getCallerInfo(); file != "" {
+ m["caller"] = Sprintf("%s:%d", file, line)
+ }
+
+ b, _ := json.Marshal(m)
+ return string(b)
+}
+
+func (l Logger) argsToMap(args []LoggerArgument) map[string]any {
+ m := make(map[string]any)
+
+ for _, arg := range args {
+ m[arg.Key] = arg.Value
+ }
+
+ return m
+}
+
+// Trace prints a trace log.
+func (l Logger) Trace(msg string, args ...[]LoggerArgument) {
+ l.print(LogLevelTrace, msg, l.combineArgs(args...))
+}
+
+// Debug prints a debug log.
+func (l Logger) Debug(msg string, args ...[]LoggerArgument) {
+ l.print(LogLevelDebug, msg, l.combineArgs(args...))
+}
+
+// Info prints an info log.
+func (l Logger) Info(msg string, args ...[]LoggerArgument) {
+ l.print(LogLevelInfo, msg, l.combineArgs(args...))
+}
+
+// Warn prints a warning log.
+func (l Logger) Warn(msg string, args ...[]LoggerArgument) {
+ l.print(LogLevelWarn, msg, l.combineArgs(args...))
+}
+
+// Error prints an error log.
+func (l Logger) Error(msg string, args ...[]LoggerArgument) {
+ l.print(LogLevelError, msg, l.combineArgs(args...))
+}
+
+// Fatal prints a fatal log and exits the program.
+func (l Logger) Fatal(msg string, args ...[]LoggerArgument) {
+ l.print(LogLevelFatal, msg, l.combineArgs(args...))
+ if l.CanPrint(LogLevelFatal) {
+ os.Exit(1)
+ }
+}
+
+// Print prints a log.
+func (l Logger) Print(msg string, args ...[]LoggerArgument) {
+ l.print(LogLevelPrint, msg, l.combineArgs(args...))
+}
+
+// LoggerArgument is a key-value pair for a logger.
+type LoggerArgument struct {
+ // Key is the key of the argument.
+ Key string
+ // Value is the value of the argument.
+ Value any
+}
diff --git a/vendor/github.com/pterm/pterm/multi_live_printer.go b/vendor/github.com/pterm/pterm/multi_live_printer.go
new file mode 100644
index 0000000..b9e0d0e
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/multi_live_printer.go
@@ -0,0 +1,124 @@
+package pterm
+
+import (
+ "atomicgo.dev/schedule"
+ "bytes"
+ "io"
+ "os"
+ "strings"
+ "time"
+)
+
+var DefaultMultiPrinter = MultiPrinter{
+ printers: []LivePrinter{},
+ Writer: os.Stdout,
+ UpdateDelay: time.Millisecond * 200,
+
+ buffers: []*bytes.Buffer{},
+ area: DefaultArea,
+}
+
+type MultiPrinter struct {
+ IsActive bool
+ Writer io.Writer
+ UpdateDelay time.Duration
+
+ printers []LivePrinter
+ buffers []*bytes.Buffer
+ area AreaPrinter
+}
+
+// SetWriter sets the writer for the AreaPrinter.
+func (p *MultiPrinter) SetWriter(writer io.Writer) {
+ p.Writer = writer
+}
+
+// WithWriter returns a fork of the MultiPrinter with a new writer.
+func (p MultiPrinter) WithWriter(writer io.Writer) *MultiPrinter {
+ p.Writer = writer
+ return &p
+}
+
+// WithUpdateDelay returns a fork of the MultiPrinter with a new update delay.
+func (p MultiPrinter) WithUpdateDelay(delay time.Duration) *MultiPrinter {
+ p.UpdateDelay = delay
+ return &p
+}
+
+func (p *MultiPrinter) NewWriter() io.Writer {
+ buf := bytes.NewBufferString("")
+ p.buffers = append(p.buffers, buf)
+ return buf
+}
+
+// getString returns all buffers appended and separated by a newline.
+func (p *MultiPrinter) getString() string {
+ var buffer bytes.Buffer
+ for _, b := range p.buffers {
+ s := b.String()
+ s = strings.Trim(s, "\n")
+
+ parts := strings.Split(s, "\r") // only get the last override
+ s = parts[len(parts)-1]
+
+ // check if s is empty, if so get one part before, repeat until not empty
+ for s == "" {
+ parts = parts[:len(parts)-1]
+ s = parts[len(parts)-1]
+ }
+
+ s = strings.Trim(s, "\n\r")
+ buffer.WriteString(s)
+ buffer.WriteString("\n")
+ }
+ return buffer.String()
+}
+
+func (p *MultiPrinter) Start() (*MultiPrinter, error) {
+ p.IsActive = true
+ for _, printer := range p.printers {
+ printer.GenericStart()
+ }
+
+ schedule.Every(p.UpdateDelay, func() bool {
+ if !p.IsActive {
+ return false
+ }
+
+ p.area.Update(p.getString())
+
+ return true
+ })
+
+ return p, nil
+}
+
+func (p *MultiPrinter) Stop() (*MultiPrinter, error) {
+ p.IsActive = false
+ for _, printer := range p.printers {
+ printer.GenericStop()
+ }
+ time.Sleep(time.Millisecond * 20)
+ p.area.Update(p.getString())
+ p.area.Stop()
+
+ 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 MultiPrinter) 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 MultiPrinter) GenericStop() (*LivePrinter, error) {
+ p2, _ := p.Stop()
+ lp := LivePrinter(p2)
+ return &lp, nil
+}
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..9b5ec3f
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/panel_printer.go
@@ -0,0 +1,190 @@
+package pterm
+
+import (
+ "io"
+ "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
+ Writer io.Writer
+}
+
+// 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 {
+ p.SameColumnWidth = internal.WithBoolean(b)
+ return &p
+}
+
+// WithBoxPrinter returns a new PanelPrinter with specific options.
+func (p PanelPrinter) WithBoxPrinter(boxPrinter BoxPrinter) *PanelPrinter {
+ p.BoxPrinter = boxPrinter
+ return &p
+}
+
+// WithWriter sets the custom Writer.
+func (p PanelPrinter) WithWriter(writer io.Writer) *PanelPrinter {
+ p.Writer = writer
+ return &p
+}
+
+func (p PanelPrinter) getRawOutput() string {
+ var ret strings.Builder
+ for _, panel := range p.Panels {
+ for _, panel2 := range panel {
+ ret.WriteString(panel2.Data)
+ ret.WriteString("\n\n")
+ }
+ ret.WriteByte('\n')
+ }
+ return ret.String()
+}
+
+// Srender renders the Template as a string.
+func (p PanelPrinter) Srender() (string, error) {
+ var ret strings.Builder
+
+ 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.WriteString(letterLine)
+ }
+ ret.WriteByte('\n')
+ }
+ }
+ }
+
+ return ret.String(), nil
+}
+
+// Render prints the Template to the terminal.
+func (p PanelPrinter) Render() error {
+ s, _ := p.Srender()
+ Fprintln(p.Writer, 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..d5060e0
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/paragraph_printer.go
@@ -0,0 +1,142 @@
+package pterm
+
+import (
+ "fmt"
+ "io"
+ "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
+ Writer io.Writer
+}
+
+// WithMaxWidth returns a new ParagraphPrinter with a specific MaxWidth
+func (p ParagraphPrinter) WithMaxWidth(width int) *ParagraphPrinter {
+ p.MaxWidth = width
+ return &p
+}
+
+// WithWriter sets the custom Writer.
+func (p ParagraphPrinter) WithWriter(writer io.Writer) *ParagraphPrinter {
+ p.Writer = writer
+ 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 ...any) 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 ...any) 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 ...any) 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 ...any) 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 ...any) *TextPrinter {
+ Fprint(p.Writer, 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 ...any) *TextPrinter {
+ Fprint(p.Writer, 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 ...any) *TextPrinter {
+ Fprint(p.Writer, 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 ...any) *TextPrinter {
+ Fprint(p.Writer, 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 ...any) *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 ...any) *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..2c2a5e8
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/prefix_printer.go
@@ -0,0 +1,364 @@
+package pterm
+
+import (
+ "fmt"
+ "io"
+ "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",
+ },
+ Writer: defaultWriter,
+ }
+
+ // 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",
+ },
+ Writer: defaultWriter,
+ }
+
+ // 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",
+ },
+ Writer: defaultWriter,
+ }
+
+ // 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 ",
+ },
+ Writer: defaultWriter,
+ }
+
+ // 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,
+ Writer: defaultWriter,
+ }
+
+ // 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,
+ Writer: defaultWriter,
+ }
+
+ // 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",
+ },
+ Writer: defaultWriter,
+ }
+)
+
+// PrefixPrinter is the printer used to print a Prefix.
+type PrefixPrinter struct {
+ Prefix Prefix
+ Scope Scope
+ MessageStyle *Style
+ Fatal bool
+ ShowLineNumber bool
+ LineNumberOffset int
+ Writer io.Writer
+ // 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
+}
+
+// WithWriter sets the custom Writer.
+func (p PrefixPrinter) WithWriter(writer io.Writer) *PrefixPrinter {
+ p.Writer = writer
+ 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 ...any) 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 strings.Builder
+ 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.WriteString(p.GetFormattedPrefix())
+ ret.WriteByte(' ')
+ if p.Scope.Text != "" {
+ ret.WriteString(NewStyle(*p.Scope.Style...).Sprint(" (" + p.Scope.Text + ") "))
+ }
+ ret.WriteString(p.MessageStyle.Sprint(m))
+ } else {
+ ret.WriteByte('\n')
+ ret.WriteString(p.Prefix.Style.Sprint(strings.Repeat(" ", len([]rune(p.Prefix.Text))+2)))
+ ret.WriteByte(' ')
+ ret.WriteString(p.MessageStyle.Sprint(m))
+ }
+ }
+
+ if p.ShowLineNumber {
+ _, fileName, line, _ := runtime.Caller(3 + p.LineNumberOffset)
+ ret.WriteString(FgGray.Sprint("\n└ " + fmt.Sprintf("(%s:%d)\n", fileName, line)))
+ newLine = false
+ }
+
+ if newLine {
+ ret.WriteByte('\n')
+ }
+
+ return Sprint(ret.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.
+func (p PrefixPrinter) Sprintln(a ...any) 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 ...any) 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 ...any) 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 ...any) *TextPrinter {
+ tp := TextPrinter(p)
+ if p.Debugger && !PrintDebugMessages {
+ return &tp
+ }
+ p.LineNumberOffset--
+ Fprint(p.Writer, p.Sprint(a...))
+ p.LineNumberOffset++
+ 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 ...any) *TextPrinter {
+ tp := TextPrinter(p)
+ if p.Debugger && !PrintDebugMessages {
+ return &tp
+ }
+ Fprint(p.Writer, 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 ...any) *TextPrinter {
+ tp := TextPrinter(p)
+ if p.Debugger && !PrintDebugMessages {
+ return &tp
+ }
+ Fprint(p.Writer, 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 ...any) *TextPrinter {
+ tp := TextPrinter(p)
+ if p.Debugger && !PrintDebugMessages {
+ return &tp
+ }
+ p.LineNumberOffset++
+ Fprint(p.Writer, p.Sprintfln(format, a...))
+ p.LineNumberOffset--
+ 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 ...any) *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 ...any) *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..fd91d29
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/print.go
@@ -0,0 +1,191 @@
+package pterm
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "strings"
+
+ "github.com/gookit/color"
+)
+
+var defaultWriter io.Writer = os.Stdout
+
+// SetDefaultOutput sets the default output of pterm.
+func SetDefaultOutput(w io.Writer) {
+ defaultWriter = w
+ 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 ...any) string {
+ return color.Sprint(a...)
+}
+
+// Sprintf formats according to a format specifier and returns the resulting string.
+func Sprintf(format string, a ...any) 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 ...any) string {
+ return color.Sprintf(format, a...) + "\n"
+}
+
+// Sprintln returns what Println would print to the terminal.
+func Sprintln(a ...any) string {
+ str := fmt.Sprintln(a...)
+ return Sprint(str)
+}
+
+// Sprinto returns what Printo would print.
+func Sprinto(a ...any) 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 ...any) {
+ Fprint(defaultWriter, 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.
+func Println(a ...any) {
+ 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 ...any) {
+ 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 ...any) {
+ 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 ...any) {
+ 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 ...any) {
+ 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 ...any) {
+ if !Output {
+ return
+ }
+
+ var ret string
+ var printed bool
+
+ for _, bar := range ActiveProgressBarPrinters {
+ if bar.IsActive && (bar.Writer == writer || bar.Writer == os.Stderr) {
+ ret += sClearLine()
+ ret += Sprinto(a...)
+ printed = true
+ }
+ }
+
+ for _, spinner := range activeSpinnerPrinters {
+ if spinner.IsActive && (spinner.Writer == writer || spinner.Writer == os.Stderr) {
+ ret += sClearLine()
+ ret += Sprinto(a...)
+ printed = true
+ }
+ }
+
+ if !printed {
+ ret = color.Sprint(Sprint(a...))
+ }
+
+ if writer != nil {
+ color.Fprint(writer, Sprint(ret))
+ } else {
+ 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)
+ }
+ }
+}
+
+// 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 ...any) {
+ 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 ...any) {
+ if !Output {
+ return
+ }
+
+ color.Print("\r" + Sprint(a...))
+}
+
+// Fprinto prints Printo to a custom writer.
+func Fprinto(w io.Writer, a ...any) {
+ if !Output {
+ return
+ }
+ if w != nil {
+ color.Fprint(w, "\r", Sprint(a...))
+ } else {
+ color.Print("\r", Sprint(a...))
+ }
+}
+
+// RemoveColorFromString removes color codes from a string.
+func RemoveColorFromString(a ...any) string {
+ return color.ClearCode(Sprint(a...))
+}
+
+func fClearLine(writer io.Writer) {
+ Fprinto(writer, 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..c1083ff
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/progressbar_printer.go
@@ -0,0 +1,355 @@
+package pterm
+
+import (
+ "atomicgo.dev/cursor"
+ "atomicgo.dev/schedule"
+ "fmt"
+ "io"
+ "math"
+ "os"
+ "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
+
+// DefaultProgressbar is the default ProgressbarPrinter.
+var DefaultProgressbar = ProgressbarPrinter{
+ Total: 100,
+ BarCharacter: "█",
+ LastCharacter: "█",
+ ElapsedTimeRoundingFactor: time.Second,
+ BarStyle: &ThemeDefault.ProgressbarBarStyle,
+ TitleStyle: &ThemeDefault.ProgressbarTitleStyle,
+ ShowTitle: true,
+ ShowCount: true,
+ ShowPercentage: true,
+ ShowElapsedTime: true,
+ BarFiller: Gray("█"),
+ MaxWidth: 80,
+ Writer: os.Stderr,
+}
+
+// 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
+ MaxWidth int
+
+ ShowElapsedTime bool
+ ShowCount bool
+ ShowTitle bool
+ ShowPercentage bool
+ RemoveWhenDone bool
+
+ TitleStyle *Style
+ BarStyle *Style
+
+ IsActive bool
+
+ startedAt time.Time
+ rerenderTask *schedule.Task
+
+ Writer io.Writer
+}
+
+// WithTitle sets the name of the ProgressbarPrinter.
+func (p ProgressbarPrinter) WithTitle(name string) *ProgressbarPrinter {
+ p.Title = name
+ return &p
+}
+
+// WithMaxWidth sets the maximum width of the ProgressbarPrinter.
+// If the terminal is smaller than the given width, the terminal width will be used instead.
+// If the width is set to zero, or below, the terminal width will be used.
+func (p ProgressbarPrinter) WithMaxWidth(maxWidth int) *ProgressbarPrinter {
+ p.MaxWidth = maxWidth
+ 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
+}
+
+// WithStartedAt sets the time when the ProgressbarPrinter started.
+func (p ProgressbarPrinter) WithStartedAt(t time.Time) *ProgressbarPrinter {
+ p.startedAt = t
+ 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
+}
+
+// WithBarFiller sets the filler character for the ProgressbarPrinter.
+func (p ProgressbarPrinter) WithBarFiller(char string) *ProgressbarPrinter {
+ p.BarFiller = char
+ return &p
+}
+
+// WithWriter sets the custom Writer.
+func (p ProgressbarPrinter) WithWriter(writer io.Writer) *ProgressbarPrinter {
+ p.Writer = writer
+ return &p
+}
+
+// SetWriter sets the custom Writer.
+func (p *ProgressbarPrinter) SetWriter(writer io.Writer) {
+ p.Writer = writer
+}
+
+// SetStartedAt sets the time when the ProgressbarPrinter started.
+func (p *ProgressbarPrinter) SetStartedAt(t time.Time) {
+ p.startedAt = t
+}
+
+// ResetTimer resets the timer of the ProgressbarPrinter.
+func (p *ProgressbarPrinter) ResetTimer() {
+ p.startedAt = time.Now()
+}
+
+// Increment current value by one.
+func (p *ProgressbarPrinter) Increment() *ProgressbarPrinter {
+ p.Add(1)
+ return p
+}
+
+// UpdateTitle updates 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 {
+ Fprinto(p.Writer, p.getString())
+ return p
+}
+
+func (p *ProgressbarPrinter) getString() string {
+ if !p.IsActive {
+ return ""
+ }
+ if p.TitleStyle == nil {
+ p.TitleStyle = NewStyle()
+ }
+ if p.BarStyle == nil {
+ p.BarStyle = NewStyle()
+ }
+ if p.Total == 0 {
+ return ""
+ }
+
+ var before string
+ var after string
+ var width int
+
+ if p.MaxWidth <= 0 {
+ width = GetTerminalWidth()
+ } else if GetTerminalWidth() < p.MaxWidth {
+ width = GetTerminalWidth()
+ } else {
+ width = p.MaxWidth
+ }
+
+ if p.ShowTitle {
+ before += p.TitleStyle.Sprint(p.Title) + " "
+ }
+ if p.ShowCount {
+ padding := 1 + int(math.Log10(float64(p.Total)))
+ before += Gray("[") + LightWhite(fmt.Sprintf("%0*d", padding, p.Current)) + Gray("/") + LightWhite(p.Total) + Gray("]") + " "
+ }
+
+ after += " "
+
+ if p.ShowPercentage {
+ currentPercentage := int(internal.PercentageRound(float64(int64(p.Total)), float64(int64(p.Current))))
+ decoratorCurrentPercentage := color.RGB(NewRGB(255, 0, 0).Fade(0, float32(p.Total), float32(p.Current), NewRGB(0, 255, 0)).GetValues()).
+ Sprintf("%3d%%", currentPercentage)
+ after += decoratorCurrentPercentage + " "
+ }
+ if p.ShowElapsedTime {
+ after += "| " + p.parseElapsedTime()
+ }
+
+ barMaxLength := width - len(RemoveColorFromString(before)) - len(RemoveColorFromString(after)) - 1
+
+ barCurrentLength := (p.Current * barMaxLength) / p.Total
+ var barFiller string
+ if barMaxLength-barCurrentLength > 0 {
+ barFiller = strings.Repeat(p.BarFiller, barMaxLength-barCurrentLength)
+ }
+
+ bar := barFiller
+ if barCurrentLength > 0 {
+ bar = p.BarStyle.Sprint(strings.Repeat(p.BarCharacter, barCurrentLength)+p.LastCharacter) + bar
+ }
+
+ return before + bar + after
+}
+
+// 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.Total = p.Current
+ p.updateProgress()
+ p.Stop()
+ }
+ return p
+}
+
+// Start the ProgressbarPrinter.
+func (p ProgressbarPrinter) Start(title ...any) (*ProgressbarPrinter, error) {
+ cursor.Hide()
+ if RawOutput && p.ShowTitle {
+ Fprintln(p.Writer, p.Title)
+ }
+ p.IsActive = true
+ if len(title) != 0 {
+ p.Title = Sprint(title...)
+ }
+ ActiveProgressBarPrinters = append(ActiveProgressBarPrinters, &p)
+ p.startedAt = time.Now()
+
+ p.updateProgress()
+
+ if p.ShowElapsedTime {
+ p.rerenderTask = schedule.Every(time.Second, func() bool {
+ p.updateProgress()
+ return true
+ })
+ }
+
+ return &p, nil
+}
+
+// Stop the ProgressbarPrinter.
+func (p *ProgressbarPrinter) Stop() (*ProgressbarPrinter, error) {
+ if p.rerenderTask != nil && p.rerenderTask.IsActive() {
+ p.rerenderTask.Stop()
+ }
+ cursor.Show()
+
+ if !p.IsActive {
+ return p, nil
+ }
+ p.IsActive = false
+ if p.RemoveWhenDone {
+ fClearLine(p.Writer)
+ Fprinto(p.Writer)
+ } else {
+ Fprintln(p.Writer)
+ }
+ 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..f9d76ca
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/pterm.go
@@ -0,0 +1,72 @@
+// 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.
+//
+// Official docs are available at: https://docs.pterm.sh
+//
+// 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 terminal 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..1b11eea
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/rgb.go
@@ -0,0 +1,298 @@
+package pterm
+
+import (
+ "fmt"
+
+ "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
+ Background bool
+}
+
+type RGBStyle struct {
+ Options []Color
+ Foreground, Background RGB
+
+ hasBg bool
+}
+
+// NewRGBStyle returns a new RGBStyle.
+// The foreground color is required, the background color is optional.
+// The colors will be set as is, ignoring the RGB.Background property.
+func NewRGBStyle(foreground RGB, background ...RGB) RGBStyle {
+ var s RGBStyle
+ s.Foreground = foreground
+ if len(background) > 0 {
+ s.Background = background[0]
+ s.hasBg = true
+ }
+ return s
+}
+
+// AddOptions adds options to the RGBStyle.
+func (p RGBStyle) AddOptions(opts ...Color) RGBStyle {
+ p.Options = append(p.Options, opts...)
+ return p
+}
+
+// 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 RGBStyle) Print(a ...any) *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 RGBStyle) Println(a ...any) *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 RGBStyle) Printf(format string, a ...any) *TextPrinter {
+ Printf(format, p.Sprint(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 RGBStyle) Printfln(format string, a ...any) *TextPrinter {
+ Printf(format, p.Sprint(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 RGBStyle) PrintOnError(a ...any) *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 RGBStyle) PrintOnErrorf(format string, a ...any) *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
+}
+
+// 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 RGBStyle) Sprint(a ...any) string {
+ var rgbStyle *color.RGBStyle
+ if !p.hasBg {
+ rgbStyle = color.NewRGBStyle(color.RGB(p.Foreground.R, p.Foreground.G, p.Foreground.B))
+ } else {
+ rgbStyle = color.NewRGBStyle(color.RGB(p.Foreground.R, p.Foreground.G, p.Foreground.B), color.RGB(p.Background.R, p.Background.G, p.Background.B))
+ }
+ if len(p.Options) > 0 {
+ for _, opt := range p.Options {
+ rgbStyle.AddOpts(color.Color(opt))
+ }
+ }
+ return rgbStyle.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 RGBStyle) Sprintln(a ...any) string {
+ return p.Sprint(a...) + "\n"
+}
+
+// Sprintf formats according to a format specifier and returns the resulting string.
+func (p RGBStyle) Sprintf(format string, a ...any) 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 RGBStyle) Sprintfln(format string, a ...any) string {
+ return p.Sprintf(format, a...) + "\n"
+}
+
+// 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, background ...bool) RGB {
+ var bg bool
+
+ if len(background) > 0 {
+ bg = background[0]
+ }
+
+ return RGB{R: r, G: g, B: b, Background: bg}
+}
+
+// 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(minRGB, maxRGB, current float32, end ...RGB) RGB {
+ if maxRGB == current {
+ return end[len(end)-1]
+ }
+ if minRGB < 0 {
+ maxRGB -= minRGB
+ current -= minRGB
+ minRGB = 0
+ }
+ // #nosec G115
+ if len(end) == 1 {
+ return RGB{
+ R: uint8(internal.MapRangeToRange(minRGB, maxRGB, float32(p.R), float32(end[0].R), current)), //nolint:gosec
+ G: uint8(internal.MapRangeToRange(minRGB, maxRGB, float32(p.G), float32(end[0].G), current)), //nolint:gosec
+ B: uint8(internal.MapRangeToRange(minRGB, maxRGB, float32(p.B), float32(end[0].B), current)), //nolint:gosec
+ Background: p.Background,
+ }
+ } else if len(end) > 1 {
+ f := (maxRGB - minRGB) / float32(len(end))
+ tempCurrent := current
+ if f > current {
+ return p.Fade(minRGB, f, current, end[0])
+ } else {
+ for i := 0; i < len(end)-1; i++ {
+ tempCurrent -= f
+ if f > tempCurrent {
+ return end[i].Fade(minRGB, minRGB+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 ...any) string {
+ if p.Background {
+ return color.RGB(p.R, p.G, p.B, p.Background).Sprint(a...) + "\033[0m\033[K"
+ }
+ return color.RGB(p.R, p.G, p.B, p.Background).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 ...any) 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 ...any) 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 ...any) 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 ...any) *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 ...any) *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 ...any) *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 ...any) *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 ...any) *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 ...any) *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
+}
+
+func (p RGB) ToRGBStyle() RGBStyle {
+ if p.Background {
+ return RGBStyle{Background: p}
+ }
+
+ return RGBStyle{Foreground: p}
+}
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..9475f42
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/section_printer.go
@@ -0,0 +1,175 @@
+package pterm
+
+import (
+ "fmt"
+ "io"
+ "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
+ Writer io.Writer
+}
+
+// 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
+}
+
+// WithWriter sets the custom Writer.
+func (p SectionPrinter) WithWriter(writer io.Writer) *SectionPrinter {
+ p.Writer = writer
+ 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 ...any) string {
+ if p.Style == nil {
+ p.Style = NewStyle()
+ }
+
+ var ret strings.Builder
+
+ for i := 0; i < p.TopPadding; i++ {
+ ret.WriteByte('\n')
+ }
+
+ if p.Level > 0 {
+ ret.WriteString(strings.Repeat(p.IndentCharacter, p.Level))
+ ret.WriteByte(' ')
+ }
+
+ ret.WriteString(p.Style.Sprint(a...))
+
+ for i := 0; i < p.BottomPadding; i++ {
+ ret.WriteByte('\n')
+ }
+
+ return ret.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.
+func (p SectionPrinter) Sprintln(a ...any) 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 ...any) 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 ...any) 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 ...any) *TextPrinter {
+ Fprint(p.Writer, 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 ...any) *TextPrinter {
+ Fprint(p.Writer, 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 ...any) *TextPrinter {
+ Fprint(p.Writer, 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 ...any) *TextPrinter {
+ Fprint(p.Writer, 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 ...any) *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 ...any) *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/slog_handler.go b/vendor/github.com/pterm/pterm/slog_handler.go
new file mode 100644
index 0000000..d607afd
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/slog_handler.go
@@ -0,0 +1,90 @@
+package pterm
+
+import (
+ "context"
+
+ "log/slog"
+)
+
+type SlogHandler struct {
+ logger *Logger
+ attrs []slog.Attr
+}
+
+// Enabled returns true if the given level is enabled.
+func (s *SlogHandler) Enabled(ctx context.Context, level slog.Level) bool {
+ switch level {
+ case slog.LevelDebug:
+ return s.logger.CanPrint(LogLevelDebug)
+ case slog.LevelInfo:
+ return s.logger.CanPrint(LogLevelInfo)
+ case slog.LevelWarn:
+ return s.logger.CanPrint(LogLevelWarn)
+ case slog.LevelError:
+ return s.logger.CanPrint(LogLevelError)
+ }
+ return false
+}
+
+// Handle handles the given record.
+func (s *SlogHandler) Handle(ctx context.Context, record slog.Record) error {
+ level := record.Level
+ message := record.Message
+
+ // Convert slog Attrs to a map.
+ keyValsMap := make(map[string]any)
+
+ record.Attrs(func(attr slog.Attr) bool {
+ keyValsMap[attr.Key] = attr.Value
+ return true
+ })
+
+ for _, attr := range s.attrs {
+ keyValsMap[attr.Key] = attr.Value
+ }
+
+ args := s.logger.ArgsFromMap(keyValsMap)
+
+ // Wrapping args inside another slice to match [][]LoggerArgument
+ argsWrapped := [][]LoggerArgument{args}
+
+ logger := s.logger
+
+ // Must be done here, see https://github.com/pterm/pterm/issues/608#issuecomment-1876001650
+ if logger.CallerOffset == 0 {
+ logger = logger.WithCallerOffset(3)
+ }
+
+ switch level {
+ case slog.LevelDebug:
+ logger.Debug(message, argsWrapped...)
+ case slog.LevelInfo:
+ logger.Info(message, argsWrapped...)
+ case slog.LevelWarn:
+ logger.Warn(message, argsWrapped...)
+ case slog.LevelError:
+ logger.Error(message, argsWrapped...)
+ default:
+ logger.Print(message, argsWrapped...)
+ }
+
+ return nil
+}
+
+// WithAttrs returns a new handler with the given attributes.
+func (s *SlogHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
+ newS := *s
+ newS.attrs = attrs
+ return &newS
+}
+
+// WithGroup is not yet supported.
+func (s *SlogHandler) WithGroup(name string) slog.Handler {
+ // Grouping is not yet supported by pterm.
+ return s
+}
+
+// NewSlogHandler returns a new logging handler that can be intrgrated with log/slog.
+func NewSlogHandler(logger *Logger) *SlogHandler {
+ return &SlogHandler{logger: logger}
+}
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..443d45d
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/spinner_printer.go
@@ -0,0 +1,277 @@
+package pterm
+
+import (
+ "io"
+ "os"
+ "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,
+ InfoPrinter: &Info,
+ SuccessPrinter: &Success,
+ FailPrinter: &Error,
+ WarningPrinter: &Warning,
+ Writer: os.Stderr,
+}
+
+// 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
+ InfoPrinter TextPrinter
+ SuccessPrinter TextPrinter
+ FailPrinter TextPrinter
+ WarningPrinter TextPrinter
+ RemoveWhenDone bool
+ ShowTimer bool
+ TimerRoundingFactor time.Duration
+ TimerStyle *Style
+
+ IsActive bool
+
+ startedAt time.Time
+ currentSequence string
+
+ Writer io.Writer
+}
+
+// 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
+}
+
+// WithStartedAt sets the time when the SpinnerPrinter started.
+func (s SpinnerPrinter) WithStartedAt(t time.Time) *SpinnerPrinter {
+ s.startedAt = t
+ 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
+}
+
+// WithWriter sets the custom Writer.
+func (p SpinnerPrinter) WithWriter(writer io.Writer) *SpinnerPrinter {
+ p.Writer = writer
+ return &p
+}
+
+// SetWriter sets the custom Writer.
+func (p *SpinnerPrinter) SetWriter(writer io.Writer) {
+ p.Writer = writer
+}
+
+// ResetTimer resets the timer of the SpinnerPrinter.
+func (s *SpinnerPrinter) ResetTimer() {
+ s.startedAt = time.Now()
+}
+
+// SetStartedAt sets the time when the SpinnerPrinter started.
+func (s *SpinnerPrinter) SetStartedAt(t time.Time) {
+ s.startedAt = t
+}
+
+// UpdateText updates the message of the active SpinnerPrinter.
+// Can be used live.
+func (s *SpinnerPrinter) UpdateText(text string) {
+ s.Text = text
+ if !RawOutput {
+ Fprinto(s.Writer, s.Style.Sprint(s.currentSequence)+" "+s.MessageStyle.Sprint(s.Text))
+ } else {
+ Fprintln(s.Writer, s.Text)
+ }
+}
+
+// Start the SpinnerPrinter.
+func (s SpinnerPrinter) Start(text ...any) (*SpinnerPrinter, error) {
+ s.IsActive = true
+ s.startedAt = time.Now()
+ activeSpinnerPrinters = append(activeSpinnerPrinters, &s)
+
+ if len(text) != 0 {
+ s.Text = Sprint(text...)
+ }
+
+ if RawOutput {
+ Fprintln(s.Writer, s.Text)
+ }
+
+ go func() {
+ for s.IsActive {
+ for _, seq := range s.Sequence {
+ if !s.IsActive {
+ continue
+ }
+ if RawOutput {
+ time.Sleep(s.Delay)
+ continue
+ }
+
+ var timer string
+ if s.ShowTimer {
+ timer = " (" + time.Since(s.startedAt).Round(s.TimerRoundingFactor).String() + ")"
+ }
+ Fprinto(s.Writer, 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 {
+ if !s.IsActive {
+ return nil
+ }
+ s.IsActive = false
+ if s.RemoveWhenDone {
+ fClearLine(s.Writer)
+ Fprinto(s.Writer)
+ } else {
+ Fprintln(s.Writer)
+ }
+ 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) {
+ p2, _ := s.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 (s *SpinnerPrinter) GenericStop() (*LivePrinter, error) {
+ _ = s.Stop()
+ lp := LivePrinter(s)
+ return &lp, nil
+}
+
+// Info displays an info message
+// If no message is given, the text of the SpinnerPrinter will be reused as the default message.
+func (s *SpinnerPrinter) Info(message ...any) {
+ if s.InfoPrinter == nil {
+ s.InfoPrinter = &Info
+ }
+
+ if len(message) == 0 {
+ message = []any{s.Text}
+ }
+ fClearLine(s.Writer)
+ Fprinto(s.Writer, s.InfoPrinter.Sprint(message...))
+ _ = s.Stop()
+}
+
+// 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 ...any) {
+ if s.SuccessPrinter == nil {
+ s.SuccessPrinter = &Success
+ }
+
+ if len(message) == 0 {
+ message = []any{s.Text}
+ }
+ fClearLine(s.Writer)
+ Fprinto(s.Writer, 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 ...any) {
+ if s.FailPrinter == nil {
+ s.FailPrinter = &Error
+ }
+
+ if len(message) == 0 {
+ message = []any{s.Text}
+ }
+ fClearLine(s.Writer)
+ Fprinto(s.Writer, 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 ...any) {
+ if s.WarningPrinter == nil {
+ s.WarningPrinter = &Warning
+ }
+
+ if len(message) == 0 {
+ message = []any{s.Text}
+ }
+ fClearLine(s.Writer)
+ Fprinto(s.Writer, 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..eb4a5b7
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/table_printer.go
@@ -0,0 +1,306 @@
+package pterm
+
+import (
+ "encoding/csv"
+ "io"
+ "strings"
+
+ "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,
+ HeaderRowSeparator: "",
+ HeaderRowSeparatorStyle: &ThemeDefault.TableSeparatorStyle,
+ Separator: " | ",
+ SeparatorStyle: &ThemeDefault.TableSeparatorStyle,
+ RowSeparator: "",
+ RowSeparatorStyle: &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
+ HeaderRowSeparator string
+ HeaderRowSeparatorStyle *Style
+ Separator string
+ SeparatorStyle *Style
+ RowSeparator string
+ RowSeparatorStyle *Style
+ Data TableData
+ Boxed bool
+ LeftAlignment bool
+ RightAlignment bool
+ Writer io.Writer
+ AlternateRowStyle *Style
+}
+
+// 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
+}
+
+// WithHeaderRowSeparator returns a new TablePrinter with a specific header HeaderRowSeparator.
+func (p TablePrinter) WithHeaderRowSeparator(separator string) *TablePrinter {
+ p.HeaderRowSeparator = separator
+ return &p
+}
+
+// WithHeaderRowSeparatorStyle returns a new TablePrinter with a specific header HeaderRowSeparatorStyle.
+func (p TablePrinter) WithHeaderRowSeparatorStyle(style *Style) *TablePrinter {
+ p.HeaderRowSeparatorStyle = 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
+}
+
+// WithRowSeparator returns a new TablePrinter with a specific RowSeparator.
+func (p TablePrinter) WithRowSeparator(separator string) *TablePrinter {
+ p.RowSeparator = separator
+ return &p
+}
+
+// WithRowSeparatorStyle returns a new TablePrinter with a specific RowSeparatorStyle.
+func (p TablePrinter) WithRowSeparatorStyle(style *Style) *TablePrinter {
+ p.RowSeparatorStyle = style
+ return &p
+}
+
+// WithData returns a new TablePrinter with specific Data.
+func (p TablePrinter) WithData(data [][]string) *TablePrinter {
+ p.Data = data
+ return &p
+}
+
+// WithCSVReader returns 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
+}
+
+// WithWriter sets the Writer.
+func (p TablePrinter) WithWriter(writer io.Writer) *TablePrinter {
+ p.Writer = writer
+ return &p
+}
+
+// WithAlternateRowStyle returns a new TablePrinter with a specific AlternateRowStyle.
+func (p TablePrinter) WithAlternateRowStyle(style *Style) *TablePrinter {
+ p.AlternateRowStyle = style
+ return &p
+}
+
+type table struct {
+ rows []row
+ maxColumnWidths []int
+}
+
+type row struct {
+ height int
+ cells []cell
+}
+
+type cell struct {
+ width int
+ height int
+ lines []string
+}
+
+// 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()
+ }
+ if p.HeaderRowSeparatorStyle == nil {
+ p.HeaderRowSeparatorStyle = NewStyle()
+ }
+ if p.RowSeparatorStyle == nil {
+ p.RowSeparatorStyle = NewStyle()
+ }
+
+ var t table
+
+ // convert data to table and calculate values
+ for _, rRaw := range p.Data {
+ var r row
+ for _, cRaw := range rRaw {
+ var c cell
+ c.lines = strings.Split(cRaw, "\n")
+ c.height = len(c.lines)
+ for _, l := range c.lines {
+ if maxWidth := internal.GetStringMaxWidth(l); maxWidth > c.width {
+ c.width = maxWidth
+ }
+ }
+ r.cells = append(r.cells, c)
+ if c.height > r.height {
+ r.height = c.height
+ }
+ }
+
+ // set max column widths of table
+ for i, c := range r.cells {
+ if len(t.maxColumnWidths) <= i {
+ t.maxColumnWidths = append(t.maxColumnWidths, c.width)
+ } else if c.width > t.maxColumnWidths[i] {
+ t.maxColumnWidths[i] = c.width
+ }
+ }
+
+ t.rows = append(t.rows, r)
+ }
+
+ var maxRowWidth int
+ for _, r := range t.rows {
+ rowWidth := internal.GetStringMaxWidth(p.renderRow(t, r))
+ if rowWidth > maxRowWidth {
+ maxRowWidth = rowWidth
+ }
+ }
+
+ // render table
+ var ret strings.Builder
+
+ for i, r := range t.rows {
+ if i == 0 && p.HasHeader {
+ ret.WriteString(p.HeaderStyle.Sprint(p.renderRow(t, r)))
+
+ if p.HeaderRowSeparator != "" {
+ ret.WriteString(strings.Repeat(p.HeaderRowSeparatorStyle.Sprint(p.HeaderRowSeparator), maxRowWidth))
+ ret.WriteByte('\n')
+ }
+ continue
+ }
+
+ // Apply AlternateRowStyle if needed
+ if i%2 == 1 && p.AlternateRowStyle != nil {
+ ret.WriteString(p.AlternateRowStyle.Sprint(p.renderRow(t, r)))
+ } else {
+ ret.WriteString(p.renderRow(t, r))
+ }
+
+ if p.RowSeparator != "" && i < len(t.rows)-1 {
+ ret.WriteString(strings.Repeat(p.RowSeparatorStyle.Sprint(p.RowSeparator), maxRowWidth) + "\n")
+ }
+ }
+
+ if p.Boxed {
+ return DefaultBox.Sprint(strings.TrimSuffix(ret.String(), "\n")), nil
+ }
+
+ return ret.String(), nil
+}
+
+// renderRow renders a row.
+// It merges the cells of a row into one string.
+// Each line of each cell is merged with the same line of the other cells.
+func (p TablePrinter) renderRow(t table, r row) string {
+ var s string
+
+ // Merge lines of cells and add separator
+ // Use t.maxColumnWidths to add padding to corresponding cell
+ // A newline in a cell should be in the same column as original cell
+ for i := 0; i < r.height; i++ {
+ for j, c := range r.cells {
+ var currentLine string
+ if i < len(c.lines) {
+ currentLine = c.lines[i]
+ }
+ paddingForLine := t.maxColumnWidths[j] - internal.GetStringMaxWidth(currentLine)
+
+ // Add right alignment if necessary
+ if p.RightAlignment {
+ s += strings.Repeat(" ", paddingForLine)
+ }
+
+ // Add line content
+ if i < len(c.lines) {
+ s += c.lines[i]
+ }
+
+ // Add padding for left alignment, except for last column
+ if j < len(r.cells)-1 {
+ if p.LeftAlignment {
+ s += strings.Repeat(" ", paddingForLine)
+ }
+ s += p.SeparatorStyle.Sprint(p.Separator)
+ } else if p.LeftAlignment {
+ // Add padding after last column
+ s += strings.Repeat(" ", paddingForLine)
+ }
+ }
+ s += "\n"
+ }
+
+ return s
+}
+
+// Render prints the TablePrinter to the terminal.
+func (p TablePrinter) Render() error {
+ s, _ := p.Srender()
+ Fprintln(p.Writer, 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..91594c8
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/theme.go
@@ -0,0 +1,259 @@
+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{
+ DefaultText: Style{FgDefault, BgDefault},
+ PrimaryStyle: Style{FgLightCyan},
+ 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},
+ HeatmapStyle: Style{FgDefault},
+ HeatmapHeaderStyle: Style{FgLightCyan},
+ HeatmapSeparatorStyle: Style{FgDefault},
+ 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},
+ Checkmark: Checkmark{
+ Checked: Green("✓"),
+ Unchecked: Red("✗"),
+ },
+ }
+)
+
+// 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 {
+ DefaultText Style
+ 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
+ HeatmapStyle Style
+ HeatmapHeaderStyle Style
+ HeatmapSeparatorStyle 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
+ Checkmark Checkmark
+}
+
+// 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..3cbeb30
--- /dev/null
+++ b/vendor/github.com/pterm/pterm/tree_printer.go
@@ -0,0 +1,161 @@
+package pterm
+
+import (
+ "io"
+ "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
+ Writer io.Writer
+}
+
+// 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
+}
+
+// WithWriter sets the Writer.
+func (p TreePrinter) WithWriter(writer io.Writer) *TreePrinter {
+ p.Writer = writer
+ return &p
+}
+
+// Render prints the list to the terminal.
+func (p TreePrinter) Render() error {
+ s, _ := p.Srender()
+ Fprintln(p.Writer, 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()
+ }
+
+ var result strings.Builder
+ if p.Root.Text != "" {
+ result.WriteString(p.TextStyle.Sprint(p.Root.Text))
+ result.WriteByte('\n')
+ }
+ result.WriteString(walkOverTree(p.Root.Children, p, ""))
+ return result.String(), 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
+}
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..25e9346
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/README.md
@@ -0,0 +1,157 @@
+# Unicode Text Segmentation for Go
+
+[![Go Reference](https://pkg.go.dev/badge/github.com/rivo/uniseg.svg)](https://pkg.go.dev/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](https://unicode.org/reports/tr29/), Unicode Line Breaking according to [Unicode Standard Annex #14](https://unicode.org/reports/tr14/) (Unicode version 14.0.0), and monospace font string width calculation similar to [wcwidth](https://man7.org/linux/man-pages/man3/wcwidth.3.html).
+
+## Background
+
+### Grapheme Clusters
+
+In Go, [strings are read-only slices of bytes](https://go.dev/blog/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 tools 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.
+
+### Word Boundaries
+
+Word boundaries are used in a number of different contexts. The most familiar ones are selection (double-click mouse selection), cursor movement ("move to next word" control-arrow keys), and the dialog option "Whole Word Search" for search and replace. They are also used in database queries, to determine whether elements are within a certain number of words of one another. Searching may also use word boundaries in determining matching items. This package provides tools to determine word boundaries within strings.
+
+### Sentence Boundaries
+
+Sentence boundaries are often used for triple-click or some other method of selecting or iterating through blocks of text that are larger than single words. They are also used to determine whether words occur within the same sentence in database queries. This package provides tools to determine sentence boundaries within strings.
+
+### Line Breaking
+
+Line breaking, also known as word wrapping, is the process of breaking a section of text into lines such that it will fit in the available width of a page, window or other display area. This package provides tools to determine where a string may or may not be broken and where it must be broken (for example after newline characters).
+
+### Monospace Width
+
+Most terminals or text displays / text editors using a monospace font (for example source code editors) use a fixed width for each character. Some characters such as emojis or characters found in Asian and other languages may take up more than one character cell. This package provides tools to determine the number of cells a string will take up when displayed in a monospace font. See [here](https://pkg.go.dev/github.com/rivo/uniseg#hdr-Monospace_Width) for more information.
+
+## Installation
+
+```bash
+go get github.com/rivo/uniseg
+```
+
+## Examples
+
+### Counting Characters in a String
+
+```go
+n := uniseg.GraphemeClusterCount("🇩🇪🏳️🌈")
+fmt.Println(n)
+// 2
+```
+
+### Calculating the Monospace String Width
+
+```go
+width := uniseg.StringWidth("🇩🇪🏳️🌈!")
+fmt.Println(width)
+// 5
+```
+
+### Using the [`Graphemes`](https://pkg.go.dev/github.com/rivo/uniseg#Graphemes) Class
+
+This is the most convenient method of iterating over grapheme clusters:
+
+```go
+gr := uniseg.NewGraphemes("👍🏼!")
+for gr.Next() {
+ fmt.Printf("%x ", gr.Runes())
+}
+// [1f44d 1f3fc] [21]
+```
+
+### Using the [`Step`](https://pkg.go.dev/github.com/rivo/uniseg#Step) or [`StepString`](https://pkg.go.dev/github.com/rivo/uniseg#StepString) Function
+
+This is orders of magnitude faster than the `Graphemes` class, but it requires the handling of states and boundaries:
+
+```go
+str := "🇩🇪🏳️🌈"
+state := -1
+var c string
+for len(str) > 0 {
+ c, str, _, state = uniseg.StepString(str, state)
+ fmt.Printf("%x ", []rune(c))
+}
+// [1f1e9 1f1ea] [1f3f3 fe0f 200d 1f308]
+```
+
+### Advanced Examples
+
+Breaking into grapheme clusters and evaluating line breaks:
+
+```go
+str := "First line.\nSecond line."
+state := -1
+var (
+ c string
+ boundaries int
+)
+for len(str) > 0 {
+ c, str, boundaries, state = uniseg.StepString(str, state)
+ fmt.Print(c)
+ if boundaries&uniseg.MaskLine == uniseg.LineCanBreak {
+ fmt.Print("|")
+ } else if boundaries&uniseg.MaskLine == uniseg.LineMustBreak {
+ fmt.Print("‖")
+ }
+}
+// First |line.
+// ‖Second |line.‖
+```
+
+If you're only interested in word segmentation, use [`FirstWord`](https://pkg.go.dev/github.com/rivo/uniseg#FirstWord) or [`FirstWordInString`](https://pkg.go.dev/github.com/rivo/uniseg#FirstWordInString):
+
+```go
+str := "Hello, world!"
+state := -1
+var c string
+for len(str) > 0 {
+ c, str, state = uniseg.FirstWordInString(str, state)
+ fmt.Printf("(%s)\n", c)
+}
+// (Hello)
+// (,)
+// ( )
+// (world)
+// (!)
+```
+
+Similarly, use
+
+- [`FirstGraphemeCluster`](https://pkg.go.dev/github.com/rivo/uniseg#FirstGraphemeCluster) or [`FirstGraphemeClusterInString`](https://pkg.go.dev/github.com/rivo/uniseg#FirstGraphemeClusterInString) for grapheme cluster determination only,
+- [`FirstSentence`](https://pkg.go.dev/github.com/rivo/uniseg#FirstSentence) or [`FirstSentenceInString`](https://pkg.go.dev/github.com/rivo/uniseg#FirstSentenceInString) for sentence segmentation only, and
+- [`FirstLineSegment`](https://pkg.go.dev/github.com/rivo/uniseg#FirstLineSegment) or [`FirstLineSegmentInString`](https://pkg.go.dev/github.com/rivo/uniseg#FirstLineSegmentInString) for line breaking / word wrapping (although using [`Step`](https://pkg.go.dev/github.com/rivo/uniseg#Step) or [`StepString`](https://pkg.go.dev/github.com/rivo/uniseg#StepString) is preferred as it will observe grapheme cluster boundaries).
+
+Finally, if you need to reverse a string while preserving grapheme clusters, use [`ReverseString`](https://pkg.go.dev/github.com/rivo/uniseg#ReverseString):
+
+```go
+fmt.Println(uniseg.ReverseString("🇩🇪🏳️🌈"))
+// 🏳️🌈🇩🇪
+```
+
+## Documentation
+
+Refer to https://pkg.go.dev/github.com/rivo/uniseg for the package's documentation.
+
+## Dependencies
+
+This package does not depend on any packages outside the standard library.
+
+## Sponsor this Project
+
+[Become a Sponsor on GitHub](https://github.com/sponsors/rivo?metadata_source=uniseg_readme) to support this project!
+
+## Your Feedback
+
+Add your issue here on GitHub, preferably before submitting any PR's. Feel free to get in touch if you have any questions.
\ No newline at end of file
diff --git a/vendor/github.com/rivo/uniseg/doc.go b/vendor/github.com/rivo/uniseg/doc.go
new file mode 100644
index 0000000..11224ae
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/doc.go
@@ -0,0 +1,108 @@
+/*
+Package uniseg implements Unicode Text Segmentation, Unicode Line Breaking, and
+string width calculation for monospace fonts. Unicode Text Segmentation conforms
+to Unicode Standard Annex #29 (https://unicode.org/reports/tr29/) and Unicode
+Line Breaking conforms to Unicode Standard Annex #14
+(https://unicode.org/reports/tr14/).
+
+In short, using this package, you can split a string into grapheme clusters
+(what people would usually refer to as a "character"), into words, and into
+sentences. Or, in its simplest case, this package allows you to count the number
+of characters in a string, especially when it contains complex characters such
+as emojis, combining characters, or characters from Asian, Arabic, Hebrew, or
+other languages. Additionally, you can use it to implement line breaking (or
+"word wrapping"), that is, to determine where text can be broken over to the
+next line when the width of the line is not big enough to fit the entire text.
+Finally, you can use it to calculate the display width of a string for monospace
+fonts.
+
+# Getting Started
+
+If you just want to count the number of characters in a string, you can use
+[GraphemeClusterCount]. If you want to determine the display width of a string,
+you can use [StringWidth]. If you want to iterate over a string, you can use
+[Step], [StepString], or the [Graphemes] class (more convenient but less
+performant). This will provide you with all information: grapheme clusters,
+word boundaries, sentence boundaries, line breaks, and monospace character
+widths. The specialized functions [FirstGraphemeCluster],
+[FirstGraphemeClusterInString], [FirstWord], [FirstWordInString],
+[FirstSentence], and [FirstSentenceInString] can be used if only one type of
+information is needed.
+
+# Grapheme Clusters
+
+Consider the rainbow flag emoji: 🏳️🌈. On most modern systems, it appears as one
+character. But its string representation actually has 14 bytes, so counting
+bytes (or using len("🏳️🌈")) will not work as expected. Counting runes won't,
+either: The flag has 4 Unicode code points, thus 4 runes. The stdlib function
+utf8.RuneCountInString("🏳️🌈") and len([]rune("🏳️🌈")) will both return 4.
+
+The [GraphemeClusterCount] function will return 1 for the rainbow flag emoji.
+The Graphemes class and a variety of functions in this package will allow you to
+split strings into its grapheme clusters.
+
+# Word Boundaries
+
+Word boundaries are used in a number of different contexts. The most familiar
+ones are selection (double-click mouse selection), cursor movement ("move to
+next word" control-arrow keys), and the dialog option "Whole Word Search" for
+search and replace. This package provides methods for determining word
+boundaries.
+
+# Sentence Boundaries
+
+Sentence boundaries are often used for triple-click or some other method of
+selecting or iterating through blocks of text that are larger than single words.
+They are also used to determine whether words occur within the same sentence in
+database queries. This package provides methods for determining sentence
+boundaries.
+
+# Line Breaking
+
+Line breaking, also known as word wrapping, is the process of breaking a section
+of text into lines such that it will fit in the available width of a page,
+window or other display area. This package provides methods to determine the
+positions in a string where a line must be broken, may be broken, or must not be
+broken.
+
+# Monospace Width
+
+Monospace width, as referred to in this package, is the width of a string in a
+monospace font. This is commonly used in terminal user interfaces or text
+displays or editors that don't support proportional fonts. A width of 1
+corresponds to a single character cell. The C function [wcswidth()] and its
+implementation in other programming languages is in widespread use for the same
+purpose. However, there is no standard for the calculation of such widths, and
+this package differs from wcswidth() in a number of ways, presumably to generate
+more visually pleasing results.
+
+To start, we assume that every code point has a width of 1, with the following
+exceptions:
+
+ - Code points with grapheme cluster break properties Control, CR, LF, Extend,
+ and ZWJ have a width of 0.
+ - U+2E3A, Two-Em Dash, has a width of 3.
+ - U+2E3B, Three-Em Dash, has a width of 4.
+ - Characters with the East-Asian Width properties "Fullwidth" (F) and "Wide"
+ (W) have a width of 2. (Properties "Ambiguous" (A) and "Neutral" (N) both
+ have a width of 1.)
+ - Code points with grapheme cluster break property Regional Indicator have a
+ width of 2.
+ - Code points with grapheme cluster break property Extended Pictographic have
+ a width of 2, unless their Emoji Presentation flag is "No", in which case
+ the width is 1.
+
+For Hangul grapheme clusters composed of conjoining Jamo and for Regional
+Indicators (flags), all code points except the first one have a width of 0. For
+grapheme clusters starting with an Extended Pictographic, any additional code
+point will force a total width of 2, except if the Variation Selector-15
+(U+FE0E) is included, in which case the total width is always 1. Grapheme
+clusters ending with Variation Selector-16 (U+FE0F) have a width of 2.
+
+Note that whether these widths appear correct depends on your application's
+render engine, to which extent it conforms to the Unicode Standard, and its
+choice of font.
+
+[wcswidth()]: https://man7.org/linux/man-pages/man3/wcswidth.3.html
+*/
+package uniseg
diff --git a/vendor/github.com/rivo/uniseg/eastasianwidth.go b/vendor/github.com/rivo/uniseg/eastasianwidth.go
new file mode 100644
index 0000000..661934a
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/eastasianwidth.go
@@ -0,0 +1,2556 @@
+package uniseg
+
+// Code generated via go generate from gen_properties.go. DO NOT EDIT.
+
+// eastAsianWidth are taken from
+// https://www.unicode.org/Public/14.0.0/ucd/EastAsianWidth.txt
+// and
+// https://unicode.org/Public/14.0.0/ucd/emoji/emoji-data.txt
+// ("Extended_Pictographic" only)
+// on September 10, 2022. See https://www.unicode.org/license.html for the Unicode
+// license agreement.
+var eastAsianWidth = [][3]int{
+ {0x0000, 0x001F, prN}, // Cc [32] ..
+ {0x0020, 0x0020, prNa}, // Zs SPACE
+ {0x0021, 0x0023, prNa}, // Po [3] EXCLAMATION MARK..NUMBER SIGN
+ {0x0024, 0x0024, prNa}, // Sc DOLLAR SIGN
+ {0x0025, 0x0027, prNa}, // Po [3] PERCENT SIGN..APOSTROPHE
+ {0x0028, 0x0028, prNa}, // Ps LEFT PARENTHESIS
+ {0x0029, 0x0029, prNa}, // Pe RIGHT PARENTHESIS
+ {0x002A, 0x002A, prNa}, // Po ASTERISK
+ {0x002B, 0x002B, prNa}, // Sm PLUS SIGN
+ {0x002C, 0x002C, prNa}, // Po COMMA
+ {0x002D, 0x002D, prNa}, // Pd HYPHEN-MINUS
+ {0x002E, 0x002F, prNa}, // Po [2] FULL STOP..SOLIDUS
+ {0x0030, 0x0039, prNa}, // Nd [10] DIGIT ZERO..DIGIT NINE
+ {0x003A, 0x003B, prNa}, // Po [2] COLON..SEMICOLON
+ {0x003C, 0x003E, prNa}, // Sm [3] LESS-THAN SIGN..GREATER-THAN SIGN
+ {0x003F, 0x0040, prNa}, // Po [2] QUESTION MARK..COMMERCIAL AT
+ {0x0041, 0x005A, prNa}, // Lu [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z
+ {0x005B, 0x005B, prNa}, // Ps LEFT SQUARE BRACKET
+ {0x005C, 0x005C, prNa}, // Po REVERSE SOLIDUS
+ {0x005D, 0x005D, prNa}, // Pe RIGHT SQUARE BRACKET
+ {0x005E, 0x005E, prNa}, // Sk CIRCUMFLEX ACCENT
+ {0x005F, 0x005F, prNa}, // Pc LOW LINE
+ {0x0060, 0x0060, prNa}, // Sk GRAVE ACCENT
+ {0x0061, 0x007A, prNa}, // Ll [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z
+ {0x007B, 0x007B, prNa}, // Ps LEFT CURLY BRACKET
+ {0x007C, 0x007C, prNa}, // Sm VERTICAL LINE
+ {0x007D, 0x007D, prNa}, // Pe RIGHT CURLY BRACKET
+ {0x007E, 0x007E, prNa}, // Sm TILDE
+ {0x007F, 0x007F, prN}, // Cc
+ {0x0080, 0x009F, prN}, // Cc [32] ..
+ {0x00A0, 0x00A0, prN}, // Zs NO-BREAK SPACE
+ {0x00A1, 0x00A1, prA}, // Po INVERTED EXCLAMATION MARK
+ {0x00A2, 0x00A3, prNa}, // Sc [2] CENT SIGN..POUND SIGN
+ {0x00A4, 0x00A4, prA}, // Sc CURRENCY SIGN
+ {0x00A5, 0x00A5, prNa}, // Sc YEN SIGN
+ {0x00A6, 0x00A6, prNa}, // So BROKEN BAR
+ {0x00A7, 0x00A7, prA}, // Po SECTION SIGN
+ {0x00A8, 0x00A8, prA}, // Sk DIAERESIS
+ {0x00A9, 0x00A9, prN}, // So COPYRIGHT SIGN
+ {0x00AA, 0x00AA, prA}, // Lo FEMININE ORDINAL INDICATOR
+ {0x00AB, 0x00AB, prN}, // Pi LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ {0x00AC, 0x00AC, prNa}, // Sm NOT SIGN
+ {0x00AD, 0x00AD, prA}, // Cf SOFT HYPHEN
+ {0x00AE, 0x00AE, prA}, // So REGISTERED SIGN
+ {0x00AF, 0x00AF, prNa}, // Sk MACRON
+ {0x00B0, 0x00B0, prA}, // So DEGREE SIGN
+ {0x00B1, 0x00B1, prA}, // Sm PLUS-MINUS SIGN
+ {0x00B2, 0x00B3, prA}, // No [2] SUPERSCRIPT TWO..SUPERSCRIPT THREE
+ {0x00B4, 0x00B4, prA}, // Sk ACUTE ACCENT
+ {0x00B5, 0x00B5, prN}, // Ll MICRO SIGN
+ {0x00B6, 0x00B7, prA}, // Po [2] PILCROW SIGN..MIDDLE DOT
+ {0x00B8, 0x00B8, prA}, // Sk CEDILLA
+ {0x00B9, 0x00B9, prA}, // No SUPERSCRIPT ONE
+ {0x00BA, 0x00BA, prA}, // Lo MASCULINE ORDINAL INDICATOR
+ {0x00BB, 0x00BB, prN}, // Pf RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ {0x00BC, 0x00BE, prA}, // No [3] VULGAR FRACTION ONE QUARTER..VULGAR FRACTION THREE QUARTERS
+ {0x00BF, 0x00BF, prA}, // Po INVERTED QUESTION MARK
+ {0x00C0, 0x00C5, prN}, // Lu [6] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER A WITH RING ABOVE
+ {0x00C6, 0x00C6, prA}, // Lu LATIN CAPITAL LETTER AE
+ {0x00C7, 0x00CF, prN}, // Lu [9] LATIN CAPITAL LETTER C WITH CEDILLA..LATIN CAPITAL LETTER I WITH DIAERESIS
+ {0x00D0, 0x00D0, prA}, // Lu LATIN CAPITAL LETTER ETH
+ {0x00D1, 0x00D6, prN}, // Lu [6] LATIN CAPITAL LETTER N WITH TILDE..LATIN CAPITAL LETTER O WITH DIAERESIS
+ {0x00D7, 0x00D7, prA}, // Sm MULTIPLICATION SIGN
+ {0x00D8, 0x00D8, prA}, // Lu LATIN CAPITAL LETTER O WITH STROKE
+ {0x00D9, 0x00DD, prN}, // Lu [5] LATIN CAPITAL LETTER U WITH GRAVE..LATIN CAPITAL LETTER Y WITH ACUTE
+ {0x00DE, 0x00E1, prA}, // L& [4] LATIN CAPITAL LETTER THORN..LATIN SMALL LETTER A WITH ACUTE
+ {0x00E2, 0x00E5, prN}, // Ll [4] LATIN SMALL LETTER A WITH CIRCUMFLEX..LATIN SMALL LETTER A WITH RING ABOVE
+ {0x00E6, 0x00E6, prA}, // Ll LATIN SMALL LETTER AE
+ {0x00E7, 0x00E7, prN}, // Ll LATIN SMALL LETTER C WITH CEDILLA
+ {0x00E8, 0x00EA, prA}, // Ll [3] LATIN SMALL LETTER E WITH GRAVE..LATIN SMALL LETTER E WITH CIRCUMFLEX
+ {0x00EB, 0x00EB, prN}, // Ll LATIN SMALL LETTER E WITH DIAERESIS
+ {0x00EC, 0x00ED, prA}, // Ll [2] LATIN SMALL LETTER I WITH GRAVE..LATIN SMALL LETTER I WITH ACUTE
+ {0x00EE, 0x00EF, prN}, // Ll [2] LATIN SMALL LETTER I WITH CIRCUMFLEX..LATIN SMALL LETTER I WITH DIAERESIS
+ {0x00F0, 0x00F0, prA}, // Ll LATIN SMALL LETTER ETH
+ {0x00F1, 0x00F1, prN}, // Ll LATIN SMALL LETTER N WITH TILDE
+ {0x00F2, 0x00F3, prA}, // Ll [2] LATIN SMALL LETTER O WITH GRAVE..LATIN SMALL LETTER O WITH ACUTE
+ {0x00F4, 0x00F6, prN}, // Ll [3] LATIN SMALL LETTER O WITH CIRCUMFLEX..LATIN SMALL LETTER O WITH DIAERESIS
+ {0x00F7, 0x00F7, prA}, // Sm DIVISION SIGN
+ {0x00F8, 0x00FA, prA}, // Ll [3] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER U WITH ACUTE
+ {0x00FB, 0x00FB, prN}, // Ll LATIN SMALL LETTER U WITH CIRCUMFLEX
+ {0x00FC, 0x00FC, prA}, // Ll LATIN SMALL LETTER U WITH DIAERESIS
+ {0x00FD, 0x00FD, prN}, // Ll LATIN SMALL LETTER Y WITH ACUTE
+ {0x00FE, 0x00FE, prA}, // Ll LATIN SMALL LETTER THORN
+ {0x00FF, 0x00FF, prN}, // Ll LATIN SMALL LETTER Y WITH DIAERESIS
+ {0x0100, 0x0100, prN}, // Lu LATIN CAPITAL LETTER A WITH MACRON
+ {0x0101, 0x0101, prA}, // Ll LATIN SMALL LETTER A WITH MACRON
+ {0x0102, 0x0110, prN}, // L& [15] LATIN CAPITAL LETTER A WITH BREVE..LATIN CAPITAL LETTER D WITH STROKE
+ {0x0111, 0x0111, prA}, // Ll LATIN SMALL LETTER D WITH STROKE
+ {0x0112, 0x0112, prN}, // Lu LATIN CAPITAL LETTER E WITH MACRON
+ {0x0113, 0x0113, prA}, // Ll LATIN SMALL LETTER E WITH MACRON
+ {0x0114, 0x011A, prN}, // L& [7] LATIN CAPITAL LETTER E WITH BREVE..LATIN CAPITAL LETTER E WITH CARON
+ {0x011B, 0x011B, prA}, // Ll LATIN SMALL LETTER E WITH CARON
+ {0x011C, 0x0125, prN}, // L& [10] LATIN CAPITAL LETTER G WITH CIRCUMFLEX..LATIN SMALL LETTER H WITH CIRCUMFLEX
+ {0x0126, 0x0127, prA}, // L& [2] LATIN CAPITAL LETTER H WITH STROKE..LATIN SMALL LETTER H WITH STROKE
+ {0x0128, 0x012A, prN}, // L& [3] LATIN CAPITAL LETTER I WITH TILDE..LATIN CAPITAL LETTER I WITH MACRON
+ {0x012B, 0x012B, prA}, // Ll LATIN SMALL LETTER I WITH MACRON
+ {0x012C, 0x0130, prN}, // L& [5] LATIN CAPITAL LETTER I WITH BREVE..LATIN CAPITAL LETTER I WITH DOT ABOVE
+ {0x0131, 0x0133, prA}, // L& [3] LATIN SMALL LETTER DOTLESS I..LATIN SMALL LIGATURE IJ
+ {0x0134, 0x0137, prN}, // L& [4] LATIN CAPITAL LETTER J WITH CIRCUMFLEX..LATIN SMALL LETTER K WITH CEDILLA
+ {0x0138, 0x0138, prA}, // Ll LATIN SMALL LETTER KRA
+ {0x0139, 0x013E, prN}, // L& [6] LATIN CAPITAL LETTER L WITH ACUTE..LATIN SMALL LETTER L WITH CARON
+ {0x013F, 0x0142, prA}, // L& [4] LATIN CAPITAL LETTER L WITH MIDDLE DOT..LATIN SMALL LETTER L WITH STROKE
+ {0x0143, 0x0143, prN}, // Lu LATIN CAPITAL LETTER N WITH ACUTE
+ {0x0144, 0x0144, prA}, // Ll LATIN SMALL LETTER N WITH ACUTE
+ {0x0145, 0x0147, prN}, // L& [3] LATIN CAPITAL LETTER N WITH CEDILLA..LATIN CAPITAL LETTER N WITH CARON
+ {0x0148, 0x014B, prA}, // L& [4] LATIN SMALL LETTER N WITH CARON..LATIN SMALL LETTER ENG
+ {0x014C, 0x014C, prN}, // Lu LATIN CAPITAL LETTER O WITH MACRON
+ {0x014D, 0x014D, prA}, // Ll LATIN SMALL LETTER O WITH MACRON
+ {0x014E, 0x0151, prN}, // L& [4] LATIN CAPITAL LETTER O WITH BREVE..LATIN SMALL LETTER O WITH DOUBLE ACUTE
+ {0x0152, 0x0153, prA}, // L& [2] LATIN CAPITAL LIGATURE OE..LATIN SMALL LIGATURE OE
+ {0x0154, 0x0165, prN}, // L& [18] LATIN CAPITAL LETTER R WITH ACUTE..LATIN SMALL LETTER T WITH CARON
+ {0x0166, 0x0167, prA}, // L& [2] LATIN CAPITAL LETTER T WITH STROKE..LATIN SMALL LETTER T WITH STROKE
+ {0x0168, 0x016A, prN}, // L& [3] LATIN CAPITAL LETTER U WITH TILDE..LATIN CAPITAL LETTER U WITH MACRON
+ {0x016B, 0x016B, prA}, // Ll LATIN SMALL LETTER U WITH MACRON
+ {0x016C, 0x017F, prN}, // L& [20] LATIN CAPITAL LETTER U WITH BREVE..LATIN SMALL LETTER LONG S
+ {0x0180, 0x01BA, prN}, // L& [59] LATIN SMALL LETTER B WITH STROKE..LATIN SMALL LETTER EZH WITH TAIL
+ {0x01BB, 0x01BB, prN}, // Lo LATIN LETTER TWO WITH STROKE
+ {0x01BC, 0x01BF, prN}, // L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN
+ {0x01C0, 0x01C3, prN}, // Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK
+ {0x01C4, 0x01CD, prN}, // L& [10] LATIN CAPITAL LETTER DZ WITH CARON..LATIN CAPITAL LETTER A WITH CARON
+ {0x01CE, 0x01CE, prA}, // Ll LATIN SMALL LETTER A WITH CARON
+ {0x01CF, 0x01CF, prN}, // Lu LATIN CAPITAL LETTER I WITH CARON
+ {0x01D0, 0x01D0, prA}, // Ll LATIN SMALL LETTER I WITH CARON
+ {0x01D1, 0x01D1, prN}, // Lu LATIN CAPITAL LETTER O WITH CARON
+ {0x01D2, 0x01D2, prA}, // Ll LATIN SMALL LETTER O WITH CARON
+ {0x01D3, 0x01D3, prN}, // Lu LATIN CAPITAL LETTER U WITH CARON
+ {0x01D4, 0x01D4, prA}, // Ll LATIN SMALL LETTER U WITH CARON
+ {0x01D5, 0x01D5, prN}, // Lu LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON
+ {0x01D6, 0x01D6, prA}, // Ll LATIN SMALL LETTER U WITH DIAERESIS AND MACRON
+ {0x01D7, 0x01D7, prN}, // Lu LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE
+ {0x01D8, 0x01D8, prA}, // Ll LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE
+ {0x01D9, 0x01D9, prN}, // Lu LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON
+ {0x01DA, 0x01DA, prA}, // Ll LATIN SMALL LETTER U WITH DIAERESIS AND CARON
+ {0x01DB, 0x01DB, prN}, // Lu LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE
+ {0x01DC, 0x01DC, prA}, // Ll LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE
+ {0x01DD, 0x024F, prN}, // L& [115] LATIN SMALL LETTER TURNED E..LATIN SMALL LETTER Y WITH STROKE
+ {0x0250, 0x0250, prN}, // Ll LATIN SMALL LETTER TURNED A
+ {0x0251, 0x0251, prA}, // Ll LATIN SMALL LETTER ALPHA
+ {0x0252, 0x0260, prN}, // Ll [15] LATIN SMALL LETTER TURNED ALPHA..LATIN SMALL LETTER G WITH HOOK
+ {0x0261, 0x0261, prA}, // Ll LATIN SMALL LETTER SCRIPT G
+ {0x0262, 0x0293, prN}, // Ll [50] LATIN LETTER SMALL CAPITAL G..LATIN SMALL LETTER EZH WITH CURL
+ {0x0294, 0x0294, prN}, // Lo LATIN LETTER GLOTTAL STOP
+ {0x0295, 0x02AF, prN}, // Ll [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL
+ {0x02B0, 0x02C1, prN}, // Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP
+ {0x02C2, 0x02C3, prN}, // Sk [2] MODIFIER LETTER LEFT ARROWHEAD..MODIFIER LETTER RIGHT ARROWHEAD
+ {0x02C4, 0x02C4, prA}, // Sk MODIFIER LETTER UP ARROWHEAD
+ {0x02C5, 0x02C5, prN}, // Sk MODIFIER LETTER DOWN ARROWHEAD
+ {0x02C6, 0x02C6, prN}, // Lm MODIFIER LETTER CIRCUMFLEX ACCENT
+ {0x02C7, 0x02C7, prA}, // Lm CARON
+ {0x02C8, 0x02C8, prN}, // Lm MODIFIER LETTER VERTICAL LINE
+ {0x02C9, 0x02CB, prA}, // Lm [3] MODIFIER LETTER MACRON..MODIFIER LETTER GRAVE ACCENT
+ {0x02CC, 0x02CC, prN}, // Lm MODIFIER LETTER LOW VERTICAL LINE
+ {0x02CD, 0x02CD, prA}, // Lm MODIFIER LETTER LOW MACRON
+ {0x02CE, 0x02CF, prN}, // Lm [2] MODIFIER LETTER LOW GRAVE ACCENT..MODIFIER LETTER LOW ACUTE ACCENT
+ {0x02D0, 0x02D0, prA}, // Lm MODIFIER LETTER TRIANGULAR COLON
+ {0x02D1, 0x02D1, prN}, // Lm MODIFIER LETTER HALF TRIANGULAR COLON
+ {0x02D2, 0x02D7, prN}, // Sk [6] MODIFIER LETTER CENTRED RIGHT HALF RING..MODIFIER LETTER MINUS SIGN
+ {0x02D8, 0x02DB, prA}, // Sk [4] BREVE..OGONEK
+ {0x02DC, 0x02DC, prN}, // Sk SMALL TILDE
+ {0x02DD, 0x02DD, prA}, // Sk DOUBLE ACUTE ACCENT
+ {0x02DE, 0x02DE, prN}, // Sk MODIFIER LETTER RHOTIC HOOK
+ {0x02DF, 0x02DF, prA}, // Sk MODIFIER LETTER CROSS ACCENT
+ {0x02E0, 0x02E4, prN}, // Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP
+ {0x02E5, 0x02EB, prN}, // Sk [7] MODIFIER LETTER EXTRA-HIGH TONE BAR..MODIFIER LETTER YANG DEPARTING TONE MARK
+ {0x02EC, 0x02EC, prN}, // Lm MODIFIER LETTER VOICING
+ {0x02ED, 0x02ED, prN}, // Sk MODIFIER LETTER UNASPIRATED
+ {0x02EE, 0x02EE, prN}, // Lm MODIFIER LETTER DOUBLE APOSTROPHE
+ {0x02EF, 0x02FF, prN}, // Sk [17] MODIFIER LETTER LOW DOWN ARROWHEAD..MODIFIER LETTER LOW LEFT ARROW
+ {0x0300, 0x036F, prA}, // Mn [112] COMBINING GRAVE ACCENT..COMBINING LATIN SMALL LETTER X
+ {0x0370, 0x0373, prN}, // L& [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI
+ {0x0374, 0x0374, prN}, // Lm GREEK NUMERAL SIGN
+ {0x0375, 0x0375, prN}, // Sk GREEK LOWER NUMERAL SIGN
+ {0x0376, 0x0377, prN}, // L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA
+ {0x037A, 0x037A, prN}, // Lm GREEK YPOGEGRAMMENI
+ {0x037B, 0x037D, prN}, // Ll [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL
+ {0x037E, 0x037E, prN}, // Po GREEK QUESTION MARK
+ {0x037F, 0x037F, prN}, // Lu GREEK CAPITAL LETTER YOT
+ {0x0384, 0x0385, prN}, // Sk [2] GREEK TONOS..GREEK DIALYTIKA TONOS
+ {0x0386, 0x0386, prN}, // Lu GREEK CAPITAL LETTER ALPHA WITH TONOS
+ {0x0387, 0x0387, prN}, // Po GREEK ANO TELEIA
+ {0x0388, 0x038A, prN}, // Lu [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS
+ {0x038C, 0x038C, prN}, // Lu GREEK CAPITAL LETTER OMICRON WITH TONOS
+ {0x038E, 0x0390, prN}, // L& [3] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
+ {0x0391, 0x03A1, prA}, // Lu [17] GREEK CAPITAL LETTER ALPHA..GREEK CAPITAL LETTER RHO
+ {0x03A3, 0x03A9, prA}, // Lu [7] GREEK CAPITAL LETTER SIGMA..GREEK CAPITAL LETTER OMEGA
+ {0x03AA, 0x03B0, prN}, // L& [7] GREEK CAPITAL LETTER IOTA WITH DIALYTIKA..GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
+ {0x03B1, 0x03C1, prA}, // Ll [17] GREEK SMALL LETTER ALPHA..GREEK SMALL LETTER RHO
+ {0x03C2, 0x03C2, prN}, // Ll GREEK SMALL LETTER FINAL SIGMA
+ {0x03C3, 0x03C9, prA}, // Ll [7] GREEK SMALL LETTER SIGMA..GREEK SMALL LETTER OMEGA
+ {0x03CA, 0x03F5, prN}, // L& [44] GREEK SMALL LETTER IOTA WITH DIALYTIKA..GREEK LUNATE EPSILON SYMBOL
+ {0x03F6, 0x03F6, prN}, // Sm GREEK REVERSED LUNATE EPSILON SYMBOL
+ {0x03F7, 0x03FF, prN}, // L& [9] GREEK CAPITAL LETTER SHO..GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL
+ {0x0400, 0x0400, prN}, // Lu CYRILLIC CAPITAL LETTER IE WITH GRAVE
+ {0x0401, 0x0401, prA}, // Lu CYRILLIC CAPITAL LETTER IO
+ {0x0402, 0x040F, prN}, // Lu [14] CYRILLIC CAPITAL LETTER DJE..CYRILLIC CAPITAL LETTER DZHE
+ {0x0410, 0x044F, prA}, // L& [64] CYRILLIC CAPITAL LETTER A..CYRILLIC SMALL LETTER YA
+ {0x0450, 0x0450, prN}, // Ll CYRILLIC SMALL LETTER IE WITH GRAVE
+ {0x0451, 0x0451, prA}, // Ll CYRILLIC SMALL LETTER IO
+ {0x0452, 0x0481, prN}, // L& [48] CYRILLIC SMALL LETTER DJE..CYRILLIC SMALL LETTER KOPPA
+ {0x0482, 0x0482, prN}, // So CYRILLIC THOUSANDS SIGN
+ {0x0483, 0x0487, prN}, // Mn [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE
+ {0x0488, 0x0489, prN}, // Me [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN
+ {0x048A, 0x04FF, prN}, // L& [118] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER HA WITH STROKE
+ {0x0500, 0x052F, prN}, // L& [48] CYRILLIC CAPITAL LETTER KOMI DE..CYRILLIC SMALL LETTER EL WITH DESCENDER
+ {0x0531, 0x0556, prN}, // Lu [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH
+ {0x0559, 0x0559, prN}, // Lm ARMENIAN MODIFIER LETTER LEFT HALF RING
+ {0x055A, 0x055F, prN}, // Po [6] ARMENIAN APOSTROPHE..ARMENIAN ABBREVIATION MARK
+ {0x0560, 0x0588, prN}, // Ll [41] ARMENIAN SMALL LETTER TURNED AYB..ARMENIAN SMALL LETTER YI WITH STROKE
+ {0x0589, 0x0589, prN}, // Po ARMENIAN FULL STOP
+ {0x058A, 0x058A, prN}, // Pd ARMENIAN HYPHEN
+ {0x058D, 0x058E, prN}, // So [2] RIGHT-FACING ARMENIAN ETERNITY SIGN..LEFT-FACING ARMENIAN ETERNITY SIGN
+ {0x058F, 0x058F, prN}, // Sc ARMENIAN DRAM SIGN
+ {0x0591, 0x05BD, prN}, // Mn [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG
+ {0x05BE, 0x05BE, prN}, // Pd HEBREW PUNCTUATION MAQAF
+ {0x05BF, 0x05BF, prN}, // Mn HEBREW POINT RAFE
+ {0x05C0, 0x05C0, prN}, // Po HEBREW PUNCTUATION PASEQ
+ {0x05C1, 0x05C2, prN}, // Mn [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT
+ {0x05C3, 0x05C3, prN}, // Po HEBREW PUNCTUATION SOF PASUQ
+ {0x05C4, 0x05C5, prN}, // Mn [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT
+ {0x05C6, 0x05C6, prN}, // Po HEBREW PUNCTUATION NUN HAFUKHA
+ {0x05C7, 0x05C7, prN}, // Mn HEBREW POINT QAMATS QATAN
+ {0x05D0, 0x05EA, prN}, // Lo [27] HEBREW LETTER ALEF..HEBREW LETTER TAV
+ {0x05EF, 0x05F2, prN}, // Lo [4] HEBREW YOD TRIANGLE..HEBREW LIGATURE YIDDISH DOUBLE YOD
+ {0x05F3, 0x05F4, prN}, // Po [2] HEBREW PUNCTUATION GERESH..HEBREW PUNCTUATION GERSHAYIM
+ {0x0600, 0x0605, prN}, // Cf [6] ARABIC NUMBER SIGN..ARABIC NUMBER MARK ABOVE
+ {0x0606, 0x0608, prN}, // Sm [3] ARABIC-INDIC CUBE ROOT..ARABIC RAY
+ {0x0609, 0x060A, prN}, // Po [2] ARABIC-INDIC PER MILLE SIGN..ARABIC-INDIC PER TEN THOUSAND SIGN
+ {0x060B, 0x060B, prN}, // Sc AFGHANI SIGN
+ {0x060C, 0x060D, prN}, // Po [2] ARABIC COMMA..ARABIC DATE SEPARATOR
+ {0x060E, 0x060F, prN}, // So [2] ARABIC POETIC VERSE SIGN..ARABIC SIGN MISRA
+ {0x0610, 0x061A, prN}, // Mn [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA
+ {0x061B, 0x061B, prN}, // Po ARABIC SEMICOLON
+ {0x061C, 0x061C, prN}, // Cf ARABIC LETTER MARK
+ {0x061D, 0x061F, prN}, // Po [3] ARABIC END OF TEXT MARK..ARABIC QUESTION MARK
+ {0x0620, 0x063F, prN}, // Lo [32] ARABIC LETTER KASHMIRI YEH..ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE
+ {0x0640, 0x0640, prN}, // Lm ARABIC TATWEEL
+ {0x0641, 0x064A, prN}, // Lo [10] ARABIC LETTER FEH..ARABIC LETTER YEH
+ {0x064B, 0x065F, prN}, // Mn [21] ARABIC FATHATAN..ARABIC WAVY HAMZA BELOW
+ {0x0660, 0x0669, prN}, // Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE
+ {0x066A, 0x066D, prN}, // Po [4] ARABIC PERCENT SIGN..ARABIC FIVE POINTED STAR
+ {0x066E, 0x066F, prN}, // Lo [2] ARABIC LETTER DOTLESS BEH..ARABIC LETTER DOTLESS QAF
+ {0x0670, 0x0670, prN}, // Mn ARABIC LETTER SUPERSCRIPT ALEF
+ {0x0671, 0x06D3, prN}, // Lo [99] ARABIC LETTER ALEF WASLA..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE
+ {0x06D4, 0x06D4, prN}, // Po ARABIC FULL STOP
+ {0x06D5, 0x06D5, prN}, // Lo ARABIC LETTER AE
+ {0x06D6, 0x06DC, prN}, // Mn [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN
+ {0x06DD, 0x06DD, prN}, // Cf ARABIC END OF AYAH
+ {0x06DE, 0x06DE, prN}, // So ARABIC START OF RUB EL HIZB
+ {0x06DF, 0x06E4, prN}, // Mn [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA
+ {0x06E5, 0x06E6, prN}, // Lm [2] ARABIC SMALL WAW..ARABIC SMALL YEH
+ {0x06E7, 0x06E8, prN}, // Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON
+ {0x06E9, 0x06E9, prN}, // So ARABIC PLACE OF SAJDAH
+ {0x06EA, 0x06ED, prN}, // Mn [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM
+ {0x06EE, 0x06EF, prN}, // Lo [2] ARABIC LETTER DAL WITH INVERTED V..ARABIC LETTER REH WITH INVERTED V
+ {0x06F0, 0x06F9, prN}, // Nd [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE
+ {0x06FA, 0x06FC, prN}, // Lo [3] ARABIC LETTER SHEEN WITH DOT BELOW..ARABIC LETTER GHAIN WITH DOT BELOW
+ {0x06FD, 0x06FE, prN}, // So [2] ARABIC SIGN SINDHI AMPERSAND..ARABIC SIGN SINDHI POSTPOSITION MEN
+ {0x06FF, 0x06FF, prN}, // Lo ARABIC LETTER HEH WITH INVERTED V
+ {0x0700, 0x070D, prN}, // Po [14] SYRIAC END OF PARAGRAPH..SYRIAC HARKLEAN ASTERISCUS
+ {0x070F, 0x070F, prN}, // Cf SYRIAC ABBREVIATION MARK
+ {0x0710, 0x0710, prN}, // Lo SYRIAC LETTER ALAPH
+ {0x0711, 0x0711, prN}, // Mn SYRIAC LETTER SUPERSCRIPT ALAPH
+ {0x0712, 0x072F, prN}, // Lo [30] SYRIAC LETTER BETH..SYRIAC LETTER PERSIAN DHALATH
+ {0x0730, 0x074A, prN}, // Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH
+ {0x074D, 0x074F, prN}, // Lo [3] SYRIAC LETTER SOGDIAN ZHAIN..SYRIAC LETTER SOGDIAN FE
+ {0x0750, 0x077F, prN}, // Lo [48] ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS ABOVE
+ {0x0780, 0x07A5, prN}, // Lo [38] THAANA LETTER HAA..THAANA LETTER WAAVU
+ {0x07A6, 0x07B0, prN}, // Mn [11] THAANA ABAFILI..THAANA SUKUN
+ {0x07B1, 0x07B1, prN}, // Lo THAANA LETTER NAA
+ {0x07C0, 0x07C9, prN}, // Nd [10] NKO DIGIT ZERO..NKO DIGIT NINE
+ {0x07CA, 0x07EA, prN}, // Lo [33] NKO LETTER A..NKO LETTER JONA RA
+ {0x07EB, 0x07F3, prN}, // Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE
+ {0x07F4, 0x07F5, prN}, // Lm [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE
+ {0x07F6, 0x07F6, prN}, // So NKO SYMBOL OO DENNEN
+ {0x07F7, 0x07F9, prN}, // Po [3] NKO SYMBOL GBAKURUNEN..NKO EXCLAMATION MARK
+ {0x07FA, 0x07FA, prN}, // Lm NKO LAJANYALAN
+ {0x07FD, 0x07FD, prN}, // Mn NKO DANTAYALAN
+ {0x07FE, 0x07FF, prN}, // Sc [2] NKO DOROME SIGN..NKO TAMAN SIGN
+ {0x0800, 0x0815, prN}, // Lo [22] SAMARITAN LETTER ALAF..SAMARITAN LETTER TAAF
+ {0x0816, 0x0819, prN}, // Mn [4] SAMARITAN MARK IN..SAMARITAN MARK DAGESH
+ {0x081A, 0x081A, prN}, // Lm SAMARITAN MODIFIER LETTER EPENTHETIC YUT
+ {0x081B, 0x0823, prN}, // Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A
+ {0x0824, 0x0824, prN}, // Lm SAMARITAN MODIFIER LETTER SHORT A
+ {0x0825, 0x0827, prN}, // Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U
+ {0x0828, 0x0828, prN}, // Lm SAMARITAN MODIFIER LETTER I
+ {0x0829, 0x082D, prN}, // Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA
+ {0x0830, 0x083E, prN}, // Po [15] SAMARITAN PUNCTUATION NEQUDAA..SAMARITAN PUNCTUATION ANNAAU
+ {0x0840, 0x0858, prN}, // Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN
+ {0x0859, 0x085B, prN}, // Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK
+ {0x085E, 0x085E, prN}, // Po MANDAIC PUNCTUATION
+ {0x0860, 0x086A, prN}, // Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA
+ {0x0870, 0x0887, prN}, // Lo [24] ARABIC LETTER ALEF WITH ATTACHED FATHA..ARABIC BASELINE ROUND DOT
+ {0x0888, 0x0888, prN}, // Sk ARABIC RAISED ROUND DOT
+ {0x0889, 0x088E, prN}, // Lo [6] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC VERTICAL TAIL
+ {0x0890, 0x0891, prN}, // Cf [2] ARABIC POUND MARK ABOVE..ARABIC PIASTRE MARK ABOVE
+ {0x0898, 0x089F, prN}, // Mn [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA
+ {0x08A0, 0x08C8, prN}, // Lo [41] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER GRAF
+ {0x08C9, 0x08C9, prN}, // Lm ARABIC SMALL FARSI YEH
+ {0x08CA, 0x08E1, prN}, // Mn [24] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH SIGN SAFHA
+ {0x08E2, 0x08E2, prN}, // Cf ARABIC DISPUTED END OF AYAH
+ {0x08E3, 0x08FF, prN}, // Mn [29] ARABIC TURNED DAMMA BELOW..ARABIC MARK SIDEWAYS NOON GHUNNA
+ {0x0900, 0x0902, prN}, // Mn [3] DEVANAGARI SIGN INVERTED CANDRABINDU..DEVANAGARI SIGN ANUSVARA
+ {0x0903, 0x0903, prN}, // Mc DEVANAGARI SIGN VISARGA
+ {0x0904, 0x0939, prN}, // Lo [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA
+ {0x093A, 0x093A, prN}, // Mn DEVANAGARI VOWEL SIGN OE
+ {0x093B, 0x093B, prN}, // Mc DEVANAGARI VOWEL SIGN OOE
+ {0x093C, 0x093C, prN}, // Mn DEVANAGARI SIGN NUKTA
+ {0x093D, 0x093D, prN}, // Lo DEVANAGARI SIGN AVAGRAHA
+ {0x093E, 0x0940, prN}, // Mc [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II
+ {0x0941, 0x0948, prN}, // Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI
+ {0x0949, 0x094C, prN}, // Mc [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU
+ {0x094D, 0x094D, prN}, // Mn DEVANAGARI SIGN VIRAMA
+ {0x094E, 0x094F, prN}, // Mc [2] DEVANAGARI VOWEL SIGN PRISHTHAMATRA E..DEVANAGARI VOWEL SIGN AW
+ {0x0950, 0x0950, prN}, // Lo DEVANAGARI OM
+ {0x0951, 0x0957, prN}, // Mn [7] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI VOWEL SIGN UUE
+ {0x0958, 0x0961, prN}, // Lo [10] DEVANAGARI LETTER QA..DEVANAGARI LETTER VOCALIC LL
+ {0x0962, 0x0963, prN}, // Mn [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL
+ {0x0964, 0x0965, prN}, // Po [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA
+ {0x0966, 0x096F, prN}, // Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE
+ {0x0970, 0x0970, prN}, // Po DEVANAGARI ABBREVIATION SIGN
+ {0x0971, 0x0971, prN}, // Lm DEVANAGARI SIGN HIGH SPACING DOT
+ {0x0972, 0x097F, prN}, // Lo [14] DEVANAGARI LETTER CANDRA A..DEVANAGARI LETTER BBA
+ {0x0980, 0x0980, prN}, // Lo BENGALI ANJI
+ {0x0981, 0x0981, prN}, // Mn BENGALI SIGN CANDRABINDU
+ {0x0982, 0x0983, prN}, // Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA
+ {0x0985, 0x098C, prN}, // Lo [8] BENGALI LETTER A..BENGALI LETTER VOCALIC L
+ {0x098F, 0x0990, prN}, // Lo [2] BENGALI LETTER E..BENGALI LETTER AI
+ {0x0993, 0x09A8, prN}, // Lo [22] BENGALI LETTER O..BENGALI LETTER NA
+ {0x09AA, 0x09B0, prN}, // Lo [7] BENGALI LETTER PA..BENGALI LETTER RA
+ {0x09B2, 0x09B2, prN}, // Lo BENGALI LETTER LA
+ {0x09B6, 0x09B9, prN}, // Lo [4] BENGALI LETTER SHA..BENGALI LETTER HA
+ {0x09BC, 0x09BC, prN}, // Mn BENGALI SIGN NUKTA
+ {0x09BD, 0x09BD, prN}, // Lo BENGALI SIGN AVAGRAHA
+ {0x09BE, 0x09C0, prN}, // Mc [3] BENGALI VOWEL SIGN AA..BENGALI VOWEL SIGN II
+ {0x09C1, 0x09C4, prN}, // Mn [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR
+ {0x09C7, 0x09C8, prN}, // Mc [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI
+ {0x09CB, 0x09CC, prN}, // Mc [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU
+ {0x09CD, 0x09CD, prN}, // Mn BENGALI SIGN VIRAMA
+ {0x09CE, 0x09CE, prN}, // Lo BENGALI LETTER KHANDA TA
+ {0x09D7, 0x09D7, prN}, // Mc BENGALI AU LENGTH MARK
+ {0x09DC, 0x09DD, prN}, // Lo [2] BENGALI LETTER RRA..BENGALI LETTER RHA
+ {0x09DF, 0x09E1, prN}, // Lo [3] BENGALI LETTER YYA..BENGALI LETTER VOCALIC LL
+ {0x09E2, 0x09E3, prN}, // Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL
+ {0x09E6, 0x09EF, prN}, // Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE
+ {0x09F0, 0x09F1, prN}, // Lo [2] BENGALI LETTER RA WITH MIDDLE DIAGONAL..BENGALI LETTER RA WITH LOWER DIAGONAL
+ {0x09F2, 0x09F3, prN}, // Sc [2] BENGALI RUPEE MARK..BENGALI RUPEE SIGN
+ {0x09F4, 0x09F9, prN}, // No [6] BENGALI CURRENCY NUMERATOR ONE..BENGALI CURRENCY DENOMINATOR SIXTEEN
+ {0x09FA, 0x09FA, prN}, // So BENGALI ISSHAR
+ {0x09FB, 0x09FB, prN}, // Sc BENGALI GANDA MARK
+ {0x09FC, 0x09FC, prN}, // Lo BENGALI LETTER VEDIC ANUSVARA
+ {0x09FD, 0x09FD, prN}, // Po BENGALI ABBREVIATION SIGN
+ {0x09FE, 0x09FE, prN}, // Mn BENGALI SANDHI MARK
+ {0x0A01, 0x0A02, prN}, // Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI
+ {0x0A03, 0x0A03, prN}, // Mc GURMUKHI SIGN VISARGA
+ {0x0A05, 0x0A0A, prN}, // Lo [6] GURMUKHI LETTER A..GURMUKHI LETTER UU
+ {0x0A0F, 0x0A10, prN}, // Lo [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI
+ {0x0A13, 0x0A28, prN}, // Lo [22] GURMUKHI LETTER OO..GURMUKHI LETTER NA
+ {0x0A2A, 0x0A30, prN}, // Lo [7] GURMUKHI LETTER PA..GURMUKHI LETTER RA
+ {0x0A32, 0x0A33, prN}, // Lo [2] GURMUKHI LETTER LA..GURMUKHI LETTER LLA
+ {0x0A35, 0x0A36, prN}, // Lo [2] GURMUKHI LETTER VA..GURMUKHI LETTER SHA
+ {0x0A38, 0x0A39, prN}, // Lo [2] GURMUKHI LETTER SA..GURMUKHI LETTER HA
+ {0x0A3C, 0x0A3C, prN}, // Mn GURMUKHI SIGN NUKTA
+ {0x0A3E, 0x0A40, prN}, // Mc [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II
+ {0x0A41, 0x0A42, prN}, // Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU
+ {0x0A47, 0x0A48, prN}, // Mn [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI
+ {0x0A4B, 0x0A4D, prN}, // Mn [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA
+ {0x0A51, 0x0A51, prN}, // Mn GURMUKHI SIGN UDAAT
+ {0x0A59, 0x0A5C, prN}, // Lo [4] GURMUKHI LETTER KHHA..GURMUKHI LETTER RRA
+ {0x0A5E, 0x0A5E, prN}, // Lo GURMUKHI LETTER FA
+ {0x0A66, 0x0A6F, prN}, // Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE
+ {0x0A70, 0x0A71, prN}, // Mn [2] GURMUKHI TIPPI..GURMUKHI ADDAK
+ {0x0A72, 0x0A74, prN}, // Lo [3] GURMUKHI IRI..GURMUKHI EK ONKAR
+ {0x0A75, 0x0A75, prN}, // Mn GURMUKHI SIGN YAKASH
+ {0x0A76, 0x0A76, prN}, // Po GURMUKHI ABBREVIATION SIGN
+ {0x0A81, 0x0A82, prN}, // Mn [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA
+ {0x0A83, 0x0A83, prN}, // Mc GUJARATI SIGN VISARGA
+ {0x0A85, 0x0A8D, prN}, // Lo [9] GUJARATI LETTER A..GUJARATI VOWEL CANDRA E
+ {0x0A8F, 0x0A91, prN}, // Lo [3] GUJARATI LETTER E..GUJARATI VOWEL CANDRA O
+ {0x0A93, 0x0AA8, prN}, // Lo [22] GUJARATI LETTER O..GUJARATI LETTER NA
+ {0x0AAA, 0x0AB0, prN}, // Lo [7] GUJARATI LETTER PA..GUJARATI LETTER RA
+ {0x0AB2, 0x0AB3, prN}, // Lo [2] GUJARATI LETTER LA..GUJARATI LETTER LLA
+ {0x0AB5, 0x0AB9, prN}, // Lo [5] GUJARATI LETTER VA..GUJARATI LETTER HA
+ {0x0ABC, 0x0ABC, prN}, // Mn GUJARATI SIGN NUKTA
+ {0x0ABD, 0x0ABD, prN}, // Lo GUJARATI SIGN AVAGRAHA
+ {0x0ABE, 0x0AC0, prN}, // Mc [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II
+ {0x0AC1, 0x0AC5, prN}, // Mn [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E
+ {0x0AC7, 0x0AC8, prN}, // Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI
+ {0x0AC9, 0x0AC9, prN}, // Mc GUJARATI VOWEL SIGN CANDRA O
+ {0x0ACB, 0x0ACC, prN}, // Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU
+ {0x0ACD, 0x0ACD, prN}, // Mn GUJARATI SIGN VIRAMA
+ {0x0AD0, 0x0AD0, prN}, // Lo GUJARATI OM
+ {0x0AE0, 0x0AE1, prN}, // Lo [2] GUJARATI LETTER VOCALIC RR..GUJARATI LETTER VOCALIC LL
+ {0x0AE2, 0x0AE3, prN}, // Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL
+ {0x0AE6, 0x0AEF, prN}, // Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE
+ {0x0AF0, 0x0AF0, prN}, // Po GUJARATI ABBREVIATION SIGN
+ {0x0AF1, 0x0AF1, prN}, // Sc GUJARATI RUPEE SIGN
+ {0x0AF9, 0x0AF9, prN}, // Lo GUJARATI LETTER ZHA
+ {0x0AFA, 0x0AFF, prN}, // Mn [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE
+ {0x0B01, 0x0B01, prN}, // Mn ORIYA SIGN CANDRABINDU
+ {0x0B02, 0x0B03, prN}, // Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA
+ {0x0B05, 0x0B0C, prN}, // Lo [8] ORIYA LETTER A..ORIYA LETTER VOCALIC L
+ {0x0B0F, 0x0B10, prN}, // Lo [2] ORIYA LETTER E..ORIYA LETTER AI
+ {0x0B13, 0x0B28, prN}, // Lo [22] ORIYA LETTER O..ORIYA LETTER NA
+ {0x0B2A, 0x0B30, prN}, // Lo [7] ORIYA LETTER PA..ORIYA LETTER RA
+ {0x0B32, 0x0B33, prN}, // Lo [2] ORIYA LETTER LA..ORIYA LETTER LLA
+ {0x0B35, 0x0B39, prN}, // Lo [5] ORIYA LETTER VA..ORIYA LETTER HA
+ {0x0B3C, 0x0B3C, prN}, // Mn ORIYA SIGN NUKTA
+ {0x0B3D, 0x0B3D, prN}, // Lo ORIYA SIGN AVAGRAHA
+ {0x0B3E, 0x0B3E, prN}, // Mc ORIYA VOWEL SIGN AA
+ {0x0B3F, 0x0B3F, prN}, // Mn ORIYA VOWEL SIGN I
+ {0x0B40, 0x0B40, prN}, // Mc ORIYA VOWEL SIGN II
+ {0x0B41, 0x0B44, prN}, // Mn [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR
+ {0x0B47, 0x0B48, prN}, // Mc [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI
+ {0x0B4B, 0x0B4C, prN}, // Mc [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU
+ {0x0B4D, 0x0B4D, prN}, // Mn ORIYA SIGN VIRAMA
+ {0x0B55, 0x0B56, prN}, // Mn [2] ORIYA SIGN OVERLINE..ORIYA AI LENGTH MARK
+ {0x0B57, 0x0B57, prN}, // Mc ORIYA AU LENGTH MARK
+ {0x0B5C, 0x0B5D, prN}, // Lo [2] ORIYA LETTER RRA..ORIYA LETTER RHA
+ {0x0B5F, 0x0B61, prN}, // Lo [3] ORIYA LETTER YYA..ORIYA LETTER VOCALIC LL
+ {0x0B62, 0x0B63, prN}, // Mn [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL
+ {0x0B66, 0x0B6F, prN}, // Nd [10] ORIYA DIGIT ZERO..ORIYA DIGIT NINE
+ {0x0B70, 0x0B70, prN}, // So ORIYA ISSHAR
+ {0x0B71, 0x0B71, prN}, // Lo ORIYA LETTER WA
+ {0x0B72, 0x0B77, prN}, // No [6] ORIYA FRACTION ONE QUARTER..ORIYA FRACTION THREE SIXTEENTHS
+ {0x0B82, 0x0B82, prN}, // Mn TAMIL SIGN ANUSVARA
+ {0x0B83, 0x0B83, prN}, // Lo TAMIL SIGN VISARGA
+ {0x0B85, 0x0B8A, prN}, // Lo [6] TAMIL LETTER A..TAMIL LETTER UU
+ {0x0B8E, 0x0B90, prN}, // Lo [3] TAMIL LETTER E..TAMIL LETTER AI
+ {0x0B92, 0x0B95, prN}, // Lo [4] TAMIL LETTER O..TAMIL LETTER KA
+ {0x0B99, 0x0B9A, prN}, // Lo [2] TAMIL LETTER NGA..TAMIL LETTER CA
+ {0x0B9C, 0x0B9C, prN}, // Lo TAMIL LETTER JA
+ {0x0B9E, 0x0B9F, prN}, // Lo [2] TAMIL LETTER NYA..TAMIL LETTER TTA
+ {0x0BA3, 0x0BA4, prN}, // Lo [2] TAMIL LETTER NNA..TAMIL LETTER TA
+ {0x0BA8, 0x0BAA, prN}, // Lo [3] TAMIL LETTER NA..TAMIL LETTER PA
+ {0x0BAE, 0x0BB9, prN}, // Lo [12] TAMIL LETTER MA..TAMIL LETTER HA
+ {0x0BBE, 0x0BBF, prN}, // Mc [2] TAMIL VOWEL SIGN AA..TAMIL VOWEL SIGN I
+ {0x0BC0, 0x0BC0, prN}, // Mn TAMIL VOWEL SIGN II
+ {0x0BC1, 0x0BC2, prN}, // Mc [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU
+ {0x0BC6, 0x0BC8, prN}, // Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI
+ {0x0BCA, 0x0BCC, prN}, // Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU
+ {0x0BCD, 0x0BCD, prN}, // Mn TAMIL SIGN VIRAMA
+ {0x0BD0, 0x0BD0, prN}, // Lo TAMIL OM
+ {0x0BD7, 0x0BD7, prN}, // Mc TAMIL AU LENGTH MARK
+ {0x0BE6, 0x0BEF, prN}, // Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE
+ {0x0BF0, 0x0BF2, prN}, // No [3] TAMIL NUMBER TEN..TAMIL NUMBER ONE THOUSAND
+ {0x0BF3, 0x0BF8, prN}, // So [6] TAMIL DAY SIGN..TAMIL AS ABOVE SIGN
+ {0x0BF9, 0x0BF9, prN}, // Sc TAMIL RUPEE SIGN
+ {0x0BFA, 0x0BFA, prN}, // So TAMIL NUMBER SIGN
+ {0x0C00, 0x0C00, prN}, // Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE
+ {0x0C01, 0x0C03, prN}, // Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA
+ {0x0C04, 0x0C04, prN}, // Mn TELUGU SIGN COMBINING ANUSVARA ABOVE
+ {0x0C05, 0x0C0C, prN}, // Lo [8] TELUGU LETTER A..TELUGU LETTER VOCALIC L
+ {0x0C0E, 0x0C10, prN}, // Lo [3] TELUGU LETTER E..TELUGU LETTER AI
+ {0x0C12, 0x0C28, prN}, // Lo [23] TELUGU LETTER O..TELUGU LETTER NA
+ {0x0C2A, 0x0C39, prN}, // Lo [16] TELUGU LETTER PA..TELUGU LETTER HA
+ {0x0C3C, 0x0C3C, prN}, // Mn TELUGU SIGN NUKTA
+ {0x0C3D, 0x0C3D, prN}, // Lo TELUGU SIGN AVAGRAHA
+ {0x0C3E, 0x0C40, prN}, // Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II
+ {0x0C41, 0x0C44, prN}, // Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR
+ {0x0C46, 0x0C48, prN}, // Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI
+ {0x0C4A, 0x0C4D, prN}, // Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA
+ {0x0C55, 0x0C56, prN}, // Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK
+ {0x0C58, 0x0C5A, prN}, // Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA
+ {0x0C5D, 0x0C5D, prN}, // Lo TELUGU LETTER NAKAARA POLLU
+ {0x0C60, 0x0C61, prN}, // Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL
+ {0x0C62, 0x0C63, prN}, // Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL
+ {0x0C66, 0x0C6F, prN}, // Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE
+ {0x0C77, 0x0C77, prN}, // Po TELUGU SIGN SIDDHAM
+ {0x0C78, 0x0C7E, prN}, // No [7] TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR..TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR
+ {0x0C7F, 0x0C7F, prN}, // So TELUGU SIGN TUUMU
+ {0x0C80, 0x0C80, prN}, // Lo KANNADA SIGN SPACING CANDRABINDU
+ {0x0C81, 0x0C81, prN}, // Mn KANNADA SIGN CANDRABINDU
+ {0x0C82, 0x0C83, prN}, // Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA
+ {0x0C84, 0x0C84, prN}, // Po KANNADA SIGN SIDDHAM
+ {0x0C85, 0x0C8C, prN}, // Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L
+ {0x0C8E, 0x0C90, prN}, // Lo [3] KANNADA LETTER E..KANNADA LETTER AI
+ {0x0C92, 0x0CA8, prN}, // Lo [23] KANNADA LETTER O..KANNADA LETTER NA
+ {0x0CAA, 0x0CB3, prN}, // Lo [10] KANNADA LETTER PA..KANNADA LETTER LLA
+ {0x0CB5, 0x0CB9, prN}, // Lo [5] KANNADA LETTER VA..KANNADA LETTER HA
+ {0x0CBC, 0x0CBC, prN}, // Mn KANNADA SIGN NUKTA
+ {0x0CBD, 0x0CBD, prN}, // Lo KANNADA SIGN AVAGRAHA
+ {0x0CBE, 0x0CBE, prN}, // Mc KANNADA VOWEL SIGN AA
+ {0x0CBF, 0x0CBF, prN}, // Mn KANNADA VOWEL SIGN I
+ {0x0CC0, 0x0CC4, prN}, // Mc [5] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN VOCALIC RR
+ {0x0CC6, 0x0CC6, prN}, // Mn KANNADA VOWEL SIGN E
+ {0x0CC7, 0x0CC8, prN}, // Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI
+ {0x0CCA, 0x0CCB, prN}, // Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO
+ {0x0CCC, 0x0CCD, prN}, // Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA
+ {0x0CD5, 0x0CD6, prN}, // Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK
+ {0x0CDD, 0x0CDE, prN}, // Lo [2] KANNADA LETTER NAKAARA POLLU..KANNADA LETTER FA
+ {0x0CE0, 0x0CE1, prN}, // Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL
+ {0x0CE2, 0x0CE3, prN}, // Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL
+ {0x0CE6, 0x0CEF, prN}, // Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE
+ {0x0CF1, 0x0CF2, prN}, // Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA
+ {0x0D00, 0x0D01, prN}, // Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU
+ {0x0D02, 0x0D03, prN}, // Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA
+ {0x0D04, 0x0D0C, prN}, // Lo [9] MALAYALAM LETTER VEDIC ANUSVARA..MALAYALAM LETTER VOCALIC L
+ {0x0D0E, 0x0D10, prN}, // Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI
+ {0x0D12, 0x0D3A, prN}, // Lo [41] MALAYALAM LETTER O..MALAYALAM LETTER TTTA
+ {0x0D3B, 0x0D3C, prN}, // Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA
+ {0x0D3D, 0x0D3D, prN}, // Lo MALAYALAM SIGN AVAGRAHA
+ {0x0D3E, 0x0D40, prN}, // Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II
+ {0x0D41, 0x0D44, prN}, // Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR
+ {0x0D46, 0x0D48, prN}, // Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI
+ {0x0D4A, 0x0D4C, prN}, // Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU
+ {0x0D4D, 0x0D4D, prN}, // Mn MALAYALAM SIGN VIRAMA
+ {0x0D4E, 0x0D4E, prN}, // Lo MALAYALAM LETTER DOT REPH
+ {0x0D4F, 0x0D4F, prN}, // So MALAYALAM SIGN PARA
+ {0x0D54, 0x0D56, prN}, // Lo [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL
+ {0x0D57, 0x0D57, prN}, // Mc MALAYALAM AU LENGTH MARK
+ {0x0D58, 0x0D5E, prN}, // No [7] MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH..MALAYALAM FRACTION ONE FIFTH
+ {0x0D5F, 0x0D61, prN}, // Lo [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL
+ {0x0D62, 0x0D63, prN}, // Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL
+ {0x0D66, 0x0D6F, prN}, // Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE
+ {0x0D70, 0x0D78, prN}, // No [9] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE SIXTEENTHS
+ {0x0D79, 0x0D79, prN}, // So MALAYALAM DATE MARK
+ {0x0D7A, 0x0D7F, prN}, // Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K
+ {0x0D81, 0x0D81, prN}, // Mn SINHALA SIGN CANDRABINDU
+ {0x0D82, 0x0D83, prN}, // Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA
+ {0x0D85, 0x0D96, prN}, // Lo [18] SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA
+ {0x0D9A, 0x0DB1, prN}, // Lo [24] SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER DANTAJA NAYANNA
+ {0x0DB3, 0x0DBB, prN}, // Lo [9] SINHALA LETTER SANYAKA DAYANNA..SINHALA LETTER RAYANNA
+ {0x0DBD, 0x0DBD, prN}, // Lo SINHALA LETTER DANTAJA LAYANNA
+ {0x0DC0, 0x0DC6, prN}, // Lo [7] SINHALA LETTER VAYANNA..SINHALA LETTER FAYANNA
+ {0x0DCA, 0x0DCA, prN}, // Mn SINHALA SIGN AL-LAKUNA
+ {0x0DCF, 0x0DD1, prN}, // Mc [3] SINHALA VOWEL SIGN AELA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA
+ {0x0DD2, 0x0DD4, prN}, // Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA
+ {0x0DD6, 0x0DD6, prN}, // Mn SINHALA VOWEL SIGN DIGA PAA-PILLA
+ {0x0DD8, 0x0DDF, prN}, // Mc [8] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA
+ {0x0DE6, 0x0DEF, prN}, // Nd [10] SINHALA LITH DIGIT ZERO..SINHALA LITH DIGIT NINE
+ {0x0DF2, 0x0DF3, prN}, // Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA
+ {0x0DF4, 0x0DF4, prN}, // Po SINHALA PUNCTUATION KUNDDALIYA
+ {0x0E01, 0x0E30, prN}, // Lo [48] THAI CHARACTER KO KAI..THAI CHARACTER SARA A
+ {0x0E31, 0x0E31, prN}, // Mn THAI CHARACTER MAI HAN-AKAT
+ {0x0E32, 0x0E33, prN}, // Lo [2] THAI CHARACTER SARA AA..THAI CHARACTER SARA AM
+ {0x0E34, 0x0E3A, prN}, // Mn [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU
+ {0x0E3F, 0x0E3F, prN}, // Sc THAI CURRENCY SYMBOL BAHT
+ {0x0E40, 0x0E45, prN}, // Lo [6] THAI CHARACTER SARA E..THAI CHARACTER LAKKHANGYAO
+ {0x0E46, 0x0E46, prN}, // Lm THAI CHARACTER MAIYAMOK
+ {0x0E47, 0x0E4E, prN}, // Mn [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN
+ {0x0E4F, 0x0E4F, prN}, // Po THAI CHARACTER FONGMAN
+ {0x0E50, 0x0E59, prN}, // Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE
+ {0x0E5A, 0x0E5B, prN}, // Po [2] THAI CHARACTER ANGKHANKHU..THAI CHARACTER KHOMUT
+ {0x0E81, 0x0E82, prN}, // Lo [2] LAO LETTER KO..LAO LETTER KHO SUNG
+ {0x0E84, 0x0E84, prN}, // Lo LAO LETTER KHO TAM
+ {0x0E86, 0x0E8A, prN}, // Lo [5] LAO LETTER PALI GHA..LAO LETTER SO TAM
+ {0x0E8C, 0x0EA3, prN}, // Lo [24] LAO LETTER PALI JHA..LAO LETTER LO LING
+ {0x0EA5, 0x0EA5, prN}, // Lo LAO LETTER LO LOOT
+ {0x0EA7, 0x0EB0, prN}, // Lo [10] LAO LETTER WO..LAO VOWEL SIGN A
+ {0x0EB1, 0x0EB1, prN}, // Mn LAO VOWEL SIGN MAI KAN
+ {0x0EB2, 0x0EB3, prN}, // Lo [2] LAO VOWEL SIGN AA..LAO VOWEL SIGN AM
+ {0x0EB4, 0x0EBC, prN}, // Mn [9] LAO VOWEL SIGN I..LAO SEMIVOWEL SIGN LO
+ {0x0EBD, 0x0EBD, prN}, // Lo LAO SEMIVOWEL SIGN NYO
+ {0x0EC0, 0x0EC4, prN}, // Lo [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI
+ {0x0EC6, 0x0EC6, prN}, // Lm LAO KO LA
+ {0x0EC8, 0x0ECD, prN}, // Mn [6] LAO TONE MAI EK..LAO NIGGAHITA
+ {0x0ED0, 0x0ED9, prN}, // Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE
+ {0x0EDC, 0x0EDF, prN}, // Lo [4] LAO HO NO..LAO LETTER KHMU NYO
+ {0x0F00, 0x0F00, prN}, // Lo TIBETAN SYLLABLE OM
+ {0x0F01, 0x0F03, prN}, // So [3] TIBETAN MARK GTER YIG MGO TRUNCATED A..TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA
+ {0x0F04, 0x0F12, prN}, // Po [15] TIBETAN MARK INITIAL YIG MGO MDUN MA..TIBETAN MARK RGYA GRAM SHAD
+ {0x0F13, 0x0F13, prN}, // So TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN
+ {0x0F14, 0x0F14, prN}, // Po TIBETAN MARK GTER TSHEG
+ {0x0F15, 0x0F17, prN}, // So [3] TIBETAN LOGOTYPE SIGN CHAD RTAGS..TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS
+ {0x0F18, 0x0F19, prN}, // Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS
+ {0x0F1A, 0x0F1F, prN}, // So [6] TIBETAN SIGN RDEL DKAR GCIG..TIBETAN SIGN RDEL DKAR RDEL NAG
+ {0x0F20, 0x0F29, prN}, // Nd [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE
+ {0x0F2A, 0x0F33, prN}, // No [10] TIBETAN DIGIT HALF ONE..TIBETAN DIGIT HALF ZERO
+ {0x0F34, 0x0F34, prN}, // So TIBETAN MARK BSDUS RTAGS
+ {0x0F35, 0x0F35, prN}, // Mn TIBETAN MARK NGAS BZUNG NYI ZLA
+ {0x0F36, 0x0F36, prN}, // So TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN
+ {0x0F37, 0x0F37, prN}, // Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS
+ {0x0F38, 0x0F38, prN}, // So TIBETAN MARK CHE MGO
+ {0x0F39, 0x0F39, prN}, // Mn TIBETAN MARK TSA -PHRU
+ {0x0F3A, 0x0F3A, prN}, // Ps TIBETAN MARK GUG RTAGS GYON
+ {0x0F3B, 0x0F3B, prN}, // Pe TIBETAN MARK GUG RTAGS GYAS
+ {0x0F3C, 0x0F3C, prN}, // Ps TIBETAN MARK ANG KHANG GYON
+ {0x0F3D, 0x0F3D, prN}, // Pe TIBETAN MARK ANG KHANG GYAS
+ {0x0F3E, 0x0F3F, prN}, // Mc [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES
+ {0x0F40, 0x0F47, prN}, // Lo [8] TIBETAN LETTER KA..TIBETAN LETTER JA
+ {0x0F49, 0x0F6C, prN}, // Lo [36] TIBETAN LETTER NYA..TIBETAN LETTER RRA
+ {0x0F71, 0x0F7E, prN}, // Mn [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO
+ {0x0F7F, 0x0F7F, prN}, // Mc TIBETAN SIGN RNAM BCAD
+ {0x0F80, 0x0F84, prN}, // Mn [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA
+ {0x0F85, 0x0F85, prN}, // Po TIBETAN MARK PALUTA
+ {0x0F86, 0x0F87, prN}, // Mn [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS
+ {0x0F88, 0x0F8C, prN}, // Lo [5] TIBETAN SIGN LCE TSA CAN..TIBETAN SIGN INVERTED MCHU CAN
+ {0x0F8D, 0x0F97, prN}, // Mn [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA
+ {0x0F99, 0x0FBC, prN}, // Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA
+ {0x0FBE, 0x0FC5, prN}, // So [8] TIBETAN KU RU KHA..TIBETAN SYMBOL RDO RJE
+ {0x0FC6, 0x0FC6, prN}, // Mn TIBETAN SYMBOL PADMA GDAN
+ {0x0FC7, 0x0FCC, prN}, // So [6] TIBETAN SYMBOL RDO RJE RGYA GRAM..TIBETAN SYMBOL NOR BU BZHI -KHYIL
+ {0x0FCE, 0x0FCF, prN}, // So [2] TIBETAN SIGN RDEL NAG RDEL DKAR..TIBETAN SIGN RDEL NAG GSUM
+ {0x0FD0, 0x0FD4, prN}, // Po [5] TIBETAN MARK BSKA- SHOG GI MGO RGYAN..TIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB MA
+ {0x0FD5, 0x0FD8, prN}, // So [4] RIGHT-FACING SVASTI SIGN..LEFT-FACING SVASTI SIGN WITH DOTS
+ {0x0FD9, 0x0FDA, prN}, // Po [2] TIBETAN MARK LEADING MCHAN RTAGS..TIBETAN MARK TRAILING MCHAN RTAGS
+ {0x1000, 0x102A, prN}, // Lo [43] MYANMAR LETTER KA..MYANMAR LETTER AU
+ {0x102B, 0x102C, prN}, // Mc [2] MYANMAR VOWEL SIGN TALL AA..MYANMAR VOWEL SIGN AA
+ {0x102D, 0x1030, prN}, // Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU
+ {0x1031, 0x1031, prN}, // Mc MYANMAR VOWEL SIGN E
+ {0x1032, 0x1037, prN}, // Mn [6] MYANMAR VOWEL SIGN AI..MYANMAR SIGN DOT BELOW
+ {0x1038, 0x1038, prN}, // Mc MYANMAR SIGN VISARGA
+ {0x1039, 0x103A, prN}, // Mn [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT
+ {0x103B, 0x103C, prN}, // Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA
+ {0x103D, 0x103E, prN}, // Mn [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA
+ {0x103F, 0x103F, prN}, // Lo MYANMAR LETTER GREAT SA
+ {0x1040, 0x1049, prN}, // Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE
+ {0x104A, 0x104F, prN}, // Po [6] MYANMAR SIGN LITTLE SECTION..MYANMAR SYMBOL GENITIVE
+ {0x1050, 0x1055, prN}, // Lo [6] MYANMAR LETTER SHA..MYANMAR LETTER VOCALIC LL
+ {0x1056, 0x1057, prN}, // Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR
+ {0x1058, 0x1059, prN}, // Mn [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL
+ {0x105A, 0x105D, prN}, // Lo [4] MYANMAR LETTER MON NGA..MYANMAR LETTER MON BBE
+ {0x105E, 0x1060, prN}, // Mn [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA
+ {0x1061, 0x1061, prN}, // Lo MYANMAR LETTER SGAW KAREN SHA
+ {0x1062, 0x1064, prN}, // Mc [3] MYANMAR VOWEL SIGN SGAW KAREN EU..MYANMAR TONE MARK SGAW KAREN KE PHO
+ {0x1065, 0x1066, prN}, // Lo [2] MYANMAR LETTER WESTERN PWO KAREN THA..MYANMAR LETTER WESTERN PWO KAREN PWA
+ {0x1067, 0x106D, prN}, // Mc [7] MYANMAR VOWEL SIGN WESTERN PWO KAREN EU..MYANMAR SIGN WESTERN PWO KAREN TONE-5
+ {0x106E, 0x1070, prN}, // Lo [3] MYANMAR LETTER EASTERN PWO KAREN NNA..MYANMAR LETTER EASTERN PWO KAREN GHWA
+ {0x1071, 0x1074, prN}, // Mn [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE
+ {0x1075, 0x1081, prN}, // Lo [13] MYANMAR LETTER SHAN KA..MYANMAR LETTER SHAN HA
+ {0x1082, 0x1082, prN}, // Mn MYANMAR CONSONANT SIGN SHAN MEDIAL WA
+ {0x1083, 0x1084, prN}, // Mc [2] MYANMAR VOWEL SIGN SHAN AA..MYANMAR VOWEL SIGN SHAN E
+ {0x1085, 0x1086, prN}, // Mn [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y
+ {0x1087, 0x108C, prN}, // Mc [6] MYANMAR SIGN SHAN TONE-2..MYANMAR SIGN SHAN COUNCIL TONE-3
+ {0x108D, 0x108D, prN}, // Mn MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE
+ {0x108E, 0x108E, prN}, // Lo MYANMAR LETTER RUMAI PALAUNG FA
+ {0x108F, 0x108F, prN}, // Mc MYANMAR SIGN RUMAI PALAUNG TONE-5
+ {0x1090, 0x1099, prN}, // Nd [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE
+ {0x109A, 0x109C, prN}, // Mc [3] MYANMAR SIGN KHAMTI TONE-1..MYANMAR VOWEL SIGN AITON A
+ {0x109D, 0x109D, prN}, // Mn MYANMAR VOWEL SIGN AITON AI
+ {0x109E, 0x109F, prN}, // So [2] MYANMAR SYMBOL SHAN ONE..MYANMAR SYMBOL SHAN EXCLAMATION
+ {0x10A0, 0x10C5, prN}, // Lu [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE
+ {0x10C7, 0x10C7, prN}, // Lu GEORGIAN CAPITAL LETTER YN
+ {0x10CD, 0x10CD, prN}, // Lu GEORGIAN CAPITAL LETTER AEN
+ {0x10D0, 0x10FA, prN}, // Ll [43] GEORGIAN LETTER AN..GEORGIAN LETTER AIN
+ {0x10FB, 0x10FB, prN}, // Po GEORGIAN PARAGRAPH SEPARATOR
+ {0x10FC, 0x10FC, prN}, // Lm MODIFIER LETTER GEORGIAN NAR
+ {0x10FD, 0x10FF, prN}, // Ll [3] GEORGIAN LETTER AEN..GEORGIAN LETTER LABIAL SIGN
+ {0x1100, 0x115F, prW}, // Lo [96] HANGUL CHOSEONG KIYEOK..HANGUL CHOSEONG FILLER
+ {0x1160, 0x11FF, prN}, // Lo [160] HANGUL JUNGSEONG FILLER..HANGUL JONGSEONG SSANGNIEUN
+ {0x1200, 0x1248, prN}, // Lo [73] ETHIOPIC SYLLABLE HA..ETHIOPIC SYLLABLE QWA
+ {0x124A, 0x124D, prN}, // Lo [4] ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE
+ {0x1250, 0x1256, prN}, // Lo [7] ETHIOPIC SYLLABLE QHA..ETHIOPIC SYLLABLE QHO
+ {0x1258, 0x1258, prN}, // Lo ETHIOPIC SYLLABLE QHWA
+ {0x125A, 0x125D, prN}, // Lo [4] ETHIOPIC SYLLABLE QHWI..ETHIOPIC SYLLABLE QHWE
+ {0x1260, 0x1288, prN}, // Lo [41] ETHIOPIC SYLLABLE BA..ETHIOPIC SYLLABLE XWA
+ {0x128A, 0x128D, prN}, // Lo [4] ETHIOPIC SYLLABLE XWI..ETHIOPIC SYLLABLE XWE
+ {0x1290, 0x12B0, prN}, // Lo [33] ETHIOPIC SYLLABLE NA..ETHIOPIC SYLLABLE KWA
+ {0x12B2, 0x12B5, prN}, // Lo [4] ETHIOPIC SYLLABLE KWI..ETHIOPIC SYLLABLE KWE
+ {0x12B8, 0x12BE, prN}, // Lo [7] ETHIOPIC SYLLABLE KXA..ETHIOPIC SYLLABLE KXO
+ {0x12C0, 0x12C0, prN}, // Lo ETHIOPIC SYLLABLE KXWA
+ {0x12C2, 0x12C5, prN}, // Lo [4] ETHIOPIC SYLLABLE KXWI..ETHIOPIC SYLLABLE KXWE
+ {0x12C8, 0x12D6, prN}, // Lo [15] ETHIOPIC SYLLABLE WA..ETHIOPIC SYLLABLE PHARYNGEAL O
+ {0x12D8, 0x1310, prN}, // Lo [57] ETHIOPIC SYLLABLE ZA..ETHIOPIC SYLLABLE GWA
+ {0x1312, 0x1315, prN}, // Lo [4] ETHIOPIC SYLLABLE GWI..ETHIOPIC SYLLABLE GWE
+ {0x1318, 0x135A, prN}, // Lo [67] ETHIOPIC SYLLABLE GGA..ETHIOPIC SYLLABLE FYA
+ {0x135D, 0x135F, prN}, // Mn [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK
+ {0x1360, 0x1368, prN}, // Po [9] ETHIOPIC SECTION MARK..ETHIOPIC PARAGRAPH SEPARATOR
+ {0x1369, 0x137C, prN}, // No [20] ETHIOPIC DIGIT ONE..ETHIOPIC NUMBER TEN THOUSAND
+ {0x1380, 0x138F, prN}, // Lo [16] ETHIOPIC SYLLABLE SEBATBEIT MWA..ETHIOPIC SYLLABLE PWE
+ {0x1390, 0x1399, prN}, // So [10] ETHIOPIC TONAL MARK YIZET..ETHIOPIC TONAL MARK KURT
+ {0x13A0, 0x13F5, prN}, // Lu [86] CHEROKEE LETTER A..CHEROKEE LETTER MV
+ {0x13F8, 0x13FD, prN}, // Ll [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV
+ {0x1400, 0x1400, prN}, // Pd CANADIAN SYLLABICS HYPHEN
+ {0x1401, 0x166C, prN}, // Lo [620] CANADIAN SYLLABICS E..CANADIAN SYLLABICS CARRIER TTSA
+ {0x166D, 0x166D, prN}, // So CANADIAN SYLLABICS CHI SIGN
+ {0x166E, 0x166E, prN}, // Po CANADIAN SYLLABICS FULL STOP
+ {0x166F, 0x167F, prN}, // Lo [17] CANADIAN SYLLABICS QAI..CANADIAN SYLLABICS BLACKFOOT W
+ {0x1680, 0x1680, prN}, // Zs OGHAM SPACE MARK
+ {0x1681, 0x169A, prN}, // Lo [26] OGHAM LETTER BEITH..OGHAM LETTER PEITH
+ {0x169B, 0x169B, prN}, // Ps OGHAM FEATHER MARK
+ {0x169C, 0x169C, prN}, // Pe OGHAM REVERSED FEATHER MARK
+ {0x16A0, 0x16EA, prN}, // Lo [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X
+ {0x16EB, 0x16ED, prN}, // Po [3] RUNIC SINGLE PUNCTUATION..RUNIC CROSS PUNCTUATION
+ {0x16EE, 0x16F0, prN}, // Nl [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL
+ {0x16F1, 0x16F8, prN}, // Lo [8] RUNIC LETTER K..RUNIC LETTER FRANKS CASKET AESC
+ {0x1700, 0x1711, prN}, // Lo [18] TAGALOG LETTER A..TAGALOG LETTER HA
+ {0x1712, 0x1714, prN}, // Mn [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA
+ {0x1715, 0x1715, prN}, // Mc TAGALOG SIGN PAMUDPOD
+ {0x171F, 0x171F, prN}, // Lo TAGALOG LETTER ARCHAIC RA
+ {0x1720, 0x1731, prN}, // Lo [18] HANUNOO LETTER A..HANUNOO LETTER HA
+ {0x1732, 0x1733, prN}, // Mn [2] HANUNOO VOWEL SIGN I..HANUNOO VOWEL SIGN U
+ {0x1734, 0x1734, prN}, // Mc HANUNOO SIGN PAMUDPOD
+ {0x1735, 0x1736, prN}, // Po [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION
+ {0x1740, 0x1751, prN}, // Lo [18] BUHID LETTER A..BUHID LETTER HA
+ {0x1752, 0x1753, prN}, // Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U
+ {0x1760, 0x176C, prN}, // Lo [13] TAGBANWA LETTER A..TAGBANWA LETTER YA
+ {0x176E, 0x1770, prN}, // Lo [3] TAGBANWA LETTER LA..TAGBANWA LETTER SA
+ {0x1772, 0x1773, prN}, // Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U
+ {0x1780, 0x17B3, prN}, // Lo [52] KHMER LETTER KA..KHMER INDEPENDENT VOWEL QAU
+ {0x17B4, 0x17B5, prN}, // Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
+ {0x17B6, 0x17B6, prN}, // Mc KHMER VOWEL SIGN AA
+ {0x17B7, 0x17BD, prN}, // Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA
+ {0x17BE, 0x17C5, prN}, // Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU
+ {0x17C6, 0x17C6, prN}, // Mn KHMER SIGN NIKAHIT
+ {0x17C7, 0x17C8, prN}, // Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU
+ {0x17C9, 0x17D3, prN}, // Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT
+ {0x17D4, 0x17D6, prN}, // Po [3] KHMER SIGN KHAN..KHMER SIGN CAMNUC PII KUUH
+ {0x17D7, 0x17D7, prN}, // Lm KHMER SIGN LEK TOO
+ {0x17D8, 0x17DA, prN}, // Po [3] KHMER SIGN BEYYAL..KHMER SIGN KOOMUUT
+ {0x17DB, 0x17DB, prN}, // Sc KHMER CURRENCY SYMBOL RIEL
+ {0x17DC, 0x17DC, prN}, // Lo KHMER SIGN AVAKRAHASANYA
+ {0x17DD, 0x17DD, prN}, // Mn KHMER SIGN ATTHACAN
+ {0x17E0, 0x17E9, prN}, // Nd [10] KHMER DIGIT ZERO..KHMER DIGIT NINE
+ {0x17F0, 0x17F9, prN}, // No [10] KHMER SYMBOL LEK ATTAK SON..KHMER SYMBOL LEK ATTAK PRAM-BUON
+ {0x1800, 0x1805, prN}, // Po [6] MONGOLIAN BIRGA..MONGOLIAN FOUR DOTS
+ {0x1806, 0x1806, prN}, // Pd MONGOLIAN TODO SOFT HYPHEN
+ {0x1807, 0x180A, prN}, // Po [4] MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER..MONGOLIAN NIRUGU
+ {0x180B, 0x180D, prN}, // Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
+ {0x180E, 0x180E, prN}, // Cf MONGOLIAN VOWEL SEPARATOR
+ {0x180F, 0x180F, prN}, // Mn MONGOLIAN FREE VARIATION SELECTOR FOUR
+ {0x1810, 0x1819, prN}, // Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE
+ {0x1820, 0x1842, prN}, // Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI
+ {0x1843, 0x1843, prN}, // Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN
+ {0x1844, 0x1878, prN}, // Lo [53] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER CHA WITH TWO DOTS
+ {0x1880, 0x1884, prN}, // Lo [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA
+ {0x1885, 0x1886, prN}, // Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA
+ {0x1887, 0x18A8, prN}, // Lo [34] MONGOLIAN LETTER ALI GALI A..MONGOLIAN LETTER MANCHU ALI GALI BHA
+ {0x18A9, 0x18A9, prN}, // Mn MONGOLIAN LETTER ALI GALI DAGALGA
+ {0x18AA, 0x18AA, prN}, // Lo MONGOLIAN LETTER MANCHU ALI GALI LHA
+ {0x18B0, 0x18F5, prN}, // Lo [70] CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S
+ {0x1900, 0x191E, prN}, // Lo [31] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER TRA
+ {0x1920, 0x1922, prN}, // Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U
+ {0x1923, 0x1926, prN}, // Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU
+ {0x1927, 0x1928, prN}, // Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O
+ {0x1929, 0x192B, prN}, // Mc [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA
+ {0x1930, 0x1931, prN}, // Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA
+ {0x1932, 0x1932, prN}, // Mn LIMBU SMALL LETTER ANUSVARA
+ {0x1933, 0x1938, prN}, // Mc [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA
+ {0x1939, 0x193B, prN}, // Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I
+ {0x1940, 0x1940, prN}, // So LIMBU SIGN LOO
+ {0x1944, 0x1945, prN}, // Po [2] LIMBU EXCLAMATION MARK..LIMBU QUESTION MARK
+ {0x1946, 0x194F, prN}, // Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE
+ {0x1950, 0x196D, prN}, // Lo [30] TAI LE LETTER KA..TAI LE LETTER AI
+ {0x1970, 0x1974, prN}, // Lo [5] TAI LE LETTER TONE-2..TAI LE LETTER TONE-6
+ {0x1980, 0x19AB, prN}, // Lo [44] NEW TAI LUE LETTER HIGH QA..NEW TAI LUE LETTER LOW SUA
+ {0x19B0, 0x19C9, prN}, // Lo [26] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE TONE MARK-2
+ {0x19D0, 0x19D9, prN}, // Nd [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE
+ {0x19DA, 0x19DA, prN}, // No NEW TAI LUE THAM DIGIT ONE
+ {0x19DE, 0x19DF, prN}, // So [2] NEW TAI LUE SIGN LAE..NEW TAI LUE SIGN LAEV
+ {0x19E0, 0x19FF, prN}, // So [32] KHMER SYMBOL PATHAMASAT..KHMER SYMBOL DAP-PRAM ROC
+ {0x1A00, 0x1A16, prN}, // Lo [23] BUGINESE LETTER KA..BUGINESE LETTER HA
+ {0x1A17, 0x1A18, prN}, // Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U
+ {0x1A19, 0x1A1A, prN}, // Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O
+ {0x1A1B, 0x1A1B, prN}, // Mn BUGINESE VOWEL SIGN AE
+ {0x1A1E, 0x1A1F, prN}, // Po [2] BUGINESE PALLAWA..BUGINESE END OF SECTION
+ {0x1A20, 0x1A54, prN}, // Lo [53] TAI THAM LETTER HIGH KA..TAI THAM LETTER GREAT SA
+ {0x1A55, 0x1A55, prN}, // Mc TAI THAM CONSONANT SIGN MEDIAL RA
+ {0x1A56, 0x1A56, prN}, // Mn TAI THAM CONSONANT SIGN MEDIAL LA
+ {0x1A57, 0x1A57, prN}, // Mc TAI THAM CONSONANT SIGN LA TANG LAI
+ {0x1A58, 0x1A5E, prN}, // Mn [7] TAI THAM SIGN MAI KANG LAI..TAI THAM CONSONANT SIGN SA
+ {0x1A60, 0x1A60, prN}, // Mn TAI THAM SIGN SAKOT
+ {0x1A61, 0x1A61, prN}, // Mc TAI THAM VOWEL SIGN A
+ {0x1A62, 0x1A62, prN}, // Mn TAI THAM VOWEL SIGN MAI SAT
+ {0x1A63, 0x1A64, prN}, // Mc [2] TAI THAM VOWEL SIGN AA..TAI THAM VOWEL SIGN TALL AA
+ {0x1A65, 0x1A6C, prN}, // Mn [8] TAI THAM VOWEL SIGN I..TAI THAM VOWEL SIGN OA BELOW
+ {0x1A6D, 0x1A72, prN}, // Mc [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI
+ {0x1A73, 0x1A7C, prN}, // Mn [10] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN KHUEN-LUE KARAN
+ {0x1A7F, 0x1A7F, prN}, // Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT
+ {0x1A80, 0x1A89, prN}, // Nd [10] TAI THAM HORA DIGIT ZERO..TAI THAM HORA DIGIT NINE
+ {0x1A90, 0x1A99, prN}, // Nd [10] TAI THAM THAM DIGIT ZERO..TAI THAM THAM DIGIT NINE
+ {0x1AA0, 0x1AA6, prN}, // Po [7] TAI THAM SIGN WIANG..TAI THAM SIGN REVERSED ROTATED RANA
+ {0x1AA7, 0x1AA7, prN}, // Lm TAI THAM SIGN MAI YAMOK
+ {0x1AA8, 0x1AAD, prN}, // Po [6] TAI THAM SIGN KAAN..TAI THAM SIGN CAANG
+ {0x1AB0, 0x1ABD, prN}, // Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW
+ {0x1ABE, 0x1ABE, prN}, // Me COMBINING PARENTHESES OVERLAY
+ {0x1ABF, 0x1ACE, prN}, // Mn [16] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER INSULAR T
+ {0x1B00, 0x1B03, prN}, // Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG
+ {0x1B04, 0x1B04, prN}, // Mc BALINESE SIGN BISAH
+ {0x1B05, 0x1B33, prN}, // Lo [47] BALINESE LETTER AKARA..BALINESE LETTER HA
+ {0x1B34, 0x1B34, prN}, // Mn BALINESE SIGN REREKAN
+ {0x1B35, 0x1B35, prN}, // Mc BALINESE VOWEL SIGN TEDUNG
+ {0x1B36, 0x1B3A, prN}, // Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA
+ {0x1B3B, 0x1B3B, prN}, // Mc BALINESE VOWEL SIGN RA REPA TEDUNG
+ {0x1B3C, 0x1B3C, prN}, // Mn BALINESE VOWEL SIGN LA LENGA
+ {0x1B3D, 0x1B41, prN}, // Mc [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG
+ {0x1B42, 0x1B42, prN}, // Mn BALINESE VOWEL SIGN PEPET
+ {0x1B43, 0x1B44, prN}, // Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG
+ {0x1B45, 0x1B4C, prN}, // Lo [8] BALINESE LETTER KAF SASAK..BALINESE LETTER ARCHAIC JNYA
+ {0x1B50, 0x1B59, prN}, // Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE
+ {0x1B5A, 0x1B60, prN}, // Po [7] BALINESE PANTI..BALINESE PAMENENG
+ {0x1B61, 0x1B6A, prN}, // So [10] BALINESE MUSICAL SYMBOL DONG..BALINESE MUSICAL SYMBOL DANG GEDE
+ {0x1B6B, 0x1B73, prN}, // Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG
+ {0x1B74, 0x1B7C, prN}, // So [9] BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG..BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING
+ {0x1B7D, 0x1B7E, prN}, // Po [2] BALINESE PANTI LANTANG..BALINESE PAMADA LANTANG
+ {0x1B80, 0x1B81, prN}, // Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR
+ {0x1B82, 0x1B82, prN}, // Mc SUNDANESE SIGN PANGWISAD
+ {0x1B83, 0x1BA0, prN}, // Lo [30] SUNDANESE LETTER A..SUNDANESE LETTER HA
+ {0x1BA1, 0x1BA1, prN}, // Mc SUNDANESE CONSONANT SIGN PAMINGKAL
+ {0x1BA2, 0x1BA5, prN}, // Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU
+ {0x1BA6, 0x1BA7, prN}, // Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG
+ {0x1BA8, 0x1BA9, prN}, // Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG
+ {0x1BAA, 0x1BAA, prN}, // Mc SUNDANESE SIGN PAMAAEH
+ {0x1BAB, 0x1BAD, prN}, // Mn [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA
+ {0x1BAE, 0x1BAF, prN}, // Lo [2] SUNDANESE LETTER KHA..SUNDANESE LETTER SYA
+ {0x1BB0, 0x1BB9, prN}, // Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE
+ {0x1BBA, 0x1BBF, prN}, // Lo [6] SUNDANESE AVAGRAHA..SUNDANESE LETTER FINAL M
+ {0x1BC0, 0x1BE5, prN}, // Lo [38] BATAK LETTER A..BATAK LETTER U
+ {0x1BE6, 0x1BE6, prN}, // Mn BATAK SIGN TOMPI
+ {0x1BE7, 0x1BE7, prN}, // Mc BATAK VOWEL SIGN E
+ {0x1BE8, 0x1BE9, prN}, // Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE
+ {0x1BEA, 0x1BEC, prN}, // Mc [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O
+ {0x1BED, 0x1BED, prN}, // Mn BATAK VOWEL SIGN KARO O
+ {0x1BEE, 0x1BEE, prN}, // Mc BATAK VOWEL SIGN U
+ {0x1BEF, 0x1BF1, prN}, // Mn [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H
+ {0x1BF2, 0x1BF3, prN}, // Mc [2] BATAK PANGOLAT..BATAK PANONGONAN
+ {0x1BFC, 0x1BFF, prN}, // Po [4] BATAK SYMBOL BINDU NA METEK..BATAK SYMBOL BINDU PANGOLAT
+ {0x1C00, 0x1C23, prN}, // Lo [36] LEPCHA LETTER KA..LEPCHA LETTER A
+ {0x1C24, 0x1C2B, prN}, // Mc [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU
+ {0x1C2C, 0x1C33, prN}, // Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T
+ {0x1C34, 0x1C35, prN}, // Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG
+ {0x1C36, 0x1C37, prN}, // Mn [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA
+ {0x1C3B, 0x1C3F, prN}, // Po [5] LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION TSHOOK
+ {0x1C40, 0x1C49, prN}, // Nd [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE
+ {0x1C4D, 0x1C4F, prN}, // Lo [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA
+ {0x1C50, 0x1C59, prN}, // Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE
+ {0x1C5A, 0x1C77, prN}, // Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH
+ {0x1C78, 0x1C7D, prN}, // Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD
+ {0x1C7E, 0x1C7F, prN}, // Po [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD
+ {0x1C80, 0x1C88, prN}, // Ll [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK
+ {0x1C90, 0x1CBA, prN}, // Lu [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN
+ {0x1CBD, 0x1CBF, prN}, // Lu [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN
+ {0x1CC0, 0x1CC7, prN}, // Po [8] SUNDANESE PUNCTUATION BINDU SURYA..SUNDANESE PUNCTUATION BINDU BA SATANGA
+ {0x1CD0, 0x1CD2, prN}, // Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA
+ {0x1CD3, 0x1CD3, prN}, // Po VEDIC SIGN NIHSHVASA
+ {0x1CD4, 0x1CE0, prN}, // Mn [13] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA
+ {0x1CE1, 0x1CE1, prN}, // Mc VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA
+ {0x1CE2, 0x1CE8, prN}, // Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL
+ {0x1CE9, 0x1CEC, prN}, // Lo [4] VEDIC SIGN ANUSVARA ANTARGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL
+ {0x1CED, 0x1CED, prN}, // Mn VEDIC SIGN TIRYAK
+ {0x1CEE, 0x1CF3, prN}, // Lo [6] VEDIC SIGN HEXIFORM LONG ANUSVARA..VEDIC SIGN ROTATED ARDHAVISARGA
+ {0x1CF4, 0x1CF4, prN}, // Mn VEDIC TONE CANDRA ABOVE
+ {0x1CF5, 0x1CF6, prN}, // Lo [2] VEDIC SIGN JIHVAMULIYA..VEDIC SIGN UPADHMANIYA
+ {0x1CF7, 0x1CF7, prN}, // Mc VEDIC SIGN ATIKRAMA
+ {0x1CF8, 0x1CF9, prN}, // Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE
+ {0x1CFA, 0x1CFA, prN}, // Lo VEDIC SIGN DOUBLE ANUSVARA ANTARGOMUKHA
+ {0x1D00, 0x1D2B, prN}, // Ll [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL
+ {0x1D2C, 0x1D6A, prN}, // Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI
+ {0x1D6B, 0x1D77, prN}, // Ll [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G
+ {0x1D78, 0x1D78, prN}, // Lm MODIFIER LETTER CYRILLIC EN
+ {0x1D79, 0x1D7F, prN}, // Ll [7] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER UPSILON WITH STROKE
+ {0x1D80, 0x1D9A, prN}, // Ll [27] LATIN SMALL LETTER B WITH PALATAL HOOK..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK
+ {0x1D9B, 0x1DBF, prN}, // Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA
+ {0x1DC0, 0x1DFF, prN}, // Mn [64] COMBINING DOTTED GRAVE ACCENT..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW
+ {0x1E00, 0x1EFF, prN}, // L& [256] LATIN CAPITAL LETTER A WITH RING BELOW..LATIN SMALL LETTER Y WITH LOOP
+ {0x1F00, 0x1F15, prN}, // L& [22] GREEK SMALL LETTER ALPHA WITH PSILI..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA
+ {0x1F18, 0x1F1D, prN}, // Lu [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
+ {0x1F20, 0x1F45, prN}, // L& [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA
+ {0x1F48, 0x1F4D, prN}, // Lu [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
+ {0x1F50, 0x1F57, prN}, // Ll [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI
+ {0x1F59, 0x1F59, prN}, // Lu GREEK CAPITAL LETTER UPSILON WITH DASIA
+ {0x1F5B, 0x1F5B, prN}, // Lu GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
+ {0x1F5D, 0x1F5D, prN}, // Lu GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
+ {0x1F5F, 0x1F7D, prN}, // L& [31] GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI..GREEK SMALL LETTER OMEGA WITH OXIA
+ {0x1F80, 0x1FB4, prN}, // L& [53] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+ {0x1FB6, 0x1FBC, prN}, // L& [7] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+ {0x1FBD, 0x1FBD, prN}, // Sk GREEK KORONIS
+ {0x1FBE, 0x1FBE, prN}, // Ll GREEK PROSGEGRAMMENI
+ {0x1FBF, 0x1FC1, prN}, // Sk [3] GREEK PSILI..GREEK DIALYTIKA AND PERISPOMENI
+ {0x1FC2, 0x1FC4, prN}, // Ll [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+ {0x1FC6, 0x1FCC, prN}, // L& [7] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+ {0x1FCD, 0x1FCF, prN}, // Sk [3] GREEK PSILI AND VARIA..GREEK PSILI AND PERISPOMENI
+ {0x1FD0, 0x1FD3, prN}, // Ll [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+ {0x1FD6, 0x1FDB, prN}, // L& [6] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK CAPITAL LETTER IOTA WITH OXIA
+ {0x1FDD, 0x1FDF, prN}, // Sk [3] GREEK DASIA AND VARIA..GREEK DASIA AND PERISPOMENI
+ {0x1FE0, 0x1FEC, prN}, // L& [13] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA
+ {0x1FED, 0x1FEF, prN}, // Sk [3] GREEK DIALYTIKA AND VARIA..GREEK VARIA
+ {0x1FF2, 0x1FF4, prN}, // Ll [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+ {0x1FF6, 0x1FFC, prN}, // L& [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+ {0x1FFD, 0x1FFE, prN}, // Sk [2] GREEK OXIA..GREEK DASIA
+ {0x2000, 0x200A, prN}, // Zs [11] EN QUAD..HAIR SPACE
+ {0x200B, 0x200F, prN}, // Cf [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK
+ {0x2010, 0x2010, prA}, // Pd HYPHEN
+ {0x2011, 0x2012, prN}, // Pd [2] NON-BREAKING HYPHEN..FIGURE DASH
+ {0x2013, 0x2015, prA}, // Pd [3] EN DASH..HORIZONTAL BAR
+ {0x2016, 0x2016, prA}, // Po DOUBLE VERTICAL LINE
+ {0x2017, 0x2017, prN}, // Po DOUBLE LOW LINE
+ {0x2018, 0x2018, prA}, // Pi LEFT SINGLE QUOTATION MARK
+ {0x2019, 0x2019, prA}, // Pf RIGHT SINGLE QUOTATION MARK
+ {0x201A, 0x201A, prN}, // Ps SINGLE LOW-9 QUOTATION MARK
+ {0x201B, 0x201B, prN}, // Pi SINGLE HIGH-REVERSED-9 QUOTATION MARK
+ {0x201C, 0x201C, prA}, // Pi LEFT DOUBLE QUOTATION MARK
+ {0x201D, 0x201D, prA}, // Pf RIGHT DOUBLE QUOTATION MARK
+ {0x201E, 0x201E, prN}, // Ps DOUBLE LOW-9 QUOTATION MARK
+ {0x201F, 0x201F, prN}, // Pi DOUBLE HIGH-REVERSED-9 QUOTATION MARK
+ {0x2020, 0x2022, prA}, // Po [3] DAGGER..BULLET
+ {0x2023, 0x2023, prN}, // Po TRIANGULAR BULLET
+ {0x2024, 0x2027, prA}, // Po [4] ONE DOT LEADER..HYPHENATION POINT
+ {0x2028, 0x2028, prN}, // Zl LINE SEPARATOR
+ {0x2029, 0x2029, prN}, // Zp PARAGRAPH SEPARATOR
+ {0x202A, 0x202E, prN}, // Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE
+ {0x202F, 0x202F, prN}, // Zs NARROW NO-BREAK SPACE
+ {0x2030, 0x2030, prA}, // Po PER MILLE SIGN
+ {0x2031, 0x2031, prN}, // Po PER TEN THOUSAND SIGN
+ {0x2032, 0x2033, prA}, // Po [2] PRIME..DOUBLE PRIME
+ {0x2034, 0x2034, prN}, // Po TRIPLE PRIME
+ {0x2035, 0x2035, prA}, // Po REVERSED PRIME
+ {0x2036, 0x2038, prN}, // Po [3] REVERSED DOUBLE PRIME..CARET
+ {0x2039, 0x2039, prN}, // Pi SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ {0x203A, 0x203A, prN}, // Pf SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ {0x203B, 0x203B, prA}, // Po REFERENCE MARK
+ {0x203C, 0x203D, prN}, // Po [2] DOUBLE EXCLAMATION MARK..INTERROBANG
+ {0x203E, 0x203E, prA}, // Po OVERLINE
+ {0x203F, 0x2040, prN}, // Pc [2] UNDERTIE..CHARACTER TIE
+ {0x2041, 0x2043, prN}, // Po [3] CARET INSERTION POINT..HYPHEN BULLET
+ {0x2044, 0x2044, prN}, // Sm FRACTION SLASH
+ {0x2045, 0x2045, prN}, // Ps LEFT SQUARE BRACKET WITH QUILL
+ {0x2046, 0x2046, prN}, // Pe RIGHT SQUARE BRACKET WITH QUILL
+ {0x2047, 0x2051, prN}, // Po [11] DOUBLE QUESTION MARK..TWO ASTERISKS ALIGNED VERTICALLY
+ {0x2052, 0x2052, prN}, // Sm COMMERCIAL MINUS SIGN
+ {0x2053, 0x2053, prN}, // Po SWUNG DASH
+ {0x2054, 0x2054, prN}, // Pc INVERTED UNDERTIE
+ {0x2055, 0x205E, prN}, // Po [10] FLOWER PUNCTUATION MARK..VERTICAL FOUR DOTS
+ {0x205F, 0x205F, prN}, // Zs MEDIUM MATHEMATICAL SPACE
+ {0x2060, 0x2064, prN}, // Cf [5] WORD JOINER..INVISIBLE PLUS
+ {0x2066, 0x206F, prN}, // Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES
+ {0x2070, 0x2070, prN}, // No SUPERSCRIPT ZERO
+ {0x2071, 0x2071, prN}, // Lm SUPERSCRIPT LATIN SMALL LETTER I
+ {0x2074, 0x2074, prA}, // No SUPERSCRIPT FOUR
+ {0x2075, 0x2079, prN}, // No [5] SUPERSCRIPT FIVE..SUPERSCRIPT NINE
+ {0x207A, 0x207C, prN}, // Sm [3] SUPERSCRIPT PLUS SIGN..SUPERSCRIPT EQUALS SIGN
+ {0x207D, 0x207D, prN}, // Ps SUPERSCRIPT LEFT PARENTHESIS
+ {0x207E, 0x207E, prN}, // Pe SUPERSCRIPT RIGHT PARENTHESIS
+ {0x207F, 0x207F, prA}, // Lm SUPERSCRIPT LATIN SMALL LETTER N
+ {0x2080, 0x2080, prN}, // No SUBSCRIPT ZERO
+ {0x2081, 0x2084, prA}, // No [4] SUBSCRIPT ONE..SUBSCRIPT FOUR
+ {0x2085, 0x2089, prN}, // No [5] SUBSCRIPT FIVE..SUBSCRIPT NINE
+ {0x208A, 0x208C, prN}, // Sm [3] SUBSCRIPT PLUS SIGN..SUBSCRIPT EQUALS SIGN
+ {0x208D, 0x208D, prN}, // Ps SUBSCRIPT LEFT PARENTHESIS
+ {0x208E, 0x208E, prN}, // Pe SUBSCRIPT RIGHT PARENTHESIS
+ {0x2090, 0x209C, prN}, // Lm [13] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER T
+ {0x20A0, 0x20A8, prN}, // Sc [9] EURO-CURRENCY SIGN..RUPEE SIGN
+ {0x20A9, 0x20A9, prH}, // Sc WON SIGN
+ {0x20AA, 0x20AB, prN}, // Sc [2] NEW SHEQEL SIGN..DONG SIGN
+ {0x20AC, 0x20AC, prA}, // Sc EURO SIGN
+ {0x20AD, 0x20C0, prN}, // Sc [20] KIP SIGN..SOM SIGN
+ {0x20D0, 0x20DC, prN}, // Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE
+ {0x20DD, 0x20E0, prN}, // Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH
+ {0x20E1, 0x20E1, prN}, // Mn COMBINING LEFT RIGHT ARROW ABOVE
+ {0x20E2, 0x20E4, prN}, // Me [3] COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING UPWARD POINTING TRIANGLE
+ {0x20E5, 0x20F0, prN}, // Mn [12] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING ASTERISK ABOVE
+ {0x2100, 0x2101, prN}, // So [2] ACCOUNT OF..ADDRESSED TO THE SUBJECT
+ {0x2102, 0x2102, prN}, // Lu DOUBLE-STRUCK CAPITAL C
+ {0x2103, 0x2103, prA}, // So DEGREE CELSIUS
+ {0x2104, 0x2104, prN}, // So CENTRE LINE SYMBOL
+ {0x2105, 0x2105, prA}, // So CARE OF
+ {0x2106, 0x2106, prN}, // So CADA UNA
+ {0x2107, 0x2107, prN}, // Lu EULER CONSTANT
+ {0x2108, 0x2108, prN}, // So SCRUPLE
+ {0x2109, 0x2109, prA}, // So DEGREE FAHRENHEIT
+ {0x210A, 0x2112, prN}, // L& [9] SCRIPT SMALL G..SCRIPT CAPITAL L
+ {0x2113, 0x2113, prA}, // Ll SCRIPT SMALL L
+ {0x2114, 0x2114, prN}, // So L B BAR SYMBOL
+ {0x2115, 0x2115, prN}, // Lu DOUBLE-STRUCK CAPITAL N
+ {0x2116, 0x2116, prA}, // So NUMERO SIGN
+ {0x2117, 0x2117, prN}, // So SOUND RECORDING COPYRIGHT
+ {0x2118, 0x2118, prN}, // Sm SCRIPT CAPITAL P
+ {0x2119, 0x211D, prN}, // Lu [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R
+ {0x211E, 0x2120, prN}, // So [3] PRESCRIPTION TAKE..SERVICE MARK
+ {0x2121, 0x2122, prA}, // So [2] TELEPHONE SIGN..TRADE MARK SIGN
+ {0x2123, 0x2123, prN}, // So VERSICLE
+ {0x2124, 0x2124, prN}, // Lu DOUBLE-STRUCK CAPITAL Z
+ {0x2125, 0x2125, prN}, // So OUNCE SIGN
+ {0x2126, 0x2126, prA}, // Lu OHM SIGN
+ {0x2127, 0x2127, prN}, // So INVERTED OHM SIGN
+ {0x2128, 0x2128, prN}, // Lu BLACK-LETTER CAPITAL Z
+ {0x2129, 0x2129, prN}, // So TURNED GREEK SMALL LETTER IOTA
+ {0x212A, 0x212A, prN}, // Lu KELVIN SIGN
+ {0x212B, 0x212B, prA}, // Lu ANGSTROM SIGN
+ {0x212C, 0x212D, prN}, // Lu [2] SCRIPT CAPITAL B..BLACK-LETTER CAPITAL C
+ {0x212E, 0x212E, prN}, // So ESTIMATED SYMBOL
+ {0x212F, 0x2134, prN}, // L& [6] SCRIPT SMALL E..SCRIPT SMALL O
+ {0x2135, 0x2138, prN}, // Lo [4] ALEF SYMBOL..DALET SYMBOL
+ {0x2139, 0x2139, prN}, // Ll INFORMATION SOURCE
+ {0x213A, 0x213B, prN}, // So [2] ROTATED CAPITAL Q..FACSIMILE SIGN
+ {0x213C, 0x213F, prN}, // L& [4] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK CAPITAL PI
+ {0x2140, 0x2144, prN}, // Sm [5] DOUBLE-STRUCK N-ARY SUMMATION..TURNED SANS-SERIF CAPITAL Y
+ {0x2145, 0x2149, prN}, // L& [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J
+ {0x214A, 0x214A, prN}, // So PROPERTY LINE
+ {0x214B, 0x214B, prN}, // Sm TURNED AMPERSAND
+ {0x214C, 0x214D, prN}, // So [2] PER SIGN..AKTIESELSKAB
+ {0x214E, 0x214E, prN}, // Ll TURNED SMALL F
+ {0x214F, 0x214F, prN}, // So SYMBOL FOR SAMARITAN SOURCE
+ {0x2150, 0x2152, prN}, // No [3] VULGAR FRACTION ONE SEVENTH..VULGAR FRACTION ONE TENTH
+ {0x2153, 0x2154, prA}, // No [2] VULGAR FRACTION ONE THIRD..VULGAR FRACTION TWO THIRDS
+ {0x2155, 0x215A, prN}, // No [6] VULGAR FRACTION ONE FIFTH..VULGAR FRACTION FIVE SIXTHS
+ {0x215B, 0x215E, prA}, // No [4] VULGAR FRACTION ONE EIGHTH..VULGAR FRACTION SEVEN EIGHTHS
+ {0x215F, 0x215F, prN}, // No FRACTION NUMERATOR ONE
+ {0x2160, 0x216B, prA}, // Nl [12] ROMAN NUMERAL ONE..ROMAN NUMERAL TWELVE
+ {0x216C, 0x216F, prN}, // Nl [4] ROMAN NUMERAL FIFTY..ROMAN NUMERAL ONE THOUSAND
+ {0x2170, 0x2179, prA}, // Nl [10] SMALL ROMAN NUMERAL ONE..SMALL ROMAN NUMERAL TEN
+ {0x217A, 0x2182, prN}, // Nl [9] SMALL ROMAN NUMERAL ELEVEN..ROMAN NUMERAL TEN THOUSAND
+ {0x2183, 0x2184, prN}, // L& [2] ROMAN NUMERAL REVERSED ONE HUNDRED..LATIN SMALL LETTER REVERSED C
+ {0x2185, 0x2188, prN}, // Nl [4] ROMAN NUMERAL SIX LATE FORM..ROMAN NUMERAL ONE HUNDRED THOUSAND
+ {0x2189, 0x2189, prA}, // No VULGAR FRACTION ZERO THIRDS
+ {0x218A, 0x218B, prN}, // So [2] TURNED DIGIT TWO..TURNED DIGIT THREE
+ {0x2190, 0x2194, prA}, // Sm [5] LEFTWARDS ARROW..LEFT RIGHT ARROW
+ {0x2195, 0x2199, prA}, // So [5] UP DOWN ARROW..SOUTH WEST ARROW
+ {0x219A, 0x219B, prN}, // Sm [2] LEFTWARDS ARROW WITH STROKE..RIGHTWARDS ARROW WITH STROKE
+ {0x219C, 0x219F, prN}, // So [4] LEFTWARDS WAVE ARROW..UPWARDS TWO HEADED ARROW
+ {0x21A0, 0x21A0, prN}, // Sm RIGHTWARDS TWO HEADED ARROW
+ {0x21A1, 0x21A2, prN}, // So [2] DOWNWARDS TWO HEADED ARROW..LEFTWARDS ARROW WITH TAIL
+ {0x21A3, 0x21A3, prN}, // Sm RIGHTWARDS ARROW WITH TAIL
+ {0x21A4, 0x21A5, prN}, // So [2] LEFTWARDS ARROW FROM BAR..UPWARDS ARROW FROM BAR
+ {0x21A6, 0x21A6, prN}, // Sm RIGHTWARDS ARROW FROM BAR
+ {0x21A7, 0x21AD, prN}, // So [7] DOWNWARDS ARROW FROM BAR..LEFT RIGHT WAVE ARROW
+ {0x21AE, 0x21AE, prN}, // Sm LEFT RIGHT ARROW WITH STROKE
+ {0x21AF, 0x21B7, prN}, // So [9] DOWNWARDS ZIGZAG ARROW..CLOCKWISE TOP SEMICIRCLE ARROW
+ {0x21B8, 0x21B9, prA}, // So [2] NORTH WEST ARROW TO LONG BAR..LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR
+ {0x21BA, 0x21CD, prN}, // So [20] ANTICLOCKWISE OPEN CIRCLE ARROW..LEFTWARDS DOUBLE ARROW WITH STROKE
+ {0x21CE, 0x21CF, prN}, // Sm [2] LEFT RIGHT DOUBLE ARROW WITH STROKE..RIGHTWARDS DOUBLE ARROW WITH STROKE
+ {0x21D0, 0x21D1, prN}, // So [2] LEFTWARDS DOUBLE ARROW..UPWARDS DOUBLE ARROW
+ {0x21D2, 0x21D2, prA}, // Sm RIGHTWARDS DOUBLE ARROW
+ {0x21D3, 0x21D3, prN}, // So DOWNWARDS DOUBLE ARROW
+ {0x21D4, 0x21D4, prA}, // Sm LEFT RIGHT DOUBLE ARROW
+ {0x21D5, 0x21E6, prN}, // So [18] UP DOWN DOUBLE ARROW..LEFTWARDS WHITE ARROW
+ {0x21E7, 0x21E7, prA}, // So UPWARDS WHITE ARROW
+ {0x21E8, 0x21F3, prN}, // So [12] RIGHTWARDS WHITE ARROW..UP DOWN WHITE ARROW
+ {0x21F4, 0x21FF, prN}, // Sm [12] RIGHT ARROW WITH SMALL CIRCLE..LEFT RIGHT OPEN-HEADED ARROW
+ {0x2200, 0x2200, prA}, // Sm FOR ALL
+ {0x2201, 0x2201, prN}, // Sm COMPLEMENT
+ {0x2202, 0x2203, prA}, // Sm [2] PARTIAL DIFFERENTIAL..THERE EXISTS
+ {0x2204, 0x2206, prN}, // Sm [3] THERE DOES NOT EXIST..INCREMENT
+ {0x2207, 0x2208, prA}, // Sm [2] NABLA..ELEMENT OF
+ {0x2209, 0x220A, prN}, // Sm [2] NOT AN ELEMENT OF..SMALL ELEMENT OF
+ {0x220B, 0x220B, prA}, // Sm CONTAINS AS MEMBER
+ {0x220C, 0x220E, prN}, // Sm [3] DOES NOT CONTAIN AS MEMBER..END OF PROOF
+ {0x220F, 0x220F, prA}, // Sm N-ARY PRODUCT
+ {0x2210, 0x2210, prN}, // Sm N-ARY COPRODUCT
+ {0x2211, 0x2211, prA}, // Sm N-ARY SUMMATION
+ {0x2212, 0x2214, prN}, // Sm [3] MINUS SIGN..DOT PLUS
+ {0x2215, 0x2215, prA}, // Sm DIVISION SLASH
+ {0x2216, 0x2219, prN}, // Sm [4] SET MINUS..BULLET OPERATOR
+ {0x221A, 0x221A, prA}, // Sm SQUARE ROOT
+ {0x221B, 0x221C, prN}, // Sm [2] CUBE ROOT..FOURTH ROOT
+ {0x221D, 0x2220, prA}, // Sm [4] PROPORTIONAL TO..ANGLE
+ {0x2221, 0x2222, prN}, // Sm [2] MEASURED ANGLE..SPHERICAL ANGLE
+ {0x2223, 0x2223, prA}, // Sm DIVIDES
+ {0x2224, 0x2224, prN}, // Sm DOES NOT DIVIDE
+ {0x2225, 0x2225, prA}, // Sm PARALLEL TO
+ {0x2226, 0x2226, prN}, // Sm NOT PARALLEL TO
+ {0x2227, 0x222C, prA}, // Sm [6] LOGICAL AND..DOUBLE INTEGRAL
+ {0x222D, 0x222D, prN}, // Sm TRIPLE INTEGRAL
+ {0x222E, 0x222E, prA}, // Sm CONTOUR INTEGRAL
+ {0x222F, 0x2233, prN}, // Sm [5] SURFACE INTEGRAL..ANTICLOCKWISE CONTOUR INTEGRAL
+ {0x2234, 0x2237, prA}, // Sm [4] THEREFORE..PROPORTION
+ {0x2238, 0x223B, prN}, // Sm [4] DOT MINUS..HOMOTHETIC
+ {0x223C, 0x223D, prA}, // Sm [2] TILDE OPERATOR..REVERSED TILDE
+ {0x223E, 0x2247, prN}, // Sm [10] INVERTED LAZY S..NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO
+ {0x2248, 0x2248, prA}, // Sm ALMOST EQUAL TO
+ {0x2249, 0x224B, prN}, // Sm [3] NOT ALMOST EQUAL TO..TRIPLE TILDE
+ {0x224C, 0x224C, prA}, // Sm ALL EQUAL TO
+ {0x224D, 0x2251, prN}, // Sm [5] EQUIVALENT TO..GEOMETRICALLY EQUAL TO
+ {0x2252, 0x2252, prA}, // Sm APPROXIMATELY EQUAL TO OR THE IMAGE OF
+ {0x2253, 0x225F, prN}, // Sm [13] IMAGE OF OR APPROXIMATELY EQUAL TO..QUESTIONED EQUAL TO
+ {0x2260, 0x2261, prA}, // Sm [2] NOT EQUAL TO..IDENTICAL TO
+ {0x2262, 0x2263, prN}, // Sm [2] NOT IDENTICAL TO..STRICTLY EQUIVALENT TO
+ {0x2264, 0x2267, prA}, // Sm [4] LESS-THAN OR EQUAL TO..GREATER-THAN OVER EQUAL TO
+ {0x2268, 0x2269, prN}, // Sm [2] LESS-THAN BUT NOT EQUAL TO..GREATER-THAN BUT NOT EQUAL TO
+ {0x226A, 0x226B, prA}, // Sm [2] MUCH LESS-THAN..MUCH GREATER-THAN
+ {0x226C, 0x226D, prN}, // Sm [2] BETWEEN..NOT EQUIVALENT TO
+ {0x226E, 0x226F, prA}, // Sm [2] NOT LESS-THAN..NOT GREATER-THAN
+ {0x2270, 0x2281, prN}, // Sm [18] NEITHER LESS-THAN NOR EQUAL TO..DOES NOT SUCCEED
+ {0x2282, 0x2283, prA}, // Sm [2] SUBSET OF..SUPERSET OF
+ {0x2284, 0x2285, prN}, // Sm [2] NOT A SUBSET OF..NOT A SUPERSET OF
+ {0x2286, 0x2287, prA}, // Sm [2] SUBSET OF OR EQUAL TO..SUPERSET OF OR EQUAL TO
+ {0x2288, 0x2294, prN}, // Sm [13] NEITHER A SUBSET OF NOR EQUAL TO..SQUARE CUP
+ {0x2295, 0x2295, prA}, // Sm CIRCLED PLUS
+ {0x2296, 0x2298, prN}, // Sm [3] CIRCLED MINUS..CIRCLED DIVISION SLASH
+ {0x2299, 0x2299, prA}, // Sm CIRCLED DOT OPERATOR
+ {0x229A, 0x22A4, prN}, // Sm [11] CIRCLED RING OPERATOR..DOWN TACK
+ {0x22A5, 0x22A5, prA}, // Sm UP TACK
+ {0x22A6, 0x22BE, prN}, // Sm [25] ASSERTION..RIGHT ANGLE WITH ARC
+ {0x22BF, 0x22BF, prA}, // Sm RIGHT TRIANGLE
+ {0x22C0, 0x22FF, prN}, // Sm [64] N-ARY LOGICAL AND..Z NOTATION BAG MEMBERSHIP
+ {0x2300, 0x2307, prN}, // So [8] DIAMETER SIGN..WAVY LINE
+ {0x2308, 0x2308, prN}, // Ps LEFT CEILING
+ {0x2309, 0x2309, prN}, // Pe RIGHT CEILING
+ {0x230A, 0x230A, prN}, // Ps LEFT FLOOR
+ {0x230B, 0x230B, prN}, // Pe RIGHT FLOOR
+ {0x230C, 0x2311, prN}, // So [6] BOTTOM RIGHT CROP..SQUARE LOZENGE
+ {0x2312, 0x2312, prA}, // So ARC
+ {0x2313, 0x2319, prN}, // So [7] SEGMENT..TURNED NOT SIGN
+ {0x231A, 0x231B, prW}, // So [2] WATCH..HOURGLASS
+ {0x231C, 0x231F, prN}, // So [4] TOP LEFT CORNER..BOTTOM RIGHT CORNER
+ {0x2320, 0x2321, prN}, // Sm [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL
+ {0x2322, 0x2328, prN}, // So [7] FROWN..KEYBOARD
+ {0x2329, 0x2329, prW}, // Ps LEFT-POINTING ANGLE BRACKET
+ {0x232A, 0x232A, prW}, // Pe RIGHT-POINTING ANGLE BRACKET
+ {0x232B, 0x237B, prN}, // So [81] ERASE TO THE LEFT..NOT CHECK MARK
+ {0x237C, 0x237C, prN}, // Sm RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW
+ {0x237D, 0x239A, prN}, // So [30] SHOULDERED OPEN BOX..CLEAR SCREEN SYMBOL
+ {0x239B, 0x23B3, prN}, // Sm [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM
+ {0x23B4, 0x23DB, prN}, // So [40] TOP SQUARE BRACKET..FUSE
+ {0x23DC, 0x23E1, prN}, // Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET
+ {0x23E2, 0x23E8, prN}, // So [7] WHITE TRAPEZIUM..DECIMAL EXPONENT SYMBOL
+ {0x23E9, 0x23EC, prW}, // So [4] BLACK RIGHT-POINTING DOUBLE TRIANGLE..BLACK DOWN-POINTING DOUBLE TRIANGLE
+ {0x23ED, 0x23EF, prN}, // So [3] BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR..BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR
+ {0x23F0, 0x23F0, prW}, // So ALARM CLOCK
+ {0x23F1, 0x23F2, prN}, // So [2] STOPWATCH..TIMER CLOCK
+ {0x23F3, 0x23F3, prW}, // So HOURGLASS WITH FLOWING SAND
+ {0x23F4, 0x23FF, prN}, // So [12] BLACK MEDIUM LEFT-POINTING TRIANGLE..OBSERVER EYE SYMBOL
+ {0x2400, 0x2426, prN}, // So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO
+ {0x2440, 0x244A, prN}, // So [11] OCR HOOK..OCR DOUBLE BACKSLASH
+ {0x2460, 0x249B, prA}, // No [60] CIRCLED DIGIT ONE..NUMBER TWENTY FULL STOP
+ {0x249C, 0x24E9, prA}, // So [78] PARENTHESIZED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z
+ {0x24EA, 0x24EA, prN}, // No CIRCLED DIGIT ZERO
+ {0x24EB, 0x24FF, prA}, // No [21] NEGATIVE CIRCLED NUMBER ELEVEN..NEGATIVE CIRCLED DIGIT ZERO
+ {0x2500, 0x254B, prA}, // So [76] BOX DRAWINGS LIGHT HORIZONTAL..BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL
+ {0x254C, 0x254F, prN}, // So [4] BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL..BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL
+ {0x2550, 0x2573, prA}, // So [36] BOX DRAWINGS DOUBLE HORIZONTAL..BOX DRAWINGS LIGHT DIAGONAL CROSS
+ {0x2574, 0x257F, prN}, // So [12] BOX DRAWINGS LIGHT LEFT..BOX DRAWINGS HEAVY UP AND LIGHT DOWN
+ {0x2580, 0x258F, prA}, // So [16] UPPER HALF BLOCK..LEFT ONE EIGHTH BLOCK
+ {0x2590, 0x2591, prN}, // So [2] RIGHT HALF BLOCK..LIGHT SHADE
+ {0x2592, 0x2595, prA}, // So [4] MEDIUM SHADE..RIGHT ONE EIGHTH BLOCK
+ {0x2596, 0x259F, prN}, // So [10] QUADRANT LOWER LEFT..QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT
+ {0x25A0, 0x25A1, prA}, // So [2] BLACK SQUARE..WHITE SQUARE
+ {0x25A2, 0x25A2, prN}, // So WHITE SQUARE WITH ROUNDED CORNERS
+ {0x25A3, 0x25A9, prA}, // So [7] WHITE SQUARE CONTAINING BLACK SMALL SQUARE..SQUARE WITH DIAGONAL CROSSHATCH FILL
+ {0x25AA, 0x25B1, prN}, // So [8] BLACK SMALL SQUARE..WHITE PARALLELOGRAM
+ {0x25B2, 0x25B3, prA}, // So [2] BLACK UP-POINTING TRIANGLE..WHITE UP-POINTING TRIANGLE
+ {0x25B4, 0x25B5, prN}, // So [2] BLACK UP-POINTING SMALL TRIANGLE..WHITE UP-POINTING SMALL TRIANGLE
+ {0x25B6, 0x25B6, prA}, // So BLACK RIGHT-POINTING TRIANGLE
+ {0x25B7, 0x25B7, prA}, // Sm WHITE RIGHT-POINTING TRIANGLE
+ {0x25B8, 0x25BB, prN}, // So [4] BLACK RIGHT-POINTING SMALL TRIANGLE..WHITE RIGHT-POINTING POINTER
+ {0x25BC, 0x25BD, prA}, // So [2] BLACK DOWN-POINTING TRIANGLE..WHITE DOWN-POINTING TRIANGLE
+ {0x25BE, 0x25BF, prN}, // So [2] BLACK DOWN-POINTING SMALL TRIANGLE..WHITE DOWN-POINTING SMALL TRIANGLE
+ {0x25C0, 0x25C0, prA}, // So BLACK LEFT-POINTING TRIANGLE
+ {0x25C1, 0x25C1, prA}, // Sm WHITE LEFT-POINTING TRIANGLE
+ {0x25C2, 0x25C5, prN}, // So [4] BLACK LEFT-POINTING SMALL TRIANGLE..WHITE LEFT-POINTING POINTER
+ {0x25C6, 0x25C8, prA}, // So [3] BLACK DIAMOND..WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND
+ {0x25C9, 0x25CA, prN}, // So [2] FISHEYE..LOZENGE
+ {0x25CB, 0x25CB, prA}, // So WHITE CIRCLE
+ {0x25CC, 0x25CD, prN}, // So [2] DOTTED CIRCLE..CIRCLE WITH VERTICAL FILL
+ {0x25CE, 0x25D1, prA}, // So [4] BULLSEYE..CIRCLE WITH RIGHT HALF BLACK
+ {0x25D2, 0x25E1, prN}, // So [16] CIRCLE WITH LOWER HALF BLACK..LOWER HALF CIRCLE
+ {0x25E2, 0x25E5, prA}, // So [4] BLACK LOWER RIGHT TRIANGLE..BLACK UPPER RIGHT TRIANGLE
+ {0x25E6, 0x25EE, prN}, // So [9] WHITE BULLET..UP-POINTING TRIANGLE WITH RIGHT HALF BLACK
+ {0x25EF, 0x25EF, prA}, // So LARGE CIRCLE
+ {0x25F0, 0x25F7, prN}, // So [8] WHITE SQUARE WITH UPPER LEFT QUADRANT..WHITE CIRCLE WITH UPPER RIGHT QUADRANT
+ {0x25F8, 0x25FC, prN}, // Sm [5] UPPER LEFT TRIANGLE..BLACK MEDIUM SQUARE
+ {0x25FD, 0x25FE, prW}, // Sm [2] WHITE MEDIUM SMALL SQUARE..BLACK MEDIUM SMALL SQUARE
+ {0x25FF, 0x25FF, prN}, // Sm LOWER RIGHT TRIANGLE
+ {0x2600, 0x2604, prN}, // So [5] BLACK SUN WITH RAYS..COMET
+ {0x2605, 0x2606, prA}, // So [2] BLACK STAR..WHITE STAR
+ {0x2607, 0x2608, prN}, // So [2] LIGHTNING..THUNDERSTORM
+ {0x2609, 0x2609, prA}, // So SUN
+ {0x260A, 0x260D, prN}, // So [4] ASCENDING NODE..OPPOSITION
+ {0x260E, 0x260F, prA}, // So [2] BLACK TELEPHONE..WHITE TELEPHONE
+ {0x2610, 0x2613, prN}, // So [4] BALLOT BOX..SALTIRE
+ {0x2614, 0x2615, prW}, // So [2] UMBRELLA WITH RAIN DROPS..HOT BEVERAGE
+ {0x2616, 0x261B, prN}, // So [6] WHITE SHOGI PIECE..BLACK RIGHT POINTING INDEX
+ {0x261C, 0x261C, prA}, // So WHITE LEFT POINTING INDEX
+ {0x261D, 0x261D, prN}, // So WHITE UP POINTING INDEX
+ {0x261E, 0x261E, prA}, // So WHITE RIGHT POINTING INDEX
+ {0x261F, 0x263F, prN}, // So [33] WHITE DOWN POINTING INDEX..MERCURY
+ {0x2640, 0x2640, prA}, // So FEMALE SIGN
+ {0x2641, 0x2641, prN}, // So EARTH
+ {0x2642, 0x2642, prA}, // So MALE SIGN
+ {0x2643, 0x2647, prN}, // So [5] JUPITER..PLUTO
+ {0x2648, 0x2653, prW}, // So [12] ARIES..PISCES
+ {0x2654, 0x265F, prN}, // So [12] WHITE CHESS KING..BLACK CHESS PAWN
+ {0x2660, 0x2661, prA}, // So [2] BLACK SPADE SUIT..WHITE HEART SUIT
+ {0x2662, 0x2662, prN}, // So WHITE DIAMOND SUIT
+ {0x2663, 0x2665, prA}, // So [3] BLACK CLUB SUIT..BLACK HEART SUIT
+ {0x2666, 0x2666, prN}, // So BLACK DIAMOND SUIT
+ {0x2667, 0x266A, prA}, // So [4] WHITE CLUB SUIT..EIGHTH NOTE
+ {0x266B, 0x266B, prN}, // So BEAMED EIGHTH NOTES
+ {0x266C, 0x266D, prA}, // So [2] BEAMED SIXTEENTH NOTES..MUSIC FLAT SIGN
+ {0x266E, 0x266E, prN}, // So MUSIC NATURAL SIGN
+ {0x266F, 0x266F, prA}, // Sm MUSIC SHARP SIGN
+ {0x2670, 0x267E, prN}, // So [15] WEST SYRIAC CROSS..PERMANENT PAPER SIGN
+ {0x267F, 0x267F, prW}, // So WHEELCHAIR SYMBOL
+ {0x2680, 0x2692, prN}, // So [19] DIE FACE-1..HAMMER AND PICK
+ {0x2693, 0x2693, prW}, // So ANCHOR
+ {0x2694, 0x269D, prN}, // So [10] CROSSED SWORDS..OUTLINED WHITE STAR
+ {0x269E, 0x269F, prA}, // So [2] THREE LINES CONVERGING RIGHT..THREE LINES CONVERGING LEFT
+ {0x26A0, 0x26A0, prN}, // So WARNING SIGN
+ {0x26A1, 0x26A1, prW}, // So HIGH VOLTAGE SIGN
+ {0x26A2, 0x26A9, prN}, // So [8] DOUBLED FEMALE SIGN..HORIZONTAL MALE WITH STROKE SIGN
+ {0x26AA, 0x26AB, prW}, // So [2] MEDIUM WHITE CIRCLE..MEDIUM BLACK CIRCLE
+ {0x26AC, 0x26BC, prN}, // So [17] MEDIUM SMALL WHITE CIRCLE..SESQUIQUADRATE
+ {0x26BD, 0x26BE, prW}, // So [2] SOCCER BALL..BASEBALL
+ {0x26BF, 0x26BF, prA}, // So SQUARED KEY
+ {0x26C0, 0x26C3, prN}, // So [4] WHITE DRAUGHTS MAN..BLACK DRAUGHTS KING
+ {0x26C4, 0x26C5, prW}, // So [2] SNOWMAN WITHOUT SNOW..SUN BEHIND CLOUD
+ {0x26C6, 0x26CD, prA}, // So [8] RAIN..DISABLED CAR
+ {0x26CE, 0x26CE, prW}, // So OPHIUCHUS
+ {0x26CF, 0x26D3, prA}, // So [5] PICK..CHAINS
+ {0x26D4, 0x26D4, prW}, // So NO ENTRY
+ {0x26D5, 0x26E1, prA}, // So [13] ALTERNATE ONE-WAY LEFT WAY TRAFFIC..RESTRICTED LEFT ENTRY-2
+ {0x26E2, 0x26E2, prN}, // So ASTRONOMICAL SYMBOL FOR URANUS
+ {0x26E3, 0x26E3, prA}, // So HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVE
+ {0x26E4, 0x26E7, prN}, // So [4] PENTAGRAM..INVERTED PENTAGRAM
+ {0x26E8, 0x26E9, prA}, // So [2] BLACK CROSS ON SHIELD..SHINTO SHRINE
+ {0x26EA, 0x26EA, prW}, // So CHURCH
+ {0x26EB, 0x26F1, prA}, // So [7] CASTLE..UMBRELLA ON GROUND
+ {0x26F2, 0x26F3, prW}, // So [2] FOUNTAIN..FLAG IN HOLE
+ {0x26F4, 0x26F4, prA}, // So FERRY
+ {0x26F5, 0x26F5, prW}, // So SAILBOAT
+ {0x26F6, 0x26F9, prA}, // So [4] SQUARE FOUR CORNERS..PERSON WITH BALL
+ {0x26FA, 0x26FA, prW}, // So TENT
+ {0x26FB, 0x26FC, prA}, // So [2] JAPANESE BANK SYMBOL..HEADSTONE GRAVEYARD SYMBOL
+ {0x26FD, 0x26FD, prW}, // So FUEL PUMP
+ {0x26FE, 0x26FF, prA}, // So [2] CUP ON BLACK SQUARE..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE
+ {0x2700, 0x2704, prN}, // So [5] BLACK SAFETY SCISSORS..WHITE SCISSORS
+ {0x2705, 0x2705, prW}, // So WHITE HEAVY CHECK MARK
+ {0x2706, 0x2709, prN}, // So [4] TELEPHONE LOCATION SIGN..ENVELOPE
+ {0x270A, 0x270B, prW}, // So [2] RAISED FIST..RAISED HAND
+ {0x270C, 0x2727, prN}, // So [28] VICTORY HAND..WHITE FOUR POINTED STAR
+ {0x2728, 0x2728, prW}, // So SPARKLES
+ {0x2729, 0x273C, prN}, // So [20] STRESS OUTLINED WHITE STAR..OPEN CENTRE TEARDROP-SPOKED ASTERISK
+ {0x273D, 0x273D, prA}, // So HEAVY TEARDROP-SPOKED ASTERISK
+ {0x273E, 0x274B, prN}, // So [14] SIX PETALLED BLACK AND WHITE FLORETTE..HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK
+ {0x274C, 0x274C, prW}, // So CROSS MARK
+ {0x274D, 0x274D, prN}, // So SHADOWED WHITE CIRCLE
+ {0x274E, 0x274E, prW}, // So NEGATIVE SQUARED CROSS MARK
+ {0x274F, 0x2752, prN}, // So [4] LOWER RIGHT DROP-SHADOWED WHITE SQUARE..UPPER RIGHT SHADOWED WHITE SQUARE
+ {0x2753, 0x2755, prW}, // So [3] BLACK QUESTION MARK ORNAMENT..WHITE EXCLAMATION MARK ORNAMENT
+ {0x2756, 0x2756, prN}, // So BLACK DIAMOND MINUS WHITE X
+ {0x2757, 0x2757, prW}, // So HEAVY EXCLAMATION MARK SYMBOL
+ {0x2758, 0x2767, prN}, // So [16] LIGHT VERTICAL BAR..ROTATED FLORAL HEART BULLET
+ {0x2768, 0x2768, prN}, // Ps MEDIUM LEFT PARENTHESIS ORNAMENT
+ {0x2769, 0x2769, prN}, // Pe MEDIUM RIGHT PARENTHESIS ORNAMENT
+ {0x276A, 0x276A, prN}, // Ps MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT
+ {0x276B, 0x276B, prN}, // Pe MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT
+ {0x276C, 0x276C, prN}, // Ps MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT
+ {0x276D, 0x276D, prN}, // Pe MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT
+ {0x276E, 0x276E, prN}, // Ps HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT
+ {0x276F, 0x276F, prN}, // Pe HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT
+ {0x2770, 0x2770, prN}, // Ps HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT
+ {0x2771, 0x2771, prN}, // Pe HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT
+ {0x2772, 0x2772, prN}, // Ps LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT
+ {0x2773, 0x2773, prN}, // Pe LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT
+ {0x2774, 0x2774, prN}, // Ps MEDIUM LEFT CURLY BRACKET ORNAMENT
+ {0x2775, 0x2775, prN}, // Pe MEDIUM RIGHT CURLY BRACKET ORNAMENT
+ {0x2776, 0x277F, prA}, // No [10] DINGBAT NEGATIVE CIRCLED DIGIT ONE..DINGBAT NEGATIVE CIRCLED NUMBER TEN
+ {0x2780, 0x2793, prN}, // No [20] DINGBAT CIRCLED SANS-SERIF DIGIT ONE..DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN
+ {0x2794, 0x2794, prN}, // So HEAVY WIDE-HEADED RIGHTWARDS ARROW
+ {0x2795, 0x2797, prW}, // So [3] HEAVY PLUS SIGN..HEAVY DIVISION SIGN
+ {0x2798, 0x27AF, prN}, // So [24] HEAVY SOUTH EAST ARROW..NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW
+ {0x27B0, 0x27B0, prW}, // So CURLY LOOP
+ {0x27B1, 0x27BE, prN}, // So [14] NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW..OPEN-OUTLINED RIGHTWARDS ARROW
+ {0x27BF, 0x27BF, prW}, // So DOUBLE CURLY LOOP
+ {0x27C0, 0x27C4, prN}, // Sm [5] THREE DIMENSIONAL ANGLE..OPEN SUPERSET
+ {0x27C5, 0x27C5, prN}, // Ps LEFT S-SHAPED BAG DELIMITER
+ {0x27C6, 0x27C6, prN}, // Pe RIGHT S-SHAPED BAG DELIMITER
+ {0x27C7, 0x27E5, prN}, // Sm [31] OR WITH DOT INSIDE..WHITE SQUARE WITH RIGHTWARDS TICK
+ {0x27E6, 0x27E6, prNa}, // Ps MATHEMATICAL LEFT WHITE SQUARE BRACKET
+ {0x27E7, 0x27E7, prNa}, // Pe MATHEMATICAL RIGHT WHITE SQUARE BRACKET
+ {0x27E8, 0x27E8, prNa}, // Ps MATHEMATICAL LEFT ANGLE BRACKET
+ {0x27E9, 0x27E9, prNa}, // Pe MATHEMATICAL RIGHT ANGLE BRACKET
+ {0x27EA, 0x27EA, prNa}, // Ps MATHEMATICAL LEFT DOUBLE ANGLE BRACKET
+ {0x27EB, 0x27EB, prNa}, // Pe MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET
+ {0x27EC, 0x27EC, prNa}, // Ps MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET
+ {0x27ED, 0x27ED, prNa}, // Pe MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET
+ {0x27EE, 0x27EE, prN}, // Ps MATHEMATICAL LEFT FLATTENED PARENTHESIS
+ {0x27EF, 0x27EF, prN}, // Pe MATHEMATICAL RIGHT FLATTENED PARENTHESIS
+ {0x27F0, 0x27FF, prN}, // Sm [16] UPWARDS QUADRUPLE ARROW..LONG RIGHTWARDS SQUIGGLE ARROW
+ {0x2800, 0x28FF, prN}, // So [256] BRAILLE PATTERN BLANK..BRAILLE PATTERN DOTS-12345678
+ {0x2900, 0x297F, prN}, // Sm [128] RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE..DOWN FISH TAIL
+ {0x2980, 0x2982, prN}, // Sm [3] TRIPLE VERTICAL BAR DELIMITER..Z NOTATION TYPE COLON
+ {0x2983, 0x2983, prN}, // Ps LEFT WHITE CURLY BRACKET
+ {0x2984, 0x2984, prN}, // Pe RIGHT WHITE CURLY BRACKET
+ {0x2985, 0x2985, prNa}, // Ps LEFT WHITE PARENTHESIS
+ {0x2986, 0x2986, prNa}, // Pe RIGHT WHITE PARENTHESIS
+ {0x2987, 0x2987, prN}, // Ps Z NOTATION LEFT IMAGE BRACKET
+ {0x2988, 0x2988, prN}, // Pe Z NOTATION RIGHT IMAGE BRACKET
+ {0x2989, 0x2989, prN}, // Ps Z NOTATION LEFT BINDING BRACKET
+ {0x298A, 0x298A, prN}, // Pe Z NOTATION RIGHT BINDING BRACKET
+ {0x298B, 0x298B, prN}, // Ps LEFT SQUARE BRACKET WITH UNDERBAR
+ {0x298C, 0x298C, prN}, // Pe RIGHT SQUARE BRACKET WITH UNDERBAR
+ {0x298D, 0x298D, prN}, // Ps LEFT SQUARE BRACKET WITH TICK IN TOP CORNER
+ {0x298E, 0x298E, prN}, // Pe RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+ {0x298F, 0x298F, prN}, // Ps LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+ {0x2990, 0x2990, prN}, // Pe RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER
+ {0x2991, 0x2991, prN}, // Ps LEFT ANGLE BRACKET WITH DOT
+ {0x2992, 0x2992, prN}, // Pe RIGHT ANGLE BRACKET WITH DOT
+ {0x2993, 0x2993, prN}, // Ps LEFT ARC LESS-THAN BRACKET
+ {0x2994, 0x2994, prN}, // Pe RIGHT ARC GREATER-THAN BRACKET
+ {0x2995, 0x2995, prN}, // Ps DOUBLE LEFT ARC GREATER-THAN BRACKET
+ {0x2996, 0x2996, prN}, // Pe DOUBLE RIGHT ARC LESS-THAN BRACKET
+ {0x2997, 0x2997, prN}, // Ps LEFT BLACK TORTOISE SHELL BRACKET
+ {0x2998, 0x2998, prN}, // Pe RIGHT BLACK TORTOISE SHELL BRACKET
+ {0x2999, 0x29D7, prN}, // Sm [63] DOTTED FENCE..BLACK HOURGLASS
+ {0x29D8, 0x29D8, prN}, // Ps LEFT WIGGLY FENCE
+ {0x29D9, 0x29D9, prN}, // Pe RIGHT WIGGLY FENCE
+ {0x29DA, 0x29DA, prN}, // Ps LEFT DOUBLE WIGGLY FENCE
+ {0x29DB, 0x29DB, prN}, // Pe RIGHT DOUBLE WIGGLY FENCE
+ {0x29DC, 0x29FB, prN}, // Sm [32] INCOMPLETE INFINITY..TRIPLE PLUS
+ {0x29FC, 0x29FC, prN}, // Ps LEFT-POINTING CURVED ANGLE BRACKET
+ {0x29FD, 0x29FD, prN}, // Pe RIGHT-POINTING CURVED ANGLE BRACKET
+ {0x29FE, 0x29FF, prN}, // Sm [2] TINY..MINY
+ {0x2A00, 0x2AFF, prN}, // Sm [256] N-ARY CIRCLED DOT OPERATOR..N-ARY WHITE VERTICAL BAR
+ {0x2B00, 0x2B1A, prN}, // So [27] NORTH EAST WHITE ARROW..DOTTED SQUARE
+ {0x2B1B, 0x2B1C, prW}, // So [2] BLACK LARGE SQUARE..WHITE LARGE SQUARE
+ {0x2B1D, 0x2B2F, prN}, // So [19] BLACK VERY SMALL SQUARE..WHITE VERTICAL ELLIPSE
+ {0x2B30, 0x2B44, prN}, // Sm [21] LEFT ARROW WITH SMALL CIRCLE..RIGHTWARDS ARROW THROUGH SUPERSET
+ {0x2B45, 0x2B46, prN}, // So [2] LEFTWARDS QUADRUPLE ARROW..RIGHTWARDS QUADRUPLE ARROW
+ {0x2B47, 0x2B4C, prN}, // Sm [6] REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR
+ {0x2B4D, 0x2B4F, prN}, // So [3] DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW..SHORT BACKSLANTED SOUTH ARROW
+ {0x2B50, 0x2B50, prW}, // So WHITE MEDIUM STAR
+ {0x2B51, 0x2B54, prN}, // So [4] BLACK SMALL STAR..WHITE RIGHT-POINTING PENTAGON
+ {0x2B55, 0x2B55, prW}, // So HEAVY LARGE CIRCLE
+ {0x2B56, 0x2B59, prA}, // So [4] HEAVY OVAL WITH OVAL INSIDE..HEAVY CIRCLED SALTIRE
+ {0x2B5A, 0x2B73, prN}, // So [26] SLANTED NORTH ARROW WITH HOOKED HEAD..DOWNWARDS TRIANGLE-HEADED ARROW TO BAR
+ {0x2B76, 0x2B95, prN}, // So [32] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW
+ {0x2B97, 0x2BFF, prN}, // So [105] SYMBOL FOR TYPE A ELECTRONICS..HELLSCHREIBER PAUSE SYMBOL
+ {0x2C00, 0x2C5F, prN}, // L& [96] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC SMALL LETTER CAUDATE CHRIVI
+ {0x2C60, 0x2C7B, prN}, // L& [28] LATIN CAPITAL LETTER L WITH DOUBLE BAR..LATIN LETTER SMALL CAPITAL TURNED E
+ {0x2C7C, 0x2C7D, prN}, // Lm [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V
+ {0x2C7E, 0x2C7F, prN}, // Lu [2] LATIN CAPITAL LETTER S WITH SWASH TAIL..LATIN CAPITAL LETTER Z WITH SWASH TAIL
+ {0x2C80, 0x2CE4, prN}, // L& [101] COPTIC CAPITAL LETTER ALFA..COPTIC SYMBOL KAI
+ {0x2CE5, 0x2CEA, prN}, // So [6] COPTIC SYMBOL MI RO..COPTIC SYMBOL SHIMA SIMA
+ {0x2CEB, 0x2CEE, prN}, // L& [4] COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI..COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA
+ {0x2CEF, 0x2CF1, prN}, // Mn [3] COPTIC COMBINING NI ABOVE..COPTIC COMBINING SPIRITUS LENIS
+ {0x2CF2, 0x2CF3, prN}, // L& [2] COPTIC CAPITAL LETTER BOHAIRIC KHEI..COPTIC SMALL LETTER BOHAIRIC KHEI
+ {0x2CF9, 0x2CFC, prN}, // Po [4] COPTIC OLD NUBIAN FULL STOP..COPTIC OLD NUBIAN VERSE DIVIDER
+ {0x2CFD, 0x2CFD, prN}, // No COPTIC FRACTION ONE HALF
+ {0x2CFE, 0x2CFF, prN}, // Po [2] COPTIC FULL STOP..COPTIC MORPHOLOGICAL DIVIDER
+ {0x2D00, 0x2D25, prN}, // Ll [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE
+ {0x2D27, 0x2D27, prN}, // Ll GEORGIAN SMALL LETTER YN
+ {0x2D2D, 0x2D2D, prN}, // Ll GEORGIAN SMALL LETTER AEN
+ {0x2D30, 0x2D67, prN}, // Lo [56] TIFINAGH LETTER YA..TIFINAGH LETTER YO
+ {0x2D6F, 0x2D6F, prN}, // Lm TIFINAGH MODIFIER LETTER LABIALIZATION MARK
+ {0x2D70, 0x2D70, prN}, // Po TIFINAGH SEPARATOR MARK
+ {0x2D7F, 0x2D7F, prN}, // Mn TIFINAGH CONSONANT JOINER
+ {0x2D80, 0x2D96, prN}, // Lo [23] ETHIOPIC SYLLABLE LOA..ETHIOPIC SYLLABLE GGWE
+ {0x2DA0, 0x2DA6, prN}, // Lo [7] ETHIOPIC SYLLABLE SSA..ETHIOPIC SYLLABLE SSO
+ {0x2DA8, 0x2DAE, prN}, // Lo [7] ETHIOPIC SYLLABLE CCA..ETHIOPIC SYLLABLE CCO
+ {0x2DB0, 0x2DB6, prN}, // Lo [7] ETHIOPIC SYLLABLE ZZA..ETHIOPIC SYLLABLE ZZO
+ {0x2DB8, 0x2DBE, prN}, // Lo [7] ETHIOPIC SYLLABLE CCHA..ETHIOPIC SYLLABLE CCHO
+ {0x2DC0, 0x2DC6, prN}, // Lo [7] ETHIOPIC SYLLABLE QYA..ETHIOPIC SYLLABLE QYO
+ {0x2DC8, 0x2DCE, prN}, // Lo [7] ETHIOPIC SYLLABLE KYA..ETHIOPIC SYLLABLE KYO
+ {0x2DD0, 0x2DD6, prN}, // Lo [7] ETHIOPIC SYLLABLE XYA..ETHIOPIC SYLLABLE XYO
+ {0x2DD8, 0x2DDE, prN}, // Lo [7] ETHIOPIC SYLLABLE GYA..ETHIOPIC SYLLABLE GYO
+ {0x2DE0, 0x2DFF, prN}, // Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS
+ {0x2E00, 0x2E01, prN}, // Po [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER
+ {0x2E02, 0x2E02, prN}, // Pi LEFT SUBSTITUTION BRACKET
+ {0x2E03, 0x2E03, prN}, // Pf RIGHT SUBSTITUTION BRACKET
+ {0x2E04, 0x2E04, prN}, // Pi LEFT DOTTED SUBSTITUTION BRACKET
+ {0x2E05, 0x2E05, prN}, // Pf RIGHT DOTTED SUBSTITUTION BRACKET
+ {0x2E06, 0x2E08, prN}, // Po [3] RAISED INTERPOLATION MARKER..DOTTED TRANSPOSITION MARKER
+ {0x2E09, 0x2E09, prN}, // Pi LEFT TRANSPOSITION BRACKET
+ {0x2E0A, 0x2E0A, prN}, // Pf RIGHT TRANSPOSITION BRACKET
+ {0x2E0B, 0x2E0B, prN}, // Po RAISED SQUARE
+ {0x2E0C, 0x2E0C, prN}, // Pi LEFT RAISED OMISSION BRACKET
+ {0x2E0D, 0x2E0D, prN}, // Pf RIGHT RAISED OMISSION BRACKET
+ {0x2E0E, 0x2E16, prN}, // Po [9] EDITORIAL CORONIS..DOTTED RIGHT-POINTING ANGLE
+ {0x2E17, 0x2E17, prN}, // Pd DOUBLE OBLIQUE HYPHEN
+ {0x2E18, 0x2E19, prN}, // Po [2] INVERTED INTERROBANG..PALM BRANCH
+ {0x2E1A, 0x2E1A, prN}, // Pd HYPHEN WITH DIAERESIS
+ {0x2E1B, 0x2E1B, prN}, // Po TILDE WITH RING ABOVE
+ {0x2E1C, 0x2E1C, prN}, // Pi LEFT LOW PARAPHRASE BRACKET
+ {0x2E1D, 0x2E1D, prN}, // Pf RIGHT LOW PARAPHRASE BRACKET
+ {0x2E1E, 0x2E1F, prN}, // Po [2] TILDE WITH DOT ABOVE..TILDE WITH DOT BELOW
+ {0x2E20, 0x2E20, prN}, // Pi LEFT VERTICAL BAR WITH QUILL
+ {0x2E21, 0x2E21, prN}, // Pf RIGHT VERTICAL BAR WITH QUILL
+ {0x2E22, 0x2E22, prN}, // Ps TOP LEFT HALF BRACKET
+ {0x2E23, 0x2E23, prN}, // Pe TOP RIGHT HALF BRACKET
+ {0x2E24, 0x2E24, prN}, // Ps BOTTOM LEFT HALF BRACKET
+ {0x2E25, 0x2E25, prN}, // Pe BOTTOM RIGHT HALF BRACKET
+ {0x2E26, 0x2E26, prN}, // Ps LEFT SIDEWAYS U BRACKET
+ {0x2E27, 0x2E27, prN}, // Pe RIGHT SIDEWAYS U BRACKET
+ {0x2E28, 0x2E28, prN}, // Ps LEFT DOUBLE PARENTHESIS
+ {0x2E29, 0x2E29, prN}, // Pe RIGHT DOUBLE PARENTHESIS
+ {0x2E2A, 0x2E2E, prN}, // Po [5] TWO DOTS OVER ONE DOT PUNCTUATION..REVERSED QUESTION MARK
+ {0x2E2F, 0x2E2F, prN}, // Lm VERTICAL TILDE
+ {0x2E30, 0x2E39, prN}, // Po [10] RING POINT..TOP HALF SECTION SIGN
+ {0x2E3A, 0x2E3B, prN}, // Pd [2] TWO-EM DASH..THREE-EM DASH
+ {0x2E3C, 0x2E3F, prN}, // Po [4] STENOGRAPHIC FULL STOP..CAPITULUM
+ {0x2E40, 0x2E40, prN}, // Pd DOUBLE HYPHEN
+ {0x2E41, 0x2E41, prN}, // Po REVERSED COMMA
+ {0x2E42, 0x2E42, prN}, // Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK
+ {0x2E43, 0x2E4F, prN}, // Po [13] DASH WITH LEFT UPTURN..CORNISH VERSE DIVIDER
+ {0x2E50, 0x2E51, prN}, // So [2] CROSS PATTY WITH RIGHT CROSSBAR..CROSS PATTY WITH LEFT CROSSBAR
+ {0x2E52, 0x2E54, prN}, // Po [3] TIRONIAN SIGN CAPITAL ET..MEDIEVAL QUESTION MARK
+ {0x2E55, 0x2E55, prN}, // Ps LEFT SQUARE BRACKET WITH STROKE
+ {0x2E56, 0x2E56, prN}, // Pe RIGHT SQUARE BRACKET WITH STROKE
+ {0x2E57, 0x2E57, prN}, // Ps LEFT SQUARE BRACKET WITH DOUBLE STROKE
+ {0x2E58, 0x2E58, prN}, // Pe RIGHT SQUARE BRACKET WITH DOUBLE STROKE
+ {0x2E59, 0x2E59, prN}, // Ps TOP HALF LEFT PARENTHESIS
+ {0x2E5A, 0x2E5A, prN}, // Pe TOP HALF RIGHT PARENTHESIS
+ {0x2E5B, 0x2E5B, prN}, // Ps BOTTOM HALF LEFT PARENTHESIS
+ {0x2E5C, 0x2E5C, prN}, // Pe BOTTOM HALF RIGHT PARENTHESIS
+ {0x2E5D, 0x2E5D, prN}, // Pd OBLIQUE HYPHEN
+ {0x2E80, 0x2E99, prW}, // So [26] CJK RADICAL REPEAT..CJK RADICAL RAP
+ {0x2E9B, 0x2EF3, prW}, // So [89] CJK RADICAL CHOKE..CJK RADICAL C-SIMPLIFIED TURTLE
+ {0x2F00, 0x2FD5, prW}, // So [214] KANGXI RADICAL ONE..KANGXI RADICAL FLUTE
+ {0x2FF0, 0x2FFB, prW}, // So [12] IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID
+ {0x3000, 0x3000, prF}, // Zs IDEOGRAPHIC SPACE
+ {0x3001, 0x3003, prW}, // Po [3] IDEOGRAPHIC COMMA..DITTO MARK
+ {0x3004, 0x3004, prW}, // So JAPANESE INDUSTRIAL STANDARD SYMBOL
+ {0x3005, 0x3005, prW}, // Lm IDEOGRAPHIC ITERATION MARK
+ {0x3006, 0x3006, prW}, // Lo IDEOGRAPHIC CLOSING MARK
+ {0x3007, 0x3007, prW}, // Nl IDEOGRAPHIC NUMBER ZERO
+ {0x3008, 0x3008, prW}, // Ps LEFT ANGLE BRACKET
+ {0x3009, 0x3009, prW}, // Pe RIGHT ANGLE BRACKET
+ {0x300A, 0x300A, prW}, // Ps LEFT DOUBLE ANGLE BRACKET
+ {0x300B, 0x300B, prW}, // Pe RIGHT DOUBLE ANGLE BRACKET
+ {0x300C, 0x300C, prW}, // Ps LEFT CORNER BRACKET
+ {0x300D, 0x300D, prW}, // Pe RIGHT CORNER BRACKET
+ {0x300E, 0x300E, prW}, // Ps LEFT WHITE CORNER BRACKET
+ {0x300F, 0x300F, prW}, // Pe RIGHT WHITE CORNER BRACKET
+ {0x3010, 0x3010, prW}, // Ps LEFT BLACK LENTICULAR BRACKET
+ {0x3011, 0x3011, prW}, // Pe RIGHT BLACK LENTICULAR BRACKET
+ {0x3012, 0x3013, prW}, // So [2] POSTAL MARK..GETA MARK
+ {0x3014, 0x3014, prW}, // Ps LEFT TORTOISE SHELL BRACKET
+ {0x3015, 0x3015, prW}, // Pe RIGHT TORTOISE SHELL BRACKET
+ {0x3016, 0x3016, prW}, // Ps LEFT WHITE LENTICULAR BRACKET
+ {0x3017, 0x3017, prW}, // Pe RIGHT WHITE LENTICULAR BRACKET
+ {0x3018, 0x3018, prW}, // Ps LEFT WHITE TORTOISE SHELL BRACKET
+ {0x3019, 0x3019, prW}, // Pe RIGHT WHITE TORTOISE SHELL BRACKET
+ {0x301A, 0x301A, prW}, // Ps LEFT WHITE SQUARE BRACKET
+ {0x301B, 0x301B, prW}, // Pe RIGHT WHITE SQUARE BRACKET
+ {0x301C, 0x301C, prW}, // Pd WAVE DASH
+ {0x301D, 0x301D, prW}, // Ps REVERSED DOUBLE PRIME QUOTATION MARK
+ {0x301E, 0x301F, prW}, // Pe [2] DOUBLE PRIME QUOTATION MARK..LOW DOUBLE PRIME QUOTATION MARK
+ {0x3020, 0x3020, prW}, // So POSTAL MARK FACE
+ {0x3021, 0x3029, prW}, // Nl [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE
+ {0x302A, 0x302D, prW}, // Mn [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK
+ {0x302E, 0x302F, prW}, // Mc [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK
+ {0x3030, 0x3030, prW}, // Pd WAVY DASH
+ {0x3031, 0x3035, prW}, // Lm [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF
+ {0x3036, 0x3037, prW}, // So [2] CIRCLED POSTAL MARK..IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL
+ {0x3038, 0x303A, prW}, // Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY
+ {0x303B, 0x303B, prW}, // Lm VERTICAL IDEOGRAPHIC ITERATION MARK
+ {0x303C, 0x303C, prW}, // Lo MASU MARK
+ {0x303D, 0x303D, prW}, // Po PART ALTERNATION MARK
+ {0x303E, 0x303E, prW}, // So IDEOGRAPHIC VARIATION INDICATOR
+ {0x303F, 0x303F, prN}, // So IDEOGRAPHIC HALF FILL SPACE
+ {0x3041, 0x3096, prW}, // Lo [86] HIRAGANA LETTER SMALL A..HIRAGANA LETTER SMALL KE
+ {0x3099, 0x309A, prW}, // Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+ {0x309B, 0x309C, prW}, // Sk [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+ {0x309D, 0x309E, prW}, // Lm [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK
+ {0x309F, 0x309F, prW}, // Lo HIRAGANA DIGRAPH YORI
+ {0x30A0, 0x30A0, prW}, // Pd KATAKANA-HIRAGANA DOUBLE HYPHEN
+ {0x30A1, 0x30FA, prW}, // Lo [90] KATAKANA LETTER SMALL A..KATAKANA LETTER VO
+ {0x30FB, 0x30FB, prW}, // Po KATAKANA MIDDLE DOT
+ {0x30FC, 0x30FE, prW}, // Lm [3] KATAKANA-HIRAGANA PROLONGED SOUND MARK..KATAKANA VOICED ITERATION MARK
+ {0x30FF, 0x30FF, prW}, // Lo KATAKANA DIGRAPH KOTO
+ {0x3105, 0x312F, prW}, // Lo [43] BOPOMOFO LETTER B..BOPOMOFO LETTER NN
+ {0x3131, 0x318E, prW}, // Lo [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE
+ {0x3190, 0x3191, prW}, // So [2] IDEOGRAPHIC ANNOTATION LINKING MARK..IDEOGRAPHIC ANNOTATION REVERSE MARK
+ {0x3192, 0x3195, prW}, // No [4] IDEOGRAPHIC ANNOTATION ONE MARK..IDEOGRAPHIC ANNOTATION FOUR MARK
+ {0x3196, 0x319F, prW}, // So [10] IDEOGRAPHIC ANNOTATION TOP MARK..IDEOGRAPHIC ANNOTATION MAN MARK
+ {0x31A0, 0x31BF, prW}, // Lo [32] BOPOMOFO LETTER BU..BOPOMOFO LETTER AH
+ {0x31C0, 0x31E3, prW}, // So [36] CJK STROKE T..CJK STROKE Q
+ {0x31F0, 0x31FF, prW}, // Lo [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO
+ {0x3200, 0x321E, prW}, // So [31] PARENTHESIZED HANGUL KIYEOK..PARENTHESIZED KOREAN CHARACTER O HU
+ {0x3220, 0x3229, prW}, // No [10] PARENTHESIZED IDEOGRAPH ONE..PARENTHESIZED IDEOGRAPH TEN
+ {0x322A, 0x3247, prW}, // So [30] PARENTHESIZED IDEOGRAPH MOON..CIRCLED IDEOGRAPH KOTO
+ {0x3248, 0x324F, prA}, // No [8] CIRCLED NUMBER TEN ON BLACK SQUARE..CIRCLED NUMBER EIGHTY ON BLACK SQUARE
+ {0x3250, 0x3250, prW}, // So PARTNERSHIP SIGN
+ {0x3251, 0x325F, prW}, // No [15] CIRCLED NUMBER TWENTY ONE..CIRCLED NUMBER THIRTY FIVE
+ {0x3260, 0x327F, prW}, // So [32] CIRCLED HANGUL KIYEOK..KOREAN STANDARD SYMBOL
+ {0x3280, 0x3289, prW}, // No [10] CIRCLED IDEOGRAPH ONE..CIRCLED IDEOGRAPH TEN
+ {0x328A, 0x32B0, prW}, // So [39] CIRCLED IDEOGRAPH MOON..CIRCLED IDEOGRAPH NIGHT
+ {0x32B1, 0x32BF, prW}, // No [15] CIRCLED NUMBER THIRTY SIX..CIRCLED NUMBER FIFTY
+ {0x32C0, 0x32FF, prW}, // So [64] IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY..SQUARE ERA NAME REIWA
+ {0x3300, 0x33FF, prW}, // So [256] SQUARE APAATO..SQUARE GAL
+ {0x3400, 0x4DBF, prW}, // Lo [6592] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DBF
+ {0x4DC0, 0x4DFF, prN}, // So [64] HEXAGRAM FOR THE CREATIVE HEAVEN..HEXAGRAM FOR BEFORE COMPLETION
+ {0x4E00, 0x9FFF, prW}, // Lo [20992] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FFF
+ {0xA000, 0xA014, prW}, // Lo [21] YI SYLLABLE IT..YI SYLLABLE E
+ {0xA015, 0xA015, prW}, // Lm YI SYLLABLE WU
+ {0xA016, 0xA48C, prW}, // Lo [1143] YI SYLLABLE BIT..YI SYLLABLE YYR
+ {0xA490, 0xA4C6, prW}, // So [55] YI RADICAL QOT..YI RADICAL KE
+ {0xA4D0, 0xA4F7, prN}, // Lo [40] LISU LETTER BA..LISU LETTER OE
+ {0xA4F8, 0xA4FD, prN}, // Lm [6] LISU LETTER TONE MYA TI..LISU LETTER TONE MYA JEU
+ {0xA4FE, 0xA4FF, prN}, // Po [2] LISU PUNCTUATION COMMA..LISU PUNCTUATION FULL STOP
+ {0xA500, 0xA60B, prN}, // Lo [268] VAI SYLLABLE EE..VAI SYLLABLE NG
+ {0xA60C, 0xA60C, prN}, // Lm VAI SYLLABLE LENGTHENER
+ {0xA60D, 0xA60F, prN}, // Po [3] VAI COMMA..VAI QUESTION MARK
+ {0xA610, 0xA61F, prN}, // Lo [16] VAI SYLLABLE NDOLE FA..VAI SYMBOL JONG
+ {0xA620, 0xA629, prN}, // Nd [10] VAI DIGIT ZERO..VAI DIGIT NINE
+ {0xA62A, 0xA62B, prN}, // Lo [2] VAI SYLLABLE NDOLE MA..VAI SYLLABLE NDOLE DO
+ {0xA640, 0xA66D, prN}, // L& [46] CYRILLIC CAPITAL LETTER ZEMLYA..CYRILLIC SMALL LETTER DOUBLE MONOCULAR O
+ {0xA66E, 0xA66E, prN}, // Lo CYRILLIC LETTER MULTIOCULAR O
+ {0xA66F, 0xA66F, prN}, // Mn COMBINING CYRILLIC VZMET
+ {0xA670, 0xA672, prN}, // Me [3] COMBINING CYRILLIC TEN MILLIONS SIGN..COMBINING CYRILLIC THOUSAND MILLIONS SIGN
+ {0xA673, 0xA673, prN}, // Po SLAVONIC ASTERISK
+ {0xA674, 0xA67D, prN}, // Mn [10] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC PAYEROK
+ {0xA67E, 0xA67E, prN}, // Po CYRILLIC KAVYKA
+ {0xA67F, 0xA67F, prN}, // Lm CYRILLIC PAYEROK
+ {0xA680, 0xA69B, prN}, // L& [28] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER CROSSED O
+ {0xA69C, 0xA69D, prN}, // Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN
+ {0xA69E, 0xA69F, prN}, // Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E
+ {0xA6A0, 0xA6E5, prN}, // Lo [70] BAMUM LETTER A..BAMUM LETTER KI
+ {0xA6E6, 0xA6EF, prN}, // Nl [10] BAMUM LETTER MO..BAMUM LETTER KOGHOM
+ {0xA6F0, 0xA6F1, prN}, // Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS
+ {0xA6F2, 0xA6F7, prN}, // Po [6] BAMUM NJAEMLI..BAMUM QUESTION MARK
+ {0xA700, 0xA716, prN}, // Sk [23] MODIFIER LETTER CHINESE TONE YIN PING..MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR
+ {0xA717, 0xA71F, prN}, // Lm [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK
+ {0xA720, 0xA721, prN}, // Sk [2] MODIFIER LETTER STRESS AND HIGH TONE..MODIFIER LETTER STRESS AND LOW TONE
+ {0xA722, 0xA76F, prN}, // L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN SMALL LETTER CON
+ {0xA770, 0xA770, prN}, // Lm MODIFIER LETTER US
+ {0xA771, 0xA787, prN}, // L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T
+ {0xA788, 0xA788, prN}, // Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT
+ {0xA789, 0xA78A, prN}, // Sk [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN
+ {0xA78B, 0xA78E, prN}, // L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT
+ {0xA78F, 0xA78F, prN}, // Lo LATIN LETTER SINOLOGICAL DOT
+ {0xA790, 0xA7CA, prN}, // L& [59] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY
+ {0xA7D0, 0xA7D1, prN}, // L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G
+ {0xA7D3, 0xA7D3, prN}, // Ll LATIN SMALL LETTER DOUBLE THORN
+ {0xA7D5, 0xA7D9, prN}, // L& [5] LATIN SMALL LETTER DOUBLE WYNN..LATIN SMALL LETTER SIGMOID S
+ {0xA7F2, 0xA7F4, prN}, // Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q
+ {0xA7F5, 0xA7F6, prN}, // L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H
+ {0xA7F7, 0xA7F7, prN}, // Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I
+ {0xA7F8, 0xA7F9, prN}, // Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE
+ {0xA7FA, 0xA7FA, prN}, // Ll LATIN LETTER SMALL CAPITAL TURNED M
+ {0xA7FB, 0xA7FF, prN}, // Lo [5] LATIN EPIGRAPHIC LETTER REVERSED F..LATIN EPIGRAPHIC LETTER ARCHAIC M
+ {0xA800, 0xA801, prN}, // Lo [2] SYLOTI NAGRI LETTER A..SYLOTI NAGRI LETTER I
+ {0xA802, 0xA802, prN}, // Mn SYLOTI NAGRI SIGN DVISVARA
+ {0xA803, 0xA805, prN}, // Lo [3] SYLOTI NAGRI LETTER U..SYLOTI NAGRI LETTER O
+ {0xA806, 0xA806, prN}, // Mn SYLOTI NAGRI SIGN HASANTA
+ {0xA807, 0xA80A, prN}, // Lo [4] SYLOTI NAGRI LETTER KO..SYLOTI NAGRI LETTER GHO
+ {0xA80B, 0xA80B, prN}, // Mn SYLOTI NAGRI SIGN ANUSVARA
+ {0xA80C, 0xA822, prN}, // Lo [23] SYLOTI NAGRI LETTER CO..SYLOTI NAGRI LETTER HO
+ {0xA823, 0xA824, prN}, // Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I
+ {0xA825, 0xA826, prN}, // Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E
+ {0xA827, 0xA827, prN}, // Mc SYLOTI NAGRI VOWEL SIGN OO
+ {0xA828, 0xA82B, prN}, // So [4] SYLOTI NAGRI POETRY MARK-1..SYLOTI NAGRI POETRY MARK-4
+ {0xA82C, 0xA82C, prN}, // Mn SYLOTI NAGRI SIGN ALTERNATE HASANTA
+ {0xA830, 0xA835, prN}, // No [6] NORTH INDIC FRACTION ONE QUARTER..NORTH INDIC FRACTION THREE SIXTEENTHS
+ {0xA836, 0xA837, prN}, // So [2] NORTH INDIC QUARTER MARK..NORTH INDIC PLACEHOLDER MARK
+ {0xA838, 0xA838, prN}, // Sc NORTH INDIC RUPEE MARK
+ {0xA839, 0xA839, prN}, // So NORTH INDIC QUANTITY MARK
+ {0xA840, 0xA873, prN}, // Lo [52] PHAGS-PA LETTER KA..PHAGS-PA LETTER CANDRABINDU
+ {0xA874, 0xA877, prN}, // Po [4] PHAGS-PA SINGLE HEAD MARK..PHAGS-PA MARK DOUBLE SHAD
+ {0xA880, 0xA881, prN}, // Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA
+ {0xA882, 0xA8B3, prN}, // Lo [50] SAURASHTRA LETTER A..SAURASHTRA LETTER LLA
+ {0xA8B4, 0xA8C3, prN}, // Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU
+ {0xA8C4, 0xA8C5, prN}, // Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU
+ {0xA8CE, 0xA8CF, prN}, // Po [2] SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA
+ {0xA8D0, 0xA8D9, prN}, // Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE
+ {0xA8E0, 0xA8F1, prN}, // Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA
+ {0xA8F2, 0xA8F7, prN}, // Lo [6] DEVANAGARI SIGN SPACING CANDRABINDU..DEVANAGARI SIGN CANDRABINDU AVAGRAHA
+ {0xA8F8, 0xA8FA, prN}, // Po [3] DEVANAGARI SIGN PUSHPIKA..DEVANAGARI CARET
+ {0xA8FB, 0xA8FB, prN}, // Lo DEVANAGARI HEADSTROKE
+ {0xA8FC, 0xA8FC, prN}, // Po DEVANAGARI SIGN SIDDHAM
+ {0xA8FD, 0xA8FE, prN}, // Lo [2] DEVANAGARI JAIN OM..DEVANAGARI LETTER AY
+ {0xA8FF, 0xA8FF, prN}, // Mn DEVANAGARI VOWEL SIGN AY
+ {0xA900, 0xA909, prN}, // Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE
+ {0xA90A, 0xA925, prN}, // Lo [28] KAYAH LI LETTER KA..KAYAH LI LETTER OO
+ {0xA926, 0xA92D, prN}, // Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU
+ {0xA92E, 0xA92F, prN}, // Po [2] KAYAH LI SIGN CWI..KAYAH LI SIGN SHYA
+ {0xA930, 0xA946, prN}, // Lo [23] REJANG LETTER KA..REJANG LETTER A
+ {0xA947, 0xA951, prN}, // Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R
+ {0xA952, 0xA953, prN}, // Mc [2] REJANG CONSONANT SIGN H..REJANG VIRAMA
+ {0xA95F, 0xA95F, prN}, // Po REJANG SECTION MARK
+ {0xA960, 0xA97C, prW}, // Lo [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANGYEORINHIEUH
+ {0xA980, 0xA982, prN}, // Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR
+ {0xA983, 0xA983, prN}, // Mc JAVANESE SIGN WIGNYAN
+ {0xA984, 0xA9B2, prN}, // Lo [47] JAVANESE LETTER A..JAVANESE LETTER HA
+ {0xA9B3, 0xA9B3, prN}, // Mn JAVANESE SIGN CECAK TELU
+ {0xA9B4, 0xA9B5, prN}, // Mc [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN TOLONG
+ {0xA9B6, 0xA9B9, prN}, // Mn [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT
+ {0xA9BA, 0xA9BB, prN}, // Mc [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE
+ {0xA9BC, 0xA9BD, prN}, // Mn [2] JAVANESE VOWEL SIGN PEPET..JAVANESE CONSONANT SIGN KERET
+ {0xA9BE, 0xA9C0, prN}, // Mc [3] JAVANESE CONSONANT SIGN PENGKAL..JAVANESE PANGKON
+ {0xA9C1, 0xA9CD, prN}, // Po [13] JAVANESE LEFT RERENGGAN..JAVANESE TURNED PADA PISELEH
+ {0xA9CF, 0xA9CF, prN}, // Lm JAVANESE PANGRANGKEP
+ {0xA9D0, 0xA9D9, prN}, // Nd [10] JAVANESE DIGIT ZERO..JAVANESE DIGIT NINE
+ {0xA9DE, 0xA9DF, prN}, // Po [2] JAVANESE PADA TIRTA TUMETES..JAVANESE PADA ISEN-ISEN
+ {0xA9E0, 0xA9E4, prN}, // Lo [5] MYANMAR LETTER SHAN GHA..MYANMAR LETTER SHAN BHA
+ {0xA9E5, 0xA9E5, prN}, // Mn MYANMAR SIGN SHAN SAW
+ {0xA9E6, 0xA9E6, prN}, // Lm MYANMAR MODIFIER LETTER SHAN REDUPLICATION
+ {0xA9E7, 0xA9EF, prN}, // Lo [9] MYANMAR LETTER TAI LAING NYA..MYANMAR LETTER TAI LAING NNA
+ {0xA9F0, 0xA9F9, prN}, // Nd [10] MYANMAR TAI LAING DIGIT ZERO..MYANMAR TAI LAING DIGIT NINE
+ {0xA9FA, 0xA9FE, prN}, // Lo [5] MYANMAR LETTER TAI LAING LLA..MYANMAR LETTER TAI LAING BHA
+ {0xAA00, 0xAA28, prN}, // Lo [41] CHAM LETTER A..CHAM LETTER HA
+ {0xAA29, 0xAA2E, prN}, // Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE
+ {0xAA2F, 0xAA30, prN}, // Mc [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI
+ {0xAA31, 0xAA32, prN}, // Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE
+ {0xAA33, 0xAA34, prN}, // Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA
+ {0xAA35, 0xAA36, prN}, // Mn [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA
+ {0xAA40, 0xAA42, prN}, // Lo [3] CHAM LETTER FINAL K..CHAM LETTER FINAL NG
+ {0xAA43, 0xAA43, prN}, // Mn CHAM CONSONANT SIGN FINAL NG
+ {0xAA44, 0xAA4B, prN}, // Lo [8] CHAM LETTER FINAL CH..CHAM LETTER FINAL SS
+ {0xAA4C, 0xAA4C, prN}, // Mn CHAM CONSONANT SIGN FINAL M
+ {0xAA4D, 0xAA4D, prN}, // Mc CHAM CONSONANT SIGN FINAL H
+ {0xAA50, 0xAA59, prN}, // Nd [10] CHAM DIGIT ZERO..CHAM DIGIT NINE
+ {0xAA5C, 0xAA5F, prN}, // Po [4] CHAM PUNCTUATION SPIRAL..CHAM PUNCTUATION TRIPLE DANDA
+ {0xAA60, 0xAA6F, prN}, // Lo [16] MYANMAR LETTER KHAMTI GA..MYANMAR LETTER KHAMTI FA
+ {0xAA70, 0xAA70, prN}, // Lm MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION
+ {0xAA71, 0xAA76, prN}, // Lo [6] MYANMAR LETTER KHAMTI XA..MYANMAR LOGOGRAM KHAMTI HM
+ {0xAA77, 0xAA79, prN}, // So [3] MYANMAR SYMBOL AITON EXCLAMATION..MYANMAR SYMBOL AITON TWO
+ {0xAA7A, 0xAA7A, prN}, // Lo MYANMAR LETTER AITON RA
+ {0xAA7B, 0xAA7B, prN}, // Mc MYANMAR SIGN PAO KAREN TONE
+ {0xAA7C, 0xAA7C, prN}, // Mn MYANMAR SIGN TAI LAING TONE-2
+ {0xAA7D, 0xAA7D, prN}, // Mc MYANMAR SIGN TAI LAING TONE-5
+ {0xAA7E, 0xAA7F, prN}, // Lo [2] MYANMAR LETTER SHWE PALAUNG CHA..MYANMAR LETTER SHWE PALAUNG SHA
+ {0xAA80, 0xAAAF, prN}, // Lo [48] TAI VIET LETTER LOW KO..TAI VIET LETTER HIGH O
+ {0xAAB0, 0xAAB0, prN}, // Mn TAI VIET MAI KANG
+ {0xAAB1, 0xAAB1, prN}, // Lo TAI VIET VOWEL AA
+ {0xAAB2, 0xAAB4, prN}, // Mn [3] TAI VIET VOWEL I..TAI VIET VOWEL U
+ {0xAAB5, 0xAAB6, prN}, // Lo [2] TAI VIET VOWEL E..TAI VIET VOWEL O
+ {0xAAB7, 0xAAB8, prN}, // Mn [2] TAI VIET MAI KHIT..TAI VIET VOWEL IA
+ {0xAAB9, 0xAABD, prN}, // Lo [5] TAI VIET VOWEL UEA..TAI VIET VOWEL AN
+ {0xAABE, 0xAABF, prN}, // Mn [2] TAI VIET VOWEL AM..TAI VIET TONE MAI EK
+ {0xAAC0, 0xAAC0, prN}, // Lo TAI VIET TONE MAI NUENG
+ {0xAAC1, 0xAAC1, prN}, // Mn TAI VIET TONE MAI THO
+ {0xAAC2, 0xAAC2, prN}, // Lo TAI VIET TONE MAI SONG
+ {0xAADB, 0xAADC, prN}, // Lo [2] TAI VIET SYMBOL KON..TAI VIET SYMBOL NUENG
+ {0xAADD, 0xAADD, prN}, // Lm TAI VIET SYMBOL SAM
+ {0xAADE, 0xAADF, prN}, // Po [2] TAI VIET SYMBOL HO HOI..TAI VIET SYMBOL KOI KOI
+ {0xAAE0, 0xAAEA, prN}, // Lo [11] MEETEI MAYEK LETTER E..MEETEI MAYEK LETTER SSA
+ {0xAAEB, 0xAAEB, prN}, // Mc MEETEI MAYEK VOWEL SIGN II
+ {0xAAEC, 0xAAED, prN}, // Mn [2] MEETEI MAYEK VOWEL SIGN UU..MEETEI MAYEK VOWEL SIGN AAI
+ {0xAAEE, 0xAAEF, prN}, // Mc [2] MEETEI MAYEK VOWEL SIGN AU..MEETEI MAYEK VOWEL SIGN AAU
+ {0xAAF0, 0xAAF1, prN}, // Po [2] MEETEI MAYEK CHEIKHAN..MEETEI MAYEK AHANG KHUDAM
+ {0xAAF2, 0xAAF2, prN}, // Lo MEETEI MAYEK ANJI
+ {0xAAF3, 0xAAF4, prN}, // Lm [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETEI MAYEK WORD REPETITION MARK
+ {0xAAF5, 0xAAF5, prN}, // Mc MEETEI MAYEK VOWEL SIGN VISARGA
+ {0xAAF6, 0xAAF6, prN}, // Mn MEETEI MAYEK VIRAMA
+ {0xAB01, 0xAB06, prN}, // Lo [6] ETHIOPIC SYLLABLE TTHU..ETHIOPIC SYLLABLE TTHO
+ {0xAB09, 0xAB0E, prN}, // Lo [6] ETHIOPIC SYLLABLE DDHU..ETHIOPIC SYLLABLE DDHO
+ {0xAB11, 0xAB16, prN}, // Lo [6] ETHIOPIC SYLLABLE DZU..ETHIOPIC SYLLABLE DZO
+ {0xAB20, 0xAB26, prN}, // Lo [7] ETHIOPIC SYLLABLE CCHHA..ETHIOPIC SYLLABLE CCHHO
+ {0xAB28, 0xAB2E, prN}, // Lo [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO
+ {0xAB30, 0xAB5A, prN}, // Ll [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG
+ {0xAB5B, 0xAB5B, prN}, // Sk MODIFIER BREVE WITH INVERTED BREVE
+ {0xAB5C, 0xAB5F, prN}, // Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK
+ {0xAB60, 0xAB68, prN}, // Ll [9] LATIN SMALL LETTER SAKHA YAT..LATIN SMALL LETTER TURNED R WITH MIDDLE TILDE
+ {0xAB69, 0xAB69, prN}, // Lm MODIFIER LETTER SMALL TURNED W
+ {0xAB6A, 0xAB6B, prN}, // Sk [2] MODIFIER LETTER LEFT TACK..MODIFIER LETTER RIGHT TACK
+ {0xAB70, 0xABBF, prN}, // Ll [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA
+ {0xABC0, 0xABE2, prN}, // Lo [35] MEETEI MAYEK LETTER KOK..MEETEI MAYEK LETTER I LONSUM
+ {0xABE3, 0xABE4, prN}, // Mc [2] MEETEI MAYEK VOWEL SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP
+ {0xABE5, 0xABE5, prN}, // Mn MEETEI MAYEK VOWEL SIGN ANAP
+ {0xABE6, 0xABE7, prN}, // Mc [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETEI MAYEK VOWEL SIGN SOUNAP
+ {0xABE8, 0xABE8, prN}, // Mn MEETEI MAYEK VOWEL SIGN UNAP
+ {0xABE9, 0xABEA, prN}, // Mc [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG
+ {0xABEB, 0xABEB, prN}, // Po MEETEI MAYEK CHEIKHEI
+ {0xABEC, 0xABEC, prN}, // Mc MEETEI MAYEK LUM IYEK
+ {0xABED, 0xABED, prN}, // Mn MEETEI MAYEK APUN IYEK
+ {0xABF0, 0xABF9, prN}, // Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DIGIT NINE
+ {0xAC00, 0xD7A3, prW}, // Lo [11172] HANGUL SYLLABLE GA..HANGUL SYLLABLE HIH
+ {0xD7B0, 0xD7C6, prN}, // Lo [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E
+ {0xD7CB, 0xD7FB, prN}, // Lo [49] HANGUL JONGSEONG NIEUN-RIEUL..HANGUL JONGSEONG PHIEUPH-THIEUTH
+ {0xD800, 0xDB7F, prN}, // Cs [896] ..
+ {0xDB80, 0xDBFF, prN}, // Cs [128] ..
+ {0xDC00, 0xDFFF, prN}, // Cs [1024] ..
+ {0xE000, 0xF8FF, prA}, // Co [6400] ..
+ {0xF900, 0xFA6D, prW}, // Lo [366] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA6D
+ {0xFA6E, 0xFA6F, prW}, // Cn [2] ..
+ {0xFA70, 0xFAD9, prW}, // Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9
+ {0xFADA, 0xFAFF, prW}, // Cn [38] ..
+ {0xFB00, 0xFB06, prN}, // Ll [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST
+ {0xFB13, 0xFB17, prN}, // Ll [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH
+ {0xFB1D, 0xFB1D, prN}, // Lo HEBREW LETTER YOD WITH HIRIQ
+ {0xFB1E, 0xFB1E, prN}, // Mn HEBREW POINT JUDEO-SPANISH VARIKA
+ {0xFB1F, 0xFB28, prN}, // Lo [10] HEBREW LIGATURE YIDDISH YOD YOD PATAH..HEBREW LETTER WIDE TAV
+ {0xFB29, 0xFB29, prN}, // Sm HEBREW LETTER ALTERNATIVE PLUS SIGN
+ {0xFB2A, 0xFB36, prN}, // Lo [13] HEBREW LETTER SHIN WITH SHIN DOT..HEBREW LETTER ZAYIN WITH DAGESH
+ {0xFB38, 0xFB3C, prN}, // Lo [5] HEBREW LETTER TET WITH DAGESH..HEBREW LETTER LAMED WITH DAGESH
+ {0xFB3E, 0xFB3E, prN}, // Lo HEBREW LETTER MEM WITH DAGESH
+ {0xFB40, 0xFB41, prN}, // Lo [2] HEBREW LETTER NUN WITH DAGESH..HEBREW LETTER SAMEKH WITH DAGESH
+ {0xFB43, 0xFB44, prN}, // Lo [2] HEBREW LETTER FINAL PE WITH DAGESH..HEBREW LETTER PE WITH DAGESH
+ {0xFB46, 0xFB4F, prN}, // Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW LIGATURE ALEF LAMED
+ {0xFB50, 0xFBB1, prN}, // Lo [98] ARABIC LETTER ALEF WASLA ISOLATED FORM..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM
+ {0xFBB2, 0xFBC2, prN}, // Sk [17] ARABIC SYMBOL DOT ABOVE..ARABIC SYMBOL WASLA ABOVE
+ {0xFBD3, 0xFD3D, prN}, // Lo [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM
+ {0xFD3E, 0xFD3E, prN}, // Pe ORNATE LEFT PARENTHESIS
+ {0xFD3F, 0xFD3F, prN}, // Ps ORNATE RIGHT PARENTHESIS
+ {0xFD40, 0xFD4F, prN}, // So [16] ARABIC LIGATURE RAHIMAHU ALLAAH..ARABIC LIGATURE RAHIMAHUM ALLAAH
+ {0xFD50, 0xFD8F, prN}, // Lo [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM..ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM
+ {0xFD92, 0xFDC7, prN}, // Lo [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM
+ {0xFDCF, 0xFDCF, prN}, // So ARABIC LIGATURE SALAAMUHU ALAYNAA
+ {0xFDF0, 0xFDFB, prN}, // Lo [12] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE JALLAJALALOUHOU
+ {0xFDFC, 0xFDFC, prN}, // Sc RIAL SIGN
+ {0xFDFD, 0xFDFF, prN}, // So [3] ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM..ARABIC LIGATURE AZZA WA JALL
+ {0xFE00, 0xFE0F, prA}, // Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
+ {0xFE10, 0xFE16, prW}, // Po [7] PRESENTATION FORM FOR VERTICAL COMMA..PRESENTATION FORM FOR VERTICAL QUESTION MARK
+ {0xFE17, 0xFE17, prW}, // Ps PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET
+ {0xFE18, 0xFE18, prW}, // Pe PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET
+ {0xFE19, 0xFE19, prW}, // Po PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS
+ {0xFE20, 0xFE2F, prN}, // Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF
+ {0xFE30, 0xFE30, prW}, // Po PRESENTATION FORM FOR VERTICAL TWO DOT LEADER
+ {0xFE31, 0xFE32, prW}, // Pd [2] PRESENTATION FORM FOR VERTICAL EM DASH..PRESENTATION FORM FOR VERTICAL EN DASH
+ {0xFE33, 0xFE34, prW}, // Pc [2] PRESENTATION FORM FOR VERTICAL LOW LINE..PRESENTATION FORM FOR VERTICAL WAVY LOW LINE
+ {0xFE35, 0xFE35, prW}, // Ps PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS
+ {0xFE36, 0xFE36, prW}, // Pe PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS
+ {0xFE37, 0xFE37, prW}, // Ps PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET
+ {0xFE38, 0xFE38, prW}, // Pe PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET
+ {0xFE39, 0xFE39, prW}, // Ps PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET
+ {0xFE3A, 0xFE3A, prW}, // Pe PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET
+ {0xFE3B, 0xFE3B, prW}, // Ps PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET
+ {0xFE3C, 0xFE3C, prW}, // Pe PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET
+ {0xFE3D, 0xFE3D, prW}, // Ps PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET
+ {0xFE3E, 0xFE3E, prW}, // Pe PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET
+ {0xFE3F, 0xFE3F, prW}, // Ps PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET
+ {0xFE40, 0xFE40, prW}, // Pe PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET
+ {0xFE41, 0xFE41, prW}, // Ps PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET
+ {0xFE42, 0xFE42, prW}, // Pe PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET
+ {0xFE43, 0xFE43, prW}, // Ps PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET
+ {0xFE44, 0xFE44, prW}, // Pe PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET
+ {0xFE45, 0xFE46, prW}, // Po [2] SESAME DOT..WHITE SESAME DOT
+ {0xFE47, 0xFE47, prW}, // Ps PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET
+ {0xFE48, 0xFE48, prW}, // Pe PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET
+ {0xFE49, 0xFE4C, prW}, // Po [4] DASHED OVERLINE..DOUBLE WAVY OVERLINE
+ {0xFE4D, 0xFE4F, prW}, // Pc [3] DASHED LOW LINE..WAVY LOW LINE
+ {0xFE50, 0xFE52, prW}, // Po [3] SMALL COMMA..SMALL FULL STOP
+ {0xFE54, 0xFE57, prW}, // Po [4] SMALL SEMICOLON..SMALL EXCLAMATION MARK
+ {0xFE58, 0xFE58, prW}, // Pd SMALL EM DASH
+ {0xFE59, 0xFE59, prW}, // Ps SMALL LEFT PARENTHESIS
+ {0xFE5A, 0xFE5A, prW}, // Pe SMALL RIGHT PARENTHESIS
+ {0xFE5B, 0xFE5B, prW}, // Ps SMALL LEFT CURLY BRACKET
+ {0xFE5C, 0xFE5C, prW}, // Pe SMALL RIGHT CURLY BRACKET
+ {0xFE5D, 0xFE5D, prW}, // Ps SMALL LEFT TORTOISE SHELL BRACKET
+ {0xFE5E, 0xFE5E, prW}, // Pe SMALL RIGHT TORTOISE SHELL BRACKET
+ {0xFE5F, 0xFE61, prW}, // Po [3] SMALL NUMBER SIGN..SMALL ASTERISK
+ {0xFE62, 0xFE62, prW}, // Sm SMALL PLUS SIGN
+ {0xFE63, 0xFE63, prW}, // Pd SMALL HYPHEN-MINUS
+ {0xFE64, 0xFE66, prW}, // Sm [3] SMALL LESS-THAN SIGN..SMALL EQUALS SIGN
+ {0xFE68, 0xFE68, prW}, // Po SMALL REVERSE SOLIDUS
+ {0xFE69, 0xFE69, prW}, // Sc SMALL DOLLAR SIGN
+ {0xFE6A, 0xFE6B, prW}, // Po [2] SMALL PERCENT SIGN..SMALL COMMERCIAL AT
+ {0xFE70, 0xFE74, prN}, // Lo [5] ARABIC FATHATAN ISOLATED FORM..ARABIC KASRATAN ISOLATED FORM
+ {0xFE76, 0xFEFC, prN}, // Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM
+ {0xFEFF, 0xFEFF, prN}, // Cf ZERO WIDTH NO-BREAK SPACE
+ {0xFF01, 0xFF03, prF}, // Po [3] FULLWIDTH EXCLAMATION MARK..FULLWIDTH NUMBER SIGN
+ {0xFF04, 0xFF04, prF}, // Sc FULLWIDTH DOLLAR SIGN
+ {0xFF05, 0xFF07, prF}, // Po [3] FULLWIDTH PERCENT SIGN..FULLWIDTH APOSTROPHE
+ {0xFF08, 0xFF08, prF}, // Ps FULLWIDTH LEFT PARENTHESIS
+ {0xFF09, 0xFF09, prF}, // Pe FULLWIDTH RIGHT PARENTHESIS
+ {0xFF0A, 0xFF0A, prF}, // Po FULLWIDTH ASTERISK
+ {0xFF0B, 0xFF0B, prF}, // Sm FULLWIDTH PLUS SIGN
+ {0xFF0C, 0xFF0C, prF}, // Po FULLWIDTH COMMA
+ {0xFF0D, 0xFF0D, prF}, // Pd FULLWIDTH HYPHEN-MINUS
+ {0xFF0E, 0xFF0F, prF}, // Po [2] FULLWIDTH FULL STOP..FULLWIDTH SOLIDUS
+ {0xFF10, 0xFF19, prF}, // Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE
+ {0xFF1A, 0xFF1B, prF}, // Po [2] FULLWIDTH COLON..FULLWIDTH SEMICOLON
+ {0xFF1C, 0xFF1E, prF}, // Sm [3] FULLWIDTH LESS-THAN SIGN..FULLWIDTH GREATER-THAN SIGN
+ {0xFF1F, 0xFF20, prF}, // Po [2] FULLWIDTH QUESTION MARK..FULLWIDTH COMMERCIAL AT
+ {0xFF21, 0xFF3A, prF}, // Lu [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z
+ {0xFF3B, 0xFF3B, prF}, // Ps FULLWIDTH LEFT SQUARE BRACKET
+ {0xFF3C, 0xFF3C, prF}, // Po FULLWIDTH REVERSE SOLIDUS
+ {0xFF3D, 0xFF3D, prF}, // Pe FULLWIDTH RIGHT SQUARE BRACKET
+ {0xFF3E, 0xFF3E, prF}, // Sk FULLWIDTH CIRCUMFLEX ACCENT
+ {0xFF3F, 0xFF3F, prF}, // Pc FULLWIDTH LOW LINE
+ {0xFF40, 0xFF40, prF}, // Sk FULLWIDTH GRAVE ACCENT
+ {0xFF41, 0xFF5A, prF}, // Ll [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z
+ {0xFF5B, 0xFF5B, prF}, // Ps FULLWIDTH LEFT CURLY BRACKET
+ {0xFF5C, 0xFF5C, prF}, // Sm FULLWIDTH VERTICAL LINE
+ {0xFF5D, 0xFF5D, prF}, // Pe FULLWIDTH RIGHT CURLY BRACKET
+ {0xFF5E, 0xFF5E, prF}, // Sm FULLWIDTH TILDE
+ {0xFF5F, 0xFF5F, prF}, // Ps FULLWIDTH LEFT WHITE PARENTHESIS
+ {0xFF60, 0xFF60, prF}, // Pe FULLWIDTH RIGHT WHITE PARENTHESIS
+ {0xFF61, 0xFF61, prH}, // Po HALFWIDTH IDEOGRAPHIC FULL STOP
+ {0xFF62, 0xFF62, prH}, // Ps HALFWIDTH LEFT CORNER BRACKET
+ {0xFF63, 0xFF63, prH}, // Pe HALFWIDTH RIGHT CORNER BRACKET
+ {0xFF64, 0xFF65, prH}, // Po [2] HALFWIDTH IDEOGRAPHIC COMMA..HALFWIDTH KATAKANA MIDDLE DOT
+ {0xFF66, 0xFF6F, prH}, // Lo [10] HALFWIDTH KATAKANA LETTER WO..HALFWIDTH KATAKANA LETTER SMALL TU
+ {0xFF70, 0xFF70, prH}, // Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
+ {0xFF71, 0xFF9D, prH}, // Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAKANA LETTER N
+ {0xFF9E, 0xFF9F, prH}, // Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
+ {0xFFA0, 0xFFBE, prH}, // Lo [31] HALFWIDTH HANGUL FILLER..HALFWIDTH HANGUL LETTER HIEUH
+ {0xFFC2, 0xFFC7, prH}, // Lo [6] HALFWIDTH HANGUL LETTER A..HALFWIDTH HANGUL LETTER E
+ {0xFFCA, 0xFFCF, prH}, // Lo [6] HALFWIDTH HANGUL LETTER YEO..HALFWIDTH HANGUL LETTER OE
+ {0xFFD2, 0xFFD7, prH}, // Lo [6] HALFWIDTH HANGUL LETTER YO..HALFWIDTH HANGUL LETTER YU
+ {0xFFDA, 0xFFDC, prH}, // Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I
+ {0xFFE0, 0xFFE1, prF}, // Sc [2] FULLWIDTH CENT SIGN..FULLWIDTH POUND SIGN
+ {0xFFE2, 0xFFE2, prF}, // Sm FULLWIDTH NOT SIGN
+ {0xFFE3, 0xFFE3, prF}, // Sk FULLWIDTH MACRON
+ {0xFFE4, 0xFFE4, prF}, // So FULLWIDTH BROKEN BAR
+ {0xFFE5, 0xFFE6, prF}, // Sc [2] FULLWIDTH YEN SIGN..FULLWIDTH WON SIGN
+ {0xFFE8, 0xFFE8, prH}, // So HALFWIDTH FORMS LIGHT VERTICAL
+ {0xFFE9, 0xFFEC, prH}, // Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS ARROW
+ {0xFFED, 0xFFEE, prH}, // So [2] HALFWIDTH BLACK SQUARE..HALFWIDTH WHITE CIRCLE
+ {0xFFF9, 0xFFFB, prN}, // Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR
+ {0xFFFC, 0xFFFC, prN}, // So OBJECT REPLACEMENT CHARACTER
+ {0xFFFD, 0xFFFD, prA}, // So REPLACEMENT CHARACTER
+ {0x10000, 0x1000B, prN}, // Lo [12] LINEAR B SYLLABLE B008 A..LINEAR B SYLLABLE B046 JE
+ {0x1000D, 0x10026, prN}, // Lo [26] LINEAR B SYLLABLE B036 JO..LINEAR B SYLLABLE B032 QO
+ {0x10028, 0x1003A, prN}, // Lo [19] LINEAR B SYLLABLE B060 RA..LINEAR B SYLLABLE B042 WO
+ {0x1003C, 0x1003D, prN}, // Lo [2] LINEAR B SYLLABLE B017 ZA..LINEAR B SYLLABLE B074 ZE
+ {0x1003F, 0x1004D, prN}, // Lo [15] LINEAR B SYLLABLE B020 ZO..LINEAR B SYLLABLE B091 TWO
+ {0x10050, 0x1005D, prN}, // Lo [14] LINEAR B SYMBOL B018..LINEAR B SYMBOL B089
+ {0x10080, 0x100FA, prN}, // Lo [123] LINEAR B IDEOGRAM B100 MAN..LINEAR B IDEOGRAM VESSEL B305
+ {0x10100, 0x10102, prN}, // Po [3] AEGEAN WORD SEPARATOR LINE..AEGEAN CHECK MARK
+ {0x10107, 0x10133, prN}, // No [45] AEGEAN NUMBER ONE..AEGEAN NUMBER NINETY THOUSAND
+ {0x10137, 0x1013F, prN}, // So [9] AEGEAN WEIGHT BASE UNIT..AEGEAN MEASURE THIRD SUBUNIT
+ {0x10140, 0x10174, prN}, // Nl [53] GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ACROPHONIC STRATIAN FIFTY MNAS
+ {0x10175, 0x10178, prN}, // No [4] GREEK ONE HALF SIGN..GREEK THREE QUARTERS SIGN
+ {0x10179, 0x10189, prN}, // So [17] GREEK YEAR SIGN..GREEK TRYBLION BASE SIGN
+ {0x1018A, 0x1018B, prN}, // No [2] GREEK ZERO SIGN..GREEK ONE QUARTER SIGN
+ {0x1018C, 0x1018E, prN}, // So [3] GREEK SINUSOID SIGN..NOMISMA SIGN
+ {0x10190, 0x1019C, prN}, // So [13] ROMAN SEXTANS SIGN..ASCIA SYMBOL
+ {0x101A0, 0x101A0, prN}, // So GREEK SYMBOL TAU RHO
+ {0x101D0, 0x101FC, prN}, // So [45] PHAISTOS DISC SIGN PEDESTRIAN..PHAISTOS DISC SIGN WAVY BAND
+ {0x101FD, 0x101FD, prN}, // Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE
+ {0x10280, 0x1029C, prN}, // Lo [29] LYCIAN LETTER A..LYCIAN LETTER X
+ {0x102A0, 0x102D0, prN}, // Lo [49] CARIAN LETTER A..CARIAN LETTER UUU3
+ {0x102E0, 0x102E0, prN}, // Mn COPTIC EPACT THOUSANDS MARK
+ {0x102E1, 0x102FB, prN}, // No [27] COPTIC EPACT DIGIT ONE..COPTIC EPACT NUMBER NINE HUNDRED
+ {0x10300, 0x1031F, prN}, // Lo [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS
+ {0x10320, 0x10323, prN}, // No [4] OLD ITALIC NUMERAL ONE..OLD ITALIC NUMERAL FIFTY
+ {0x1032D, 0x1032F, prN}, // Lo [3] OLD ITALIC LETTER YE..OLD ITALIC LETTER SOUTHERN TSE
+ {0x10330, 0x10340, prN}, // Lo [17] GOTHIC LETTER AHSA..GOTHIC LETTER PAIRTHRA
+ {0x10341, 0x10341, prN}, // Nl GOTHIC LETTER NINETY
+ {0x10342, 0x10349, prN}, // Lo [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL
+ {0x1034A, 0x1034A, prN}, // Nl GOTHIC LETTER NINE HUNDRED
+ {0x10350, 0x10375, prN}, // Lo [38] OLD PERMIC LETTER AN..OLD PERMIC LETTER IA
+ {0x10376, 0x1037A, prN}, // Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII
+ {0x10380, 0x1039D, prN}, // Lo [30] UGARITIC LETTER ALPA..UGARITIC LETTER SSU
+ {0x1039F, 0x1039F, prN}, // Po UGARITIC WORD DIVIDER
+ {0x103A0, 0x103C3, prN}, // Lo [36] OLD PERSIAN SIGN A..OLD PERSIAN SIGN HA
+ {0x103C8, 0x103CF, prN}, // Lo [8] OLD PERSIAN SIGN AURAMAZDAA..OLD PERSIAN SIGN BUUMISH
+ {0x103D0, 0x103D0, prN}, // Po OLD PERSIAN WORD DIVIDER
+ {0x103D1, 0x103D5, prN}, // Nl [5] OLD PERSIAN NUMBER ONE..OLD PERSIAN NUMBER HUNDRED
+ {0x10400, 0x1044F, prN}, // L& [80] DESERET CAPITAL LETTER LONG I..DESERET SMALL LETTER EW
+ {0x10450, 0x1047F, prN}, // Lo [48] SHAVIAN LETTER PEEP..SHAVIAN LETTER YEW
+ {0x10480, 0x1049D, prN}, // Lo [30] OSMANYA LETTER ALEF..OSMANYA LETTER OO
+ {0x104A0, 0x104A9, prN}, // Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE
+ {0x104B0, 0x104D3, prN}, // Lu [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA
+ {0x104D8, 0x104FB, prN}, // Ll [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA
+ {0x10500, 0x10527, prN}, // Lo [40] ELBASAN LETTER A..ELBASAN LETTER KHE
+ {0x10530, 0x10563, prN}, // Lo [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW
+ {0x1056F, 0x1056F, prN}, // Po CAUCASIAN ALBANIAN CITATION MARK
+ {0x10570, 0x1057A, prN}, // Lu [11] VITHKUQI CAPITAL LETTER A..VITHKUQI CAPITAL LETTER GA
+ {0x1057C, 0x1058A, prN}, // Lu [15] VITHKUQI CAPITAL LETTER HA..VITHKUQI CAPITAL LETTER RE
+ {0x1058C, 0x10592, prN}, // Lu [7] VITHKUQI CAPITAL LETTER SE..VITHKUQI CAPITAL LETTER XE
+ {0x10594, 0x10595, prN}, // Lu [2] VITHKUQI CAPITAL LETTER Y..VITHKUQI CAPITAL LETTER ZE
+ {0x10597, 0x105A1, prN}, // Ll [11] VITHKUQI SMALL LETTER A..VITHKUQI SMALL LETTER GA
+ {0x105A3, 0x105B1, prN}, // Ll [15] VITHKUQI SMALL LETTER HA..VITHKUQI SMALL LETTER RE
+ {0x105B3, 0x105B9, prN}, // Ll [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE
+ {0x105BB, 0x105BC, prN}, // Ll [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE
+ {0x10600, 0x10736, prN}, // Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664
+ {0x10740, 0x10755, prN}, // Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE
+ {0x10760, 0x10767, prN}, // Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807
+ {0x10780, 0x10785, prN}, // Lm [6] MODIFIER LETTER SMALL CAPITAL AA..MODIFIER LETTER SMALL B WITH HOOK
+ {0x10787, 0x107B0, prN}, // Lm [42] MODIFIER LETTER SMALL DZ DIGRAPH..MODIFIER LETTER SMALL V WITH RIGHT HOOK
+ {0x107B2, 0x107BA, prN}, // Lm [9] MODIFIER LETTER SMALL CAPITAL Y..MODIFIER LETTER SMALL S WITH CURL
+ {0x10800, 0x10805, prN}, // Lo [6] CYPRIOT SYLLABLE A..CYPRIOT SYLLABLE JA
+ {0x10808, 0x10808, prN}, // Lo CYPRIOT SYLLABLE JO
+ {0x1080A, 0x10835, prN}, // Lo [44] CYPRIOT SYLLABLE KA..CYPRIOT SYLLABLE WO
+ {0x10837, 0x10838, prN}, // Lo [2] CYPRIOT SYLLABLE XA..CYPRIOT SYLLABLE XE
+ {0x1083C, 0x1083C, prN}, // Lo CYPRIOT SYLLABLE ZA
+ {0x1083F, 0x1083F, prN}, // Lo CYPRIOT SYLLABLE ZO
+ {0x10840, 0x10855, prN}, // Lo [22] IMPERIAL ARAMAIC LETTER ALEPH..IMPERIAL ARAMAIC LETTER TAW
+ {0x10857, 0x10857, prN}, // Po IMPERIAL ARAMAIC SECTION SIGN
+ {0x10858, 0x1085F, prN}, // No [8] IMPERIAL ARAMAIC NUMBER ONE..IMPERIAL ARAMAIC NUMBER TEN THOUSAND
+ {0x10860, 0x10876, prN}, // Lo [23] PALMYRENE LETTER ALEPH..PALMYRENE LETTER TAW
+ {0x10877, 0x10878, prN}, // So [2] PALMYRENE LEFT-POINTING FLEURON..PALMYRENE RIGHT-POINTING FLEURON
+ {0x10879, 0x1087F, prN}, // No [7] PALMYRENE NUMBER ONE..PALMYRENE NUMBER TWENTY
+ {0x10880, 0x1089E, prN}, // Lo [31] NABATAEAN LETTER FINAL ALEPH..NABATAEAN LETTER TAW
+ {0x108A7, 0x108AF, prN}, // No [9] NABATAEAN NUMBER ONE..NABATAEAN NUMBER ONE HUNDRED
+ {0x108E0, 0x108F2, prN}, // Lo [19] HATRAN LETTER ALEPH..HATRAN LETTER QOPH
+ {0x108F4, 0x108F5, prN}, // Lo [2] HATRAN LETTER SHIN..HATRAN LETTER TAW
+ {0x108FB, 0x108FF, prN}, // No [5] HATRAN NUMBER ONE..HATRAN NUMBER ONE HUNDRED
+ {0x10900, 0x10915, prN}, // Lo [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU
+ {0x10916, 0x1091B, prN}, // No [6] PHOENICIAN NUMBER ONE..PHOENICIAN NUMBER THREE
+ {0x1091F, 0x1091F, prN}, // Po PHOENICIAN WORD SEPARATOR
+ {0x10920, 0x10939, prN}, // Lo [26] LYDIAN LETTER A..LYDIAN LETTER C
+ {0x1093F, 0x1093F, prN}, // Po LYDIAN TRIANGULAR MARK
+ {0x10980, 0x1099F, prN}, // Lo [32] MEROITIC HIEROGLYPHIC LETTER A..MEROITIC HIEROGLYPHIC SYMBOL VIDJ-2
+ {0x109A0, 0x109B7, prN}, // Lo [24] MEROITIC CURSIVE LETTER A..MEROITIC CURSIVE LETTER DA
+ {0x109BC, 0x109BD, prN}, // No [2] MEROITIC CURSIVE FRACTION ELEVEN TWELFTHS..MEROITIC CURSIVE FRACTION ONE HALF
+ {0x109BE, 0x109BF, prN}, // Lo [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN
+ {0x109C0, 0x109CF, prN}, // No [16] MEROITIC CURSIVE NUMBER ONE..MEROITIC CURSIVE NUMBER SEVENTY
+ {0x109D2, 0x109FF, prN}, // No [46] MEROITIC CURSIVE NUMBER ONE HUNDRED..MEROITIC CURSIVE FRACTION TEN TWELFTHS
+ {0x10A00, 0x10A00, prN}, // Lo KHAROSHTHI LETTER A
+ {0x10A01, 0x10A03, prN}, // Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R
+ {0x10A05, 0x10A06, prN}, // Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O
+ {0x10A0C, 0x10A0F, prN}, // Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA
+ {0x10A10, 0x10A13, prN}, // Lo [4] KHAROSHTHI LETTER KA..KHAROSHTHI LETTER GHA
+ {0x10A15, 0x10A17, prN}, // Lo [3] KHAROSHTHI LETTER CA..KHAROSHTHI LETTER JA
+ {0x10A19, 0x10A35, prN}, // Lo [29] KHAROSHTHI LETTER NYA..KHAROSHTHI LETTER VHA
+ {0x10A38, 0x10A3A, prN}, // Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW
+ {0x10A3F, 0x10A3F, prN}, // Mn KHAROSHTHI VIRAMA
+ {0x10A40, 0x10A48, prN}, // No [9] KHAROSHTHI DIGIT ONE..KHAROSHTHI FRACTION ONE HALF
+ {0x10A50, 0x10A58, prN}, // Po [9] KHAROSHTHI PUNCTUATION DOT..KHAROSHTHI PUNCTUATION LINES
+ {0x10A60, 0x10A7C, prN}, // Lo [29] OLD SOUTH ARABIAN LETTER HE..OLD SOUTH ARABIAN LETTER THETH
+ {0x10A7D, 0x10A7E, prN}, // No [2] OLD SOUTH ARABIAN NUMBER ONE..OLD SOUTH ARABIAN NUMBER FIFTY
+ {0x10A7F, 0x10A7F, prN}, // Po OLD SOUTH ARABIAN NUMERIC INDICATOR
+ {0x10A80, 0x10A9C, prN}, // Lo [29] OLD NORTH ARABIAN LETTER HEH..OLD NORTH ARABIAN LETTER ZAH
+ {0x10A9D, 0x10A9F, prN}, // No [3] OLD NORTH ARABIAN NUMBER ONE..OLD NORTH ARABIAN NUMBER TWENTY
+ {0x10AC0, 0x10AC7, prN}, // Lo [8] MANICHAEAN LETTER ALEPH..MANICHAEAN LETTER WAW
+ {0x10AC8, 0x10AC8, prN}, // So MANICHAEAN SIGN UD
+ {0x10AC9, 0x10AE4, prN}, // Lo [28] MANICHAEAN LETTER ZAYIN..MANICHAEAN LETTER TAW
+ {0x10AE5, 0x10AE6, prN}, // Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW
+ {0x10AEB, 0x10AEF, prN}, // No [5] MANICHAEAN NUMBER ONE..MANICHAEAN NUMBER ONE HUNDRED
+ {0x10AF0, 0x10AF6, prN}, // Po [7] MANICHAEAN PUNCTUATION STAR..MANICHAEAN PUNCTUATION LINE FILLER
+ {0x10B00, 0x10B35, prN}, // Lo [54] AVESTAN LETTER A..AVESTAN LETTER HE
+ {0x10B39, 0x10B3F, prN}, // Po [7] AVESTAN ABBREVIATION MARK..LARGE ONE RING OVER TWO RINGS PUNCTUATION
+ {0x10B40, 0x10B55, prN}, // Lo [22] INSCRIPTIONAL PARTHIAN LETTER ALEPH..INSCRIPTIONAL PARTHIAN LETTER TAW
+ {0x10B58, 0x10B5F, prN}, // No [8] INSCRIPTIONAL PARTHIAN NUMBER ONE..INSCRIPTIONAL PARTHIAN NUMBER ONE THOUSAND
+ {0x10B60, 0x10B72, prN}, // Lo [19] INSCRIPTIONAL PAHLAVI LETTER ALEPH..INSCRIPTIONAL PAHLAVI LETTER TAW
+ {0x10B78, 0x10B7F, prN}, // No [8] INSCRIPTIONAL PAHLAVI NUMBER ONE..INSCRIPTIONAL PAHLAVI NUMBER ONE THOUSAND
+ {0x10B80, 0x10B91, prN}, // Lo [18] PSALTER PAHLAVI LETTER ALEPH..PSALTER PAHLAVI LETTER TAW
+ {0x10B99, 0x10B9C, prN}, // Po [4] PSALTER PAHLAVI SECTION MARK..PSALTER PAHLAVI FOUR DOTS WITH DOT
+ {0x10BA9, 0x10BAF, prN}, // No [7] PSALTER PAHLAVI NUMBER ONE..PSALTER PAHLAVI NUMBER ONE HUNDRED
+ {0x10C00, 0x10C48, prN}, // Lo [73] OLD TURKIC LETTER ORKHON A..OLD TURKIC LETTER ORKHON BASH
+ {0x10C80, 0x10CB2, prN}, // Lu [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US
+ {0x10CC0, 0x10CF2, prN}, // Ll [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US
+ {0x10CFA, 0x10CFF, prN}, // No [6] OLD HUNGARIAN NUMBER ONE..OLD HUNGARIAN NUMBER ONE THOUSAND
+ {0x10D00, 0x10D23, prN}, // Lo [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA
+ {0x10D24, 0x10D27, prN}, // Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI
+ {0x10D30, 0x10D39, prN}, // Nd [10] HANIFI ROHINGYA DIGIT ZERO..HANIFI ROHINGYA DIGIT NINE
+ {0x10E60, 0x10E7E, prN}, // No [31] RUMI DIGIT ONE..RUMI FRACTION TWO THIRDS
+ {0x10E80, 0x10EA9, prN}, // Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET
+ {0x10EAB, 0x10EAC, prN}, // Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK
+ {0x10EAD, 0x10EAD, prN}, // Pd YEZIDI HYPHENATION MARK
+ {0x10EB0, 0x10EB1, prN}, // Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE
+ {0x10F00, 0x10F1C, prN}, // Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL
+ {0x10F1D, 0x10F26, prN}, // No [10] OLD SOGDIAN NUMBER ONE..OLD SOGDIAN FRACTION ONE HALF
+ {0x10F27, 0x10F27, prN}, // Lo OLD SOGDIAN LIGATURE AYIN-DALETH
+ {0x10F30, 0x10F45, prN}, // Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN
+ {0x10F46, 0x10F50, prN}, // Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW
+ {0x10F51, 0x10F54, prN}, // No [4] SOGDIAN NUMBER ONE..SOGDIAN NUMBER ONE HUNDRED
+ {0x10F55, 0x10F59, prN}, // Po [5] SOGDIAN PUNCTUATION TWO VERTICAL BARS..SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT
+ {0x10F70, 0x10F81, prN}, // Lo [18] OLD UYGHUR LETTER ALEPH..OLD UYGHUR LETTER LESH
+ {0x10F82, 0x10F85, prN}, // Mn [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW
+ {0x10F86, 0x10F89, prN}, // Po [4] OLD UYGHUR PUNCTUATION BAR..OLD UYGHUR PUNCTUATION FOUR DOTS
+ {0x10FB0, 0x10FC4, prN}, // Lo [21] CHORASMIAN LETTER ALEPH..CHORASMIAN LETTER TAW
+ {0x10FC5, 0x10FCB, prN}, // No [7] CHORASMIAN NUMBER ONE..CHORASMIAN NUMBER ONE HUNDRED
+ {0x10FE0, 0x10FF6, prN}, // Lo [23] ELYMAIC LETTER ALEPH..ELYMAIC LIGATURE ZAYIN-YODH
+ {0x11000, 0x11000, prN}, // Mc BRAHMI SIGN CANDRABINDU
+ {0x11001, 0x11001, prN}, // Mn BRAHMI SIGN ANUSVARA
+ {0x11002, 0x11002, prN}, // Mc BRAHMI SIGN VISARGA
+ {0x11003, 0x11037, prN}, // Lo [53] BRAHMI SIGN JIHVAMULIYA..BRAHMI LETTER OLD TAMIL NNNA
+ {0x11038, 0x11046, prN}, // Mn [15] BRAHMI VOWEL SIGN AA..BRAHMI VIRAMA
+ {0x11047, 0x1104D, prN}, // Po [7] BRAHMI DANDA..BRAHMI PUNCTUATION LOTUS
+ {0x11052, 0x11065, prN}, // No [20] BRAHMI NUMBER ONE..BRAHMI NUMBER ONE THOUSAND
+ {0x11066, 0x1106F, prN}, // Nd [10] BRAHMI DIGIT ZERO..BRAHMI DIGIT NINE
+ {0x11070, 0x11070, prN}, // Mn BRAHMI SIGN OLD TAMIL VIRAMA
+ {0x11071, 0x11072, prN}, // Lo [2] BRAHMI LETTER OLD TAMIL SHORT E..BRAHMI LETTER OLD TAMIL SHORT O
+ {0x11073, 0x11074, prN}, // Mn [2] BRAHMI VOWEL SIGN OLD TAMIL SHORT E..BRAHMI VOWEL SIGN OLD TAMIL SHORT O
+ {0x11075, 0x11075, prN}, // Lo BRAHMI LETTER OLD TAMIL LLA
+ {0x1107F, 0x1107F, prN}, // Mn BRAHMI NUMBER JOINER
+ {0x11080, 0x11081, prN}, // Mn [2] KAITHI SIGN CANDRABINDU..KAITHI SIGN ANUSVARA
+ {0x11082, 0x11082, prN}, // Mc KAITHI SIGN VISARGA
+ {0x11083, 0x110AF, prN}, // Lo [45] KAITHI LETTER A..KAITHI LETTER HA
+ {0x110B0, 0x110B2, prN}, // Mc [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II
+ {0x110B3, 0x110B6, prN}, // Mn [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI
+ {0x110B7, 0x110B8, prN}, // Mc [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU
+ {0x110B9, 0x110BA, prN}, // Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA
+ {0x110BB, 0x110BC, prN}, // Po [2] KAITHI ABBREVIATION SIGN..KAITHI ENUMERATION SIGN
+ {0x110BD, 0x110BD, prN}, // Cf KAITHI NUMBER SIGN
+ {0x110BE, 0x110C1, prN}, // Po [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA
+ {0x110C2, 0x110C2, prN}, // Mn KAITHI VOWEL SIGN VOCALIC R
+ {0x110CD, 0x110CD, prN}, // Cf KAITHI NUMBER SIGN ABOVE
+ {0x110D0, 0x110E8, prN}, // Lo [25] SORA SOMPENG LETTER SAH..SORA SOMPENG LETTER MAE
+ {0x110F0, 0x110F9, prN}, // Nd [10] SORA SOMPENG DIGIT ZERO..SORA SOMPENG DIGIT NINE
+ {0x11100, 0x11102, prN}, // Mn [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA
+ {0x11103, 0x11126, prN}, // Lo [36] CHAKMA LETTER AA..CHAKMA LETTER HAA
+ {0x11127, 0x1112B, prN}, // Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU
+ {0x1112C, 0x1112C, prN}, // Mc CHAKMA VOWEL SIGN E
+ {0x1112D, 0x11134, prN}, // Mn [8] CHAKMA VOWEL SIGN AI..CHAKMA MAAYYAA
+ {0x11136, 0x1113F, prN}, // Nd [10] CHAKMA DIGIT ZERO..CHAKMA DIGIT NINE
+ {0x11140, 0x11143, prN}, // Po [4] CHAKMA SECTION MARK..CHAKMA QUESTION MARK
+ {0x11144, 0x11144, prN}, // Lo CHAKMA LETTER LHAA
+ {0x11145, 0x11146, prN}, // Mc [2] CHAKMA VOWEL SIGN AA..CHAKMA VOWEL SIGN EI
+ {0x11147, 0x11147, prN}, // Lo CHAKMA LETTER VAA
+ {0x11150, 0x11172, prN}, // Lo [35] MAHAJANI LETTER A..MAHAJANI LETTER RRA
+ {0x11173, 0x11173, prN}, // Mn MAHAJANI SIGN NUKTA
+ {0x11174, 0x11175, prN}, // Po [2] MAHAJANI ABBREVIATION SIGN..MAHAJANI SECTION MARK
+ {0x11176, 0x11176, prN}, // Lo MAHAJANI LIGATURE SHRI
+ {0x11180, 0x11181, prN}, // Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA
+ {0x11182, 0x11182, prN}, // Mc SHARADA SIGN VISARGA
+ {0x11183, 0x111B2, prN}, // Lo [48] SHARADA LETTER A..SHARADA LETTER HA
+ {0x111B3, 0x111B5, prN}, // Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II
+ {0x111B6, 0x111BE, prN}, // Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O
+ {0x111BF, 0x111C0, prN}, // Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA
+ {0x111C1, 0x111C4, prN}, // Lo [4] SHARADA SIGN AVAGRAHA..SHARADA OM
+ {0x111C5, 0x111C8, prN}, // Po [4] SHARADA DANDA..SHARADA SEPARATOR
+ {0x111C9, 0x111CC, prN}, // Mn [4] SHARADA SANDHI MARK..SHARADA EXTRA SHORT VOWEL MARK
+ {0x111CD, 0x111CD, prN}, // Po SHARADA SUTRA MARK
+ {0x111CE, 0x111CE, prN}, // Mc SHARADA VOWEL SIGN PRISHTHAMATRA E
+ {0x111CF, 0x111CF, prN}, // Mn SHARADA SIGN INVERTED CANDRABINDU
+ {0x111D0, 0x111D9, prN}, // Nd [10] SHARADA DIGIT ZERO..SHARADA DIGIT NINE
+ {0x111DA, 0x111DA, prN}, // Lo SHARADA EKAM
+ {0x111DB, 0x111DB, prN}, // Po SHARADA SIGN SIDDHAM
+ {0x111DC, 0x111DC, prN}, // Lo SHARADA HEADSTROKE
+ {0x111DD, 0x111DF, prN}, // Po [3] SHARADA CONTINUATION SIGN..SHARADA SECTION MARK-2
+ {0x111E1, 0x111F4, prN}, // No [20] SINHALA ARCHAIC DIGIT ONE..SINHALA ARCHAIC NUMBER ONE THOUSAND
+ {0x11200, 0x11211, prN}, // Lo [18] KHOJKI LETTER A..KHOJKI LETTER JJA
+ {0x11213, 0x1122B, prN}, // Lo [25] KHOJKI LETTER NYA..KHOJKI LETTER LLA
+ {0x1122C, 0x1122E, prN}, // Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II
+ {0x1122F, 0x11231, prN}, // Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI
+ {0x11232, 0x11233, prN}, // Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU
+ {0x11234, 0x11234, prN}, // Mn KHOJKI SIGN ANUSVARA
+ {0x11235, 0x11235, prN}, // Mc KHOJKI SIGN VIRAMA
+ {0x11236, 0x11237, prN}, // Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA
+ {0x11238, 0x1123D, prN}, // Po [6] KHOJKI DANDA..KHOJKI ABBREVIATION SIGN
+ {0x1123E, 0x1123E, prN}, // Mn KHOJKI SIGN SUKUN
+ {0x11280, 0x11286, prN}, // Lo [7] MULTANI LETTER A..MULTANI LETTER GA
+ {0x11288, 0x11288, prN}, // Lo MULTANI LETTER GHA
+ {0x1128A, 0x1128D, prN}, // Lo [4] MULTANI LETTER CA..MULTANI LETTER JJA
+ {0x1128F, 0x1129D, prN}, // Lo [15] MULTANI LETTER NYA..MULTANI LETTER BA
+ {0x1129F, 0x112A8, prN}, // Lo [10] MULTANI LETTER BHA..MULTANI LETTER RHA
+ {0x112A9, 0x112A9, prN}, // Po MULTANI SECTION MARK
+ {0x112B0, 0x112DE, prN}, // Lo [47] KHUDAWADI LETTER A..KHUDAWADI LETTER HA
+ {0x112DF, 0x112DF, prN}, // Mn KHUDAWADI SIGN ANUSVARA
+ {0x112E0, 0x112E2, prN}, // Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II
+ {0x112E3, 0x112EA, prN}, // Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA
+ {0x112F0, 0x112F9, prN}, // Nd [10] KHUDAWADI DIGIT ZERO..KHUDAWADI DIGIT NINE
+ {0x11300, 0x11301, prN}, // Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU
+ {0x11302, 0x11303, prN}, // Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA
+ {0x11305, 0x1130C, prN}, // Lo [8] GRANTHA LETTER A..GRANTHA LETTER VOCALIC L
+ {0x1130F, 0x11310, prN}, // Lo [2] GRANTHA LETTER EE..GRANTHA LETTER AI
+ {0x11313, 0x11328, prN}, // Lo [22] GRANTHA LETTER OO..GRANTHA LETTER NA
+ {0x1132A, 0x11330, prN}, // Lo [7] GRANTHA LETTER PA..GRANTHA LETTER RA
+ {0x11332, 0x11333, prN}, // Lo [2] GRANTHA LETTER LA..GRANTHA LETTER LLA
+ {0x11335, 0x11339, prN}, // Lo [5] GRANTHA LETTER VA..GRANTHA LETTER HA
+ {0x1133B, 0x1133C, prN}, // Mn [2] COMBINING BINDU BELOW..GRANTHA SIGN NUKTA
+ {0x1133D, 0x1133D, prN}, // Lo GRANTHA SIGN AVAGRAHA
+ {0x1133E, 0x1133F, prN}, // Mc [2] GRANTHA VOWEL SIGN AA..GRANTHA VOWEL SIGN I
+ {0x11340, 0x11340, prN}, // Mn GRANTHA VOWEL SIGN II
+ {0x11341, 0x11344, prN}, // Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR
+ {0x11347, 0x11348, prN}, // Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI
+ {0x1134B, 0x1134D, prN}, // Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA
+ {0x11350, 0x11350, prN}, // Lo GRANTHA OM
+ {0x11357, 0x11357, prN}, // Mc GRANTHA AU LENGTH MARK
+ {0x1135D, 0x11361, prN}, // Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL
+ {0x11362, 0x11363, prN}, // Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL
+ {0x11366, 0x1136C, prN}, // Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX
+ {0x11370, 0x11374, prN}, // Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA
+ {0x11400, 0x11434, prN}, // Lo [53] NEWA LETTER A..NEWA LETTER HA
+ {0x11435, 0x11437, prN}, // Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II
+ {0x11438, 0x1143F, prN}, // Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI
+ {0x11440, 0x11441, prN}, // Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU
+ {0x11442, 0x11444, prN}, // Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA
+ {0x11445, 0x11445, prN}, // Mc NEWA SIGN VISARGA
+ {0x11446, 0x11446, prN}, // Mn NEWA SIGN NUKTA
+ {0x11447, 0x1144A, prN}, // Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI
+ {0x1144B, 0x1144F, prN}, // Po [5] NEWA DANDA..NEWA ABBREVIATION SIGN
+ {0x11450, 0x11459, prN}, // Nd [10] NEWA DIGIT ZERO..NEWA DIGIT NINE
+ {0x1145A, 0x1145B, prN}, // Po [2] NEWA DOUBLE COMMA..NEWA PLACEHOLDER MARK
+ {0x1145D, 0x1145D, prN}, // Po NEWA INSERTION SIGN
+ {0x1145E, 0x1145E, prN}, // Mn NEWA SANDHI MARK
+ {0x1145F, 0x11461, prN}, // Lo [3] NEWA LETTER VEDIC ANUSVARA..NEWA SIGN UPADHMANIYA
+ {0x11480, 0x114AF, prN}, // Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA
+ {0x114B0, 0x114B2, prN}, // Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II
+ {0x114B3, 0x114B8, prN}, // Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL
+ {0x114B9, 0x114B9, prN}, // Mc TIRHUTA VOWEL SIGN E
+ {0x114BA, 0x114BA, prN}, // Mn TIRHUTA VOWEL SIGN SHORT E
+ {0x114BB, 0x114BE, prN}, // Mc [4] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN AU
+ {0x114BF, 0x114C0, prN}, // Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA
+ {0x114C1, 0x114C1, prN}, // Mc TIRHUTA SIGN VISARGA
+ {0x114C2, 0x114C3, prN}, // Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA
+ {0x114C4, 0x114C5, prN}, // Lo [2] TIRHUTA SIGN AVAGRAHA..TIRHUTA GVANG
+ {0x114C6, 0x114C6, prN}, // Po TIRHUTA ABBREVIATION SIGN
+ {0x114C7, 0x114C7, prN}, // Lo TIRHUTA OM
+ {0x114D0, 0x114D9, prN}, // Nd [10] TIRHUTA DIGIT ZERO..TIRHUTA DIGIT NINE
+ {0x11580, 0x115AE, prN}, // Lo [47] SIDDHAM LETTER A..SIDDHAM LETTER HA
+ {0x115AF, 0x115B1, prN}, // Mc [3] SIDDHAM VOWEL SIGN AA..SIDDHAM VOWEL SIGN II
+ {0x115B2, 0x115B5, prN}, // Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR
+ {0x115B8, 0x115BB, prN}, // Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU
+ {0x115BC, 0x115BD, prN}, // Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA
+ {0x115BE, 0x115BE, prN}, // Mc SIDDHAM SIGN VISARGA
+ {0x115BF, 0x115C0, prN}, // Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA
+ {0x115C1, 0x115D7, prN}, // Po [23] SIDDHAM SIGN SIDDHAM..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES
+ {0x115D8, 0x115DB, prN}, // Lo [4] SIDDHAM LETTER THREE-CIRCLE ALTERNATE I..SIDDHAM LETTER ALTERNATE U
+ {0x115DC, 0x115DD, prN}, // Mn [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU
+ {0x11600, 0x1162F, prN}, // Lo [48] MODI LETTER A..MODI LETTER LLA
+ {0x11630, 0x11632, prN}, // Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II
+ {0x11633, 0x1163A, prN}, // Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI
+ {0x1163B, 0x1163C, prN}, // Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU
+ {0x1163D, 0x1163D, prN}, // Mn MODI SIGN ANUSVARA
+ {0x1163E, 0x1163E, prN}, // Mc MODI SIGN VISARGA
+ {0x1163F, 0x11640, prN}, // Mn [2] MODI SIGN VIRAMA..MODI SIGN ARDHACANDRA
+ {0x11641, 0x11643, prN}, // Po [3] MODI DANDA..MODI ABBREVIATION SIGN
+ {0x11644, 0x11644, prN}, // Lo MODI SIGN HUVA
+ {0x11650, 0x11659, prN}, // Nd [10] MODI DIGIT ZERO..MODI DIGIT NINE
+ {0x11660, 0x1166C, prN}, // Po [13] MONGOLIAN BIRGA WITH ORNAMENT..MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT
+ {0x11680, 0x116AA, prN}, // Lo [43] TAKRI LETTER A..TAKRI LETTER RRA
+ {0x116AB, 0x116AB, prN}, // Mn TAKRI SIGN ANUSVARA
+ {0x116AC, 0x116AC, prN}, // Mc TAKRI SIGN VISARGA
+ {0x116AD, 0x116AD, prN}, // Mn TAKRI VOWEL SIGN AA
+ {0x116AE, 0x116AF, prN}, // Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II
+ {0x116B0, 0x116B5, prN}, // Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU
+ {0x116B6, 0x116B6, prN}, // Mc TAKRI SIGN VIRAMA
+ {0x116B7, 0x116B7, prN}, // Mn TAKRI SIGN NUKTA
+ {0x116B8, 0x116B8, prN}, // Lo TAKRI LETTER ARCHAIC KHA
+ {0x116B9, 0x116B9, prN}, // Po TAKRI ABBREVIATION SIGN
+ {0x116C0, 0x116C9, prN}, // Nd [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE
+ {0x11700, 0x1171A, prN}, // Lo [27] AHOM LETTER KA..AHOM LETTER ALTERNATE BA
+ {0x1171D, 0x1171F, prN}, // Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA
+ {0x11720, 0x11721, prN}, // Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA
+ {0x11722, 0x11725, prN}, // Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU
+ {0x11726, 0x11726, prN}, // Mc AHOM VOWEL SIGN E
+ {0x11727, 0x1172B, prN}, // Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER
+ {0x11730, 0x11739, prN}, // Nd [10] AHOM DIGIT ZERO..AHOM DIGIT NINE
+ {0x1173A, 0x1173B, prN}, // No [2] AHOM NUMBER TEN..AHOM NUMBER TWENTY
+ {0x1173C, 0x1173E, prN}, // Po [3] AHOM SIGN SMALL SECTION..AHOM SIGN RULAI
+ {0x1173F, 0x1173F, prN}, // So AHOM SYMBOL VI
+ {0x11740, 0x11746, prN}, // Lo [7] AHOM LETTER CA..AHOM LETTER LLA
+ {0x11800, 0x1182B, prN}, // Lo [44] DOGRA LETTER A..DOGRA LETTER RRA
+ {0x1182C, 0x1182E, prN}, // Mc [3] DOGRA VOWEL SIGN AA..DOGRA VOWEL SIGN II
+ {0x1182F, 0x11837, prN}, // Mn [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA
+ {0x11838, 0x11838, prN}, // Mc DOGRA SIGN VISARGA
+ {0x11839, 0x1183A, prN}, // Mn [2] DOGRA SIGN VIRAMA..DOGRA SIGN NUKTA
+ {0x1183B, 0x1183B, prN}, // Po DOGRA ABBREVIATION SIGN
+ {0x118A0, 0x118DF, prN}, // L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO
+ {0x118E0, 0x118E9, prN}, // Nd [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE
+ {0x118EA, 0x118F2, prN}, // No [9] WARANG CITI NUMBER TEN..WARANG CITI NUMBER NINETY
+ {0x118FF, 0x118FF, prN}, // Lo WARANG CITI OM
+ {0x11900, 0x11906, prN}, // Lo [7] DIVES AKURU LETTER A..DIVES AKURU LETTER E
+ {0x11909, 0x11909, prN}, // Lo DIVES AKURU LETTER O
+ {0x1190C, 0x11913, prN}, // Lo [8] DIVES AKURU LETTER KA..DIVES AKURU LETTER JA
+ {0x11915, 0x11916, prN}, // Lo [2] DIVES AKURU LETTER NYA..DIVES AKURU LETTER TTA
+ {0x11918, 0x1192F, prN}, // Lo [24] DIVES AKURU LETTER DDA..DIVES AKURU LETTER ZA
+ {0x11930, 0x11935, prN}, // Mc [6] DIVES AKURU VOWEL SIGN AA..DIVES AKURU VOWEL SIGN E
+ {0x11937, 0x11938, prN}, // Mc [2] DIVES AKURU VOWEL SIGN AI..DIVES AKURU VOWEL SIGN O
+ {0x1193B, 0x1193C, prN}, // Mn [2] DIVES AKURU SIGN ANUSVARA..DIVES AKURU SIGN CANDRABINDU
+ {0x1193D, 0x1193D, prN}, // Mc DIVES AKURU SIGN HALANTA
+ {0x1193E, 0x1193E, prN}, // Mn DIVES AKURU VIRAMA
+ {0x1193F, 0x1193F, prN}, // Lo DIVES AKURU PREFIXED NASAL SIGN
+ {0x11940, 0x11940, prN}, // Mc DIVES AKURU MEDIAL YA
+ {0x11941, 0x11941, prN}, // Lo DIVES AKURU INITIAL RA
+ {0x11942, 0x11942, prN}, // Mc DIVES AKURU MEDIAL RA
+ {0x11943, 0x11943, prN}, // Mn DIVES AKURU SIGN NUKTA
+ {0x11944, 0x11946, prN}, // Po [3] DIVES AKURU DOUBLE DANDA..DIVES AKURU END OF TEXT MARK
+ {0x11950, 0x11959, prN}, // Nd [10] DIVES AKURU DIGIT ZERO..DIVES AKURU DIGIT NINE
+ {0x119A0, 0x119A7, prN}, // Lo [8] NANDINAGARI LETTER A..NANDINAGARI LETTER VOCALIC RR
+ {0x119AA, 0x119D0, prN}, // Lo [39] NANDINAGARI LETTER E..NANDINAGARI LETTER RRA
+ {0x119D1, 0x119D3, prN}, // Mc [3] NANDINAGARI VOWEL SIGN AA..NANDINAGARI VOWEL SIGN II
+ {0x119D4, 0x119D7, prN}, // Mn [4] NANDINAGARI VOWEL SIGN U..NANDINAGARI VOWEL SIGN VOCALIC RR
+ {0x119DA, 0x119DB, prN}, // Mn [2] NANDINAGARI VOWEL SIGN E..NANDINAGARI VOWEL SIGN AI
+ {0x119DC, 0x119DF, prN}, // Mc [4] NANDINAGARI VOWEL SIGN O..NANDINAGARI SIGN VISARGA
+ {0x119E0, 0x119E0, prN}, // Mn NANDINAGARI SIGN VIRAMA
+ {0x119E1, 0x119E1, prN}, // Lo NANDINAGARI SIGN AVAGRAHA
+ {0x119E2, 0x119E2, prN}, // Po NANDINAGARI SIGN SIDDHAM
+ {0x119E3, 0x119E3, prN}, // Lo NANDINAGARI HEADSTROKE
+ {0x119E4, 0x119E4, prN}, // Mc NANDINAGARI VOWEL SIGN PRISHTHAMATRA E
+ {0x11A00, 0x11A00, prN}, // Lo ZANABAZAR SQUARE LETTER A
+ {0x11A01, 0x11A0A, prN}, // Mn [10] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL LENGTH MARK
+ {0x11A0B, 0x11A32, prN}, // Lo [40] ZANABAZAR SQUARE LETTER KA..ZANABAZAR SQUARE LETTER KSSA
+ {0x11A33, 0x11A38, prN}, // Mn [6] ZANABAZAR SQUARE FINAL CONSONANT MARK..ZANABAZAR SQUARE SIGN ANUSVARA
+ {0x11A39, 0x11A39, prN}, // Mc ZANABAZAR SQUARE SIGN VISARGA
+ {0x11A3A, 0x11A3A, prN}, // Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA
+ {0x11A3B, 0x11A3E, prN}, // Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA
+ {0x11A3F, 0x11A46, prN}, // Po [8] ZANABAZAR SQUARE INITIAL HEAD MARK..ZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARK
+ {0x11A47, 0x11A47, prN}, // Mn ZANABAZAR SQUARE SUBJOINER
+ {0x11A50, 0x11A50, prN}, // Lo SOYOMBO LETTER A
+ {0x11A51, 0x11A56, prN}, // Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE
+ {0x11A57, 0x11A58, prN}, // Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU
+ {0x11A59, 0x11A5B, prN}, // Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK
+ {0x11A5C, 0x11A89, prN}, // Lo [46] SOYOMBO LETTER KA..SOYOMBO CLUSTER-INITIAL LETTER SA
+ {0x11A8A, 0x11A96, prN}, // Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA
+ {0x11A97, 0x11A97, prN}, // Mc SOYOMBO SIGN VISARGA
+ {0x11A98, 0x11A99, prN}, // Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER
+ {0x11A9A, 0x11A9C, prN}, // Po [3] SOYOMBO MARK TSHEG..SOYOMBO MARK DOUBLE SHAD
+ {0x11A9D, 0x11A9D, prN}, // Lo SOYOMBO MARK PLUTA
+ {0x11A9E, 0x11AA2, prN}, // Po [5] SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME..SOYOMBO TERMINAL MARK-2
+ {0x11AB0, 0x11ABF, prN}, // Lo [16] CANADIAN SYLLABICS NATTILIK HI..CANADIAN SYLLABICS SPA
+ {0x11AC0, 0x11AF8, prN}, // Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL
+ {0x11C00, 0x11C08, prN}, // Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L
+ {0x11C0A, 0x11C2E, prN}, // Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA
+ {0x11C2F, 0x11C2F, prN}, // Mc BHAIKSUKI VOWEL SIGN AA
+ {0x11C30, 0x11C36, prN}, // Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L
+ {0x11C38, 0x11C3D, prN}, // Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA
+ {0x11C3E, 0x11C3E, prN}, // Mc BHAIKSUKI SIGN VISARGA
+ {0x11C3F, 0x11C3F, prN}, // Mn BHAIKSUKI SIGN VIRAMA
+ {0x11C40, 0x11C40, prN}, // Lo BHAIKSUKI SIGN AVAGRAHA
+ {0x11C41, 0x11C45, prN}, // Po [5] BHAIKSUKI DANDA..BHAIKSUKI GAP FILLER-2
+ {0x11C50, 0x11C59, prN}, // Nd [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE
+ {0x11C5A, 0x11C6C, prN}, // No [19] BHAIKSUKI NUMBER ONE..BHAIKSUKI HUNDREDS UNIT MARK
+ {0x11C70, 0x11C71, prN}, // Po [2] MARCHEN HEAD MARK..MARCHEN MARK SHAD
+ {0x11C72, 0x11C8F, prN}, // Lo [30] MARCHEN LETTER KA..MARCHEN LETTER A
+ {0x11C92, 0x11CA7, prN}, // Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA
+ {0x11CA9, 0x11CA9, prN}, // Mc MARCHEN SUBJOINED LETTER YA
+ {0x11CAA, 0x11CB0, prN}, // Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA
+ {0x11CB1, 0x11CB1, prN}, // Mc MARCHEN VOWEL SIGN I
+ {0x11CB2, 0x11CB3, prN}, // Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E
+ {0x11CB4, 0x11CB4, prN}, // Mc MARCHEN VOWEL SIGN O
+ {0x11CB5, 0x11CB6, prN}, // Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU
+ {0x11D00, 0x11D06, prN}, // Lo [7] MASARAM GONDI LETTER A..MASARAM GONDI LETTER E
+ {0x11D08, 0x11D09, prN}, // Lo [2] MASARAM GONDI LETTER AI..MASARAM GONDI LETTER O
+ {0x11D0B, 0x11D30, prN}, // Lo [38] MASARAM GONDI LETTER AU..MASARAM GONDI LETTER TRA
+ {0x11D31, 0x11D36, prN}, // Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R
+ {0x11D3A, 0x11D3A, prN}, // Mn MASARAM GONDI VOWEL SIGN E
+ {0x11D3C, 0x11D3D, prN}, // Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O
+ {0x11D3F, 0x11D45, prN}, // Mn [7] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI VIRAMA
+ {0x11D46, 0x11D46, prN}, // Lo MASARAM GONDI REPHA
+ {0x11D47, 0x11D47, prN}, // Mn MASARAM GONDI RA-KARA
+ {0x11D50, 0x11D59, prN}, // Nd [10] MASARAM GONDI DIGIT ZERO..MASARAM GONDI DIGIT NINE
+ {0x11D60, 0x11D65, prN}, // Lo [6] GUNJALA GONDI LETTER A..GUNJALA GONDI LETTER UU
+ {0x11D67, 0x11D68, prN}, // Lo [2] GUNJALA GONDI LETTER EE..GUNJALA GONDI LETTER AI
+ {0x11D6A, 0x11D89, prN}, // Lo [32] GUNJALA GONDI LETTER OO..GUNJALA GONDI LETTER SA
+ {0x11D8A, 0x11D8E, prN}, // Mc [5] GUNJALA GONDI VOWEL SIGN AA..GUNJALA GONDI VOWEL SIGN UU
+ {0x11D90, 0x11D91, prN}, // Mn [2] GUNJALA GONDI VOWEL SIGN EE..GUNJALA GONDI VOWEL SIGN AI
+ {0x11D93, 0x11D94, prN}, // Mc [2] GUNJALA GONDI VOWEL SIGN OO..GUNJALA GONDI VOWEL SIGN AU
+ {0x11D95, 0x11D95, prN}, // Mn GUNJALA GONDI SIGN ANUSVARA
+ {0x11D96, 0x11D96, prN}, // Mc GUNJALA GONDI SIGN VISARGA
+ {0x11D97, 0x11D97, prN}, // Mn GUNJALA GONDI VIRAMA
+ {0x11D98, 0x11D98, prN}, // Lo GUNJALA GONDI OM
+ {0x11DA0, 0x11DA9, prN}, // Nd [10] GUNJALA GONDI DIGIT ZERO..GUNJALA GONDI DIGIT NINE
+ {0x11EE0, 0x11EF2, prN}, // Lo [19] MAKASAR LETTER KA..MAKASAR ANGKA
+ {0x11EF3, 0x11EF4, prN}, // Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U
+ {0x11EF5, 0x11EF6, prN}, // Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O
+ {0x11EF7, 0x11EF8, prN}, // Po [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION
+ {0x11FB0, 0x11FB0, prN}, // Lo LISU LETTER YHA
+ {0x11FC0, 0x11FD4, prN}, // No [21] TAMIL FRACTION ONE THREE-HUNDRED-AND-TWENTIETH..TAMIL FRACTION DOWNSCALING FACTOR KIIZH
+ {0x11FD5, 0x11FDC, prN}, // So [8] TAMIL SIGN NEL..TAMIL SIGN MUKKURUNI
+ {0x11FDD, 0x11FE0, prN}, // Sc [4] TAMIL SIGN KAACU..TAMIL SIGN VARAAKAN
+ {0x11FE1, 0x11FF1, prN}, // So [17] TAMIL SIGN PAARAM..TAMIL SIGN VAKAIYARAA
+ {0x11FFF, 0x11FFF, prN}, // Po TAMIL PUNCTUATION END OF TEXT
+ {0x12000, 0x12399, prN}, // Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U
+ {0x12400, 0x1246E, prN}, // Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM
+ {0x12470, 0x12474, prN}, // Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON
+ {0x12480, 0x12543, prN}, // Lo [196] CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU
+ {0x12F90, 0x12FF0, prN}, // Lo [97] CYPRO-MINOAN SIGN CM001..CYPRO-MINOAN SIGN CM114
+ {0x12FF1, 0x12FF2, prN}, // Po [2] CYPRO-MINOAN SIGN CM301..CYPRO-MINOAN SIGN CM302
+ {0x13000, 0x1342E, prN}, // Lo [1071] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH AA032
+ {0x13430, 0x13438, prN}, // Cf [9] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH END SEGMENT
+ {0x14400, 0x14646, prN}, // Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530
+ {0x16800, 0x16A38, prN}, // Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ
+ {0x16A40, 0x16A5E, prN}, // Lo [31] MRO LETTER TA..MRO LETTER TEK
+ {0x16A60, 0x16A69, prN}, // Nd [10] MRO DIGIT ZERO..MRO DIGIT NINE
+ {0x16A6E, 0x16A6F, prN}, // Po [2] MRO DANDA..MRO DOUBLE DANDA
+ {0x16A70, 0x16ABE, prN}, // Lo [79] TANGSA LETTER OZ..TANGSA LETTER ZA
+ {0x16AC0, 0x16AC9, prN}, // Nd [10] TANGSA DIGIT ZERO..TANGSA DIGIT NINE
+ {0x16AD0, 0x16AED, prN}, // Lo [30] BASSA VAH LETTER ENNI..BASSA VAH LETTER I
+ {0x16AF0, 0x16AF4, prN}, // Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE
+ {0x16AF5, 0x16AF5, prN}, // Po BASSA VAH FULL STOP
+ {0x16B00, 0x16B2F, prN}, // Lo [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU
+ {0x16B30, 0x16B36, prN}, // Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
+ {0x16B37, 0x16B3B, prN}, // Po [5] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS FEEM
+ {0x16B3C, 0x16B3F, prN}, // So [4] PAHAWH HMONG SIGN XYEEM NTXIV..PAHAWH HMONG SIGN XYEEM FAIB
+ {0x16B40, 0x16B43, prN}, // Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM
+ {0x16B44, 0x16B44, prN}, // Po PAHAWH HMONG SIGN XAUS
+ {0x16B45, 0x16B45, prN}, // So PAHAWH HMONG SIGN CIM TSOV ROG
+ {0x16B50, 0x16B59, prN}, // Nd [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE
+ {0x16B5B, 0x16B61, prN}, // No [7] PAHAWH HMONG NUMBER TENS..PAHAWH HMONG NUMBER TRILLIONS
+ {0x16B63, 0x16B77, prN}, // Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS
+ {0x16B7D, 0x16B8F, prN}, // Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ
+ {0x16E40, 0x16E7F, prN}, // L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y
+ {0x16E80, 0x16E96, prN}, // No [23] MEDEFAIDRIN DIGIT ZERO..MEDEFAIDRIN DIGIT THREE ALTERNATE FORM
+ {0x16E97, 0x16E9A, prN}, // Po [4] MEDEFAIDRIN COMMA..MEDEFAIDRIN EXCLAMATION OH
+ {0x16F00, 0x16F4A, prN}, // Lo [75] MIAO LETTER PA..MIAO LETTER RTE
+ {0x16F4F, 0x16F4F, prN}, // Mn MIAO SIGN CONSONANT MODIFIER BAR
+ {0x16F50, 0x16F50, prN}, // Lo MIAO LETTER NASALIZATION
+ {0x16F51, 0x16F87, prN}, // Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI
+ {0x16F8F, 0x16F92, prN}, // Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW
+ {0x16F93, 0x16F9F, prN}, // Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8
+ {0x16FE0, 0x16FE1, prW}, // Lm [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK
+ {0x16FE2, 0x16FE2, prW}, // Po OLD CHINESE HOOK MARK
+ {0x16FE3, 0x16FE3, prW}, // Lm OLD CHINESE ITERATION MARK
+ {0x16FE4, 0x16FE4, prW}, // Mn KHITAN SMALL SCRIPT FILLER
+ {0x16FF0, 0x16FF1, prW}, // Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY
+ {0x17000, 0x187F7, prW}, // Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7
+ {0x18800, 0x18AFF, prW}, // Lo [768] TANGUT COMPONENT-001..TANGUT COMPONENT-768
+ {0x18B00, 0x18CD5, prW}, // Lo [470] KHITAN SMALL SCRIPT CHARACTER-18B00..KHITAN SMALL SCRIPT CHARACTER-18CD5
+ {0x18D00, 0x18D08, prW}, // Lo [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08
+ {0x1AFF0, 0x1AFF3, prW}, // Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5
+ {0x1AFF5, 0x1AFFB, prW}, // Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5
+ {0x1AFFD, 0x1AFFE, prW}, // Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8
+ {0x1B000, 0x1B0FF, prW}, // Lo [256] KATAKANA LETTER ARCHAIC E..HENTAIGANA LETTER RE-2
+ {0x1B100, 0x1B122, prW}, // Lo [35] HENTAIGANA LETTER RE-3..KATAKANA LETTER ARCHAIC WU
+ {0x1B150, 0x1B152, prW}, // Lo [3] HIRAGANA LETTER SMALL WI..HIRAGANA LETTER SMALL WO
+ {0x1B164, 0x1B167, prW}, // Lo [4] KATAKANA LETTER SMALL WI..KATAKANA LETTER SMALL N
+ {0x1B170, 0x1B2FB, prW}, // Lo [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB
+ {0x1BC00, 0x1BC6A, prN}, // Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M
+ {0x1BC70, 0x1BC7C, prN}, // Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK
+ {0x1BC80, 0x1BC88, prN}, // Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL
+ {0x1BC90, 0x1BC99, prN}, // Lo [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW
+ {0x1BC9C, 0x1BC9C, prN}, // So DUPLOYAN SIGN O WITH CROSS
+ {0x1BC9D, 0x1BC9E, prN}, // Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK
+ {0x1BC9F, 0x1BC9F, prN}, // Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP
+ {0x1BCA0, 0x1BCA3, prN}, // Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP
+ {0x1CF00, 0x1CF2D, prN}, // Mn [46] ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT..ZNAMENNY COMBINING MARK KRYZH ON LEFT
+ {0x1CF30, 0x1CF46, prN}, // Mn [23] ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO..ZNAMENNY PRIZNAK MODIFIER ROG
+ {0x1CF50, 0x1CFC3, prN}, // So [116] ZNAMENNY NEUME KRYUK..ZNAMENNY NEUME PAUK
+ {0x1D000, 0x1D0F5, prN}, // So [246] BYZANTINE MUSICAL SYMBOL PSILI..BYZANTINE MUSICAL SYMBOL GORGON NEO KATO
+ {0x1D100, 0x1D126, prN}, // So [39] MUSICAL SYMBOL SINGLE BARLINE..MUSICAL SYMBOL DRUM CLEF-2
+ {0x1D129, 0x1D164, prN}, // So [60] MUSICAL SYMBOL MULTIPLE MEASURE REST..MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE
+ {0x1D165, 0x1D166, prN}, // Mc [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM
+ {0x1D167, 0x1D169, prN}, // Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3
+ {0x1D16A, 0x1D16C, prN}, // So [3] MUSICAL SYMBOL FINGERED TREMOLO-1..MUSICAL SYMBOL FINGERED TREMOLO-3
+ {0x1D16D, 0x1D172, prN}, // Mc [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5
+ {0x1D173, 0x1D17A, prN}, // Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE
+ {0x1D17B, 0x1D182, prN}, // Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE
+ {0x1D183, 0x1D184, prN}, // So [2] MUSICAL SYMBOL ARPEGGIATO UP..MUSICAL SYMBOL ARPEGGIATO DOWN
+ {0x1D185, 0x1D18B, prN}, // Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE
+ {0x1D18C, 0x1D1A9, prN}, // So [30] MUSICAL SYMBOL RINFORZANDO..MUSICAL SYMBOL DEGREE SLASH
+ {0x1D1AA, 0x1D1AD, prN}, // Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO
+ {0x1D1AE, 0x1D1EA, prN}, // So [61] MUSICAL SYMBOL PEDAL MARK..MUSICAL SYMBOL KORON
+ {0x1D200, 0x1D241, prN}, // So [66] GREEK VOCAL NOTATION SYMBOL-1..GREEK INSTRUMENTAL NOTATION SYMBOL-54
+ {0x1D242, 0x1D244, prN}, // Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME
+ {0x1D245, 0x1D245, prN}, // So GREEK MUSICAL LEIMMA
+ {0x1D2E0, 0x1D2F3, prN}, // No [20] MAYAN NUMERAL ZERO..MAYAN NUMERAL NINETEEN
+ {0x1D300, 0x1D356, prN}, // So [87] MONOGRAM FOR EARTH..TETRAGRAM FOR FOSTERING
+ {0x1D360, 0x1D378, prN}, // No [25] COUNTING ROD UNIT DIGIT ONE..TALLY MARK FIVE
+ {0x1D400, 0x1D454, prN}, // L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G
+ {0x1D456, 0x1D49C, prN}, // L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A
+ {0x1D49E, 0x1D49F, prN}, // Lu [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D
+ {0x1D4A2, 0x1D4A2, prN}, // Lu MATHEMATICAL SCRIPT CAPITAL G
+ {0x1D4A5, 0x1D4A6, prN}, // Lu [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K
+ {0x1D4A9, 0x1D4AC, prN}, // Lu [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q
+ {0x1D4AE, 0x1D4B9, prN}, // L& [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D
+ {0x1D4BB, 0x1D4BB, prN}, // Ll MATHEMATICAL SCRIPT SMALL F
+ {0x1D4BD, 0x1D4C3, prN}, // Ll [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N
+ {0x1D4C5, 0x1D505, prN}, // L& [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B
+ {0x1D507, 0x1D50A, prN}, // Lu [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G
+ {0x1D50D, 0x1D514, prN}, // Lu [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q
+ {0x1D516, 0x1D51C, prN}, // Lu [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y
+ {0x1D51E, 0x1D539, prN}, // L& [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B
+ {0x1D53B, 0x1D53E, prN}, // Lu [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G
+ {0x1D540, 0x1D544, prN}, // Lu [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M
+ {0x1D546, 0x1D546, prN}, // Lu MATHEMATICAL DOUBLE-STRUCK CAPITAL O
+ {0x1D54A, 0x1D550, prN}, // Lu [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y
+ {0x1D552, 0x1D6A5, prN}, // L& [340] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J
+ {0x1D6A8, 0x1D6C0, prN}, // Lu [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA
+ {0x1D6C1, 0x1D6C1, prN}, // Sm MATHEMATICAL BOLD NABLA
+ {0x1D6C2, 0x1D6DA, prN}, // Ll [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA
+ {0x1D6DB, 0x1D6DB, prN}, // Sm MATHEMATICAL BOLD PARTIAL DIFFERENTIAL
+ {0x1D6DC, 0x1D6FA, prN}, // L& [31] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL ITALIC CAPITAL OMEGA
+ {0x1D6FB, 0x1D6FB, prN}, // Sm MATHEMATICAL ITALIC NABLA
+ {0x1D6FC, 0x1D714, prN}, // Ll [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA
+ {0x1D715, 0x1D715, prN}, // Sm MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL
+ {0x1D716, 0x1D734, prN}, // L& [31] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA
+ {0x1D735, 0x1D735, prN}, // Sm MATHEMATICAL BOLD ITALIC NABLA
+ {0x1D736, 0x1D74E, prN}, // Ll [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA
+ {0x1D74F, 0x1D74F, prN}, // Sm MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL
+ {0x1D750, 0x1D76E, prN}, // L& [31] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA
+ {0x1D76F, 0x1D76F, prN}, // Sm MATHEMATICAL SANS-SERIF BOLD NABLA
+ {0x1D770, 0x1D788, prN}, // Ll [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA
+ {0x1D789, 0x1D789, prN}, // Sm MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL
+ {0x1D78A, 0x1D7A8, prN}, // L& [31] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA
+ {0x1D7A9, 0x1D7A9, prN}, // Sm MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA
+ {0x1D7AA, 0x1D7C2, prN}, // Ll [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA
+ {0x1D7C3, 0x1D7C3, prN}, // Sm MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL
+ {0x1D7C4, 0x1D7CB, prN}, // L& [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA
+ {0x1D7CE, 0x1D7FF, prN}, // Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE
+ {0x1D800, 0x1D9FF, prN}, // So [512] SIGNWRITING HAND-FIST INDEX..SIGNWRITING HEAD
+ {0x1DA00, 0x1DA36, prN}, // Mn [55] SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN
+ {0x1DA37, 0x1DA3A, prN}, // So [4] SIGNWRITING AIR BLOW SMALL ROTATIONS..SIGNWRITING BREATH EXHALE
+ {0x1DA3B, 0x1DA6C, prN}, // Mn [50] SIGNWRITING MOUTH CLOSED NEUTRAL..SIGNWRITING EXCITEMENT
+ {0x1DA6D, 0x1DA74, prN}, // So [8] SIGNWRITING SHOULDER HIP SPINE..SIGNWRITING TORSO-FLOORPLANE TWISTING
+ {0x1DA75, 0x1DA75, prN}, // Mn SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS
+ {0x1DA76, 0x1DA83, prN}, // So [14] SIGNWRITING LIMB COMBINATION..SIGNWRITING LOCATION DEPTH
+ {0x1DA84, 0x1DA84, prN}, // Mn SIGNWRITING LOCATION HEAD NECK
+ {0x1DA85, 0x1DA86, prN}, // So [2] SIGNWRITING LOCATION TORSO..SIGNWRITING LOCATION LIMBS DIGITS
+ {0x1DA87, 0x1DA8B, prN}, // Po [5] SIGNWRITING COMMA..SIGNWRITING PARENTHESIS
+ {0x1DA9B, 0x1DA9F, prN}, // Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6
+ {0x1DAA1, 0x1DAAF, prN}, // Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16
+ {0x1DF00, 0x1DF09, prN}, // Ll [10] LATIN SMALL LETTER FENG DIGRAPH WITH TRILL..LATIN SMALL LETTER T WITH HOOK AND RETROFLEX HOOK
+ {0x1DF0A, 0x1DF0A, prN}, // Lo LATIN LETTER RETROFLEX CLICK WITH RETROFLEX HOOK
+ {0x1DF0B, 0x1DF1E, prN}, // Ll [20] LATIN SMALL LETTER ESH WITH DOUBLE BAR..LATIN SMALL LETTER S WITH CURL
+ {0x1E000, 0x1E006, prN}, // Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE
+ {0x1E008, 0x1E018, prN}, // Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU
+ {0x1E01B, 0x1E021, prN}, // Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI
+ {0x1E023, 0x1E024, prN}, // Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS
+ {0x1E026, 0x1E02A, prN}, // Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA
+ {0x1E100, 0x1E12C, prN}, // Lo [45] NYIAKENG PUACHUE HMONG LETTER MA..NYIAKENG PUACHUE HMONG LETTER W
+ {0x1E130, 0x1E136, prN}, // Mn [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D
+ {0x1E137, 0x1E13D, prN}, // Lm [7] NYIAKENG PUACHUE HMONG SIGN FOR PERSON..NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER
+ {0x1E140, 0x1E149, prN}, // Nd [10] NYIAKENG PUACHUE HMONG DIGIT ZERO..NYIAKENG PUACHUE HMONG DIGIT NINE
+ {0x1E14E, 0x1E14E, prN}, // Lo NYIAKENG PUACHUE HMONG LOGOGRAM NYAJ
+ {0x1E14F, 0x1E14F, prN}, // So NYIAKENG PUACHUE HMONG CIRCLED CA
+ {0x1E290, 0x1E2AD, prN}, // Lo [30] TOTO LETTER PA..TOTO LETTER A
+ {0x1E2AE, 0x1E2AE, prN}, // Mn TOTO SIGN RISING TONE
+ {0x1E2C0, 0x1E2EB, prN}, // Lo [44] WANCHO LETTER AA..WANCHO LETTER YIH
+ {0x1E2EC, 0x1E2EF, prN}, // Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI
+ {0x1E2F0, 0x1E2F9, prN}, // Nd [10] WANCHO DIGIT ZERO..WANCHO DIGIT NINE
+ {0x1E2FF, 0x1E2FF, prN}, // Sc WANCHO NGUN SIGN
+ {0x1E7E0, 0x1E7E6, prN}, // Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO
+ {0x1E7E8, 0x1E7EB, prN}, // Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE
+ {0x1E7ED, 0x1E7EE, prN}, // Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE
+ {0x1E7F0, 0x1E7FE, prN}, // Lo [15] ETHIOPIC SYLLABLE GURAGE QWI..ETHIOPIC SYLLABLE GURAGE PWEE
+ {0x1E800, 0x1E8C4, prN}, // Lo [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON
+ {0x1E8C7, 0x1E8CF, prN}, // No [9] MENDE KIKAKUI DIGIT ONE..MENDE KIKAKUI DIGIT NINE
+ {0x1E8D0, 0x1E8D6, prN}, // Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS
+ {0x1E900, 0x1E943, prN}, // L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA
+ {0x1E944, 0x1E94A, prN}, // Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA
+ {0x1E94B, 0x1E94B, prN}, // Lm ADLAM NASALIZATION MARK
+ {0x1E950, 0x1E959, prN}, // Nd [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE
+ {0x1E95E, 0x1E95F, prN}, // Po [2] ADLAM INITIAL EXCLAMATION MARK..ADLAM INITIAL QUESTION MARK
+ {0x1EC71, 0x1ECAB, prN}, // No [59] INDIC SIYAQ NUMBER ONE..INDIC SIYAQ NUMBER PREFIXED NINE
+ {0x1ECAC, 0x1ECAC, prN}, // So INDIC SIYAQ PLACEHOLDER
+ {0x1ECAD, 0x1ECAF, prN}, // No [3] INDIC SIYAQ FRACTION ONE QUARTER..INDIC SIYAQ FRACTION THREE QUARTERS
+ {0x1ECB0, 0x1ECB0, prN}, // Sc INDIC SIYAQ RUPEE MARK
+ {0x1ECB1, 0x1ECB4, prN}, // No [4] INDIC SIYAQ NUMBER ALTERNATE ONE..INDIC SIYAQ ALTERNATE LAKH MARK
+ {0x1ED01, 0x1ED2D, prN}, // No [45] OTTOMAN SIYAQ NUMBER ONE..OTTOMAN SIYAQ NUMBER NINETY THOUSAND
+ {0x1ED2E, 0x1ED2E, prN}, // So OTTOMAN SIYAQ MARRATAN
+ {0x1ED2F, 0x1ED3D, prN}, // No [15] OTTOMAN SIYAQ ALTERNATE NUMBER TWO..OTTOMAN SIYAQ FRACTION ONE SIXTH
+ {0x1EE00, 0x1EE03, prN}, // Lo [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL
+ {0x1EE05, 0x1EE1F, prN}, // Lo [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF
+ {0x1EE21, 0x1EE22, prN}, // Lo [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM
+ {0x1EE24, 0x1EE24, prN}, // Lo ARABIC MATHEMATICAL INITIAL HEH
+ {0x1EE27, 0x1EE27, prN}, // Lo ARABIC MATHEMATICAL INITIAL HAH
+ {0x1EE29, 0x1EE32, prN}, // Lo [10] ARABIC MATHEMATICAL INITIAL YEH..ARABIC MATHEMATICAL INITIAL QAF
+ {0x1EE34, 0x1EE37, prN}, // Lo [4] ARABIC MATHEMATICAL INITIAL SHEEN..ARABIC MATHEMATICAL INITIAL KHAH
+ {0x1EE39, 0x1EE39, prN}, // Lo ARABIC MATHEMATICAL INITIAL DAD
+ {0x1EE3B, 0x1EE3B, prN}, // Lo ARABIC MATHEMATICAL INITIAL GHAIN
+ {0x1EE42, 0x1EE42, prN}, // Lo ARABIC MATHEMATICAL TAILED JEEM
+ {0x1EE47, 0x1EE47, prN}, // Lo ARABIC MATHEMATICAL TAILED HAH
+ {0x1EE49, 0x1EE49, prN}, // Lo ARABIC MATHEMATICAL TAILED YEH
+ {0x1EE4B, 0x1EE4B, prN}, // Lo ARABIC MATHEMATICAL TAILED LAM
+ {0x1EE4D, 0x1EE4F, prN}, // Lo [3] ARABIC MATHEMATICAL TAILED NOON..ARABIC MATHEMATICAL TAILED AIN
+ {0x1EE51, 0x1EE52, prN}, // Lo [2] ARABIC MATHEMATICAL TAILED SAD..ARABIC MATHEMATICAL TAILED QAF
+ {0x1EE54, 0x1EE54, prN}, // Lo ARABIC MATHEMATICAL TAILED SHEEN
+ {0x1EE57, 0x1EE57, prN}, // Lo ARABIC MATHEMATICAL TAILED KHAH
+ {0x1EE59, 0x1EE59, prN}, // Lo ARABIC MATHEMATICAL TAILED DAD
+ {0x1EE5B, 0x1EE5B, prN}, // Lo ARABIC MATHEMATICAL TAILED GHAIN
+ {0x1EE5D, 0x1EE5D, prN}, // Lo ARABIC MATHEMATICAL TAILED DOTLESS NOON
+ {0x1EE5F, 0x1EE5F, prN}, // Lo ARABIC MATHEMATICAL TAILED DOTLESS QAF
+ {0x1EE61, 0x1EE62, prN}, // Lo [2] ARABIC MATHEMATICAL STRETCHED BEH..ARABIC MATHEMATICAL STRETCHED JEEM
+ {0x1EE64, 0x1EE64, prN}, // Lo ARABIC MATHEMATICAL STRETCHED HEH
+ {0x1EE67, 0x1EE6A, prN}, // Lo [4] ARABIC MATHEMATICAL STRETCHED HAH..ARABIC MATHEMATICAL STRETCHED KAF
+ {0x1EE6C, 0x1EE72, prN}, // Lo [7] ARABIC MATHEMATICAL STRETCHED MEEM..ARABIC MATHEMATICAL STRETCHED QAF
+ {0x1EE74, 0x1EE77, prN}, // Lo [4] ARABIC MATHEMATICAL STRETCHED SHEEN..ARABIC MATHEMATICAL STRETCHED KHAH
+ {0x1EE79, 0x1EE7C, prN}, // Lo [4] ARABIC MATHEMATICAL STRETCHED DAD..ARABIC MATHEMATICAL STRETCHED DOTLESS BEH
+ {0x1EE7E, 0x1EE7E, prN}, // Lo ARABIC MATHEMATICAL STRETCHED DOTLESS FEH
+ {0x1EE80, 0x1EE89, prN}, // Lo [10] ARABIC MATHEMATICAL LOOPED ALEF..ARABIC MATHEMATICAL LOOPED YEH
+ {0x1EE8B, 0x1EE9B, prN}, // Lo [17] ARABIC MATHEMATICAL LOOPED LAM..ARABIC MATHEMATICAL LOOPED GHAIN
+ {0x1EEA1, 0x1EEA3, prN}, // Lo [3] ARABIC MATHEMATICAL DOUBLE-STRUCK BEH..ARABIC MATHEMATICAL DOUBLE-STRUCK DAL
+ {0x1EEA5, 0x1EEA9, prN}, // Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH
+ {0x1EEAB, 0x1EEBB, prN}, // Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN
+ {0x1EEF0, 0x1EEF1, prN}, // Sm [2] ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL
+ {0x1F000, 0x1F003, prN}, // So [4] MAHJONG TILE EAST WIND..MAHJONG TILE NORTH WIND
+ {0x1F004, 0x1F004, prW}, // So MAHJONG TILE RED DRAGON
+ {0x1F005, 0x1F02B, prN}, // So [39] MAHJONG TILE GREEN DRAGON..MAHJONG TILE BACK
+ {0x1F030, 0x1F093, prN}, // So [100] DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06
+ {0x1F0A0, 0x1F0AE, prN}, // So [15] PLAYING CARD BACK..PLAYING CARD KING OF SPADES
+ {0x1F0B1, 0x1F0BF, prN}, // So [15] PLAYING CARD ACE OF HEARTS..PLAYING CARD RED JOKER
+ {0x1F0C1, 0x1F0CE, prN}, // So [14] PLAYING CARD ACE OF DIAMONDS..PLAYING CARD KING OF DIAMONDS
+ {0x1F0CF, 0x1F0CF, prW}, // So PLAYING CARD BLACK JOKER
+ {0x1F0D1, 0x1F0F5, prN}, // So [37] PLAYING CARD ACE OF CLUBS..PLAYING CARD TRUMP-21
+ {0x1F100, 0x1F10A, prA}, // No [11] DIGIT ZERO FULL STOP..DIGIT NINE COMMA
+ {0x1F10B, 0x1F10C, prN}, // No [2] DINGBAT CIRCLED SANS-SERIF DIGIT ZERO..DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO
+ {0x1F10D, 0x1F10F, prN}, // So [3] CIRCLED ZERO WITH SLASH..CIRCLED DOLLAR SIGN WITH OVERLAID BACKSLASH
+ {0x1F110, 0x1F12D, prA}, // So [30] PARENTHESIZED LATIN CAPITAL LETTER A..CIRCLED CD
+ {0x1F12E, 0x1F12F, prN}, // So [2] CIRCLED WZ..COPYLEFT SYMBOL
+ {0x1F130, 0x1F169, prA}, // So [58] SQUARED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z
+ {0x1F16A, 0x1F16F, prN}, // So [6] RAISED MC SIGN..CIRCLED HUMAN FIGURE
+ {0x1F170, 0x1F18D, prA}, // So [30] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED SA
+ {0x1F18E, 0x1F18E, prW}, // So NEGATIVE SQUARED AB
+ {0x1F18F, 0x1F190, prA}, // So [2] NEGATIVE SQUARED WC..SQUARE DJ
+ {0x1F191, 0x1F19A, prW}, // So [10] SQUARED CL..SQUARED VS
+ {0x1F19B, 0x1F1AC, prA}, // So [18] SQUARED THREE D..SQUARED VOD
+ {0x1F1AD, 0x1F1AD, prN}, // So MASK WORK SYMBOL
+ {0x1F1E6, 0x1F1FF, prN}, // So [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z
+ {0x1F200, 0x1F202, prW}, // So [3] SQUARE HIRAGANA HOKA..SQUARED KATAKANA SA
+ {0x1F210, 0x1F23B, prW}, // So [44] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-914D
+ {0x1F240, 0x1F248, prW}, // So [9] TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C..TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557
+ {0x1F250, 0x1F251, prW}, // So [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT
+ {0x1F260, 0x1F265, prW}, // So [6] ROUNDED SYMBOL FOR FU..ROUNDED SYMBOL FOR CAI
+ {0x1F300, 0x1F320, prW}, // So [33] CYCLONE..SHOOTING STAR
+ {0x1F321, 0x1F32C, prN}, // So [12] THERMOMETER..WIND BLOWING FACE
+ {0x1F32D, 0x1F335, prW}, // So [9] HOT DOG..CACTUS
+ {0x1F336, 0x1F336, prN}, // So HOT PEPPER
+ {0x1F337, 0x1F37C, prW}, // So [70] TULIP..BABY BOTTLE
+ {0x1F37D, 0x1F37D, prN}, // So FORK AND KNIFE WITH PLATE
+ {0x1F37E, 0x1F393, prW}, // So [22] BOTTLE WITH POPPING CORK..GRADUATION CAP
+ {0x1F394, 0x1F39F, prN}, // So [12] HEART WITH TIP ON THE LEFT..ADMISSION TICKETS
+ {0x1F3A0, 0x1F3CA, prW}, // So [43] CAROUSEL HORSE..SWIMMER
+ {0x1F3CB, 0x1F3CE, prN}, // So [4] WEIGHT LIFTER..RACING CAR
+ {0x1F3CF, 0x1F3D3, prW}, // So [5] CRICKET BAT AND BALL..TABLE TENNIS PADDLE AND BALL
+ {0x1F3D4, 0x1F3DF, prN}, // So [12] SNOW CAPPED MOUNTAIN..STADIUM
+ {0x1F3E0, 0x1F3F0, prW}, // So [17] HOUSE BUILDING..EUROPEAN CASTLE
+ {0x1F3F1, 0x1F3F3, prN}, // So [3] WHITE PENNANT..WAVING WHITE FLAG
+ {0x1F3F4, 0x1F3F4, prW}, // So WAVING BLACK FLAG
+ {0x1F3F5, 0x1F3F7, prN}, // So [3] ROSETTE..LABEL
+ {0x1F3F8, 0x1F3FA, prW}, // So [3] BADMINTON RACQUET AND SHUTTLECOCK..AMPHORA
+ {0x1F3FB, 0x1F3FF, prW}, // Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6
+ {0x1F400, 0x1F43E, prW}, // So [63] RAT..PAW PRINTS
+ {0x1F43F, 0x1F43F, prN}, // So CHIPMUNK
+ {0x1F440, 0x1F440, prW}, // So EYES
+ {0x1F441, 0x1F441, prN}, // So EYE
+ {0x1F442, 0x1F4FC, prW}, // So [187] EAR..VIDEOCASSETTE
+ {0x1F4FD, 0x1F4FE, prN}, // So [2] FILM PROJECTOR..PORTABLE STEREO
+ {0x1F4FF, 0x1F53D, prW}, // So [63] PRAYER BEADS..DOWN-POINTING SMALL RED TRIANGLE
+ {0x1F53E, 0x1F54A, prN}, // So [13] LOWER RIGHT SHADOWED WHITE CIRCLE..DOVE OF PEACE
+ {0x1F54B, 0x1F54E, prW}, // So [4] KAABA..MENORAH WITH NINE BRANCHES
+ {0x1F54F, 0x1F54F, prN}, // So BOWL OF HYGIEIA
+ {0x1F550, 0x1F567, prW}, // So [24] CLOCK FACE ONE OCLOCK..CLOCK FACE TWELVE-THIRTY
+ {0x1F568, 0x1F579, prN}, // So [18] RIGHT SPEAKER..JOYSTICK
+ {0x1F57A, 0x1F57A, prW}, // So MAN DANCING
+ {0x1F57B, 0x1F594, prN}, // So [26] LEFT HAND TELEPHONE RECEIVER..REVERSED VICTORY HAND
+ {0x1F595, 0x1F596, prW}, // So [2] REVERSED HAND WITH MIDDLE FINGER EXTENDED..RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS
+ {0x1F597, 0x1F5A3, prN}, // So [13] WHITE DOWN POINTING LEFT HAND INDEX..BLACK DOWN POINTING BACKHAND INDEX
+ {0x1F5A4, 0x1F5A4, prW}, // So BLACK HEART
+ {0x1F5A5, 0x1F5FA, prN}, // So [86] DESKTOP COMPUTER..WORLD MAP
+ {0x1F5FB, 0x1F5FF, prW}, // So [5] MOUNT FUJI..MOYAI
+ {0x1F600, 0x1F64F, prW}, // So [80] GRINNING FACE..PERSON WITH FOLDED HANDS
+ {0x1F650, 0x1F67F, prN}, // So [48] NORTH WEST POINTING LEAF..REVERSE CHECKER BOARD
+ {0x1F680, 0x1F6C5, prW}, // So [70] ROCKET..LEFT LUGGAGE
+ {0x1F6C6, 0x1F6CB, prN}, // So [6] TRIANGLE WITH ROUNDED CORNERS..COUCH AND LAMP
+ {0x1F6CC, 0x1F6CC, prW}, // So SLEEPING ACCOMMODATION
+ {0x1F6CD, 0x1F6CF, prN}, // So [3] SHOPPING BAGS..BED
+ {0x1F6D0, 0x1F6D2, prW}, // So [3] PLACE OF WORSHIP..SHOPPING TROLLEY
+ {0x1F6D3, 0x1F6D4, prN}, // So [2] STUPA..PAGODA
+ {0x1F6D5, 0x1F6D7, prW}, // So [3] HINDU TEMPLE..ELEVATOR
+ {0x1F6DD, 0x1F6DF, prW}, // So [3] PLAYGROUND SLIDE..RING BUOY
+ {0x1F6E0, 0x1F6EA, prN}, // So [11] HAMMER AND WRENCH..NORTHEAST-POINTING AIRPLANE
+ {0x1F6EB, 0x1F6EC, prW}, // So [2] AIRPLANE DEPARTURE..AIRPLANE ARRIVING
+ {0x1F6F0, 0x1F6F3, prN}, // So [4] SATELLITE..PASSENGER SHIP
+ {0x1F6F4, 0x1F6FC, prW}, // So [9] SCOOTER..ROLLER SKATE
+ {0x1F700, 0x1F773, prN}, // So [116] ALCHEMICAL SYMBOL FOR QUINTESSENCE..ALCHEMICAL SYMBOL FOR HALF OUNCE
+ {0x1F780, 0x1F7D8, prN}, // So [89] BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE..NEGATIVE CIRCLED SQUARE
+ {0x1F7E0, 0x1F7EB, prW}, // So [12] LARGE ORANGE CIRCLE..LARGE BROWN SQUARE
+ {0x1F7F0, 0x1F7F0, prW}, // So HEAVY EQUALS SIGN
+ {0x1F800, 0x1F80B, prN}, // So [12] LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD..DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD
+ {0x1F810, 0x1F847, prN}, // So [56] LEFTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD..DOWNWARDS HEAVY ARROW
+ {0x1F850, 0x1F859, prN}, // So [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW
+ {0x1F860, 0x1F887, prN}, // So [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW
+ {0x1F890, 0x1F8AD, prN}, // So [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS
+ {0x1F8B0, 0x1F8B1, prN}, // So [2] ARROW POINTING UPWARDS THEN NORTH WEST..ARROW POINTING RIGHTWARDS THEN CURVING SOUTH WEST
+ {0x1F900, 0x1F90B, prN}, // So [12] CIRCLED CROSS FORMEE WITH FOUR DOTS..DOWNWARD FACING NOTCHED HOOK WITH DOT
+ {0x1F90C, 0x1F93A, prW}, // So [47] PINCHED FINGERS..FENCER
+ {0x1F93B, 0x1F93B, prN}, // So MODERN PENTATHLON
+ {0x1F93C, 0x1F945, prW}, // So [10] WRESTLERS..GOAL NET
+ {0x1F946, 0x1F946, prN}, // So RIFLE
+ {0x1F947, 0x1F9FF, prW}, // So [185] FIRST PLACE MEDAL..NAZAR AMULET
+ {0x1FA00, 0x1FA53, prN}, // So [84] NEUTRAL CHESS KING..BLACK CHESS KNIGHT-BISHOP
+ {0x1FA60, 0x1FA6D, prN}, // So [14] XIANGQI RED GENERAL..XIANGQI BLACK SOLDIER
+ {0x1FA70, 0x1FA74, prW}, // So [5] BALLET SHOES..THONG SANDAL
+ {0x1FA78, 0x1FA7C, prW}, // So [5] DROP OF BLOOD..CRUTCH
+ {0x1FA80, 0x1FA86, prW}, // So [7] YO-YO..NESTING DOLLS
+ {0x1FA90, 0x1FAAC, prW}, // So [29] RINGED PLANET..HAMSA
+ {0x1FAB0, 0x1FABA, prW}, // So [11] FLY..NEST WITH EGGS
+ {0x1FAC0, 0x1FAC5, prW}, // So [6] ANATOMICAL HEART..PERSON WITH CROWN
+ {0x1FAD0, 0x1FAD9, prW}, // So [10] BLUEBERRIES..JAR
+ {0x1FAE0, 0x1FAE7, prW}, // So [8] MELTING FACE..BUBBLES
+ {0x1FAF0, 0x1FAF6, prW}, // So [7] HAND WITH INDEX FINGER AND THUMB CROSSED..HEART HANDS
+ {0x1FB00, 0x1FB92, prN}, // So [147] BLOCK SEXTANT-1..UPPER HALF INVERSE MEDIUM SHADE AND LOWER HALF BLOCK
+ {0x1FB94, 0x1FBCA, prN}, // So [55] LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK..WHITE UP-POINTING CHEVRON
+ {0x1FBF0, 0x1FBF9, prN}, // Nd [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE
+ {0x20000, 0x2A6DF, prW}, // Lo [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF
+ {0x2A6E0, 0x2A6FF, prW}, // Cn [32] ..
+ {0x2A700, 0x2B738, prW}, // Lo [4153] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B738
+ {0x2B739, 0x2B73F, prW}, // Cn [7] ..
+ {0x2B740, 0x2B81D, prW}, // Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D
+ {0x2B81E, 0x2B81F, prW}, // Cn [2] ..
+ {0x2B820, 0x2CEA1, prW}, // Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1
+ {0x2CEA2, 0x2CEAF, prW}, // Cn [14] ..
+ {0x2CEB0, 0x2EBE0, prW}, // Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0
+ {0x2EBE1, 0x2F7FF, prW}, // Cn [3103] ..
+ {0x2F800, 0x2FA1D, prW}, // Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D
+ {0x2FA1E, 0x2FA1F, prW}, // Cn [2] ..
+ {0x2FA20, 0x2FFFD, prW}, // Cn [1502] ..
+ {0x30000, 0x3134A, prW}, // Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A
+ {0x3134B, 0x3FFFD, prW}, // Cn [60595] ..
+ {0xE0001, 0xE0001, prN}, // Cf LANGUAGE TAG
+ {0xE0020, 0xE007F, prN}, // Cf [96] TAG SPACE..CANCEL TAG
+ {0xE0100, 0xE01EF, prA}, // Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
+ {0xF0000, 0xFFFFD, prA}, // Co [65534] ..
+ {0x100000, 0x10FFFD, prA}, // Co [65534] ..
+}
diff --git a/vendor/github.com/rivo/uniseg/emojipresentation.go b/vendor/github.com/rivo/uniseg/emojipresentation.go
new file mode 100644
index 0000000..fd0f745
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/emojipresentation.go
@@ -0,0 +1,285 @@
+package uniseg
+
+// Code generated via go generate from gen_properties.go. DO NOT EDIT.
+
+// emojiPresentation are taken from
+//
+// and
+// https://unicode.org/Public/14.0.0/ucd/emoji/emoji-data.txt
+// ("Extended_Pictographic" only)
+// on September 10, 2022. See https://www.unicode.org/license.html for the Unicode
+// license agreement.
+var emojiPresentation = [][3]int{
+ {0x231A, 0x231B, prEmojiPresentation}, // E0.6 [2] (⌚..⌛) watch..hourglass done
+ {0x23E9, 0x23EC, prEmojiPresentation}, // E0.6 [4] (⏩..⏬) fast-forward button..fast down button
+ {0x23F0, 0x23F0, prEmojiPresentation}, // E0.6 [1] (⏰) alarm clock
+ {0x23F3, 0x23F3, prEmojiPresentation}, // E0.6 [1] (⏳) hourglass not done
+ {0x25FD, 0x25FE, prEmojiPresentation}, // E0.6 [2] (◽..◾) white medium-small square..black medium-small square
+ {0x2614, 0x2615, prEmojiPresentation}, // E0.6 [2] (☔..☕) umbrella with rain drops..hot beverage
+ {0x2648, 0x2653, prEmojiPresentation}, // E0.6 [12] (♈..♓) Aries..Pisces
+ {0x267F, 0x267F, prEmojiPresentation}, // E0.6 [1] (♿) wheelchair symbol
+ {0x2693, 0x2693, prEmojiPresentation}, // E0.6 [1] (⚓) anchor
+ {0x26A1, 0x26A1, prEmojiPresentation}, // E0.6 [1] (⚡) high voltage
+ {0x26AA, 0x26AB, prEmojiPresentation}, // E0.6 [2] (⚪..⚫) white circle..black circle
+ {0x26BD, 0x26BE, prEmojiPresentation}, // E0.6 [2] (⚽..⚾) soccer ball..baseball
+ {0x26C4, 0x26C5, prEmojiPresentation}, // E0.6 [2] (⛄..⛅) snowman without snow..sun behind cloud
+ {0x26CE, 0x26CE, prEmojiPresentation}, // E0.6 [1] (⛎) Ophiuchus
+ {0x26D4, 0x26D4, prEmojiPresentation}, // E0.6 [1] (⛔) no entry
+ {0x26EA, 0x26EA, prEmojiPresentation}, // E0.6 [1] (⛪) church
+ {0x26F2, 0x26F3, prEmojiPresentation}, // E0.6 [2] (⛲..⛳) fountain..flag in hole
+ {0x26F5, 0x26F5, prEmojiPresentation}, // E0.6 [1] (⛵) sailboat
+ {0x26FA, 0x26FA, prEmojiPresentation}, // E0.6 [1] (⛺) tent
+ {0x26FD, 0x26FD, prEmojiPresentation}, // E0.6 [1] (⛽) fuel pump
+ {0x2705, 0x2705, prEmojiPresentation}, // E0.6 [1] (✅) check mark button
+ {0x270A, 0x270B, prEmojiPresentation}, // E0.6 [2] (✊..✋) raised fist..raised hand
+ {0x2728, 0x2728, prEmojiPresentation}, // E0.6 [1] (✨) sparkles
+ {0x274C, 0x274C, prEmojiPresentation}, // E0.6 [1] (❌) cross mark
+ {0x274E, 0x274E, prEmojiPresentation}, // E0.6 [1] (❎) cross mark button
+ {0x2753, 0x2755, prEmojiPresentation}, // E0.6 [3] (❓..❕) red question mark..white exclamation mark
+ {0x2757, 0x2757, prEmojiPresentation}, // E0.6 [1] (❗) red exclamation mark
+ {0x2795, 0x2797, prEmojiPresentation}, // E0.6 [3] (➕..➗) plus..divide
+ {0x27B0, 0x27B0, prEmojiPresentation}, // E0.6 [1] (➰) curly loop
+ {0x27BF, 0x27BF, prEmojiPresentation}, // E1.0 [1] (➿) double curly loop
+ {0x2B1B, 0x2B1C, prEmojiPresentation}, // E0.6 [2] (⬛..⬜) black large square..white large square
+ {0x2B50, 0x2B50, prEmojiPresentation}, // E0.6 [1] (⭐) star
+ {0x2B55, 0x2B55, prEmojiPresentation}, // E0.6 [1] (⭕) hollow red circle
+ {0x1F004, 0x1F004, prEmojiPresentation}, // E0.6 [1] (🀄) mahjong red dragon
+ {0x1F0CF, 0x1F0CF, prEmojiPresentation}, // E0.6 [1] (🃏) joker
+ {0x1F18E, 0x1F18E, prEmojiPresentation}, // E0.6 [1] (🆎) AB button (blood type)
+ {0x1F191, 0x1F19A, prEmojiPresentation}, // E0.6 [10] (🆑..🆚) CL button..VS button
+ {0x1F1E6, 0x1F1FF, prEmojiPresentation}, // E0.0 [26] (🇦..🇿) regional indicator symbol letter a..regional indicator symbol letter z
+ {0x1F201, 0x1F201, prEmojiPresentation}, // E0.6 [1] (🈁) Japanese “here” button
+ {0x1F21A, 0x1F21A, prEmojiPresentation}, // E0.6 [1] (🈚) Japanese “free of charge” button
+ {0x1F22F, 0x1F22F, prEmojiPresentation}, // E0.6 [1] (🈯) Japanese “reserved” button
+ {0x1F232, 0x1F236, prEmojiPresentation}, // E0.6 [5] (🈲..🈶) Japanese “prohibited” button..Japanese “not free of charge” button
+ {0x1F238, 0x1F23A, prEmojiPresentation}, // E0.6 [3] (🈸..🈺) Japanese “application” button..Japanese “open for business” button
+ {0x1F250, 0x1F251, prEmojiPresentation}, // E0.6 [2] (🉐..🉑) Japanese “bargain” button..Japanese “acceptable” button
+ {0x1F300, 0x1F30C, prEmojiPresentation}, // E0.6 [13] (🌀..🌌) cyclone..milky way
+ {0x1F30D, 0x1F30E, prEmojiPresentation}, // E0.7 [2] (🌍..🌎) globe showing Europe-Africa..globe showing Americas
+ {0x1F30F, 0x1F30F, prEmojiPresentation}, // E0.6 [1] (🌏) globe showing Asia-Australia
+ {0x1F310, 0x1F310, prEmojiPresentation}, // E1.0 [1] (🌐) globe with meridians
+ {0x1F311, 0x1F311, prEmojiPresentation}, // E0.6 [1] (🌑) new moon
+ {0x1F312, 0x1F312, prEmojiPresentation}, // E1.0 [1] (🌒) waxing crescent moon
+ {0x1F313, 0x1F315, prEmojiPresentation}, // E0.6 [3] (🌓..🌕) first quarter moon..full moon
+ {0x1F316, 0x1F318, prEmojiPresentation}, // E1.0 [3] (🌖..🌘) waning gibbous moon..waning crescent moon
+ {0x1F319, 0x1F319, prEmojiPresentation}, // E0.6 [1] (🌙) crescent moon
+ {0x1F31A, 0x1F31A, prEmojiPresentation}, // E1.0 [1] (🌚) new moon face
+ {0x1F31B, 0x1F31B, prEmojiPresentation}, // E0.6 [1] (🌛) first quarter moon face
+ {0x1F31C, 0x1F31C, prEmojiPresentation}, // E0.7 [1] (🌜) last quarter moon face
+ {0x1F31D, 0x1F31E, prEmojiPresentation}, // E1.0 [2] (🌝..🌞) full moon face..sun with face
+ {0x1F31F, 0x1F320, prEmojiPresentation}, // E0.6 [2] (🌟..🌠) glowing star..shooting star
+ {0x1F32D, 0x1F32F, prEmojiPresentation}, // E1.0 [3] (🌭..🌯) hot dog..burrito
+ {0x1F330, 0x1F331, prEmojiPresentation}, // E0.6 [2] (🌰..🌱) chestnut..seedling
+ {0x1F332, 0x1F333, prEmojiPresentation}, // E1.0 [2] (🌲..🌳) evergreen tree..deciduous tree
+ {0x1F334, 0x1F335, prEmojiPresentation}, // E0.6 [2] (🌴..🌵) palm tree..cactus
+ {0x1F337, 0x1F34A, prEmojiPresentation}, // E0.6 [20] (🌷..🍊) tulip..tangerine
+ {0x1F34B, 0x1F34B, prEmojiPresentation}, // E1.0 [1] (🍋) lemon
+ {0x1F34C, 0x1F34F, prEmojiPresentation}, // E0.6 [4] (🍌..🍏) banana..green apple
+ {0x1F350, 0x1F350, prEmojiPresentation}, // E1.0 [1] (🍐) pear
+ {0x1F351, 0x1F37B, prEmojiPresentation}, // E0.6 [43] (🍑..🍻) peach..clinking beer mugs
+ {0x1F37C, 0x1F37C, prEmojiPresentation}, // E1.0 [1] (🍼) baby bottle
+ {0x1F37E, 0x1F37F, prEmojiPresentation}, // E1.0 [2] (🍾..🍿) bottle with popping cork..popcorn
+ {0x1F380, 0x1F393, prEmojiPresentation}, // E0.6 [20] (🎀..🎓) ribbon..graduation cap
+ {0x1F3A0, 0x1F3C4, prEmojiPresentation}, // E0.6 [37] (🎠..🏄) carousel horse..person surfing
+ {0x1F3C5, 0x1F3C5, prEmojiPresentation}, // E1.0 [1] (🏅) sports medal
+ {0x1F3C6, 0x1F3C6, prEmojiPresentation}, // E0.6 [1] (🏆) trophy
+ {0x1F3C7, 0x1F3C7, prEmojiPresentation}, // E1.0 [1] (🏇) horse racing
+ {0x1F3C8, 0x1F3C8, prEmojiPresentation}, // E0.6 [1] (🏈) american football
+ {0x1F3C9, 0x1F3C9, prEmojiPresentation}, // E1.0 [1] (🏉) rugby football
+ {0x1F3CA, 0x1F3CA, prEmojiPresentation}, // E0.6 [1] (🏊) person swimming
+ {0x1F3CF, 0x1F3D3, prEmojiPresentation}, // E1.0 [5] (🏏..🏓) cricket game..ping pong
+ {0x1F3E0, 0x1F3E3, prEmojiPresentation}, // E0.6 [4] (🏠..🏣) house..Japanese post office
+ {0x1F3E4, 0x1F3E4, prEmojiPresentation}, // E1.0 [1] (🏤) post office
+ {0x1F3E5, 0x1F3F0, prEmojiPresentation}, // E0.6 [12] (🏥..🏰) hospital..castle
+ {0x1F3F4, 0x1F3F4, prEmojiPresentation}, // E1.0 [1] (🏴) black flag
+ {0x1F3F8, 0x1F407, prEmojiPresentation}, // E1.0 [16] (🏸..🐇) badminton..rabbit
+ {0x1F408, 0x1F408, prEmojiPresentation}, // E0.7 [1] (🐈) cat
+ {0x1F409, 0x1F40B, prEmojiPresentation}, // E1.0 [3] (🐉..🐋) dragon..whale
+ {0x1F40C, 0x1F40E, prEmojiPresentation}, // E0.6 [3] (🐌..🐎) snail..horse
+ {0x1F40F, 0x1F410, prEmojiPresentation}, // E1.0 [2] (🐏..🐐) ram..goat
+ {0x1F411, 0x1F412, prEmojiPresentation}, // E0.6 [2] (🐑..🐒) ewe..monkey
+ {0x1F413, 0x1F413, prEmojiPresentation}, // E1.0 [1] (🐓) rooster
+ {0x1F414, 0x1F414, prEmojiPresentation}, // E0.6 [1] (🐔) chicken
+ {0x1F415, 0x1F415, prEmojiPresentation}, // E0.7 [1] (🐕) dog
+ {0x1F416, 0x1F416, prEmojiPresentation}, // E1.0 [1] (🐖) pig
+ {0x1F417, 0x1F429, prEmojiPresentation}, // E0.6 [19] (🐗..🐩) boar..poodle
+ {0x1F42A, 0x1F42A, prEmojiPresentation}, // E1.0 [1] (🐪) camel
+ {0x1F42B, 0x1F43E, prEmojiPresentation}, // E0.6 [20] (🐫..🐾) two-hump camel..paw prints
+ {0x1F440, 0x1F440, prEmojiPresentation}, // E0.6 [1] (👀) eyes
+ {0x1F442, 0x1F464, prEmojiPresentation}, // E0.6 [35] (👂..👤) ear..bust in silhouette
+ {0x1F465, 0x1F465, prEmojiPresentation}, // E1.0 [1] (👥) busts in silhouette
+ {0x1F466, 0x1F46B, prEmojiPresentation}, // E0.6 [6] (👦..👫) boy..woman and man holding hands
+ {0x1F46C, 0x1F46D, prEmojiPresentation}, // E1.0 [2] (👬..👭) men holding hands..women holding hands
+ {0x1F46E, 0x1F4AC, prEmojiPresentation}, // E0.6 [63] (👮..💬) police officer..speech balloon
+ {0x1F4AD, 0x1F4AD, prEmojiPresentation}, // E1.0 [1] (💭) thought balloon
+ {0x1F4AE, 0x1F4B5, prEmojiPresentation}, // E0.6 [8] (💮..💵) white flower..dollar banknote
+ {0x1F4B6, 0x1F4B7, prEmojiPresentation}, // E1.0 [2] (💶..💷) euro banknote..pound banknote
+ {0x1F4B8, 0x1F4EB, prEmojiPresentation}, // E0.6 [52] (💸..📫) money with wings..closed mailbox with raised flag
+ {0x1F4EC, 0x1F4ED, prEmojiPresentation}, // E0.7 [2] (📬..📭) open mailbox with raised flag..open mailbox with lowered flag
+ {0x1F4EE, 0x1F4EE, prEmojiPresentation}, // E0.6 [1] (📮) postbox
+ {0x1F4EF, 0x1F4EF, prEmojiPresentation}, // E1.0 [1] (📯) postal horn
+ {0x1F4F0, 0x1F4F4, prEmojiPresentation}, // E0.6 [5] (📰..📴) newspaper..mobile phone off
+ {0x1F4F5, 0x1F4F5, prEmojiPresentation}, // E1.0 [1] (📵) no mobile phones
+ {0x1F4F6, 0x1F4F7, prEmojiPresentation}, // E0.6 [2] (📶..📷) antenna bars..camera
+ {0x1F4F8, 0x1F4F8, prEmojiPresentation}, // E1.0 [1] (📸) camera with flash
+ {0x1F4F9, 0x1F4FC, prEmojiPresentation}, // E0.6 [4] (📹..📼) video camera..videocassette
+ {0x1F4FF, 0x1F502, prEmojiPresentation}, // E1.0 [4] (📿..🔂) prayer beads..repeat single button
+ {0x1F503, 0x1F503, prEmojiPresentation}, // E0.6 [1] (🔃) clockwise vertical arrows
+ {0x1F504, 0x1F507, prEmojiPresentation}, // E1.0 [4] (🔄..🔇) counterclockwise arrows button..muted speaker
+ {0x1F508, 0x1F508, prEmojiPresentation}, // E0.7 [1] (🔈) speaker low volume
+ {0x1F509, 0x1F509, prEmojiPresentation}, // E1.0 [1] (🔉) speaker medium volume
+ {0x1F50A, 0x1F514, prEmojiPresentation}, // E0.6 [11] (🔊..🔔) speaker high volume..bell
+ {0x1F515, 0x1F515, prEmojiPresentation}, // E1.0 [1] (🔕) bell with slash
+ {0x1F516, 0x1F52B, prEmojiPresentation}, // E0.6 [22] (🔖..🔫) bookmark..water pistol
+ {0x1F52C, 0x1F52D, prEmojiPresentation}, // E1.0 [2] (🔬..🔭) microscope..telescope
+ {0x1F52E, 0x1F53D, prEmojiPresentation}, // E0.6 [16] (🔮..🔽) crystal ball..downwards button
+ {0x1F54B, 0x1F54E, prEmojiPresentation}, // E1.0 [4] (🕋..🕎) kaaba..menorah
+ {0x1F550, 0x1F55B, prEmojiPresentation}, // E0.6 [12] (🕐..🕛) one o’clock..twelve o’clock
+ {0x1F55C, 0x1F567, prEmojiPresentation}, // E0.7 [12] (🕜..🕧) one-thirty..twelve-thirty
+ {0x1F57A, 0x1F57A, prEmojiPresentation}, // E3.0 [1] (🕺) man dancing
+ {0x1F595, 0x1F596, prEmojiPresentation}, // E1.0 [2] (🖕..🖖) middle finger..vulcan salute
+ {0x1F5A4, 0x1F5A4, prEmojiPresentation}, // E3.0 [1] (🖤) black heart
+ {0x1F5FB, 0x1F5FF, prEmojiPresentation}, // E0.6 [5] (🗻..🗿) mount fuji..moai
+ {0x1F600, 0x1F600, prEmojiPresentation}, // E1.0 [1] (😀) grinning face
+ {0x1F601, 0x1F606, prEmojiPresentation}, // E0.6 [6] (😁..😆) beaming face with smiling eyes..grinning squinting face
+ {0x1F607, 0x1F608, prEmojiPresentation}, // E1.0 [2] (😇..😈) smiling face with halo..smiling face with horns
+ {0x1F609, 0x1F60D, prEmojiPresentation}, // E0.6 [5] (😉..😍) winking face..smiling face with heart-eyes
+ {0x1F60E, 0x1F60E, prEmojiPresentation}, // E1.0 [1] (😎) smiling face with sunglasses
+ {0x1F60F, 0x1F60F, prEmojiPresentation}, // E0.6 [1] (😏) smirking face
+ {0x1F610, 0x1F610, prEmojiPresentation}, // E0.7 [1] (😐) neutral face
+ {0x1F611, 0x1F611, prEmojiPresentation}, // E1.0 [1] (😑) expressionless face
+ {0x1F612, 0x1F614, prEmojiPresentation}, // E0.6 [3] (😒..😔) unamused face..pensive face
+ {0x1F615, 0x1F615, prEmojiPresentation}, // E1.0 [1] (😕) confused face
+ {0x1F616, 0x1F616, prEmojiPresentation}, // E0.6 [1] (😖) confounded face
+ {0x1F617, 0x1F617, prEmojiPresentation}, // E1.0 [1] (😗) kissing face
+ {0x1F618, 0x1F618, prEmojiPresentation}, // E0.6 [1] (😘) face blowing a kiss
+ {0x1F619, 0x1F619, prEmojiPresentation}, // E1.0 [1] (😙) kissing face with smiling eyes
+ {0x1F61A, 0x1F61A, prEmojiPresentation}, // E0.6 [1] (😚) kissing face with closed eyes
+ {0x1F61B, 0x1F61B, prEmojiPresentation}, // E1.0 [1] (😛) face with tongue
+ {0x1F61C, 0x1F61E, prEmojiPresentation}, // E0.6 [3] (😜..😞) winking face with tongue..disappointed face
+ {0x1F61F, 0x1F61F, prEmojiPresentation}, // E1.0 [1] (😟) worried face
+ {0x1F620, 0x1F625, prEmojiPresentation}, // E0.6 [6] (😠..😥) angry face..sad but relieved face
+ {0x1F626, 0x1F627, prEmojiPresentation}, // E1.0 [2] (😦..😧) frowning face with open mouth..anguished face
+ {0x1F628, 0x1F62B, prEmojiPresentation}, // E0.6 [4] (😨..😫) fearful face..tired face
+ {0x1F62C, 0x1F62C, prEmojiPresentation}, // E1.0 [1] (😬) grimacing face
+ {0x1F62D, 0x1F62D, prEmojiPresentation}, // E0.6 [1] (😭) loudly crying face
+ {0x1F62E, 0x1F62F, prEmojiPresentation}, // E1.0 [2] (😮..😯) face with open mouth..hushed face
+ {0x1F630, 0x1F633, prEmojiPresentation}, // E0.6 [4] (😰..😳) anxious face with sweat..flushed face
+ {0x1F634, 0x1F634, prEmojiPresentation}, // E1.0 [1] (😴) sleeping face
+ {0x1F635, 0x1F635, prEmojiPresentation}, // E0.6 [1] (😵) face with crossed-out eyes
+ {0x1F636, 0x1F636, prEmojiPresentation}, // E1.0 [1] (😶) face without mouth
+ {0x1F637, 0x1F640, prEmojiPresentation}, // E0.6 [10] (😷..🙀) face with medical mask..weary cat
+ {0x1F641, 0x1F644, prEmojiPresentation}, // E1.0 [4] (🙁..🙄) slightly frowning face..face with rolling eyes
+ {0x1F645, 0x1F64F, prEmojiPresentation}, // E0.6 [11] (🙅..🙏) person gesturing NO..folded hands
+ {0x1F680, 0x1F680, prEmojiPresentation}, // E0.6 [1] (🚀) rocket
+ {0x1F681, 0x1F682, prEmojiPresentation}, // E1.0 [2] (🚁..🚂) helicopter..locomotive
+ {0x1F683, 0x1F685, prEmojiPresentation}, // E0.6 [3] (🚃..🚅) railway car..bullet train
+ {0x1F686, 0x1F686, prEmojiPresentation}, // E1.0 [1] (🚆) train
+ {0x1F687, 0x1F687, prEmojiPresentation}, // E0.6 [1] (🚇) metro
+ {0x1F688, 0x1F688, prEmojiPresentation}, // E1.0 [1] (🚈) light rail
+ {0x1F689, 0x1F689, prEmojiPresentation}, // E0.6 [1] (🚉) station
+ {0x1F68A, 0x1F68B, prEmojiPresentation}, // E1.0 [2] (🚊..🚋) tram..tram car
+ {0x1F68C, 0x1F68C, prEmojiPresentation}, // E0.6 [1] (🚌) bus
+ {0x1F68D, 0x1F68D, prEmojiPresentation}, // E0.7 [1] (🚍) oncoming bus
+ {0x1F68E, 0x1F68E, prEmojiPresentation}, // E1.0 [1] (🚎) trolleybus
+ {0x1F68F, 0x1F68F, prEmojiPresentation}, // E0.6 [1] (🚏) bus stop
+ {0x1F690, 0x1F690, prEmojiPresentation}, // E1.0 [1] (🚐) minibus
+ {0x1F691, 0x1F693, prEmojiPresentation}, // E0.6 [3] (🚑..🚓) ambulance..police car
+ {0x1F694, 0x1F694, prEmojiPresentation}, // E0.7 [1] (🚔) oncoming police car
+ {0x1F695, 0x1F695, prEmojiPresentation}, // E0.6 [1] (🚕) taxi
+ {0x1F696, 0x1F696, prEmojiPresentation}, // E1.0 [1] (🚖) oncoming taxi
+ {0x1F697, 0x1F697, prEmojiPresentation}, // E0.6 [1] (🚗) automobile
+ {0x1F698, 0x1F698, prEmojiPresentation}, // E0.7 [1] (🚘) oncoming automobile
+ {0x1F699, 0x1F69A, prEmojiPresentation}, // E0.6 [2] (🚙..🚚) sport utility vehicle..delivery truck
+ {0x1F69B, 0x1F6A1, prEmojiPresentation}, // E1.0 [7] (🚛..🚡) articulated lorry..aerial tramway
+ {0x1F6A2, 0x1F6A2, prEmojiPresentation}, // E0.6 [1] (🚢) ship
+ {0x1F6A3, 0x1F6A3, prEmojiPresentation}, // E1.0 [1] (🚣) person rowing boat
+ {0x1F6A4, 0x1F6A5, prEmojiPresentation}, // E0.6 [2] (🚤..🚥) speedboat..horizontal traffic light
+ {0x1F6A6, 0x1F6A6, prEmojiPresentation}, // E1.0 [1] (🚦) vertical traffic light
+ {0x1F6A7, 0x1F6AD, prEmojiPresentation}, // E0.6 [7] (🚧..🚭) construction..no smoking
+ {0x1F6AE, 0x1F6B1, prEmojiPresentation}, // E1.0 [4] (🚮..🚱) litter in bin sign..non-potable water
+ {0x1F6B2, 0x1F6B2, prEmojiPresentation}, // E0.6 [1] (🚲) bicycle
+ {0x1F6B3, 0x1F6B5, prEmojiPresentation}, // E1.0 [3] (🚳..🚵) no bicycles..person mountain biking
+ {0x1F6B6, 0x1F6B6, prEmojiPresentation}, // E0.6 [1] (🚶) person walking
+ {0x1F6B7, 0x1F6B8, prEmojiPresentation}, // E1.0 [2] (🚷..🚸) no pedestrians..children crossing
+ {0x1F6B9, 0x1F6BE, prEmojiPresentation}, // E0.6 [6] (🚹..🚾) men’s room..water closet
+ {0x1F6BF, 0x1F6BF, prEmojiPresentation}, // E1.0 [1] (🚿) shower
+ {0x1F6C0, 0x1F6C0, prEmojiPresentation}, // E0.6 [1] (🛀) person taking bath
+ {0x1F6C1, 0x1F6C5, prEmojiPresentation}, // E1.0 [5] (🛁..🛅) bathtub..left luggage
+ {0x1F6CC, 0x1F6CC, prEmojiPresentation}, // E1.0 [1] (🛌) person in bed
+ {0x1F6D0, 0x1F6D0, prEmojiPresentation}, // E1.0 [1] (🛐) place of worship
+ {0x1F6D1, 0x1F6D2, prEmojiPresentation}, // E3.0 [2] (🛑..🛒) stop sign..shopping cart
+ {0x1F6D5, 0x1F6D5, prEmojiPresentation}, // E12.0 [1] (🛕) hindu temple
+ {0x1F6D6, 0x1F6D7, prEmojiPresentation}, // E13.0 [2] (🛖..🛗) hut..elevator
+ {0x1F6DD, 0x1F6DF, prEmojiPresentation}, // E14.0 [3] (🛝..🛟) playground slide..ring buoy
+ {0x1F6EB, 0x1F6EC, prEmojiPresentation}, // E1.0 [2] (🛫..🛬) airplane departure..airplane arrival
+ {0x1F6F4, 0x1F6F6, prEmojiPresentation}, // E3.0 [3] (🛴..🛶) kick scooter..canoe
+ {0x1F6F7, 0x1F6F8, prEmojiPresentation}, // E5.0 [2] (🛷..🛸) sled..flying saucer
+ {0x1F6F9, 0x1F6F9, prEmojiPresentation}, // E11.0 [1] (🛹) skateboard
+ {0x1F6FA, 0x1F6FA, prEmojiPresentation}, // E12.0 [1] (🛺) auto rickshaw
+ {0x1F6FB, 0x1F6FC, prEmojiPresentation}, // E13.0 [2] (🛻..🛼) pickup truck..roller skate
+ {0x1F7E0, 0x1F7EB, prEmojiPresentation}, // E12.0 [12] (🟠..🟫) orange circle..brown square
+ {0x1F7F0, 0x1F7F0, prEmojiPresentation}, // E14.0 [1] (🟰) heavy equals sign
+ {0x1F90C, 0x1F90C, prEmojiPresentation}, // E13.0 [1] (🤌) pinched fingers
+ {0x1F90D, 0x1F90F, prEmojiPresentation}, // E12.0 [3] (🤍..🤏) white heart..pinching hand
+ {0x1F910, 0x1F918, prEmojiPresentation}, // E1.0 [9] (🤐..🤘) zipper-mouth face..sign of the horns
+ {0x1F919, 0x1F91E, prEmojiPresentation}, // E3.0 [6] (🤙..🤞) call me hand..crossed fingers
+ {0x1F91F, 0x1F91F, prEmojiPresentation}, // E5.0 [1] (🤟) love-you gesture
+ {0x1F920, 0x1F927, prEmojiPresentation}, // E3.0 [8] (🤠..🤧) cowboy hat face..sneezing face
+ {0x1F928, 0x1F92F, prEmojiPresentation}, // E5.0 [8] (🤨..🤯) face with raised eyebrow..exploding head
+ {0x1F930, 0x1F930, prEmojiPresentation}, // E3.0 [1] (🤰) pregnant woman
+ {0x1F931, 0x1F932, prEmojiPresentation}, // E5.0 [2] (🤱..🤲) breast-feeding..palms up together
+ {0x1F933, 0x1F93A, prEmojiPresentation}, // E3.0 [8] (🤳..🤺) selfie..person fencing
+ {0x1F93C, 0x1F93E, prEmojiPresentation}, // E3.0 [3] (🤼..🤾) people wrestling..person playing handball
+ {0x1F93F, 0x1F93F, prEmojiPresentation}, // E12.0 [1] (🤿) diving mask
+ {0x1F940, 0x1F945, prEmojiPresentation}, // E3.0 [6] (🥀..🥅) wilted flower..goal net
+ {0x1F947, 0x1F94B, prEmojiPresentation}, // E3.0 [5] (🥇..🥋) 1st place medal..martial arts uniform
+ {0x1F94C, 0x1F94C, prEmojiPresentation}, // E5.0 [1] (🥌) curling stone
+ {0x1F94D, 0x1F94F, prEmojiPresentation}, // E11.0 [3] (🥍..🥏) lacrosse..flying disc
+ {0x1F950, 0x1F95E, prEmojiPresentation}, // E3.0 [15] (🥐..🥞) croissant..pancakes
+ {0x1F95F, 0x1F96B, prEmojiPresentation}, // E5.0 [13] (🥟..🥫) dumpling..canned food
+ {0x1F96C, 0x1F970, prEmojiPresentation}, // E11.0 [5] (🥬..🥰) leafy green..smiling face with hearts
+ {0x1F971, 0x1F971, prEmojiPresentation}, // E12.0 [1] (🥱) yawning face
+ {0x1F972, 0x1F972, prEmojiPresentation}, // E13.0 [1] (🥲) smiling face with tear
+ {0x1F973, 0x1F976, prEmojiPresentation}, // E11.0 [4] (🥳..🥶) partying face..cold face
+ {0x1F977, 0x1F978, prEmojiPresentation}, // E13.0 [2] (🥷..🥸) ninja..disguised face
+ {0x1F979, 0x1F979, prEmojiPresentation}, // E14.0 [1] (🥹) face holding back tears
+ {0x1F97A, 0x1F97A, prEmojiPresentation}, // E11.0 [1] (🥺) pleading face
+ {0x1F97B, 0x1F97B, prEmojiPresentation}, // E12.0 [1] (🥻) sari
+ {0x1F97C, 0x1F97F, prEmojiPresentation}, // E11.0 [4] (🥼..🥿) lab coat..flat shoe
+ {0x1F980, 0x1F984, prEmojiPresentation}, // E1.0 [5] (🦀..🦄) crab..unicorn
+ {0x1F985, 0x1F991, prEmojiPresentation}, // E3.0 [13] (🦅..🦑) eagle..squid
+ {0x1F992, 0x1F997, prEmojiPresentation}, // E5.0 [6] (🦒..🦗) giraffe..cricket
+ {0x1F998, 0x1F9A2, prEmojiPresentation}, // E11.0 [11] (🦘..🦢) kangaroo..swan
+ {0x1F9A3, 0x1F9A4, prEmojiPresentation}, // E13.0 [2] (🦣..🦤) mammoth..dodo
+ {0x1F9A5, 0x1F9AA, prEmojiPresentation}, // E12.0 [6] (🦥..🦪) sloth..oyster
+ {0x1F9AB, 0x1F9AD, prEmojiPresentation}, // E13.0 [3] (🦫..🦭) beaver..seal
+ {0x1F9AE, 0x1F9AF, prEmojiPresentation}, // E12.0 [2] (🦮..🦯) guide dog..white cane
+ {0x1F9B0, 0x1F9B9, prEmojiPresentation}, // E11.0 [10] (🦰..🦹) red hair..supervillain
+ {0x1F9BA, 0x1F9BF, prEmojiPresentation}, // E12.0 [6] (🦺..🦿) safety vest..mechanical leg
+ {0x1F9C0, 0x1F9C0, prEmojiPresentation}, // E1.0 [1] (🧀) cheese wedge
+ {0x1F9C1, 0x1F9C2, prEmojiPresentation}, // E11.0 [2] (🧁..🧂) cupcake..salt
+ {0x1F9C3, 0x1F9CA, prEmojiPresentation}, // E12.0 [8] (🧃..🧊) beverage box..ice
+ {0x1F9CB, 0x1F9CB, prEmojiPresentation}, // E13.0 [1] (🧋) bubble tea
+ {0x1F9CC, 0x1F9CC, prEmojiPresentation}, // E14.0 [1] (🧌) troll
+ {0x1F9CD, 0x1F9CF, prEmojiPresentation}, // E12.0 [3] (🧍..🧏) person standing..deaf person
+ {0x1F9D0, 0x1F9E6, prEmojiPresentation}, // E5.0 [23] (🧐..🧦) face with monocle..socks
+ {0x1F9E7, 0x1F9FF, prEmojiPresentation}, // E11.0 [25] (🧧..🧿) red envelope..nazar amulet
+ {0x1FA70, 0x1FA73, prEmojiPresentation}, // E12.0 [4] (🩰..🩳) ballet shoes..shorts
+ {0x1FA74, 0x1FA74, prEmojiPresentation}, // E13.0 [1] (🩴) thong sandal
+ {0x1FA78, 0x1FA7A, prEmojiPresentation}, // E12.0 [3] (🩸..🩺) drop of blood..stethoscope
+ {0x1FA7B, 0x1FA7C, prEmojiPresentation}, // E14.0 [2] (🩻..🩼) x-ray..crutch
+ {0x1FA80, 0x1FA82, prEmojiPresentation}, // E12.0 [3] (🪀..🪂) yo-yo..parachute
+ {0x1FA83, 0x1FA86, prEmojiPresentation}, // E13.0 [4] (🪃..🪆) boomerang..nesting dolls
+ {0x1FA90, 0x1FA95, prEmojiPresentation}, // E12.0 [6] (🪐..🪕) ringed planet..banjo
+ {0x1FA96, 0x1FAA8, prEmojiPresentation}, // E13.0 [19] (🪖..🪨) military helmet..rock
+ {0x1FAA9, 0x1FAAC, prEmojiPresentation}, // E14.0 [4] (🪩..🪬) mirror ball..hamsa
+ {0x1FAB0, 0x1FAB6, prEmojiPresentation}, // E13.0 [7] (🪰..🪶) fly..feather
+ {0x1FAB7, 0x1FABA, prEmojiPresentation}, // E14.0 [4] (🪷..🪺) lotus..nest with eggs
+ {0x1FAC0, 0x1FAC2, prEmojiPresentation}, // E13.0 [3] (🫀..🫂) anatomical heart..people hugging
+ {0x1FAC3, 0x1FAC5, prEmojiPresentation}, // E14.0 [3] (🫃..🫅) pregnant man..person with crown
+ {0x1FAD0, 0x1FAD6, prEmojiPresentation}, // E13.0 [7] (🫐..🫖) blueberries..teapot
+ {0x1FAD7, 0x1FAD9, prEmojiPresentation}, // E14.0 [3] (🫗..🫙) pouring liquid..jar
+ {0x1FAE0, 0x1FAE7, prEmojiPresentation}, // E14.0 [8] (🫠..🫧) melting face..bubbles
+ {0x1FAF0, 0x1FAF6, prEmojiPresentation}, // E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands
+}
diff --git a/vendor/github.com/rivo/uniseg/gen_breaktest.go b/vendor/github.com/rivo/uniseg/gen_breaktest.go
new file mode 100644
index 0000000..e613c4c
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/gen_breaktest.go
@@ -0,0 +1,213 @@
+//go:build generate
+
+// This program generates a Go containing a slice of test cases based on the
+// Unicode Character Database auxiliary data files. The command line arguments
+// are as follows:
+//
+// 1. The name of the Unicode data file (just the filename, without extension).
+// 2. The name of the locally generated Go file.
+// 3. The name of the slice containing the test cases.
+// 4. The name of the generator, for logging purposes.
+//
+//go:generate go run gen_breaktest.go GraphemeBreakTest graphemebreak_test.go graphemeBreakTestCases graphemes
+//go:generate go run gen_breaktest.go WordBreakTest wordbreak_test.go wordBreakTestCases words
+//go:generate go run gen_breaktest.go SentenceBreakTest sentencebreak_test.go sentenceBreakTestCases sentences
+//go:generate go run gen_breaktest.go LineBreakTest linebreak_test.go lineBreakTestCases lines
+
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "fmt"
+ "go/format"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "os"
+ "time"
+)
+
+// We want to test against a specific version rather than the latest. When the
+// package is upgraded to a new version, change these to generate new tests.
+const (
+ testCaseURL = `https://www.unicode.org/Public/14.0.0/ucd/auxiliary/%s.txt`
+)
+
+func main() {
+ if len(os.Args) < 5 {
+ fmt.Println("Not enough arguments, see code for details")
+ os.Exit(1)
+ }
+
+ log.SetPrefix("gen_breaktest (" + os.Args[4] + "): ")
+ log.SetFlags(0)
+
+ // Read text of testcases and parse into Go source code.
+ src, err := parse(fmt.Sprintf(testCaseURL, os.Args[1]))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Format the Go code.
+ formatted, err := format.Source(src)
+ if err != nil {
+ log.Fatalln("gofmt:", err)
+ }
+
+ // Write it out.
+ log.Print("Writing to ", os.Args[2])
+ if err := ioutil.WriteFile(os.Args[2], formatted, 0644); err != nil {
+ log.Fatal(err)
+ }
+}
+
+// parse reads a break text file, either from a local file or from a URL. It
+// parses the file data into Go source code representing the test cases.
+func parse(url string) ([]byte, error) {
+ log.Printf("Parsing %s", url)
+ res, err := http.Get(url)
+ if err != nil {
+ return nil, err
+ }
+ body := res.Body
+ defer body.Close()
+
+ buf := new(bytes.Buffer)
+ buf.Grow(120 << 10)
+ buf.WriteString(`package uniseg
+
+// Code generated via go generate from gen_breaktest.go. DO NOT EDIT.
+
+// ` + os.Args[3] + ` are Grapheme testcases taken from
+// ` + url + `
+// on ` + time.Now().Format("January 2, 2006") + `. See
+// https://www.unicode.org/license.html for the Unicode license agreement.
+var ` + os.Args[3] + ` = []testCase {
+`)
+
+ sc := bufio.NewScanner(body)
+ num := 1
+ var line []byte
+ original := make([]byte, 0, 64)
+ expected := make([]byte, 0, 64)
+ for sc.Scan() {
+ num++
+ line = sc.Bytes()
+ if len(line) == 0 || line[0] == '#' {
+ continue
+ }
+ var comment []byte
+ if i := bytes.IndexByte(line, '#'); i >= 0 {
+ comment = bytes.TrimSpace(line[i+1:])
+ line = bytes.TrimSpace(line[:i])
+ }
+ original, expected, err := parseRuneSequence(line, original[:0], expected[:0])
+ if err != nil {
+ return nil, fmt.Errorf(`line %d: %v: %q`, num, err, line)
+ }
+ fmt.Fprintf(buf, "\t{original: \"%s\", expected: %s}, // %s\n", original, expected, comment)
+ }
+ if err := sc.Err(); err != nil {
+ return nil, err
+ }
+
+ // Check for final "# EOF", useful check if we're streaming via HTTP
+ if !bytes.Equal(line, []byte("# EOF")) {
+ return nil, fmt.Errorf(`line %d: exected "# EOF" as final line, got %q`, num, line)
+ }
+ buf.WriteString("}\n")
+ return buf.Bytes(), nil
+}
+
+// Used by parseRuneSequence to match input via bytes.HasPrefix.
+var (
+ prefixBreak = []byte("÷ ")
+ prefixDontBreak = []byte("× ")
+ breakOk = []byte("÷")
+ breakNo = []byte("×")
+)
+
+// parseRuneSequence parses a rune + breaking opportunity sequence from b
+// and appends the Go code for testcase.original to orig
+// and appends the Go code for testcase.expected to exp.
+// It retuns the new orig and exp slices.
+//
+// E.g. for the input b="÷ 0020 × 0308 ÷ 1F1E6 ÷"
+// it will append
+// "\u0020\u0308\U0001F1E6"
+// and "[][]rune{{0x0020,0x0308},{0x1F1E6},}"
+// to orig and exp respectively.
+//
+// The formatting of exp is expected to be cleaned up by gofmt or format.Source.
+// Note we explicitly require the sequence to start with ÷ and we implicitly
+// require it to end with ÷.
+func parseRuneSequence(b, orig, exp []byte) ([]byte, []byte, error) {
+ // Check for and remove first ÷ or ×.
+ if !bytes.HasPrefix(b, prefixBreak) && !bytes.HasPrefix(b, prefixDontBreak) {
+ return nil, nil, errors.New("expected ÷ or × as first character")
+ }
+ if bytes.HasPrefix(b, prefixBreak) {
+ b = b[len(prefixBreak):]
+ } else {
+ b = b[len(prefixDontBreak):]
+ }
+
+ boundary := true
+ exp = append(exp, "[][]rune{"...)
+ for len(b) > 0 {
+ if boundary {
+ exp = append(exp, '{')
+ }
+ exp = append(exp, "0x"...)
+ // Find end of hex digits.
+ var i int
+ for i = 0; i < len(b) && b[i] != ' '; i++ {
+ if d := b[i]; ('0' <= d || d <= '9') ||
+ ('A' <= d || d <= 'F') ||
+ ('a' <= d || d <= 'f') {
+ continue
+ }
+ return nil, nil, errors.New("bad hex digit")
+ }
+ switch i {
+ case 4:
+ orig = append(orig, "\\u"...)
+ case 5:
+ orig = append(orig, "\\U000"...)
+ default:
+ return nil, nil, errors.New("unsupport code point hex length")
+ }
+ orig = append(orig, b[:i]...)
+ exp = append(exp, b[:i]...)
+ b = b[i:]
+
+ // Check for space between hex and ÷ or ×.
+ if len(b) < 1 || b[0] != ' ' {
+ return nil, nil, errors.New("bad input")
+ }
+ b = b[1:]
+
+ // Check for next boundary.
+ switch {
+ case bytes.HasPrefix(b, breakOk):
+ boundary = true
+ b = b[len(breakOk):]
+ case bytes.HasPrefix(b, breakNo):
+ boundary = false
+ b = b[len(breakNo):]
+ default:
+ return nil, nil, errors.New("missing ÷ or ×")
+ }
+ if boundary {
+ exp = append(exp, '}')
+ }
+ exp = append(exp, ',')
+ if len(b) > 0 && b[0] == ' ' {
+ b = b[1:]
+ }
+ }
+ exp = append(exp, '}')
+ return orig, exp, nil
+}
diff --git a/vendor/github.com/rivo/uniseg/gen_properties.go b/vendor/github.com/rivo/uniseg/gen_properties.go
new file mode 100644
index 0000000..999d5ef
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/gen_properties.go
@@ -0,0 +1,256 @@
+//go:build generate
+
+// This program generates a property file in Go file from Unicode Character
+// Database auxiliary data files. The command line arguments are as follows:
+//
+// 1. The name of the Unicode data file (just the filename, without extension).
+// Can be "-" (to skip) if the emoji flag is included.
+// 2. The name of the locally generated Go file.
+// 3. The name of the slice mapping code points to properties.
+// 4. The name of the generator, for logging purposes.
+// 5. (Optional) Flags, comma-separated. The following flags are available:
+// - "emojis=": include the specified emoji properties (e.g.
+// "Extended_Pictographic").
+// - "gencat": include general category properties.
+//
+//go:generate go run gen_properties.go auxiliary/GraphemeBreakProperty graphemeproperties.go graphemeCodePoints graphemes emojis=Extended_Pictographic
+//go:generate go run gen_properties.go auxiliary/WordBreakProperty wordproperties.go workBreakCodePoints words emojis=Extended_Pictographic
+//go:generate go run gen_properties.go auxiliary/SentenceBreakProperty sentenceproperties.go sentenceBreakCodePoints sentences
+//go:generate go run gen_properties.go LineBreak lineproperties.go lineBreakCodePoints lines gencat
+//go:generate go run gen_properties.go EastAsianWidth eastasianwidth.go eastAsianWidth eastasianwidth
+//go:generate go run gen_properties.go - emojipresentation.go emojiPresentation emojipresentation emojis=Emoji_Presentation
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "fmt"
+ "go/format"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "os"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// We want to test against a specific version rather than the latest. When the
+// package is upgraded to a new version, change these to generate new tests.
+const (
+ propertyURL = `https://www.unicode.org/Public/14.0.0/ucd/%s.txt`
+ emojiURL = `https://unicode.org/Public/14.0.0/ucd/emoji/emoji-data.txt`
+)
+
+// The regular expression for a line containing a code point range property.
+var propertyPattern = regexp.MustCompile(`^([0-9A-F]{4,6})(\.\.([0-9A-F]{4,6}))?\s*;\s*([A-Za-z0-9_]+)\s*#\s(.+)$`)
+
+func main() {
+ if len(os.Args) < 5 {
+ fmt.Println("Not enough arguments, see code for details")
+ os.Exit(1)
+ }
+
+ log.SetPrefix("gen_properties (" + os.Args[4] + "): ")
+ log.SetFlags(0)
+
+ // Parse flags.
+ flags := make(map[string]string)
+ if len(os.Args) >= 6 {
+ for _, flag := range strings.Split(os.Args[5], ",") {
+ flagFields := strings.Split(flag, "=")
+ if len(flagFields) == 1 {
+ flags[flagFields[0]] = "yes"
+ } else {
+ flags[flagFields[0]] = flagFields[1]
+ }
+ }
+ }
+
+ // Parse the text file and generate Go source code from it.
+ _, includeGeneralCategory := flags["gencat"]
+ var mainURL string
+ if os.Args[1] != "-" {
+ mainURL = fmt.Sprintf(propertyURL, os.Args[1])
+ }
+ src, err := parse(mainURL, flags["emojis"], includeGeneralCategory)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Format the Go code.
+ formatted, err := format.Source([]byte(src))
+ if err != nil {
+ log.Fatal("gofmt:", err)
+ }
+
+ // Save it to the (local) target file.
+ log.Print("Writing to ", os.Args[2])
+ if err := ioutil.WriteFile(os.Args[2], formatted, 0644); err != nil {
+ log.Fatal(err)
+ }
+}
+
+// parse parses the Unicode Properties text files located at the given URLs and
+// returns their equivalent Go source code to be used in the uniseg package. If
+// "emojiProperty" is not an empty string, emoji code points for that emoji
+// property (e.g. "Extended_Pictographic") will be included. In those cases, you
+// may pass an empty "propertyURL" to skip parsing the main properties file. If
+// "includeGeneralCategory" is true, the Unicode General Category property will
+// be extracted from the comments and included in the output.
+func parse(propertyURL, emojiProperty string, includeGeneralCategory bool) (string, error) {
+ if propertyURL == "" && emojiProperty == "" {
+ return "", errors.New("no properties to parse")
+ }
+
+ // Temporary buffer to hold properties.
+ var properties [][4]string
+
+ // Open the first URL.
+ if propertyURL != "" {
+ log.Printf("Parsing %s", propertyURL)
+ res, err := http.Get(propertyURL)
+ if err != nil {
+ return "", err
+ }
+ in1 := res.Body
+ defer in1.Close()
+
+ // Parse it.
+ scanner := bufio.NewScanner(in1)
+ num := 0
+ for scanner.Scan() {
+ num++
+ line := strings.TrimSpace(scanner.Text())
+
+ // Skip comments and empty lines.
+ if strings.HasPrefix(line, "#") || line == "" {
+ continue
+ }
+
+ // Everything else must be a code point range, a property and a comment.
+ from, to, property, comment, err := parseProperty(line)
+ if err != nil {
+ return "", fmt.Errorf("%s line %d: %v", os.Args[4], num, err)
+ }
+ properties = append(properties, [4]string{from, to, property, comment})
+ }
+ if err := scanner.Err(); err != nil {
+ return "", err
+ }
+ }
+
+ // Open the second URL.
+ if emojiProperty != "" {
+ log.Printf("Parsing %s", emojiURL)
+ res, err := http.Get(emojiURL)
+ if err != nil {
+ return "", err
+ }
+ in2 := res.Body
+ defer in2.Close()
+
+ // Parse it.
+ scanner := bufio.NewScanner(in2)
+ num := 0
+ for scanner.Scan() {
+ num++
+ line := scanner.Text()
+
+ // Skip comments, empty lines, and everything not containing
+ // "Extended_Pictographic".
+ if strings.HasPrefix(line, "#") || line == "" || !strings.Contains(line, emojiProperty) {
+ continue
+ }
+
+ // Everything else must be a code point range, a property and a comment.
+ from, to, property, comment, err := parseProperty(line)
+ if err != nil {
+ return "", fmt.Errorf("emojis line %d: %v", num, err)
+ }
+ properties = append(properties, [4]string{from, to, property, comment})
+ }
+ if err := scanner.Err(); err != nil {
+ return "", err
+ }
+ }
+
+ // Sort properties.
+ sort.Slice(properties, func(i, j int) bool {
+ left, _ := strconv.ParseUint(properties[i][0], 16, 64)
+ right, _ := strconv.ParseUint(properties[j][0], 16, 64)
+ return left < right
+ })
+
+ // Header.
+ var (
+ buf bytes.Buffer
+ emojiComment string
+ )
+ columns := 3
+ if includeGeneralCategory {
+ columns = 4
+ }
+ if emojiURL != "" {
+ emojiComment = `
+// and
+// ` + emojiURL + `
+// ("Extended_Pictographic" only)`
+ }
+ buf.WriteString(`package uniseg
+
+// Code generated via go generate from gen_properties.go. DO NOT EDIT.
+
+// ` + os.Args[3] + ` are taken from
+// ` + propertyURL + emojiComment + `
+// on ` + time.Now().Format("January 2, 2006") + `. See https://www.unicode.org/license.html for the Unicode
+// license agreement.
+var ` + os.Args[3] + ` = [][` + strconv.Itoa(columns) + `]int{
+ `)
+
+ // Properties.
+ for _, prop := range properties {
+ if includeGeneralCategory {
+ generalCategory := "gc" + prop[3][:2]
+ if generalCategory == "gcL&" {
+ generalCategory = "gcLC"
+ }
+ prop[3] = prop[3][3:]
+ fmt.Fprintf(&buf, "{0x%s,0x%s,%s,%s}, // %s\n", prop[0], prop[1], translateProperty("pr", prop[2]), generalCategory, prop[3])
+ } else {
+ fmt.Fprintf(&buf, "{0x%s,0x%s,%s}, // %s\n", prop[0], prop[1], translateProperty("pr", prop[2]), prop[3])
+ }
+ }
+
+ // Tail.
+ buf.WriteString("}")
+
+ return buf.String(), nil
+}
+
+// parseProperty parses a line of the Unicode properties text file containing a
+// property for a code point range and returns it along with its comment.
+func parseProperty(line string) (from, to, property, comment string, err error) {
+ fields := propertyPattern.FindStringSubmatch(line)
+ if fields == nil {
+ err = errors.New("no property found")
+ return
+ }
+ from = fields[1]
+ to = fields[3]
+ if to == "" {
+ to = from
+ }
+ property = fields[4]
+ comment = fields[5]
+ return
+}
+
+// translateProperty translates a property name as used in the Unicode data file
+// to a variable used in the Go code.
+func translateProperty(prefix, property string) string {
+ return prefix + strings.ReplaceAll(property, "_", "")
+}
diff --git a/vendor/github.com/rivo/uniseg/grapheme.go b/vendor/github.com/rivo/uniseg/grapheme.go
new file mode 100644
index 0000000..0086fc1
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/grapheme.go
@@ -0,0 +1,334 @@
+package uniseg
+
+import "unicode/utf8"
+
+// Graphemes implements an iterator over Unicode grapheme clusters, or
+// user-perceived characters. While iterating, it also provides information
+// about word boundaries, sentence boundaries, line breaks, and monospace
+// character widths.
+//
+// After constructing the class via [NewGraphemes] for a given string "str",
+// [Graphemes.Next] is called for every grapheme cluster in a loop until it
+// returns false. Inside the loop, information about the grapheme cluster as
+// well as boundary information and character width is available via the various
+// methods (see examples below).
+//
+// Using this class to iterate over a string is convenient but it is much slower
+// than using this package's [Step] or [StepString] functions or any of the
+// other specialized functions starting with "First".
+type Graphemes struct {
+ // The original string.
+ original string
+
+ // The remaining string to be parsed.
+ remaining string
+
+ // The current grapheme cluster.
+ cluster string
+
+ // The byte offset of the current grapheme cluster relative to the original
+ // string.
+ offset int
+
+ // The current boundary information of the [Step] parser.
+ boundaries int
+
+ // The current state of the [Step] parser.
+ state int
+}
+
+// NewGraphemes returns a new grapheme cluster iterator.
+func NewGraphemes(str string) *Graphemes {
+ return &Graphemes{
+ original: str,
+ remaining: str,
+ state: -1,
+ }
+}
+
+// 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 {
+ if len(g.remaining) == 0 {
+ // We're already past the end.
+ g.state = -2
+ g.cluster = ""
+ return false
+ }
+ g.offset += len(g.cluster)
+ g.cluster, g.remaining, g.boundaries, g.state = StepString(g.remaining, g.state)
+ return true
+}
+
+// Runes returns a slice of runes (code points) which corresponds to the current
+// grapheme cluster. If the iterator is already past the end or [Graphemes.Next]
+// has not yet been called, nil is returned.
+func (g *Graphemes) Runes() []rune {
+ if g.state < 0 {
+ return nil
+ }
+ return []rune(g.cluster)
+}
+
+// Str returns a substring of the original string which corresponds to the
+// current grapheme cluster. If the iterator is already past the end or
+// [Graphemes.Next] has not yet been called, an empty string is returned.
+func (g *Graphemes) Str() string {
+ return g.cluster
+}
+
+// Bytes returns a byte slice which corresponds to the current grapheme cluster.
+// If the iterator is already past the end or [Graphemes.Next] has not yet been
+// called, nil is returned.
+func (g *Graphemes) Bytes() []byte {
+ if g.state < 0 {
+ return nil
+ }
+ return []byte(g.cluster)
+}
+
+// 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 [Graphemes.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) {
+ if g.state == -1 {
+ return 0, 0
+ } else if g.state == -2 {
+ return 1, 1
+ }
+ return g.offset, g.offset + len(g.cluster)
+}
+
+// IsWordBoundary returns true if a word ends after the current grapheme
+// cluster.
+func (g *Graphemes) IsWordBoundary() bool {
+ if g.state < 0 {
+ return true
+ }
+ return g.boundaries&MaskWord != 0
+}
+
+// IsSentenceBoundary returns true if a sentence ends after the current
+// grapheme cluster.
+func (g *Graphemes) IsSentenceBoundary() bool {
+ if g.state < 0 {
+ return true
+ }
+ return g.boundaries&MaskSentence != 0
+}
+
+// LineBreak returns whether the line can be broken after the current grapheme
+// cluster. A value of [LineDontBreak] means the line may not be broken, a value
+// of [LineMustBreak] means the line must be broken, and a value of
+// [LineCanBreak] means the line may or may not be broken.
+func (g *Graphemes) LineBreak() int {
+ if g.state == -1 {
+ return LineDontBreak
+ }
+ if g.state == -2 {
+ return LineMustBreak
+ }
+ return g.boundaries & MaskLine
+}
+
+// Width returns the monospace width of the current grapheme cluster.
+func (g *Graphemes) Width() int {
+ if g.state < 0 {
+ return 0
+ }
+ return g.boundaries >> ShiftWidth
+}
+
+// Reset puts the iterator into its initial state such that the next call to
+// [Graphemes.Next] sets it to the first grapheme cluster again.
+func (g *Graphemes) Reset() {
+ g.state = -1
+ g.offset = 0
+ g.cluster = ""
+ g.remaining = g.original
+}
+
+// GraphemeClusterCount returns the number of user-perceived characters
+// (grapheme clusters) for the given string.
+func GraphemeClusterCount(s string) (n int) {
+ state := -1
+ for len(s) > 0 {
+ _, s, _, state = FirstGraphemeClusterInString(s, state)
+ n++
+ }
+ return
+}
+
+// ReverseString reverses the given string while observing grapheme cluster
+// boundaries.
+func ReverseString(s string) string {
+ str := []byte(s)
+ reversed := make([]byte, len(str))
+ state := -1
+ index := len(str)
+ for len(str) > 0 {
+ var cluster []byte
+ cluster, str, _, state = FirstGraphemeCluster(str, state)
+ index -= len(cluster)
+ copy(reversed[index:], cluster)
+ if index <= len(str)/2 {
+ break
+ }
+ }
+ return string(reversed)
+}
+
+// The number of bits the grapheme property must be shifted to make place for
+// grapheme states.
+const shiftGraphemePropState = 4
+
+// FirstGraphemeCluster returns the first grapheme cluster found in the given
+// byte slice according to the rules of [Unicode Standard Annex #29, Grapheme
+// Cluster Boundaries]. This function can be called continuously to extract all
+// grapheme clusters from a byte slice, as illustrated in the example below.
+//
+// If you don't know the current state, for example when calling the function
+// for the first time, you must pass -1. For consecutive calls, pass the state
+// and rest slice returned by the previous call.
+//
+// The "rest" slice is the sub-slice of the original byte slice "b" starting
+// after the last byte of the identified grapheme cluster. If the length of the
+// "rest" slice is 0, the entire byte slice "b" has been processed. The
+// "cluster" byte slice is the sub-slice of the input slice containing the
+// identified grapheme cluster.
+//
+// The returned width is the width of the grapheme cluster for most monospace
+// fonts where a value of 1 represents one character cell.
+//
+// Given an empty byte slice "b", the function returns nil values.
+//
+// While slightly less convenient than using the Graphemes class, this function
+// has much better performance and makes no allocations. It lends itself well to
+// large byte slices.
+//
+// [Unicode Standard Annex #29, Grapheme Cluster Boundaries]: http://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries
+func FirstGraphemeCluster(b []byte, state int) (cluster, rest []byte, width, newState int) {
+ // An empty byte slice returns nothing.
+ if len(b) == 0 {
+ return
+ }
+
+ // Extract the first rune.
+ r, length := utf8.DecodeRune(b)
+ if len(b) <= length { // If we're already past the end, there is nothing else to parse.
+ var prop int
+ if state < 0 {
+ prop = property(graphemeCodePoints, r)
+ } else {
+ prop = state >> shiftGraphemePropState
+ }
+ return b, nil, runeWidth(r, prop), grAny | (prop << shiftGraphemePropState)
+ }
+
+ // If we don't know the state, determine it now.
+ var firstProp int
+ if state < 0 {
+ state, firstProp, _ = transitionGraphemeState(state, r)
+ } else {
+ firstProp = state >> shiftGraphemePropState
+ }
+ width += runeWidth(r, firstProp)
+
+ // Transition until we find a boundary.
+ for {
+ var (
+ prop int
+ boundary bool
+ )
+
+ r, l := utf8.DecodeRune(b[length:])
+ state, prop, boundary = transitionGraphemeState(state&maskGraphemeState, r)
+
+ if boundary {
+ return b[:length], b[length:], width, state | (prop << shiftGraphemePropState)
+ }
+
+ if r == vs16 {
+ width = 2
+ } else if firstProp != prExtendedPictographic && firstProp != prRegionalIndicator && firstProp != prL {
+ width += runeWidth(r, prop)
+ } else if firstProp == prExtendedPictographic {
+ if r == vs15 {
+ width = 1
+ } else {
+ width = 2
+ }
+ }
+
+ length += l
+ if len(b) <= length {
+ return b, nil, width, grAny | (prop << shiftGraphemePropState)
+ }
+ }
+}
+
+// FirstGraphemeClusterInString is like [FirstGraphemeCluster] but its input and
+// outputs are strings.
+func FirstGraphemeClusterInString(str string, state int) (cluster, rest string, width, newState int) {
+ // An empty string returns nothing.
+ if len(str) == 0 {
+ return
+ }
+
+ // Extract the first rune.
+ r, length := utf8.DecodeRuneInString(str)
+ if len(str) <= length { // If we're already past the end, there is nothing else to parse.
+ var prop int
+ if state < 0 {
+ prop = property(graphemeCodePoints, r)
+ } else {
+ prop = state >> shiftGraphemePropState
+ }
+ return str, "", runeWidth(r, prop), grAny | (prop << shiftGraphemePropState)
+ }
+
+ // If we don't know the state, determine it now.
+ var firstProp int
+ if state < 0 {
+ state, firstProp, _ = transitionGraphemeState(state, r)
+ } else {
+ firstProp = state >> shiftGraphemePropState
+ }
+ width += runeWidth(r, firstProp)
+
+ // Transition until we find a boundary.
+ for {
+ var (
+ prop int
+ boundary bool
+ )
+
+ r, l := utf8.DecodeRuneInString(str[length:])
+ state, prop, boundary = transitionGraphemeState(state&maskGraphemeState, r)
+
+ if boundary {
+ return str[:length], str[length:], width, state | (prop << shiftGraphemePropState)
+ }
+
+ if r == vs16 {
+ width = 2
+ } else if firstProp != prExtendedPictographic && firstProp != prRegionalIndicator && firstProp != prL {
+ width += runeWidth(r, prop)
+ } else if firstProp == prExtendedPictographic {
+ if r == vs15 {
+ width = 1
+ } else {
+ width = 2
+ }
+ }
+
+ length += l
+ if len(str) <= length {
+ return str, "", width, grAny | (prop << shiftGraphemePropState)
+ }
+ }
+}
diff --git a/vendor/github.com/rivo/uniseg/graphemeproperties.go b/vendor/github.com/rivo/uniseg/graphemeproperties.go
new file mode 100644
index 0000000..a87d140
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/graphemeproperties.go
@@ -0,0 +1,1891 @@
+package uniseg
+
+// Code generated via go generate from gen_properties.go. DO NOT EDIT.
+
+// graphemeCodePoints are taken from
+// https://www.unicode.org/Public/14.0.0/ucd/auxiliary/GraphemeBreakProperty.txt
+// and
+// https://unicode.org/Public/14.0.0/ucd/emoji/emoji-data.txt
+// ("Extended_Pictographic" only)
+// on September 10, 2022. See https://www.unicode.org/license.html for the Unicode
+// license agreement.
+var graphemeCodePoints = [][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}, // E0.6 [1] (©️) copyright
+ {0x00AD, 0x00AD, prControl}, // Cf SOFT HYPHEN
+ {0x00AE, 0x00AE, prExtendedPictographic}, // E0.6 [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, prPrepend}, // 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, prPrepend}, // 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, prPrepend}, // 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
+ {0x0890, 0x0891, prPrepend}, // Cf [2] ARABIC POUND MARK ABOVE..ARABIC PIASTRE MARK ABOVE
+ {0x0898, 0x089F, prExtend}, // Mn [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA
+ {0x08CA, 0x08E1, prExtend}, // Mn [24] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH SIGN SAFHA
+ {0x08E2, 0x08E2, prPrepend}, // 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
+ {0x0B55, 0x0B56, prExtend}, // Mn [2] ORIYA SIGN OVERLINE..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
+ {0x0C3C, 0x0C3C, prExtend}, // Mn TELUGU SIGN NUKTA
+ {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, prPrepend}, // 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
+ {0x0D81, 0x0D81, prExtend}, // Mn SINHALA SIGN CANDRABINDU
+ {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
+ {0x1715, 0x1715, prSpacingMark}, // Mc TAGALOG SIGN PAMUDPOD
+ {0x1732, 0x1733, prExtend}, // Mn [2] HANUNOO VOWEL SIGN I..HANUNOO VOWEL SIGN U
+ {0x1734, 0x1734, prSpacingMark}, // Mc 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
+ {0x180F, 0x180F, prExtend}, // Mn MONGOLIAN FREE VARIATION SELECTOR FOUR
+ {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
+ {0x1ABF, 0x1ACE, prExtend}, // Mn [16] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER INSULAR T
+ {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, 0x1DFF, prExtend}, // Mn [64] COMBINING DOTTED GRAVE ACCENT..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}, // E0.6 [1] (‼️) double exclamation mark
+ {0x2049, 0x2049, prExtendedPictographic}, // E0.6 [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}, // E0.6 [1] (™️) trade mark
+ {0x2139, 0x2139, prExtendedPictographic}, // E0.6 [1] (ℹ️) information
+ {0x2194, 0x2199, prExtendedPictographic}, // E0.6 [6] (↔️..↙️) left-right arrow..down-left arrow
+ {0x21A9, 0x21AA, prExtendedPictographic}, // E0.6 [2] (↩️..↪️) right arrow curving left..left arrow curving right
+ {0x231A, 0x231B, prExtendedPictographic}, // E0.6 [2] (⌚..⌛) watch..hourglass done
+ {0x2328, 0x2328, prExtendedPictographic}, // E1.0 [1] (⌨️) keyboard
+ {0x2388, 0x2388, prExtendedPictographic}, // E0.0 [1] (⎈) HELM SYMBOL
+ {0x23CF, 0x23CF, prExtendedPictographic}, // E1.0 [1] (⏏️) eject button
+ {0x23E9, 0x23EC, prExtendedPictographic}, // E0.6 [4] (⏩..⏬) fast-forward button..fast down button
+ {0x23ED, 0x23EE, prExtendedPictographic}, // E0.7 [2] (⏭️..⏮️) next track button..last track button
+ {0x23EF, 0x23EF, prExtendedPictographic}, // E1.0 [1] (⏯️) play or pause button
+ {0x23F0, 0x23F0, prExtendedPictographic}, // E0.6 [1] (⏰) alarm clock
+ {0x23F1, 0x23F2, prExtendedPictographic}, // E1.0 [2] (⏱️..⏲️) stopwatch..timer clock
+ {0x23F3, 0x23F3, prExtendedPictographic}, // E0.6 [1] (⏳) hourglass not done
+ {0x23F8, 0x23FA, prExtendedPictographic}, // E0.7 [3] (⏸️..⏺️) pause button..record button
+ {0x24C2, 0x24C2, prExtendedPictographic}, // E0.6 [1] (Ⓜ️) circled M
+ {0x25AA, 0x25AB, prExtendedPictographic}, // E0.6 [2] (▪️..▫️) black small square..white small square
+ {0x25B6, 0x25B6, prExtendedPictographic}, // E0.6 [1] (▶️) play button
+ {0x25C0, 0x25C0, prExtendedPictographic}, // E0.6 [1] (◀️) reverse button
+ {0x25FB, 0x25FE, prExtendedPictographic}, // E0.6 [4] (◻️..◾) white medium square..black medium-small square
+ {0x2600, 0x2601, prExtendedPictographic}, // E0.6 [2] (☀️..☁️) sun..cloud
+ {0x2602, 0x2603, prExtendedPictographic}, // E0.7 [2] (☂️..☃️) umbrella..snowman
+ {0x2604, 0x2604, prExtendedPictographic}, // E1.0 [1] (☄️) comet
+ {0x2605, 0x2605, prExtendedPictographic}, // E0.0 [1] (★) BLACK STAR
+ {0x2607, 0x260D, prExtendedPictographic}, // E0.0 [7] (☇..☍) LIGHTNING..OPPOSITION
+ {0x260E, 0x260E, prExtendedPictographic}, // E0.6 [1] (☎️) telephone
+ {0x260F, 0x2610, prExtendedPictographic}, // E0.0 [2] (☏..☐) WHITE TELEPHONE..BALLOT BOX
+ {0x2611, 0x2611, prExtendedPictographic}, // E0.6 [1] (☑️) check box with check
+ {0x2612, 0x2612, prExtendedPictographic}, // E0.0 [1] (☒) BALLOT BOX WITH X
+ {0x2614, 0x2615, prExtendedPictographic}, // E0.6 [2] (☔..☕) umbrella with rain drops..hot beverage
+ {0x2616, 0x2617, prExtendedPictographic}, // E0.0 [2] (☖..☗) WHITE SHOGI PIECE..BLACK SHOGI PIECE
+ {0x2618, 0x2618, prExtendedPictographic}, // E1.0 [1] (☘️) shamrock
+ {0x2619, 0x261C, prExtendedPictographic}, // E0.0 [4] (☙..☜) REVERSED ROTATED FLORAL HEART BULLET..WHITE LEFT POINTING INDEX
+ {0x261D, 0x261D, prExtendedPictographic}, // E0.6 [1] (☝️) index pointing up
+ {0x261E, 0x261F, prExtendedPictographic}, // E0.0 [2] (☞..☟) WHITE RIGHT POINTING INDEX..WHITE DOWN POINTING INDEX
+ {0x2620, 0x2620, prExtendedPictographic}, // E1.0 [1] (☠️) skull and crossbones
+ {0x2621, 0x2621, prExtendedPictographic}, // E0.0 [1] (☡) CAUTION SIGN
+ {0x2622, 0x2623, prExtendedPictographic}, // E1.0 [2] (☢️..☣️) radioactive..biohazard
+ {0x2624, 0x2625, prExtendedPictographic}, // E0.0 [2] (☤..☥) CADUCEUS..ANKH
+ {0x2626, 0x2626, prExtendedPictographic}, // E1.0 [1] (☦️) orthodox cross
+ {0x2627, 0x2629, prExtendedPictographic}, // E0.0 [3] (☧..☩) CHI RHO..CROSS OF JERUSALEM
+ {0x262A, 0x262A, prExtendedPictographic}, // E0.7 [1] (☪️) star and crescent
+ {0x262B, 0x262D, prExtendedPictographic}, // E0.0 [3] (☫..☭) FARSI SYMBOL..HAMMER AND SICKLE
+ {0x262E, 0x262E, prExtendedPictographic}, // E1.0 [1] (☮️) peace symbol
+ {0x262F, 0x262F, prExtendedPictographic}, // E0.7 [1] (☯️) yin yang
+ {0x2630, 0x2637, prExtendedPictographic}, // E0.0 [8] (☰..☷) TRIGRAM FOR HEAVEN..TRIGRAM FOR EARTH
+ {0x2638, 0x2639, prExtendedPictographic}, // E0.7 [2] (☸️..☹️) wheel of dharma..frowning face
+ {0x263A, 0x263A, prExtendedPictographic}, // E0.6 [1] (☺️) smiling face
+ {0x263B, 0x263F, prExtendedPictographic}, // E0.0 [5] (☻..☿) BLACK SMILING FACE..MERCURY
+ {0x2640, 0x2640, prExtendedPictographic}, // E4.0 [1] (♀️) female sign
+ {0x2641, 0x2641, prExtendedPictographic}, // E0.0 [1] (♁) EARTH
+ {0x2642, 0x2642, prExtendedPictographic}, // E4.0 [1] (♂️) male sign
+ {0x2643, 0x2647, prExtendedPictographic}, // E0.0 [5] (♃..♇) JUPITER..PLUTO
+ {0x2648, 0x2653, prExtendedPictographic}, // E0.6 [12] (♈..♓) Aries..Pisces
+ {0x2654, 0x265E, prExtendedPictographic}, // E0.0 [11] (♔..♞) WHITE CHESS KING..BLACK CHESS KNIGHT
+ {0x265F, 0x265F, prExtendedPictographic}, // E11.0 [1] (♟️) chess pawn
+ {0x2660, 0x2660, prExtendedPictographic}, // E0.6 [1] (♠️) spade suit
+ {0x2661, 0x2662, prExtendedPictographic}, // E0.0 [2] (♡..♢) WHITE HEART SUIT..WHITE DIAMOND SUIT
+ {0x2663, 0x2663, prExtendedPictographic}, // E0.6 [1] (♣️) club suit
+ {0x2664, 0x2664, prExtendedPictographic}, // E0.0 [1] (♤) WHITE SPADE SUIT
+ {0x2665, 0x2666, prExtendedPictographic}, // E0.6 [2] (♥️..♦️) heart suit..diamond suit
+ {0x2667, 0x2667, prExtendedPictographic}, // E0.0 [1] (♧) WHITE CLUB SUIT
+ {0x2668, 0x2668, prExtendedPictographic}, // E0.6 [1] (♨️) hot springs
+ {0x2669, 0x267A, prExtendedPictographic}, // E0.0 [18] (♩..♺) QUARTER NOTE..RECYCLING SYMBOL FOR GENERIC MATERIALS
+ {0x267B, 0x267B, prExtendedPictographic}, // E0.6 [1] (♻️) recycling symbol
+ {0x267C, 0x267D, prExtendedPictographic}, // E0.0 [2] (♼..♽) RECYCLED PAPER SYMBOL..PARTIALLY-RECYCLED PAPER SYMBOL
+ {0x267E, 0x267E, prExtendedPictographic}, // E11.0 [1] (♾️) infinity
+ {0x267F, 0x267F, prExtendedPictographic}, // E0.6 [1] (♿) wheelchair symbol
+ {0x2680, 0x2685, prExtendedPictographic}, // E0.0 [6] (⚀..⚅) DIE FACE-1..DIE FACE-6
+ {0x2690, 0x2691, prExtendedPictographic}, // E0.0 [2] (⚐..⚑) WHITE FLAG..BLACK FLAG
+ {0x2692, 0x2692, prExtendedPictographic}, // E1.0 [1] (⚒️) hammer and pick
+ {0x2693, 0x2693, prExtendedPictographic}, // E0.6 [1] (⚓) anchor
+ {0x2694, 0x2694, prExtendedPictographic}, // E1.0 [1] (⚔️) crossed swords
+ {0x2695, 0x2695, prExtendedPictographic}, // E4.0 [1] (⚕️) medical symbol
+ {0x2696, 0x2697, prExtendedPictographic}, // E1.0 [2] (⚖️..⚗️) balance scale..alembic
+ {0x2698, 0x2698, prExtendedPictographic}, // E0.0 [1] (⚘) FLOWER
+ {0x2699, 0x2699, prExtendedPictographic}, // E1.0 [1] (⚙️) gear
+ {0x269A, 0x269A, prExtendedPictographic}, // E0.0 [1] (⚚) STAFF OF HERMES
+ {0x269B, 0x269C, prExtendedPictographic}, // E1.0 [2] (⚛️..⚜️) atom symbol..fleur-de-lis
+ {0x269D, 0x269F, prExtendedPictographic}, // E0.0 [3] (⚝..⚟) OUTLINED WHITE STAR..THREE LINES CONVERGING LEFT
+ {0x26A0, 0x26A1, prExtendedPictographic}, // E0.6 [2] (⚠️..⚡) warning..high voltage
+ {0x26A2, 0x26A6, prExtendedPictographic}, // E0.0 [5] (⚢..⚦) DOUBLED FEMALE SIGN..MALE WITH STROKE SIGN
+ {0x26A7, 0x26A7, prExtendedPictographic}, // E13.0 [1] (⚧️) transgender symbol
+ {0x26A8, 0x26A9, prExtendedPictographic}, // E0.0 [2] (⚨..⚩) VERTICAL MALE WITH STROKE SIGN..HORIZONTAL MALE WITH STROKE SIGN
+ {0x26AA, 0x26AB, prExtendedPictographic}, // E0.6 [2] (⚪..⚫) white circle..black circle
+ {0x26AC, 0x26AF, prExtendedPictographic}, // E0.0 [4] (⚬..⚯) MEDIUM SMALL WHITE CIRCLE..UNMARRIED PARTNERSHIP SYMBOL
+ {0x26B0, 0x26B1, prExtendedPictographic}, // E1.0 [2] (⚰️..⚱️) coffin..funeral urn
+ {0x26B2, 0x26BC, prExtendedPictographic}, // E0.0 [11] (⚲..⚼) NEUTER..SESQUIQUADRATE
+ {0x26BD, 0x26BE, prExtendedPictographic}, // E0.6 [2] (⚽..⚾) soccer ball..baseball
+ {0x26BF, 0x26C3, prExtendedPictographic}, // E0.0 [5] (⚿..⛃) SQUARED KEY..BLACK DRAUGHTS KING
+ {0x26C4, 0x26C5, prExtendedPictographic}, // E0.6 [2] (⛄..⛅) snowman without snow..sun behind cloud
+ {0x26C6, 0x26C7, prExtendedPictographic}, // E0.0 [2] (⛆..⛇) RAIN..BLACK SNOWMAN
+ {0x26C8, 0x26C8, prExtendedPictographic}, // E0.7 [1] (⛈️) cloud with lightning and rain
+ {0x26C9, 0x26CD, prExtendedPictographic}, // E0.0 [5] (⛉..⛍) TURNED WHITE SHOGI PIECE..DISABLED CAR
+ {0x26CE, 0x26CE, prExtendedPictographic}, // E0.6 [1] (⛎) Ophiuchus
+ {0x26CF, 0x26CF, prExtendedPictographic}, // E0.7 [1] (⛏️) pick
+ {0x26D0, 0x26D0, prExtendedPictographic}, // E0.0 [1] (⛐) CAR SLIDING
+ {0x26D1, 0x26D1, prExtendedPictographic}, // E0.7 [1] (⛑️) rescue worker’s helmet
+ {0x26D2, 0x26D2, prExtendedPictographic}, // E0.0 [1] (⛒) CIRCLED CROSSING LANES
+ {0x26D3, 0x26D3, prExtendedPictographic}, // E0.7 [1] (⛓️) chains
+ {0x26D4, 0x26D4, prExtendedPictographic}, // E0.6 [1] (⛔) no entry
+ {0x26D5, 0x26E8, prExtendedPictographic}, // E0.0 [20] (⛕..⛨) ALTERNATE ONE-WAY LEFT WAY TRAFFIC..BLACK CROSS ON SHIELD
+ {0x26E9, 0x26E9, prExtendedPictographic}, // E0.7 [1] (⛩️) shinto shrine
+ {0x26EA, 0x26EA, prExtendedPictographic}, // E0.6 [1] (⛪) church
+ {0x26EB, 0x26EF, prExtendedPictographic}, // E0.0 [5] (⛫..⛯) CASTLE..MAP SYMBOL FOR LIGHTHOUSE
+ {0x26F0, 0x26F1, prExtendedPictographic}, // E0.7 [2] (⛰️..⛱️) mountain..umbrella on ground
+ {0x26F2, 0x26F3, prExtendedPictographic}, // E0.6 [2] (⛲..⛳) fountain..flag in hole
+ {0x26F4, 0x26F4, prExtendedPictographic}, // E0.7 [1] (⛴️) ferry
+ {0x26F5, 0x26F5, prExtendedPictographic}, // E0.6 [1] (⛵) sailboat
+ {0x26F6, 0x26F6, prExtendedPictographic}, // E0.0 [1] (⛶) SQUARE FOUR CORNERS
+ {0x26F7, 0x26F9, prExtendedPictographic}, // E0.7 [3] (⛷️..⛹️) skier..person bouncing ball
+ {0x26FA, 0x26FA, prExtendedPictographic}, // E0.6 [1] (⛺) tent
+ {0x26FB, 0x26FC, prExtendedPictographic}, // E0.0 [2] (⛻..⛼) JAPANESE BANK SYMBOL..HEADSTONE GRAVEYARD SYMBOL
+ {0x26FD, 0x26FD, prExtendedPictographic}, // E0.6 [1] (⛽) fuel pump
+ {0x26FE, 0x2701, prExtendedPictographic}, // E0.0 [4] (⛾..✁) CUP ON BLACK SQUARE..UPPER BLADE SCISSORS
+ {0x2702, 0x2702, prExtendedPictographic}, // E0.6 [1] (✂️) scissors
+ {0x2703, 0x2704, prExtendedPictographic}, // E0.0 [2] (✃..✄) LOWER BLADE SCISSORS..WHITE SCISSORS
+ {0x2705, 0x2705, prExtendedPictographic}, // E0.6 [1] (✅) check mark button
+ {0x2708, 0x270C, prExtendedPictographic}, // E0.6 [5] (✈️..✌️) airplane..victory hand
+ {0x270D, 0x270D, prExtendedPictographic}, // E0.7 [1] (✍️) writing hand
+ {0x270E, 0x270E, prExtendedPictographic}, // E0.0 [1] (✎) LOWER RIGHT PENCIL
+ {0x270F, 0x270F, prExtendedPictographic}, // E0.6 [1] (✏️) pencil
+ {0x2710, 0x2711, prExtendedPictographic}, // E0.0 [2] (✐..✑) UPPER RIGHT PENCIL..WHITE NIB
+ {0x2712, 0x2712, prExtendedPictographic}, // E0.6 [1] (✒️) black nib
+ {0x2714, 0x2714, prExtendedPictographic}, // E0.6 [1] (✔️) check mark
+ {0x2716, 0x2716, prExtendedPictographic}, // E0.6 [1] (✖️) multiply
+ {0x271D, 0x271D, prExtendedPictographic}, // E0.7 [1] (✝️) latin cross
+ {0x2721, 0x2721, prExtendedPictographic}, // E0.7 [1] (✡️) star of David
+ {0x2728, 0x2728, prExtendedPictographic}, // E0.6 [1] (✨) sparkles
+ {0x2733, 0x2734, prExtendedPictographic}, // E0.6 [2] (✳️..✴️) eight-spoked asterisk..eight-pointed star
+ {0x2744, 0x2744, prExtendedPictographic}, // E0.6 [1] (❄️) snowflake
+ {0x2747, 0x2747, prExtendedPictographic}, // E0.6 [1] (❇️) sparkle
+ {0x274C, 0x274C, prExtendedPictographic}, // E0.6 [1] (❌) cross mark
+ {0x274E, 0x274E, prExtendedPictographic}, // E0.6 [1] (❎) cross mark button
+ {0x2753, 0x2755, prExtendedPictographic}, // E0.6 [3] (❓..❕) red question mark..white exclamation mark
+ {0x2757, 0x2757, prExtendedPictographic}, // E0.6 [1] (❗) red exclamation mark
+ {0x2763, 0x2763, prExtendedPictographic}, // E1.0 [1] (❣️) heart exclamation
+ {0x2764, 0x2764, prExtendedPictographic}, // E0.6 [1] (❤️) red heart
+ {0x2765, 0x2767, prExtendedPictographic}, // E0.0 [3] (❥..❧) ROTATED HEAVY BLACK HEART BULLET..ROTATED FLORAL HEART BULLET
+ {0x2795, 0x2797, prExtendedPictographic}, // E0.6 [3] (➕..➗) plus..divide
+ {0x27A1, 0x27A1, prExtendedPictographic}, // E0.6 [1] (➡️) right arrow
+ {0x27B0, 0x27B0, prExtendedPictographic}, // E0.6 [1] (➰) curly loop
+ {0x27BF, 0x27BF, prExtendedPictographic}, // E1.0 [1] (➿) double curly loop
+ {0x2934, 0x2935, prExtendedPictographic}, // E0.6 [2] (⤴️..⤵️) right arrow curving up..right arrow curving down
+ {0x2B05, 0x2B07, prExtendedPictographic}, // E0.6 [3] (⬅️..⬇️) left arrow..down arrow
+ {0x2B1B, 0x2B1C, prExtendedPictographic}, // E0.6 [2] (⬛..⬜) black large square..white large square
+ {0x2B50, 0x2B50, prExtendedPictographic}, // E0.6 [1] (⭐) star
+ {0x2B55, 0x2B55, prExtendedPictographic}, // E0.6 [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}, // E0.6 [1] (〰️) wavy dash
+ {0x303D, 0x303D, prExtendedPictographic}, // E0.6 [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}, // E0.6 [1] (㊗️) Japanese “congratulations” button
+ {0x3299, 0x3299, prExtendedPictographic}, // E0.6 [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
+ {0xA82C, 0xA82C, prExtend}, // Mn SYLOTI NAGRI SIGN ALTERNATE HASANTA
+ {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
+ {0x10EAB, 0x10EAC, prExtend}, // Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK
+ {0x10F46, 0x10F50, prExtend}, // Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW
+ {0x10F82, 0x10F85, prExtend}, // Mn [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS 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
+ {0x11070, 0x11070, prExtend}, // Mn BRAHMI SIGN OLD TAMIL VIRAMA
+ {0x11073, 0x11074, prExtend}, // Mn [2] BRAHMI VOWEL SIGN OLD TAMIL SHORT E..BRAHMI VOWEL SIGN OLD TAMIL SHORT O
+ {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, prPrepend}, // Cf KAITHI NUMBER SIGN
+ {0x110C2, 0x110C2, prExtend}, // Mn KAITHI VOWEL SIGN VOCALIC R
+ {0x110CD, 0x110CD, prPrepend}, // 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, prPrepend}, // Lo [2] SHARADA SIGN JIHVAMULIYA..SHARADA SIGN UPADHMANIYA
+ {0x111C9, 0x111CC, prExtend}, // Mn [4] SHARADA SANDHI MARK..SHARADA EXTRA SHORT VOWEL MARK
+ {0x111CE, 0x111CE, prSpacingMark}, // Mc SHARADA VOWEL SIGN PRISHTHAMATRA E
+ {0x111CF, 0x111CF, prExtend}, // Mn SHARADA SIGN INVERTED CANDRABINDU
+ {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
+ {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
+ {0x11930, 0x11930, prExtend}, // Mc DIVES AKURU VOWEL SIGN AA
+ {0x11931, 0x11935, prSpacingMark}, // Mc [5] DIVES AKURU VOWEL SIGN I..DIVES AKURU VOWEL SIGN E
+ {0x11937, 0x11938, prSpacingMark}, // Mc [2] DIVES AKURU VOWEL SIGN AI..DIVES AKURU VOWEL SIGN O
+ {0x1193B, 0x1193C, prExtend}, // Mn [2] DIVES AKURU SIGN ANUSVARA..DIVES AKURU SIGN CANDRABINDU
+ {0x1193D, 0x1193D, prSpacingMark}, // Mc DIVES AKURU SIGN HALANTA
+ {0x1193E, 0x1193E, prExtend}, // Mn DIVES AKURU VIRAMA
+ {0x1193F, 0x1193F, prPrepend}, // Lo DIVES AKURU PREFIXED NASAL SIGN
+ {0x11940, 0x11940, prSpacingMark}, // Mc DIVES AKURU MEDIAL YA
+ {0x11941, 0x11941, prPrepend}, // Lo DIVES AKURU INITIAL RA
+ {0x11942, 0x11942, prSpacingMark}, // Mc DIVES AKURU MEDIAL RA
+ {0x11943, 0x11943, prExtend}, // Mn DIVES AKURU 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, prPrepend}, // 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, prPrepend}, // 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, prPrepend}, // 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
+ {0x16FE4, 0x16FE4, prExtend}, // Mn KHITAN SMALL SCRIPT FILLER
+ {0x16FF0, 0x16FF1, prSpacingMark}, // Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY
+ {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
+ {0x1CF00, 0x1CF2D, prExtend}, // Mn [46] ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT..ZNAMENNY COMBINING MARK KRYZH ON LEFT
+ {0x1CF30, 0x1CF46, prExtend}, // Mn [23] ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO..ZNAMENNY PRIZNAK MODIFIER ROG
+ {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
+ {0x1E2AE, 0x1E2AE, prExtend}, // Mn TOTO SIGN RISING TONE
+ {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, 0x1F003, prExtendedPictographic}, // E0.0 [4] (🀀..🀃) MAHJONG TILE EAST WIND..MAHJONG TILE NORTH WIND
+ {0x1F004, 0x1F004, prExtendedPictographic}, // E0.6 [1] (🀄) mahjong red dragon
+ {0x1F005, 0x1F0CE, prExtendedPictographic}, // E0.0 [202] (🀅..🃎) MAHJONG TILE GREEN DRAGON..PLAYING CARD KING OF DIAMONDS
+ {0x1F0CF, 0x1F0CF, prExtendedPictographic}, // E0.6 [1] (🃏) joker
+ {0x1F0D0, 0x1F0FF, prExtendedPictographic}, // E0.0 [48] (..) ..
+ {0x1F10D, 0x1F10F, prExtendedPictographic}, // E0.0 [3] (🄍..🄏) CIRCLED ZERO WITH SLASH..CIRCLED DOLLAR SIGN WITH OVERLAID BACKSLASH
+ {0x1F12F, 0x1F12F, prExtendedPictographic}, // E0.0 [1] (🄯) COPYLEFT SYMBOL
+ {0x1F16C, 0x1F16F, prExtendedPictographic}, // E0.0 [4] (🅬..🅯) RAISED MR SIGN..CIRCLED HUMAN FIGURE
+ {0x1F170, 0x1F171, prExtendedPictographic}, // E0.6 [2] (🅰️..🅱️) A button (blood type)..B button (blood type)
+ {0x1F17E, 0x1F17F, prExtendedPictographic}, // E0.6 [2] (🅾️..🅿️) O button (blood type)..P button
+ {0x1F18E, 0x1F18E, prExtendedPictographic}, // E0.6 [1] (🆎) AB button (blood type)
+ {0x1F191, 0x1F19A, prExtendedPictographic}, // E0.6 [10] (🆑..🆚) CL button..VS button
+ {0x1F1AD, 0x1F1E5, prExtendedPictographic}, // E0.0 [57] (🆭..) MASK WORK SYMBOL..
+ {0x1F1E6, 0x1F1FF, prRegionalIndicator}, // So [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z
+ {0x1F201, 0x1F202, prExtendedPictographic}, // E0.6 [2] (🈁..🈂️) Japanese “here” button..Japanese “service charge” button
+ {0x1F203, 0x1F20F, prExtendedPictographic}, // E0.0 [13] (..) ..
+ {0x1F21A, 0x1F21A, prExtendedPictographic}, // E0.6 [1] (🈚) Japanese “free of charge” button
+ {0x1F22F, 0x1F22F, prExtendedPictographic}, // E0.6 [1] (🈯) Japanese “reserved” button
+ {0x1F232, 0x1F23A, prExtendedPictographic}, // E0.6 [9] (🈲..🈺) Japanese “prohibited” button..Japanese “open for business” button
+ {0x1F23C, 0x1F23F, prExtendedPictographic}, // E0.0 [4] (..) ..
+ {0x1F249, 0x1F24F, prExtendedPictographic}, // E0.0 [7] (..) ..
+ {0x1F250, 0x1F251, prExtendedPictographic}, // E0.6 [2] (🉐..🉑) Japanese “bargain” button..Japanese “acceptable” button
+ {0x1F252, 0x1F2FF, prExtendedPictographic}, // E0.0 [174] (..) ..
+ {0x1F300, 0x1F30C, prExtendedPictographic}, // E0.6 [13] (🌀..🌌) cyclone..milky way
+ {0x1F30D, 0x1F30E, prExtendedPictographic}, // E0.7 [2] (🌍..🌎) globe showing Europe-Africa..globe showing Americas
+ {0x1F30F, 0x1F30F, prExtendedPictographic}, // E0.6 [1] (🌏) globe showing Asia-Australia
+ {0x1F310, 0x1F310, prExtendedPictographic}, // E1.0 [1] (🌐) globe with meridians
+ {0x1F311, 0x1F311, prExtendedPictographic}, // E0.6 [1] (🌑) new moon
+ {0x1F312, 0x1F312, prExtendedPictographic}, // E1.0 [1] (🌒) waxing crescent moon
+ {0x1F313, 0x1F315, prExtendedPictographic}, // E0.6 [3] (🌓..🌕) first quarter moon..full moon
+ {0x1F316, 0x1F318, prExtendedPictographic}, // E1.0 [3] (🌖..🌘) waning gibbous moon..waning crescent moon
+ {0x1F319, 0x1F319, prExtendedPictographic}, // E0.6 [1] (🌙) crescent moon
+ {0x1F31A, 0x1F31A, prExtendedPictographic}, // E1.0 [1] (🌚) new moon face
+ {0x1F31B, 0x1F31B, prExtendedPictographic}, // E0.6 [1] (🌛) first quarter moon face
+ {0x1F31C, 0x1F31C, prExtendedPictographic}, // E0.7 [1] (🌜) last quarter moon face
+ {0x1F31D, 0x1F31E, prExtendedPictographic}, // E1.0 [2] (🌝..🌞) full moon face..sun with face
+ {0x1F31F, 0x1F320, prExtendedPictographic}, // E0.6 [2] (🌟..🌠) glowing star..shooting star
+ {0x1F321, 0x1F321, prExtendedPictographic}, // E0.7 [1] (🌡️) thermometer
+ {0x1F322, 0x1F323, prExtendedPictographic}, // E0.0 [2] (🌢..🌣) BLACK DROPLET..WHITE SUN
+ {0x1F324, 0x1F32C, prExtendedPictographic}, // E0.7 [9] (🌤️..🌬️) sun behind small cloud..wind face
+ {0x1F32D, 0x1F32F, prExtendedPictographic}, // E1.0 [3] (🌭..🌯) hot dog..burrito
+ {0x1F330, 0x1F331, prExtendedPictographic}, // E0.6 [2] (🌰..🌱) chestnut..seedling
+ {0x1F332, 0x1F333, prExtendedPictographic}, // E1.0 [2] (🌲..🌳) evergreen tree..deciduous tree
+ {0x1F334, 0x1F335, prExtendedPictographic}, // E0.6 [2] (🌴..🌵) palm tree..cactus
+ {0x1F336, 0x1F336, prExtendedPictographic}, // E0.7 [1] (🌶️) hot pepper
+ {0x1F337, 0x1F34A, prExtendedPictographic}, // E0.6 [20] (🌷..🍊) tulip..tangerine
+ {0x1F34B, 0x1F34B, prExtendedPictographic}, // E1.0 [1] (🍋) lemon
+ {0x1F34C, 0x1F34F, prExtendedPictographic}, // E0.6 [4] (🍌..🍏) banana..green apple
+ {0x1F350, 0x1F350, prExtendedPictographic}, // E1.0 [1] (🍐) pear
+ {0x1F351, 0x1F37B, prExtendedPictographic}, // E0.6 [43] (🍑..🍻) peach..clinking beer mugs
+ {0x1F37C, 0x1F37C, prExtendedPictographic}, // E1.0 [1] (🍼) baby bottle
+ {0x1F37D, 0x1F37D, prExtendedPictographic}, // E0.7 [1] (🍽️) fork and knife with plate
+ {0x1F37E, 0x1F37F, prExtendedPictographic}, // E1.0 [2] (🍾..🍿) bottle with popping cork..popcorn
+ {0x1F380, 0x1F393, prExtendedPictographic}, // E0.6 [20] (🎀..🎓) ribbon..graduation cap
+ {0x1F394, 0x1F395, prExtendedPictographic}, // E0.0 [2] (🎔..🎕) HEART WITH TIP ON THE LEFT..BOUQUET OF FLOWERS
+ {0x1F396, 0x1F397, prExtendedPictographic}, // E0.7 [2] (🎖️..🎗️) military medal..reminder ribbon
+ {0x1F398, 0x1F398, prExtendedPictographic}, // E0.0 [1] (🎘) MUSICAL KEYBOARD WITH JACKS
+ {0x1F399, 0x1F39B, prExtendedPictographic}, // E0.7 [3] (🎙️..🎛️) studio microphone..control knobs
+ {0x1F39C, 0x1F39D, prExtendedPictographic}, // E0.0 [2] (🎜..🎝) BEAMED ASCENDING MUSICAL NOTES..BEAMED DESCENDING MUSICAL NOTES
+ {0x1F39E, 0x1F39F, prExtendedPictographic}, // E0.7 [2] (🎞️..🎟️) film frames..admission tickets
+ {0x1F3A0, 0x1F3C4, prExtendedPictographic}, // E0.6 [37] (🎠..🏄) carousel horse..person surfing
+ {0x1F3C5, 0x1F3C5, prExtendedPictographic}, // E1.0 [1] (🏅) sports medal
+ {0x1F3C6, 0x1F3C6, prExtendedPictographic}, // E0.6 [1] (🏆) trophy
+ {0x1F3C7, 0x1F3C7, prExtendedPictographic}, // E1.0 [1] (🏇) horse racing
+ {0x1F3C8, 0x1F3C8, prExtendedPictographic}, // E0.6 [1] (🏈) american football
+ {0x1F3C9, 0x1F3C9, prExtendedPictographic}, // E1.0 [1] (🏉) rugby football
+ {0x1F3CA, 0x1F3CA, prExtendedPictographic}, // E0.6 [1] (🏊) person swimming
+ {0x1F3CB, 0x1F3CE, prExtendedPictographic}, // E0.7 [4] (🏋️..🏎️) person lifting weights..racing car
+ {0x1F3CF, 0x1F3D3, prExtendedPictographic}, // E1.0 [5] (🏏..🏓) cricket game..ping pong
+ {0x1F3D4, 0x1F3DF, prExtendedPictographic}, // E0.7 [12] (🏔️..🏟️) snow-capped mountain..stadium
+ {0x1F3E0, 0x1F3E3, prExtendedPictographic}, // E0.6 [4] (🏠..🏣) house..Japanese post office
+ {0x1F3E4, 0x1F3E4, prExtendedPictographic}, // E1.0 [1] (🏤) post office
+ {0x1F3E5, 0x1F3F0, prExtendedPictographic}, // E0.6 [12] (🏥..🏰) hospital..castle
+ {0x1F3F1, 0x1F3F2, prExtendedPictographic}, // E0.0 [2] (🏱..🏲) WHITE PENNANT..BLACK PENNANT
+ {0x1F3F3, 0x1F3F3, prExtendedPictographic}, // E0.7 [1] (🏳️) white flag
+ {0x1F3F4, 0x1F3F4, prExtendedPictographic}, // E1.0 [1] (🏴) black flag
+ {0x1F3F5, 0x1F3F5, prExtendedPictographic}, // E0.7 [1] (🏵️) rosette
+ {0x1F3F6, 0x1F3F6, prExtendedPictographic}, // E0.0 [1] (🏶) BLACK ROSETTE
+ {0x1F3F7, 0x1F3F7, prExtendedPictographic}, // E0.7 [1] (🏷️) label
+ {0x1F3F8, 0x1F3FA, prExtendedPictographic}, // E1.0 [3] (🏸..🏺) badminton..amphora
+ {0x1F3FB, 0x1F3FF, prExtend}, // Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6
+ {0x1F400, 0x1F407, prExtendedPictographic}, // E1.0 [8] (🐀..🐇) rat..rabbit
+ {0x1F408, 0x1F408, prExtendedPictographic}, // E0.7 [1] (🐈) cat
+ {0x1F409, 0x1F40B, prExtendedPictographic}, // E1.0 [3] (🐉..🐋) dragon..whale
+ {0x1F40C, 0x1F40E, prExtendedPictographic}, // E0.6 [3] (🐌..🐎) snail..horse
+ {0x1F40F, 0x1F410, prExtendedPictographic}, // E1.0 [2] (🐏..🐐) ram..goat
+ {0x1F411, 0x1F412, prExtendedPictographic}, // E0.6 [2] (🐑..🐒) ewe..monkey
+ {0x1F413, 0x1F413, prExtendedPictographic}, // E1.0 [1] (🐓) rooster
+ {0x1F414, 0x1F414, prExtendedPictographic}, // E0.6 [1] (🐔) chicken
+ {0x1F415, 0x1F415, prExtendedPictographic}, // E0.7 [1] (🐕) dog
+ {0x1F416, 0x1F416, prExtendedPictographic}, // E1.0 [1] (🐖) pig
+ {0x1F417, 0x1F429, prExtendedPictographic}, // E0.6 [19] (🐗..🐩) boar..poodle
+ {0x1F42A, 0x1F42A, prExtendedPictographic}, // E1.0 [1] (🐪) camel
+ {0x1F42B, 0x1F43E, prExtendedPictographic}, // E0.6 [20] (🐫..🐾) two-hump camel..paw prints
+ {0x1F43F, 0x1F43F, prExtendedPictographic}, // E0.7 [1] (🐿️) chipmunk
+ {0x1F440, 0x1F440, prExtendedPictographic}, // E0.6 [1] (👀) eyes
+ {0x1F441, 0x1F441, prExtendedPictographic}, // E0.7 [1] (👁️) eye
+ {0x1F442, 0x1F464, prExtendedPictographic}, // E0.6 [35] (👂..👤) ear..bust in silhouette
+ {0x1F465, 0x1F465, prExtendedPictographic}, // E1.0 [1] (👥) busts in silhouette
+ {0x1F466, 0x1F46B, prExtendedPictographic}, // E0.6 [6] (👦..👫) boy..woman and man holding hands
+ {0x1F46C, 0x1F46D, prExtendedPictographic}, // E1.0 [2] (👬..👭) men holding hands..women holding hands
+ {0x1F46E, 0x1F4AC, prExtendedPictographic}, // E0.6 [63] (👮..💬) police officer..speech balloon
+ {0x1F4AD, 0x1F4AD, prExtendedPictographic}, // E1.0 [1] (💭) thought balloon
+ {0x1F4AE, 0x1F4B5, prExtendedPictographic}, // E0.6 [8] (💮..💵) white flower..dollar banknote
+ {0x1F4B6, 0x1F4B7, prExtendedPictographic}, // E1.0 [2] (💶..💷) euro banknote..pound banknote
+ {0x1F4B8, 0x1F4EB, prExtendedPictographic}, // E0.6 [52] (💸..📫) money with wings..closed mailbox with raised flag
+ {0x1F4EC, 0x1F4ED, prExtendedPictographic}, // E0.7 [2] (📬..📭) open mailbox with raised flag..open mailbox with lowered flag
+ {0x1F4EE, 0x1F4EE, prExtendedPictographic}, // E0.6 [1] (📮) postbox
+ {0x1F4EF, 0x1F4EF, prExtendedPictographic}, // E1.0 [1] (📯) postal horn
+ {0x1F4F0, 0x1F4F4, prExtendedPictographic}, // E0.6 [5] (📰..📴) newspaper..mobile phone off
+ {0x1F4F5, 0x1F4F5, prExtendedPictographic}, // E1.0 [1] (📵) no mobile phones
+ {0x1F4F6, 0x1F4F7, prExtendedPictographic}, // E0.6 [2] (📶..📷) antenna bars..camera
+ {0x1F4F8, 0x1F4F8, prExtendedPictographic}, // E1.0 [1] (📸) camera with flash
+ {0x1F4F9, 0x1F4FC, prExtendedPictographic}, // E0.6 [4] (📹..📼) video camera..videocassette
+ {0x1F4FD, 0x1F4FD, prExtendedPictographic}, // E0.7 [1] (📽️) film projector
+ {0x1F4FE, 0x1F4FE, prExtendedPictographic}, // E0.0 [1] (📾) PORTABLE STEREO
+ {0x1F4FF, 0x1F502, prExtendedPictographic}, // E1.0 [4] (📿..🔂) prayer beads..repeat single button
+ {0x1F503, 0x1F503, prExtendedPictographic}, // E0.6 [1] (🔃) clockwise vertical arrows
+ {0x1F504, 0x1F507, prExtendedPictographic}, // E1.0 [4] (🔄..🔇) counterclockwise arrows button..muted speaker
+ {0x1F508, 0x1F508, prExtendedPictographic}, // E0.7 [1] (🔈) speaker low volume
+ {0x1F509, 0x1F509, prExtendedPictographic}, // E1.0 [1] (🔉) speaker medium volume
+ {0x1F50A, 0x1F514, prExtendedPictographic}, // E0.6 [11] (🔊..🔔) speaker high volume..bell
+ {0x1F515, 0x1F515, prExtendedPictographic}, // E1.0 [1] (🔕) bell with slash
+ {0x1F516, 0x1F52B, prExtendedPictographic}, // E0.6 [22] (🔖..🔫) bookmark..water pistol
+ {0x1F52C, 0x1F52D, prExtendedPictographic}, // E1.0 [2] (🔬..🔭) microscope..telescope
+ {0x1F52E, 0x1F53D, prExtendedPictographic}, // E0.6 [16] (🔮..🔽) crystal ball..downwards button
+ {0x1F546, 0x1F548, prExtendedPictographic}, // E0.0 [3] (🕆..🕈) WHITE LATIN CROSS..CELTIC CROSS
+ {0x1F549, 0x1F54A, prExtendedPictographic}, // E0.7 [2] (🕉️..🕊️) om..dove
+ {0x1F54B, 0x1F54E, prExtendedPictographic}, // E1.0 [4] (🕋..🕎) kaaba..menorah
+ {0x1F54F, 0x1F54F, prExtendedPictographic}, // E0.0 [1] (🕏) BOWL OF HYGIEIA
+ {0x1F550, 0x1F55B, prExtendedPictographic}, // E0.6 [12] (🕐..🕛) one o’clock..twelve o’clock
+ {0x1F55C, 0x1F567, prExtendedPictographic}, // E0.7 [12] (🕜..🕧) one-thirty..twelve-thirty
+ {0x1F568, 0x1F56E, prExtendedPictographic}, // E0.0 [7] (🕨..🕮) RIGHT SPEAKER..BOOK
+ {0x1F56F, 0x1F570, prExtendedPictographic}, // E0.7 [2] (🕯️..🕰️) candle..mantelpiece clock
+ {0x1F571, 0x1F572, prExtendedPictographic}, // E0.0 [2] (🕱..🕲) BLACK SKULL AND CROSSBONES..NO PIRACY
+ {0x1F573, 0x1F579, prExtendedPictographic}, // E0.7 [7] (🕳️..🕹️) hole..joystick
+ {0x1F57A, 0x1F57A, prExtendedPictographic}, // E3.0 [1] (🕺) man dancing
+ {0x1F57B, 0x1F586, prExtendedPictographic}, // E0.0 [12] (🕻..🖆) LEFT HAND TELEPHONE RECEIVER..PEN OVER STAMPED ENVELOPE
+ {0x1F587, 0x1F587, prExtendedPictographic}, // E0.7 [1] (🖇️) linked paperclips
+ {0x1F588, 0x1F589, prExtendedPictographic}, // E0.0 [2] (🖈..🖉) BLACK PUSHPIN..LOWER LEFT PENCIL
+ {0x1F58A, 0x1F58D, prExtendedPictographic}, // E0.7 [4] (🖊️..🖍️) pen..crayon
+ {0x1F58E, 0x1F58F, prExtendedPictographic}, // E0.0 [2] (🖎..🖏) LEFT WRITING HAND..TURNED OK HAND SIGN
+ {0x1F590, 0x1F590, prExtendedPictographic}, // E0.7 [1] (🖐️) hand with fingers splayed
+ {0x1F591, 0x1F594, prExtendedPictographic}, // E0.0 [4] (🖑..🖔) REVERSED RAISED HAND WITH FINGERS SPLAYED..REVERSED VICTORY HAND
+ {0x1F595, 0x1F596, prExtendedPictographic}, // E1.0 [2] (🖕..🖖) middle finger..vulcan salute
+ {0x1F597, 0x1F5A3, prExtendedPictographic}, // E0.0 [13] (🖗..🖣) WHITE DOWN POINTING LEFT HAND INDEX..BLACK DOWN POINTING BACKHAND INDEX
+ {0x1F5A4, 0x1F5A4, prExtendedPictographic}, // E3.0 [1] (🖤) black heart
+ {0x1F5A5, 0x1F5A5, prExtendedPictographic}, // E0.7 [1] (🖥️) desktop computer
+ {0x1F5A6, 0x1F5A7, prExtendedPictographic}, // E0.0 [2] (🖦..🖧) KEYBOARD AND MOUSE..THREE NETWORKED COMPUTERS
+ {0x1F5A8, 0x1F5A8, prExtendedPictographic}, // E0.7 [1] (🖨️) printer
+ {0x1F5A9, 0x1F5B0, prExtendedPictographic}, // E0.0 [8] (🖩..🖰) POCKET CALCULATOR..TWO BUTTON MOUSE
+ {0x1F5B1, 0x1F5B2, prExtendedPictographic}, // E0.7 [2] (🖱️..🖲️) computer mouse..trackball
+ {0x1F5B3, 0x1F5BB, prExtendedPictographic}, // E0.0 [9] (🖳..🖻) OLD PERSONAL COMPUTER..DOCUMENT WITH PICTURE
+ {0x1F5BC, 0x1F5BC, prExtendedPictographic}, // E0.7 [1] (🖼️) framed picture
+ {0x1F5BD, 0x1F5C1, prExtendedPictographic}, // E0.0 [5] (🖽..🗁) FRAME WITH TILES..OPEN FOLDER
+ {0x1F5C2, 0x1F5C4, prExtendedPictographic}, // E0.7 [3] (🗂️..🗄️) card index dividers..file cabinet
+ {0x1F5C5, 0x1F5D0, prExtendedPictographic}, // E0.0 [12] (🗅..🗐) EMPTY NOTE..PAGES
+ {0x1F5D1, 0x1F5D3, prExtendedPictographic}, // E0.7 [3] (🗑️..🗓️) wastebasket..spiral calendar
+ {0x1F5D4, 0x1F5DB, prExtendedPictographic}, // E0.0 [8] (🗔..🗛) DESKTOP WINDOW..DECREASE FONT SIZE SYMBOL
+ {0x1F5DC, 0x1F5DE, prExtendedPictographic}, // E0.7 [3] (🗜️..🗞️) clamp..rolled-up newspaper
+ {0x1F5DF, 0x1F5E0, prExtendedPictographic}, // E0.0 [2] (🗟..🗠) PAGE WITH CIRCLED TEXT..STOCK CHART
+ {0x1F5E1, 0x1F5E1, prExtendedPictographic}, // E0.7 [1] (🗡️) dagger
+ {0x1F5E2, 0x1F5E2, prExtendedPictographic}, // E0.0 [1] (🗢) LIPS
+ {0x1F5E3, 0x1F5E3, prExtendedPictographic}, // E0.7 [1] (🗣️) speaking head
+ {0x1F5E4, 0x1F5E7, prExtendedPictographic}, // E0.0 [4] (🗤..🗧) THREE RAYS ABOVE..THREE RAYS RIGHT
+ {0x1F5E8, 0x1F5E8, prExtendedPictographic}, // E2.0 [1] (🗨️) left speech bubble
+ {0x1F5E9, 0x1F5EE, prExtendedPictographic}, // E0.0 [6] (🗩..🗮) RIGHT SPEECH BUBBLE..LEFT ANGER BUBBLE
+ {0x1F5EF, 0x1F5EF, prExtendedPictographic}, // E0.7 [1] (🗯️) right anger bubble
+ {0x1F5F0, 0x1F5F2, prExtendedPictographic}, // E0.0 [3] (🗰..🗲) MOOD BUBBLE..LIGHTNING MOOD
+ {0x1F5F3, 0x1F5F3, prExtendedPictographic}, // E0.7 [1] (🗳️) ballot box with ballot
+ {0x1F5F4, 0x1F5F9, prExtendedPictographic}, // E0.0 [6] (🗴..🗹) BALLOT SCRIPT X..BALLOT BOX WITH BOLD CHECK
+ {0x1F5FA, 0x1F5FA, prExtendedPictographic}, // E0.7 [1] (🗺️) world map
+ {0x1F5FB, 0x1F5FF, prExtendedPictographic}, // E0.6 [5] (🗻..🗿) mount fuji..moai
+ {0x1F600, 0x1F600, prExtendedPictographic}, // E1.0 [1] (😀) grinning face
+ {0x1F601, 0x1F606, prExtendedPictographic}, // E0.6 [6] (😁..😆) beaming face with smiling eyes..grinning squinting face
+ {0x1F607, 0x1F608, prExtendedPictographic}, // E1.0 [2] (😇..😈) smiling face with halo..smiling face with horns
+ {0x1F609, 0x1F60D, prExtendedPictographic}, // E0.6 [5] (😉..😍) winking face..smiling face with heart-eyes
+ {0x1F60E, 0x1F60E, prExtendedPictographic}, // E1.0 [1] (😎) smiling face with sunglasses
+ {0x1F60F, 0x1F60F, prExtendedPictographic}, // E0.6 [1] (😏) smirking face
+ {0x1F610, 0x1F610, prExtendedPictographic}, // E0.7 [1] (😐) neutral face
+ {0x1F611, 0x1F611, prExtendedPictographic}, // E1.0 [1] (😑) expressionless face
+ {0x1F612, 0x1F614, prExtendedPictographic}, // E0.6 [3] (😒..😔) unamused face..pensive face
+ {0x1F615, 0x1F615, prExtendedPictographic}, // E1.0 [1] (😕) confused face
+ {0x1F616, 0x1F616, prExtendedPictographic}, // E0.6 [1] (😖) confounded face
+ {0x1F617, 0x1F617, prExtendedPictographic}, // E1.0 [1] (😗) kissing face
+ {0x1F618, 0x1F618, prExtendedPictographic}, // E0.6 [1] (😘) face blowing a kiss
+ {0x1F619, 0x1F619, prExtendedPictographic}, // E1.0 [1] (😙) kissing face with smiling eyes
+ {0x1F61A, 0x1F61A, prExtendedPictographic}, // E0.6 [1] (😚) kissing face with closed eyes
+ {0x1F61B, 0x1F61B, prExtendedPictographic}, // E1.0 [1] (😛) face with tongue
+ {0x1F61C, 0x1F61E, prExtendedPictographic}, // E0.6 [3] (😜..😞) winking face with tongue..disappointed face
+ {0x1F61F, 0x1F61F, prExtendedPictographic}, // E1.0 [1] (😟) worried face
+ {0x1F620, 0x1F625, prExtendedPictographic}, // E0.6 [6] (😠..😥) angry face..sad but relieved face
+ {0x1F626, 0x1F627, prExtendedPictographic}, // E1.0 [2] (😦..😧) frowning face with open mouth..anguished face
+ {0x1F628, 0x1F62B, prExtendedPictographic}, // E0.6 [4] (😨..😫) fearful face..tired face
+ {0x1F62C, 0x1F62C, prExtendedPictographic}, // E1.0 [1] (😬) grimacing face
+ {0x1F62D, 0x1F62D, prExtendedPictographic}, // E0.6 [1] (😭) loudly crying face
+ {0x1F62E, 0x1F62F, prExtendedPictographic}, // E1.0 [2] (😮..😯) face with open mouth..hushed face
+ {0x1F630, 0x1F633, prExtendedPictographic}, // E0.6 [4] (😰..😳) anxious face with sweat..flushed face
+ {0x1F634, 0x1F634, prExtendedPictographic}, // E1.0 [1] (😴) sleeping face
+ {0x1F635, 0x1F635, prExtendedPictographic}, // E0.6 [1] (😵) face with crossed-out eyes
+ {0x1F636, 0x1F636, prExtendedPictographic}, // E1.0 [1] (😶) face without mouth
+ {0x1F637, 0x1F640, prExtendedPictographic}, // E0.6 [10] (😷..🙀) face with medical mask..weary cat
+ {0x1F641, 0x1F644, prExtendedPictographic}, // E1.0 [4] (🙁..🙄) slightly frowning face..face with rolling eyes
+ {0x1F645, 0x1F64F, prExtendedPictographic}, // E0.6 [11] (🙅..🙏) person gesturing NO..folded hands
+ {0x1F680, 0x1F680, prExtendedPictographic}, // E0.6 [1] (🚀) rocket
+ {0x1F681, 0x1F682, prExtendedPictographic}, // E1.0 [2] (🚁..🚂) helicopter..locomotive
+ {0x1F683, 0x1F685, prExtendedPictographic}, // E0.6 [3] (🚃..🚅) railway car..bullet train
+ {0x1F686, 0x1F686, prExtendedPictographic}, // E1.0 [1] (🚆) train
+ {0x1F687, 0x1F687, prExtendedPictographic}, // E0.6 [1] (🚇) metro
+ {0x1F688, 0x1F688, prExtendedPictographic}, // E1.0 [1] (🚈) light rail
+ {0x1F689, 0x1F689, prExtendedPictographic}, // E0.6 [1] (🚉) station
+ {0x1F68A, 0x1F68B, prExtendedPictographic}, // E1.0 [2] (🚊..🚋) tram..tram car
+ {0x1F68C, 0x1F68C, prExtendedPictographic}, // E0.6 [1] (🚌) bus
+ {0x1F68D, 0x1F68D, prExtendedPictographic}, // E0.7 [1] (🚍) oncoming bus
+ {0x1F68E, 0x1F68E, prExtendedPictographic}, // E1.0 [1] (🚎) trolleybus
+ {0x1F68F, 0x1F68F, prExtendedPictographic}, // E0.6 [1] (🚏) bus stop
+ {0x1F690, 0x1F690, prExtendedPictographic}, // E1.0 [1] (🚐) minibus
+ {0x1F691, 0x1F693, prExtendedPictographic}, // E0.6 [3] (🚑..🚓) ambulance..police car
+ {0x1F694, 0x1F694, prExtendedPictographic}, // E0.7 [1] (🚔) oncoming police car
+ {0x1F695, 0x1F695, prExtendedPictographic}, // E0.6 [1] (🚕) taxi
+ {0x1F696, 0x1F696, prExtendedPictographic}, // E1.0 [1] (🚖) oncoming taxi
+ {0x1F697, 0x1F697, prExtendedPictographic}, // E0.6 [1] (🚗) automobile
+ {0x1F698, 0x1F698, prExtendedPictographic}, // E0.7 [1] (🚘) oncoming automobile
+ {0x1F699, 0x1F69A, prExtendedPictographic}, // E0.6 [2] (🚙..🚚) sport utility vehicle..delivery truck
+ {0x1F69B, 0x1F6A1, prExtendedPictographic}, // E1.0 [7] (🚛..🚡) articulated lorry..aerial tramway
+ {0x1F6A2, 0x1F6A2, prExtendedPictographic}, // E0.6 [1] (🚢) ship
+ {0x1F6A3, 0x1F6A3, prExtendedPictographic}, // E1.0 [1] (🚣) person rowing boat
+ {0x1F6A4, 0x1F6A5, prExtendedPictographic}, // E0.6 [2] (🚤..🚥) speedboat..horizontal traffic light
+ {0x1F6A6, 0x1F6A6, prExtendedPictographic}, // E1.0 [1] (🚦) vertical traffic light
+ {0x1F6A7, 0x1F6AD, prExtendedPictographic}, // E0.6 [7] (🚧..🚭) construction..no smoking
+ {0x1F6AE, 0x1F6B1, prExtendedPictographic}, // E1.0 [4] (🚮..🚱) litter in bin sign..non-potable water
+ {0x1F6B2, 0x1F6B2, prExtendedPictographic}, // E0.6 [1] (🚲) bicycle
+ {0x1F6B3, 0x1F6B5, prExtendedPictographic}, // E1.0 [3] (🚳..🚵) no bicycles..person mountain biking
+ {0x1F6B6, 0x1F6B6, prExtendedPictographic}, // E0.6 [1] (🚶) person walking
+ {0x1F6B7, 0x1F6B8, prExtendedPictographic}, // E1.0 [2] (🚷..🚸) no pedestrians..children crossing
+ {0x1F6B9, 0x1F6BE, prExtendedPictographic}, // E0.6 [6] (🚹..🚾) men’s room..water closet
+ {0x1F6BF, 0x1F6BF, prExtendedPictographic}, // E1.0 [1] (🚿) shower
+ {0x1F6C0, 0x1F6C0, prExtendedPictographic}, // E0.6 [1] (🛀) person taking bath
+ {0x1F6C1, 0x1F6C5, prExtendedPictographic}, // E1.0 [5] (🛁..🛅) bathtub..left luggage
+ {0x1F6C6, 0x1F6CA, prExtendedPictographic}, // E0.0 [5] (🛆..🛊) TRIANGLE WITH ROUNDED CORNERS..GIRLS SYMBOL
+ {0x1F6CB, 0x1F6CB, prExtendedPictographic}, // E0.7 [1] (🛋️) couch and lamp
+ {0x1F6CC, 0x1F6CC, prExtendedPictographic}, // E1.0 [1] (🛌) person in bed
+ {0x1F6CD, 0x1F6CF, prExtendedPictographic}, // E0.7 [3] (🛍️..🛏️) shopping bags..bed
+ {0x1F6D0, 0x1F6D0, prExtendedPictographic}, // E1.0 [1] (🛐) place of worship
+ {0x1F6D1, 0x1F6D2, prExtendedPictographic}, // E3.0 [2] (🛑..🛒) stop sign..shopping cart
+ {0x1F6D3, 0x1F6D4, prExtendedPictographic}, // E0.0 [2] (🛓..🛔) STUPA..PAGODA
+ {0x1F6D5, 0x1F6D5, prExtendedPictographic}, // E12.0 [1] (🛕) hindu temple
+ {0x1F6D6, 0x1F6D7, prExtendedPictographic}, // E13.0 [2] (🛖..🛗) hut..elevator
+ {0x1F6D8, 0x1F6DC, prExtendedPictographic}, // E0.0 [5] (..🛜) ..
+ {0x1F6DD, 0x1F6DF, prExtendedPictographic}, // E14.0 [3] (🛝..🛟) playground slide..ring buoy
+ {0x1F6E0, 0x1F6E5, prExtendedPictographic}, // E0.7 [6] (🛠️..🛥️) hammer and wrench..motor boat
+ {0x1F6E6, 0x1F6E8, prExtendedPictographic}, // E0.0 [3] (🛦..🛨) UP-POINTING MILITARY AIRPLANE..UP-POINTING SMALL AIRPLANE
+ {0x1F6E9, 0x1F6E9, prExtendedPictographic}, // E0.7 [1] (🛩️) small airplane
+ {0x1F6EA, 0x1F6EA, prExtendedPictographic}, // E0.0 [1] (🛪) NORTHEAST-POINTING AIRPLANE
+ {0x1F6EB, 0x1F6EC, prExtendedPictographic}, // E1.0 [2] (🛫..🛬) airplane departure..airplane arrival
+ {0x1F6ED, 0x1F6EF, prExtendedPictographic}, // E0.0 [3] (..) ..
+ {0x1F6F0, 0x1F6F0, prExtendedPictographic}, // E0.7 [1] (🛰️) satellite
+ {0x1F6F1, 0x1F6F2, prExtendedPictographic}, // E0.0 [2] (🛱..🛲) ONCOMING FIRE ENGINE..DIESEL LOCOMOTIVE
+ {0x1F6F3, 0x1F6F3, prExtendedPictographic}, // E0.7 [1] (🛳️) passenger ship
+ {0x1F6F4, 0x1F6F6, prExtendedPictographic}, // E3.0 [3] (🛴..🛶) kick scooter..canoe
+ {0x1F6F7, 0x1F6F8, prExtendedPictographic}, // E5.0 [2] (🛷..🛸) sled..flying saucer
+ {0x1F6F9, 0x1F6F9, prExtendedPictographic}, // E11.0 [1] (🛹) skateboard
+ {0x1F6FA, 0x1F6FA, prExtendedPictographic}, // E12.0 [1] (🛺) auto rickshaw
+ {0x1F6FB, 0x1F6FC, prExtendedPictographic}, // E13.0 [2] (🛻..🛼) pickup truck..roller skate
+ {0x1F6FD, 0x1F6FF, prExtendedPictographic}, // E0.0 [3] (..) ..
+ {0x1F774, 0x1F77F, prExtendedPictographic}, // E0.0 [12] (🝴..🝿) ..
+ {0x1F7D5, 0x1F7DF, prExtendedPictographic}, // E0.0 [11] (🟕..) CIRCLED TRIANGLE..
+ {0x1F7E0, 0x1F7EB, prExtendedPictographic}, // E12.0 [12] (🟠..🟫) orange circle..brown square
+ {0x1F7EC, 0x1F7EF, prExtendedPictographic}, // E0.0 [4] (..) ..
+ {0x1F7F0, 0x1F7F0, prExtendedPictographic}, // E14.0 [1] (🟰) heavy equals sign
+ {0x1F7F1, 0x1F7FF, prExtendedPictographic}, // E0.0 [15] (..) ..
+ {0x1F80C, 0x1F80F, prExtendedPictographic}, // E0.0 [4] (..) ..
+ {0x1F848, 0x1F84F, prExtendedPictographic}, // E0.0 [8] (..) ..
+ {0x1F85A, 0x1F85F, prExtendedPictographic}, // E0.0 [6] (..) ..
+ {0x1F888, 0x1F88F, prExtendedPictographic}, // E0.0 [8] (..) ..
+ {0x1F8AE, 0x1F8FF, prExtendedPictographic}, // E0.0 [82] (..)