From 69ef18e659914f6f3405140442a07f8d242fd414 Mon Sep 17 00:00:00 2001
From: Miguel Mota
Date: Thu, 26 Apr 2018 01:07:36 -0700
Subject: [PATCH] dep ensure
---
.gitignore | 1 -
Gopkg.lock | 28 +-
Gopkg.toml | 18 -
cointop/cointop.go | 4 +-
cointop/keybindings.go | 2 +-
cointop/layout.go | 2 +-
cointop/sort.go | 4 +-
cointop/update.go | 2 +-
pkg/cache/cache.go | 1161 ++
pkg/gocui/attribute.go | 32 +
pkg/gocui/edit.go | 344 +
pkg/gocui/escape.go | 229 +
pkg/gocui/gocui.go | 636 +
pkg/gocui/keybinding.go | 137 +
pkg/gocui/view.go | 503 +
pkg/slice/slice.go | 40 +
vendor/github.com/BurntSushi/toml/.gitignore | 5 +
vendor/github.com/BurntSushi/toml/.travis.yml | 15 +
vendor/github.com/BurntSushi/toml/COMPATIBLE | 3 +
vendor/github.com/BurntSushi/toml/COPYING | 14 +
vendor/github.com/BurntSushi/toml/Makefile | 19 +
vendor/github.com/BurntSushi/toml/README.md | 218 +
.../BurntSushi/toml/_examples/example.go | 61 +
.../BurntSushi/toml/_examples/example.toml | 35 +
.../BurntSushi/toml/_examples/hard.toml | 22 +
.../BurntSushi/toml/_examples/implicit.toml | 4 +
.../toml/_examples/invalid-apples.toml | 6 +
.../BurntSushi/toml/_examples/invalid.toml | 35 +
.../BurntSushi/toml/_examples/readme1.toml | 5 +
.../BurntSushi/toml/_examples/readme2.toml | 1 +
.../toml/cmd/toml-test-decoder/COPYING | 14 +
.../toml/cmd/toml-test-decoder/README.md | 13 +
.../toml/cmd/toml-test-decoder/main.go | 90 +
.../toml/cmd/toml-test-encoder/COPYING | 14 +
.../toml/cmd/toml-test-encoder/README.md | 13 +
.../toml/cmd/toml-test-encoder/main.go | 131 +
.../BurntSushi/toml/cmd/tomlv/COPYING | 14 +
.../BurntSushi/toml/cmd/tomlv/README.md | 21 +
.../BurntSushi/toml/cmd/tomlv/main.go | 61 +
vendor/github.com/BurntSushi/toml/decode.go | 509 +
.../github.com/BurntSushi/toml/decode_meta.go | 121 +
.../github.com/BurntSushi/toml/decode_test.go | 1447 ++
vendor/github.com/BurntSushi/toml/doc.go | 27 +
vendor/github.com/BurntSushi/toml/encode.go | 568 +
.../github.com/BurntSushi/toml/encode_test.go | 615 +
.../BurntSushi/toml/encoding_types.go | 19 +
.../BurntSushi/toml/encoding_types_1.1.go | 18 +
vendor/github.com/BurntSushi/toml/lex.go | 953 +
vendor/github.com/BurntSushi/toml/parse.go | 592 +
vendor/github.com/BurntSushi/toml/session.vim | 1 +
.../github.com/BurntSushi/toml/type_check.go | 91 +
.../github.com/BurntSushi/toml/type_fields.go | 242 +
vendor/github.com/anaskhan96/soup/.gitignore | 1 +
vendor/github.com/anaskhan96/soup/.travis.yml | 9 +
.../github.com/anaskhan96/soup/CHANGELOG.md | 15 +
vendor/github.com/anaskhan96/soup/README.md | 70 +
.../soup/examples/weather/weather.go | 38 +
.../soup/examples/xkcdextract/xkcdextract.go | 29 +
vendor/github.com/anaskhan96/soup/license | 21 +
vendor/github.com/anaskhan96/soup/soup.go | 373 +
.../github.com/anaskhan96/soup/soup_test.go | 169 +
vendor/github.com/fatih/color/.travis.yml | 5 +
vendor/github.com/fatih/color/Gopkg.lock | 27 +
vendor/github.com/fatih/color/Gopkg.toml | 30 +
vendor/github.com/fatih/color/LICENSE.md | 20 +
vendor/github.com/fatih/color/README.md | 179 +
vendor/github.com/fatih/color/color.go | 600 +
vendor/github.com/fatih/color/color_test.go | 342 +
vendor/github.com/fatih/color/doc.go | 133 +
.../github.com/mattn/go-colorable/.travis.yml | 9 +
vendor/github.com/mattn/go-colorable/LICENSE | 21 +
.../github.com/mattn/go-colorable/README.md | 48 +
.../go-colorable/_example/escape-seq/main.go | 16 +
.../go-colorable/_example/logrus/main.go | 16 +
.../mattn/go-colorable/_example/title/main.go | 14 +
.../mattn/go-colorable/colorable_appengine.go | 29 +
.../mattn/go-colorable/colorable_others.go | 30 +
.../mattn/go-colorable/colorable_test.go | 83 +
.../mattn/go-colorable/colorable_windows.go | 884 +
.../mattn/go-colorable/noncolorable.go | 55 +
vendor/github.com/mattn/go-isatty/.travis.yml | 9 +
vendor/github.com/mattn/go-isatty/LICENSE | 9 +
vendor/github.com/mattn/go-isatty/README.md | 50 +
vendor/github.com/mattn/go-isatty/doc.go | 2 +
.../mattn/go-isatty/example_test.go | 18 +
.../mattn/go-isatty/isatty_appengine.go | 15 +
.../github.com/mattn/go-isatty/isatty_bsd.go | 18 +
.../mattn/go-isatty/isatty_linux.go | 18 +
.../mattn/go-isatty/isatty_linux_ppc64x.go | 19 +
.../mattn/go-isatty/isatty_others.go | 10 +
.../mattn/go-isatty/isatty_others_test.go | 19 +
.../mattn/go-isatty/isatty_solaris.go | 16 +
.../mattn/go-isatty/isatty_windows.go | 94 +
.../mattn/go-isatty/isatty_windows_test.go | 35 +
.../github.com/mattn/go-runewidth/.travis.yml | 8 +
vendor/github.com/mattn/go-runewidth/LICENSE | 21 +
.../github.com/mattn/go-runewidth/README.mkd | 27 +
.../mattn/go-runewidth/runewidth.go | 1223 ++
.../mattn/go-runewidth/runewidth_js.go | 8 +
.../mattn/go-runewidth/runewidth_posix.go | 77 +
.../mattn/go-runewidth/runewidth_test.go | 275 +
.../mattn/go-runewidth/runewidth_windows.go | 25 +
.../miguelmota/go-coinmarketcap/.gitignore | 26 +
.../miguelmota/go-coinmarketcap/.travis.yml | 9 +
.../miguelmota/go-coinmarketcap/Gopkg.lock | 24 +
.../miguelmota/go-coinmarketcap/Gopkg.toml | 34 +
.../miguelmota/go-coinmarketcap/LICENSE.md | 21 +
.../miguelmota/go-coinmarketcap/Makefile | 5 +
.../miguelmota/go-coinmarketcap/README.md | 47 +
.../go-coinmarketcap/coinmarketcap.go | 210 +
.../go-coinmarketcap/coinmarketcap_test.go | 219 +
.../go-coinmarketcap/example/all_coins.go | 20 +
.../go-coinmarketcap/example/coin.go | 18 +
.../go-coinmarketcap/example/coin_graph.go | 25 +
.../go-coinmarketcap/example/global_market.go | 18 +
.../miguelmota/go-coinmarketcap/types.go | 66 +
vendor/github.com/nsf/termbox-go/AUTHORS | 4 +
vendor/github.com/nsf/termbox-go/LICENSE | 19 +
vendor/github.com/nsf/termbox-go/README.md | 39 +
.../nsf/termbox-go/_demos/editbox.go | 300 +
.../nsf/termbox-go/_demos/interrupt.go | 69 +
.../nsf/termbox-go/_demos/keyboard.go | 722 +
.../nsf/termbox-go/_demos/output.go | 228 +
.../github.com/nsf/termbox-go/_demos/paint.go | 105 +
.../nsf/termbox-go/_demos/random_output.go | 46 +
.../nsf/termbox-go/_demos/raw_input.go | 109 +
vendor/github.com/nsf/termbox-go/api.go | 489 +
.../github.com/nsf/termbox-go/api_common.go | 187 +
.../github.com/nsf/termbox-go/api_windows.go | 239 +
.../nsf/termbox-go/collect_terminfo.py | 110 +
vendor/github.com/nsf/termbox-go/escwait.go | 11 +
.../nsf/termbox-go/escwait_darwin.go | 9 +
vendor/github.com/nsf/termbox-go/syscalls.go | 39 +
.../nsf/termbox-go/syscalls_darwin.go | 41 +
.../nsf/termbox-go/syscalls_darwin_amd64.go | 40 +
.../nsf/termbox-go/syscalls_dragonfly.go | 39 +
.../nsf/termbox-go/syscalls_freebsd.go | 39 +
.../nsf/termbox-go/syscalls_linux.go | 33 +
.../nsf/termbox-go/syscalls_netbsd.go | 39 +
.../nsf/termbox-go/syscalls_openbsd.go | 39 +
.../nsf/termbox-go/syscalls_windows.go | 61 +
vendor/github.com/nsf/termbox-go/termbox.go | 529 +
.../nsf/termbox-go/termbox_common.go | 59 +
.../nsf/termbox-go/termbox_windows.go | 915 +
vendor/github.com/nsf/termbox-go/terminfo.go | 226 +
.../nsf/termbox-go/terminfo_builtin.go | 64 +
vendor/go4.org/.gitignore | 24 +
vendor/go4.org/.travis.yml | 10 +
vendor/go4.org/AUTHORS | 8 +
vendor/go4.org/LICENSE | 202 +
vendor/go4.org/README.md | 57 +
vendor/go4.org/bytereplacer/bytereplacer.go | 286 +
.../go4.org/bytereplacer/bytereplacer_test.go | 423 +
.../go4.org/cloud/cloudlaunch/cloudlaunch.go | 457 +
.../go4.org/cloud/google/gceutil/gceutil.go | 110 +
.../go4.org/cloud/google/gcsutil/storage.go | 180 +
vendor/go4.org/ctxutil/ctxutil.go | 44 +
vendor/go4.org/errorutil/highlight.go | 58 +
vendor/go4.org/fault/fault.go | 59 +
.../go4test/cloudlaunch/serve_on_cloud.go | 95 +
vendor/go4.org/jsonconfig/eval.go | 321 +
vendor/go4.org/jsonconfig/jsonconfig.go | 297 +
vendor/go4.org/jsonconfig/jsonconfig_test.go | 114 +
.../go4.org/jsonconfig/testdata/boolenv.json | 11 +
.../go4.org/jsonconfig/testdata/include1.json | 3 +
.../jsonconfig/testdata/include1bis.json | 3 +
.../go4.org/jsonconfig/testdata/include2.json | 3 +
.../jsonconfig/testdata/listexpand.json | 4 +
vendor/go4.org/jsonconfig/testdata/loop1.json | 3 +
vendor/go4.org/jsonconfig/testdata/loop2.json | 3 +
vendor/go4.org/legal/legal.go | 32 +
vendor/go4.org/legal/legal_test.go | 29 +
vendor/go4.org/lock/.gitignore | 1 +
vendor/go4.org/lock/lock.go | 186 +
vendor/go4.org/lock/lock_appengine.go | 32 +
vendor/go4.org/lock/lock_plan9.go | 41 +
vendor/go4.org/lock/lock_sigzero.go | 26 +
vendor/go4.org/lock/lock_test.go | 222 +
vendor/go4.org/lock/lock_unix.go | 58 +
vendor/go4.org/lock/lock_windows.go | 78 +
vendor/go4.org/media/heif/bmff/bmff.go | 833 +
.../go4.org/media/heif/dumpheif/dumpheif.go | 200 +
vendor/go4.org/media/heif/heif.go | 292 +
vendor/go4.org/media/heif/heif_test.go | 113 +
vendor/go4.org/media/heif/testdata/park.heic | Bin 0 -> 50000 bytes
.../go4.org/media/heif/testdata/rotate.heic | Bin 0 -> 4096 bytes
vendor/go4.org/net/throttle/throttle.go | 137 +
vendor/go4.org/oauthutil/oauth.go | 121 +
vendor/go4.org/osutil/exec_plan9.go | 35 +
vendor/go4.org/osutil/exec_procfs.go | 42 +
vendor/go4.org/osutil/exec_solaris_amd64.go | 71 +
vendor/go4.org/osutil/exec_sysctl.go | 63 +
vendor/go4.org/osutil/exec_test.go | 94 +
vendor/go4.org/osutil/exec_windows.go | 64 +
vendor/go4.org/osutil/osutil.go | 32 +
vendor/go4.org/readerutil/bufreaderat.go | 48 +
vendor/go4.org/readerutil/bufreaderat_test.go | 70 +
vendor/go4.org/readerutil/countingreader.go | 32 +
vendor/go4.org/readerutil/fakeseeker.go | 70 +
vendor/go4.org/readerutil/fakeseeker_test.go | 55 +
vendor/go4.org/readerutil/multireaderat.go | 91 +
.../go4.org/readerutil/multireaderat_test.go | 48 +
vendor/go4.org/readerutil/readersize.go | 58 +
vendor/go4.org/readerutil/readersize_test.go | 68 +
vendor/go4.org/readerutil/readerutil.go | 84 +
vendor/go4.org/readerutil/readerutil_test.go | 38 +
.../go4.org/readerutil/singlereader/opener.go | 118 +
.../readerutil/singlereader/opener_test.go | 77 +
vendor/go4.org/reflectutil/asm_b.s | 17 +
vendor/go4.org/reflectutil/asm_b_14.s | 13 +
vendor/go4.org/reflectutil/asm_jmp.s | 17 +
vendor/go4.org/reflectutil/asm_jmp_14.s | 13 +
vendor/go4.org/reflectutil/reflectutil.go | 40 +
.../go4.org/reflectutil/reflectutil_test.go | 71 +
vendor/go4.org/reflectutil/swapper.go | 21 +
vendor/go4.org/reflectutil/swapper_safe.go | 20 +
vendor/go4.org/reflectutil/swapper_test.go | 110 +
vendor/go4.org/reflectutil/swapper_unsafe.go | 106 +
.../go4.org/reflectutil/swapper_unsafe_14.go | 16 +
.../go4.org/reflectutil/swapper_unsafe_15.go | 16 +
vendor/go4.org/sort/example_interface_test.go | 45 +
vendor/go4.org/sort/example_keys_test.go | 96 +
vendor/go4.org/sort/example_multi_test.go | 133 +
vendor/go4.org/sort/example_slice_test.go | 45 +
vendor/go4.org/sort/example_test.go | 24 +
vendor/go4.org/sort/example_wrapper_test.go | 77 +
vendor/go4.org/sort/export_test.go | 9 +
vendor/go4.org/sort/genzfunc.go | 122 +
vendor/go4.org/sort/search.go | 112 +
vendor/go4.org/sort/search_test.go | 161 +
vendor/go4.org/sort/sort.go | 623 +
vendor/go4.org/sort/sort_test.go | 695 +
vendor/go4.org/sort/zfuncversion.go | 265 +
vendor/go4.org/strutil/intern.go | 39 +
vendor/go4.org/strutil/strconv.go | 117 +
vendor/go4.org/strutil/strutil.go | 200 +
vendor/go4.org/strutil/strutil_test.go | 230 +
vendor/go4.org/syncutil/gate.go | 41 +
vendor/go4.org/syncutil/group.go | 64 +
vendor/go4.org/syncutil/once.go | 60 +
vendor/go4.org/syncutil/once_test.go | 57 +
vendor/go4.org/syncutil/sem.go | 64 +
vendor/go4.org/syncutil/sem_test.go | 33 +
.../syncutil/singleflight/singleflight.go | 64 +
.../singleflight/singleflight_test.go | 85 +
.../go4.org/syncutil/syncdebug/syncdebug.go | 198 +
.../syncutil/syncdebug/syncdebug_test.go | 30 +
vendor/go4.org/syncutil/syncutil.go | 18 +
vendor/go4.org/testing/functest/functest.go | 309 +
.../go4.org/testing/functest/functest_test.go | 137 +
vendor/go4.org/types/types.go | 147 +
vendor/go4.org/types/types_test.go | 103 +
vendor/go4.org/wkfs/gcs/gcs.go | 199 +
vendor/go4.org/wkfs/gcs/gcs_test.go | 86 +
vendor/go4.org/wkfs/wkfs.go | 135 +
vendor/go4.org/writerutil/writerutil.go | 105 +
vendor/go4.org/writerutil/writerutil_test.go | 73 +
vendor/go4.org/xdgdir/example_test.go | 50 +
vendor/go4.org/xdgdir/xdgdir.go | 240 +
vendor/go4.org/xdgdir/xdgdir_test.go | 494 +
vendor/golang.org/x/net/.gitattributes | 10 +
vendor/golang.org/x/net/.gitignore | 2 +
vendor/golang.org/x/net/AUTHORS | 3 +
vendor/golang.org/x/net/CONTRIBUTING.md | 26 +
vendor/golang.org/x/net/CONTRIBUTORS | 3 +
vendor/golang.org/x/net/LICENSE | 27 +
vendor/golang.org/x/net/PATENTS | 22 +
vendor/golang.org/x/net/README.md | 16 +
vendor/golang.org/x/net/bpf/asm.go | 41 +
vendor/golang.org/x/net/bpf/constants.go | 218 +
vendor/golang.org/x/net/bpf/doc.go | 82 +
vendor/golang.org/x/net/bpf/instructions.go | 704 +
.../golang.org/x/net/bpf/instructions_test.go | 525 +
vendor/golang.org/x/net/bpf/setter.go | 10 +
.../x/net/bpf/testdata/all_instructions.bpf | 1 +
.../x/net/bpf/testdata/all_instructions.txt | 79 +
vendor/golang.org/x/net/bpf/vm.go | 140 +
vendor/golang.org/x/net/bpf/vm_aluop_test.go | 512 +
vendor/golang.org/x/net/bpf/vm_bpf_test.go | 192 +
.../golang.org/x/net/bpf/vm_extension_test.go | 49 +
.../golang.org/x/net/bpf/vm_instructions.go | 174 +
vendor/golang.org/x/net/bpf/vm_jump_test.go | 380 +
vendor/golang.org/x/net/bpf/vm_load_test.go | 246 +
vendor/golang.org/x/net/bpf/vm_ret_test.go | 115 +
.../golang.org/x/net/bpf/vm_scratch_test.go | 247 +
vendor/golang.org/x/net/bpf/vm_test.go | 144 +
vendor/golang.org/x/net/codereview.cfg | 1 +
vendor/golang.org/x/net/context/context.go | 56 +
.../golang.org/x/net/context/context_test.go | 583 +
.../x/net/context/ctxhttp/ctxhttp.go | 74 +
.../x/net/context/ctxhttp/ctxhttp_17_test.go | 29 +
.../x/net/context/ctxhttp/ctxhttp_pre17.go | 147 +
.../net/context/ctxhttp/ctxhttp_pre17_test.go | 79 +
.../x/net/context/ctxhttp/ctxhttp_test.go | 105 +
vendor/golang.org/x/net/context/go17.go | 72 +
vendor/golang.org/x/net/context/go19.go | 20 +
vendor/golang.org/x/net/context/pre_go17.go | 300 +
vendor/golang.org/x/net/context/pre_go19.go | 109 +
.../x/net/context/withtimeout_test.go | 31 +
vendor/golang.org/x/net/dict/dict.go | 210 +
.../x/net/dns/dnsmessage/example_test.go | 132 +
.../x/net/dns/dnsmessage/message.go | 2247 ++
.../x/net/dns/dnsmessage/message_test.go | 1316 ++
vendor/golang.org/x/net/html/atom/atom.go | 78 +
.../golang.org/x/net/html/atom/atom_test.go | 109 +
vendor/golang.org/x/net/html/atom/gen.go | 712 +
vendor/golang.org/x/net/html/atom/table.go | 783 +
.../golang.org/x/net/html/atom/table_test.go | 376 +
.../golang.org/x/net/html/charset/charset.go | 257 +
.../x/net/html/charset/charset_test.go | 237 +
.../html/charset/testdata/HTTP-charset.html | 48 +
.../charset/testdata/HTTP-vs-UTF-8-BOM.html | 48 +
.../testdata/HTTP-vs-meta-charset.html | 49 +
.../testdata/HTTP-vs-meta-content.html | 49 +
.../testdata/No-encoding-declaration.html | 47 +
.../x/net/html/charset/testdata/README | 9 +
.../html/charset/testdata/UTF-16BE-BOM.html | Bin 0 -> 2670 bytes
.../html/charset/testdata/UTF-16LE-BOM.html | Bin 0 -> 2682 bytes
.../testdata/UTF-8-BOM-vs-meta-charset.html | 49 +
.../testdata/UTF-8-BOM-vs-meta-content.html | 48 +
.../testdata/meta-charset-attribute.html | 48 +
.../testdata/meta-content-attribute.html | 48 +
vendor/golang.org/x/net/html/const.go | 104 +
vendor/golang.org/x/net/html/doc.go | 106 +
vendor/golang.org/x/net/html/doctype.go | 156 +
vendor/golang.org/x/net/html/entity.go | 2253 ++
vendor/golang.org/x/net/html/entity_test.go | 29 +
vendor/golang.org/x/net/html/escape.go | 258 +
vendor/golang.org/x/net/html/escape_test.go | 97 +
vendor/golang.org/x/net/html/example_test.go | 40 +
vendor/golang.org/x/net/html/foreign.go | 226 +
vendor/golang.org/x/net/html/node.go | 220 +
vendor/golang.org/x/net/html/node_test.go | 146 +
vendor/golang.org/x/net/html/parse.go | 2305 +++
vendor/golang.org/x/net/html/parse_test.go | 400 +
vendor/golang.org/x/net/html/render.go | 271 +
vendor/golang.org/x/net/html/render_test.go | 156 +
.../golang.org/x/net/html/testdata/go1.html | 2237 ++
.../x/net/html/testdata/webkit/README | 28 +
.../x/net/html/testdata/webkit/adoption01.dat | 194 +
.../x/net/html/testdata/webkit/adoption02.dat | 31 +
.../x/net/html/testdata/webkit/comments01.dat | 135 +
.../x/net/html/testdata/webkit/doctype01.dat | 370 +
.../x/net/html/testdata/webkit/entities01.dat | 603 +
.../x/net/html/testdata/webkit/entities02.dat | 249 +
.../html/testdata/webkit/html5test-com.dat | 246 +
.../x/net/html/testdata/webkit/inbody01.dat | 43 +
.../x/net/html/testdata/webkit/isindex.dat | 40 +
...pending-spec-changes-plain-text-unsafe.dat | Bin 0 -> 115 bytes
.../testdata/webkit/pending-spec-changes.dat | 52 +
.../testdata/webkit/plain-text-unsafe.dat | Bin 0 -> 4166 bytes
.../x/net/html/testdata/webkit/ruby.dat | 298 +
.../net/html/testdata/webkit/scriptdata01.dat | 308 +
.../testdata/webkit/scripted/adoption01.dat | 15 +
.../testdata/webkit/scripted/webkit01.dat | 28 +
.../x/net/html/testdata/webkit/tables01.dat | 212 +
.../x/net/html/testdata/webkit/template.dat | 1117 +
.../x/net/html/testdata/webkit/tests1.dat | 1952 ++
.../x/net/html/testdata/webkit/tests10.dat | 799 +
.../x/net/html/testdata/webkit/tests11.dat | 482 +
.../x/net/html/testdata/webkit/tests12.dat | 62 +
.../x/net/html/testdata/webkit/tests14.dat | 74 +
.../x/net/html/testdata/webkit/tests15.dat | 208 +
.../x/net/html/testdata/webkit/tests16.dat | 2299 +++
.../x/net/html/testdata/webkit/tests17.dat | 153 +
.../x/net/html/testdata/webkit/tests18.dat | 269 +
.../x/net/html/testdata/webkit/tests19.dat | 1237 ++
.../x/net/html/testdata/webkit/tests2.dat | 763 +
.../x/net/html/testdata/webkit/tests20.dat | 455 +
.../x/net/html/testdata/webkit/tests21.dat | 221 +
.../x/net/html/testdata/webkit/tests22.dat | 157 +
.../x/net/html/testdata/webkit/tests23.dat | 155 +
.../x/net/html/testdata/webkit/tests24.dat | 79 +
.../x/net/html/testdata/webkit/tests25.dat | 219 +
.../x/net/html/testdata/webkit/tests26.dat | 313 +
.../x/net/html/testdata/webkit/tests3.dat | 305 +
.../x/net/html/testdata/webkit/tests4.dat | 59 +
.../x/net/html/testdata/webkit/tests5.dat | 191 +
.../x/net/html/testdata/webkit/tests6.dat | 663 +
.../x/net/html/testdata/webkit/tests7.dat | 390 +
.../x/net/html/testdata/webkit/tests8.dat | 148 +
.../x/net/html/testdata/webkit/tests9.dat | 457 +
.../testdata/webkit/tests_innerHTML_1.dat | 741 +
.../x/net/html/testdata/webkit/tricky01.dat | 261 +
.../x/net/html/testdata/webkit/webkit01.dat | 610 +
.../x/net/html/testdata/webkit/webkit02.dat | 159 +
vendor/golang.org/x/net/html/token.go | 1219 ++
vendor/golang.org/x/net/html/token_test.go | 748 +
vendor/golang.org/x/net/http/httpguts/guts.go | 50 +
.../x/net/http/httpproxy/export_test.go | 7 +
.../x/net/http/httpproxy/go19_test.go | 13 +
.../golang.org/x/net/http/httpproxy/proxy.go | 239 +
.../x/net/http/httpproxy/proxy_test.go | 301 +
vendor/golang.org/x/net/http2/.gitignore | 2 +
vendor/golang.org/x/net/http2/Dockerfile | 51 +
vendor/golang.org/x/net/http2/Makefile | 3 +
vendor/golang.org/x/net/http2/README | 20 +
vendor/golang.org/x/net/http2/ciphers.go | 641 +
vendor/golang.org/x/net/http2/ciphers_test.go | 309 +
.../x/net/http2/client_conn_pool.go | 256 +
.../x/net/http2/configure_transport.go | 80 +
vendor/golang.org/x/net/http2/databuffer.go | 146 +
.../golang.org/x/net/http2/databuffer_test.go | 157 +
vendor/golang.org/x/net/http2/errors.go | 133 +
vendor/golang.org/x/net/http2/errors_test.go | 24 +
vendor/golang.org/x/net/http2/flow.go | 50 +
vendor/golang.org/x/net/http2/flow_test.go | 53 +
vendor/golang.org/x/net/http2/frame.go | 1579 ++
vendor/golang.org/x/net/http2/frame_test.go | 1191 ++
vendor/golang.org/x/net/http2/go16.go | 16 +
vendor/golang.org/x/net/http2/go17.go | 106 +
vendor/golang.org/x/net/http2/go17_not18.go | 36 +
vendor/golang.org/x/net/http2/go18.go | 56 +
vendor/golang.org/x/net/http2/go18_test.go | 79 +
vendor/golang.org/x/net/http2/go19.go | 16 +
vendor/golang.org/x/net/http2/go19_test.go | 59 +
vendor/golang.org/x/net/http2/gotrack.go | 170 +
vendor/golang.org/x/net/http2/gotrack_test.go | 33 +
.../golang.org/x/net/http2/h2demo/.gitignore | 6 +
.../golang.org/x/net/http2/h2demo/Dockerfile | 11 +
.../x/net/http2/h2demo/Dockerfile.0 | 134 +
vendor/golang.org/x/net/http2/h2demo/Makefile | 55 +
vendor/golang.org/x/net/http2/h2demo/README | 16 +
.../x/net/http2/h2demo/deployment-prod.yaml | 28 +
.../golang.org/x/net/http2/h2demo/h2demo.go | 543 +
.../golang.org/x/net/http2/h2demo/launch.go | 302 +
.../golang.org/x/net/http2/h2demo/rootCA.key | 27 +
.../golang.org/x/net/http2/h2demo/rootCA.pem | 26 +
.../golang.org/x/net/http2/h2demo/rootCA.srl | 1 +
.../golang.org/x/net/http2/h2demo/server.crt | 20 +
.../golang.org/x/net/http2/h2demo/server.key | 27 +
.../x/net/http2/h2demo/service.yaml | 17 +
vendor/golang.org/x/net/http2/h2demo/tmpl.go | 1991 ++
vendor/golang.org/x/net/http2/h2i/README.md | 97 +
vendor/golang.org/x/net/http2/h2i/h2i.go | 522 +
vendor/golang.org/x/net/http2/headermap.go | 78 +
vendor/golang.org/x/net/http2/hpack/encode.go | 240 +
.../x/net/http2/hpack/encode_test.go | 386 +
vendor/golang.org/x/net/http2/hpack/hpack.go | 490 +
.../x/net/http2/hpack/hpack_test.go | 722 +
.../golang.org/x/net/http2/hpack/huffman.go | 212 +
vendor/golang.org/x/net/http2/hpack/tables.go | 479 +
.../x/net/http2/hpack/tables_test.go | 214 +
vendor/golang.org/x/net/http2/http2.go | 391 +
vendor/golang.org/x/net/http2/http2_test.go | 199 +
vendor/golang.org/x/net/http2/not_go16.go | 21 +
vendor/golang.org/x/net/http2/not_go17.go | 87 +
vendor/golang.org/x/net/http2/not_go18.go | 29 +
vendor/golang.org/x/net/http2/not_go19.go | 16 +
vendor/golang.org/x/net/http2/pipe.go | 163 +
vendor/golang.org/x/net/http2/pipe_test.go | 130 +
vendor/golang.org/x/net/http2/server.go | 2862 +++
.../x/net/http2/server_push_test.go | 521 +
vendor/golang.org/x/net/http2/server_test.go | 3761 ++++
.../testdata/draft-ietf-httpbis-http2.xml | 5021 +++++
vendor/golang.org/x/net/http2/transport.go | 2306 +++
.../golang.org/x/net/http2/transport_test.go | 3847 ++++
vendor/golang.org/x/net/http2/write.go | 365 +
vendor/golang.org/x/net/http2/writesched.go | 242 +
.../x/net/http2/writesched_priority.go | 452 +
.../x/net/http2/writesched_priority_test.go | 541 +
.../x/net/http2/writesched_random.go | 72 +
.../x/net/http2/writesched_random_test.go | 44 +
.../golang.org/x/net/http2/writesched_test.go | 125 +
vendor/golang.org/x/net/http2/z_spec_test.go | 356 +
vendor/golang.org/x/net/icmp/diag_test.go | 274 +
vendor/golang.org/x/net/icmp/dstunreach.go | 41 +
vendor/golang.org/x/net/icmp/echo.go | 157 +
vendor/golang.org/x/net/icmp/endpoint.go | 113 +
vendor/golang.org/x/net/icmp/example_test.go | 63 +
vendor/golang.org/x/net/icmp/extension.go | 108 +
.../golang.org/x/net/icmp/extension_test.go | 333 +
vendor/golang.org/x/net/icmp/helper_posix.go | 75 +
vendor/golang.org/x/net/icmp/interface.go | 322 +
vendor/golang.org/x/net/icmp/ipv4.go | 61 +
vendor/golang.org/x/net/icmp/ipv4_test.go | 75 +
vendor/golang.org/x/net/icmp/ipv6.go | 23 +
vendor/golang.org/x/net/icmp/listen_posix.go | 100 +
vendor/golang.org/x/net/icmp/listen_stub.go | 33 +
vendor/golang.org/x/net/icmp/message.go | 157 +
vendor/golang.org/x/net/icmp/message_test.go | 155 +
vendor/golang.org/x/net/icmp/messagebody.go | 41 +
vendor/golang.org/x/net/icmp/mpls.go | 77 +
vendor/golang.org/x/net/icmp/multipart.go | 121 +
.../golang.org/x/net/icmp/multipart_test.go | 575 +
vendor/golang.org/x/net/icmp/packettoobig.go | 43 +
vendor/golang.org/x/net/icmp/paramprob.go | 63 +
vendor/golang.org/x/net/icmp/sys_freebsd.go | 11 +
vendor/golang.org/x/net/icmp/timeexceeded.go | 39 +
vendor/golang.org/x/net/idna/example_test.go | 70 +
vendor/golang.org/x/net/idna/idna.go | 732 +
vendor/golang.org/x/net/idna/idna_test.go | 108 +
vendor/golang.org/x/net/idna/punycode.go | 203 +
vendor/golang.org/x/net/idna/punycode_test.go | 198 +
vendor/golang.org/x/net/idna/tables.go | 4557 +++++
vendor/golang.org/x/net/idna/trie.go | 72 +
vendor/golang.org/x/net/idna/trieval.go | 119 +
.../golang.org/x/net/internal/iana/const.go | 227 +
vendor/golang.org/x/net/internal/iana/gen.go | 387 +
.../x/net/internal/nettest/helper_bsd.go | 53 +
.../x/net/internal/nettest/helper_nobsd.go | 15 +
.../x/net/internal/nettest/helper_posix.go | 31 +
.../x/net/internal/nettest/helper_stub.go | 32 +
.../x/net/internal/nettest/helper_unix.go | 29 +
.../x/net/internal/nettest/helper_windows.go | 42 +
.../x/net/internal/nettest/interface.go | 94 +
.../x/net/internal/nettest/rlimit.go | 11 +
.../x/net/internal/nettest/stack.go | 152 +
.../x/net/internal/socket/cmsghdr.go | 11 +
.../x/net/internal/socket/cmsghdr_bsd.go | 13 +
.../internal/socket/cmsghdr_linux_32bit.go | 14 +
.../internal/socket/cmsghdr_linux_64bit.go | 14 +
.../internal/socket/cmsghdr_solaris_64bit.go | 14 +
.../x/net/internal/socket/cmsghdr_stub.go | 17 +
.../x/net/internal/socket/defs_darwin.go | 44 +
.../x/net/internal/socket/defs_dragonfly.go | 44 +
.../x/net/internal/socket/defs_freebsd.go | 44 +
.../x/net/internal/socket/defs_linux.go | 49 +
.../x/net/internal/socket/defs_netbsd.go | 47 +
.../x/net/internal/socket/defs_openbsd.go | 44 +
.../x/net/internal/socket/defs_solaris.go | 44 +
.../x/net/internal/socket/error_unix.go | 31 +
.../x/net/internal/socket/error_windows.go | 26 +
.../x/net/internal/socket/iovec_32bit.go | 19 +
.../x/net/internal/socket/iovec_64bit.go | 19 +
.../internal/socket/iovec_solaris_64bit.go | 19 +
.../x/net/internal/socket/iovec_stub.go | 11 +
.../x/net/internal/socket/mmsghdr_stub.go | 21 +
.../x/net/internal/socket/mmsghdr_unix.go | 42 +
.../x/net/internal/socket/msghdr_bsd.go | 39 +
.../x/net/internal/socket/msghdr_bsdvar.go | 16 +
.../x/net/internal/socket/msghdr_linux.go | 36 +
.../net/internal/socket/msghdr_linux_32bit.go | 24 +
.../net/internal/socket/msghdr_linux_64bit.go | 24 +
.../x/net/internal/socket/msghdr_openbsd.go | 14 +
.../internal/socket/msghdr_solaris_64bit.go | 36 +
.../x/net/internal/socket/msghdr_stub.go | 14 +
.../x/net/internal/socket/rawconn.go | 66 +
.../x/net/internal/socket/rawconn_mmsg.go | 74 +
.../x/net/internal/socket/rawconn_msg.go | 77 +
.../x/net/internal/socket/rawconn_nommsg.go | 18 +
.../x/net/internal/socket/rawconn_nomsg.go | 18 +
.../x/net/internal/socket/rawconn_stub.go | 25 +
.../x/net/internal/socket/reflect.go | 62 +
.../x/net/internal/socket/socket.go | 285 +
.../net/internal/socket/socket_go1_9_test.go | 259 +
.../x/net/internal/socket/socket_test.go | 46 +
.../golang.org/x/net/internal/socket/sys.go | 33 +
.../x/net/internal/socket/sys_bsd.go | 17 +
.../x/net/internal/socket/sys_bsdvar.go | 14 +
.../x/net/internal/socket/sys_darwin.go | 7 +
.../x/net/internal/socket/sys_dragonfly.go | 7 +
.../x/net/internal/socket/sys_linux.go | 27 +
.../x/net/internal/socket/sys_linux_386.go | 55 +
.../x/net/internal/socket/sys_linux_386.s | 11 +
.../x/net/internal/socket/sys_linux_amd64.go | 10 +
.../x/net/internal/socket/sys_linux_arm.go | 10 +
.../x/net/internal/socket/sys_linux_arm64.go | 10 +
.../x/net/internal/socket/sys_linux_mips.go | 10 +
.../x/net/internal/socket/sys_linux_mips64.go | 10 +
.../net/internal/socket/sys_linux_mips64le.go | 10 +
.../x/net/internal/socket/sys_linux_mipsle.go | 10 +
.../x/net/internal/socket/sys_linux_ppc64.go | 10 +
.../net/internal/socket/sys_linux_ppc64le.go | 10 +
.../x/net/internal/socket/sys_linux_s390x.go | 55 +
.../x/net/internal/socket/sys_linux_s390x.s | 11 +
.../x/net/internal/socket/sys_netbsd.go | 25 +
.../x/net/internal/socket/sys_posix.go | 168 +
.../x/net/internal/socket/sys_solaris.go | 71 +
.../x/net/internal/socket/sys_solaris_amd64.s | 11 +
.../x/net/internal/socket/sys_stub.go | 64 +
.../x/net/internal/socket/sys_unix.go | 33 +
.../x/net/internal/socket/sys_windows.go | 70 +
.../x/net/internal/socket/zsys_darwin_386.go | 59 +
.../net/internal/socket/zsys_darwin_amd64.go | 61 +
.../x/net/internal/socket/zsys_darwin_arm.go | 59 +
.../net/internal/socket/zsys_darwin_arm64.go | 61 +
.../internal/socket/zsys_dragonfly_amd64.go | 61 +
.../x/net/internal/socket/zsys_freebsd_386.go | 59 +
.../net/internal/socket/zsys_freebsd_amd64.go | 61 +
.../x/net/internal/socket/zsys_freebsd_arm.go | 59 +
.../x/net/internal/socket/zsys_linux_386.go | 63 +
.../x/net/internal/socket/zsys_linux_amd64.go | 66 +
.../x/net/internal/socket/zsys_linux_arm.go | 63 +
.../x/net/internal/socket/zsys_linux_arm64.go | 66 +
.../x/net/internal/socket/zsys_linux_mips.go | 63 +
.../net/internal/socket/zsys_linux_mips64.go | 66 +
.../internal/socket/zsys_linux_mips64le.go | 66 +
.../net/internal/socket/zsys_linux_mipsle.go | 63 +
.../x/net/internal/socket/zsys_linux_ppc64.go | 66 +
.../net/internal/socket/zsys_linux_ppc64le.go | 66 +
.../x/net/internal/socket/zsys_linux_s390x.go | 66 +
.../x/net/internal/socket/zsys_netbsd_386.go | 65 +
.../net/internal/socket/zsys_netbsd_amd64.go | 68 +
.../x/net/internal/socket/zsys_netbsd_arm.go | 65 +
.../x/net/internal/socket/zsys_openbsd_386.go | 59 +
.../net/internal/socket/zsys_openbsd_amd64.go | 61 +
.../x/net/internal/socket/zsys_openbsd_arm.go | 59 +
.../net/internal/socket/zsys_solaris_amd64.go | 60 +
.../golang.org/x/net/internal/socks/client.go | 168 +
.../x/net/internal/socks/dial_test.go | 158 +
.../golang.org/x/net/internal/socks/socks.go | 265 +
.../x/net/internal/sockstest/server.go | 241 +
.../x/net/internal/sockstest/server_test.go | 103 +
.../x/net/internal/timeseries/timeseries.go | 525 +
.../internal/timeseries/timeseries_test.go | 170 +
vendor/golang.org/x/net/ipv4/batch.go | 191 +
vendor/golang.org/x/net/ipv4/bpf_test.go | 93 +
vendor/golang.org/x/net/ipv4/control.go | 144 +
vendor/golang.org/x/net/ipv4/control_bsd.go | 40 +
.../golang.org/x/net/ipv4/control_pktinfo.go | 39 +
vendor/golang.org/x/net/ipv4/control_stub.go | 13 +
vendor/golang.org/x/net/ipv4/control_test.go | 21 +
vendor/golang.org/x/net/ipv4/control_unix.go | 73 +
.../golang.org/x/net/ipv4/control_windows.go | 16 +
vendor/golang.org/x/net/ipv4/defs_darwin.go | 77 +
.../golang.org/x/net/ipv4/defs_dragonfly.go | 38 +
vendor/golang.org/x/net/ipv4/defs_freebsd.go | 75 +
vendor/golang.org/x/net/ipv4/defs_linux.go | 122 +
vendor/golang.org/x/net/ipv4/defs_netbsd.go | 37 +
vendor/golang.org/x/net/ipv4/defs_openbsd.go | 37 +
vendor/golang.org/x/net/ipv4/defs_solaris.go | 84 +
vendor/golang.org/x/net/ipv4/dgramopt.go | 265 +
vendor/golang.org/x/net/ipv4/doc.go | 244 +
vendor/golang.org/x/net/ipv4/endpoint.go | 187 +
vendor/golang.org/x/net/ipv4/example_test.go | 224 +
vendor/golang.org/x/net/ipv4/gen.go | 199 +
vendor/golang.org/x/net/ipv4/genericopt.go | 57 +
vendor/golang.org/x/net/ipv4/header.go | 159 +
vendor/golang.org/x/net/ipv4/header_test.go | 228 +
vendor/golang.org/x/net/ipv4/helper.go | 63 +
vendor/golang.org/x/net/ipv4/iana.go | 38 +
vendor/golang.org/x/net/ipv4/icmp.go | 57 +
vendor/golang.org/x/net/ipv4/icmp_linux.go | 25 +
vendor/golang.org/x/net/ipv4/icmp_stub.go | 25 +
vendor/golang.org/x/net/ipv4/icmp_test.go | 95 +
.../golang.org/x/net/ipv4/multicast_test.go | 334 +
.../x/net/ipv4/multicastlistener_test.go | 265 +
.../x/net/ipv4/multicastsockopt_test.go | 195 +
vendor/golang.org/x/net/ipv4/packet.go | 69 +
vendor/golang.org/x/net/ipv4/packet_go1_8.go | 56 +
vendor/golang.org/x/net/ipv4/packet_go1_9.go | 67 +
vendor/golang.org/x/net/ipv4/payload.go | 23 +
vendor/golang.org/x/net/ipv4/payload_cmsg.go | 36 +
.../x/net/ipv4/payload_cmsg_go1_8.go | 59 +
.../x/net/ipv4/payload_cmsg_go1_9.go | 67 +
.../golang.org/x/net/ipv4/payload_nocmsg.go | 42 +
.../x/net/ipv4/readwrite_go1_8_test.go | 248 +
.../x/net/ipv4/readwrite_go1_9_test.go | 388 +
.../golang.org/x/net/ipv4/readwrite_test.go | 140 +
vendor/golang.org/x/net/ipv4/sockopt.go | 44 +
vendor/golang.org/x/net/ipv4/sockopt_posix.go | 71 +
vendor/golang.org/x/net/ipv4/sockopt_stub.go | 42 +
vendor/golang.org/x/net/ipv4/sys_asmreq.go | 119 +
.../golang.org/x/net/ipv4/sys_asmreq_stub.go | 25 +
vendor/golang.org/x/net/ipv4/sys_asmreqn.go | 42 +
.../golang.org/x/net/ipv4/sys_asmreqn_stub.go | 21 +
vendor/golang.org/x/net/ipv4/sys_bpf.go | 23 +
vendor/golang.org/x/net/ipv4/sys_bpf_stub.go | 16 +
vendor/golang.org/x/net/ipv4/sys_bsd.go | 37 +
vendor/golang.org/x/net/ipv4/sys_darwin.go | 93 +
vendor/golang.org/x/net/ipv4/sys_dragonfly.go | 35 +
vendor/golang.org/x/net/ipv4/sys_freebsd.go | 76 +
vendor/golang.org/x/net/ipv4/sys_linux.go | 59 +
vendor/golang.org/x/net/ipv4/sys_solaris.go | 57 +
vendor/golang.org/x/net/ipv4/sys_ssmreq.go | 54 +
.../golang.org/x/net/ipv4/sys_ssmreq_stub.go | 21 +
vendor/golang.org/x/net/ipv4/sys_stub.go | 13 +
vendor/golang.org/x/net/ipv4/sys_windows.go | 67 +
vendor/golang.org/x/net/ipv4/unicast_test.go | 247 +
.../x/net/ipv4/unicastsockopt_test.go | 148 +
vendor/golang.org/x/net/ipv4/zsys_darwin.go | 99 +
.../golang.org/x/net/ipv4/zsys_dragonfly.go | 31 +
.../golang.org/x/net/ipv4/zsys_freebsd_386.go | 93 +
.../x/net/ipv4/zsys_freebsd_amd64.go | 95 +
.../golang.org/x/net/ipv4/zsys_freebsd_arm.go | 95 +
.../golang.org/x/net/ipv4/zsys_linux_386.go | 148 +
.../golang.org/x/net/ipv4/zsys_linux_amd64.go | 150 +
.../golang.org/x/net/ipv4/zsys_linux_arm.go | 148 +
.../golang.org/x/net/ipv4/zsys_linux_arm64.go | 150 +
.../golang.org/x/net/ipv4/zsys_linux_mips.go | 148 +
.../x/net/ipv4/zsys_linux_mips64.go | 150 +
.../x/net/ipv4/zsys_linux_mips64le.go | 150 +
.../x/net/ipv4/zsys_linux_mipsle.go | 148 +
.../golang.org/x/net/ipv4/zsys_linux_ppc.go | 148 +
.../golang.org/x/net/ipv4/zsys_linux_ppc64.go | 150 +
.../x/net/ipv4/zsys_linux_ppc64le.go | 150 +
.../golang.org/x/net/ipv4/zsys_linux_s390x.go | 150 +
vendor/golang.org/x/net/ipv4/zsys_netbsd.go | 30 +
vendor/golang.org/x/net/ipv4/zsys_openbsd.go | 30 +
vendor/golang.org/x/net/ipv4/zsys_solaris.go | 100 +
vendor/golang.org/x/net/ipv6/batch.go | 119 +
vendor/golang.org/x/net/ipv6/bpf_test.go | 96 +
vendor/golang.org/x/net/ipv6/control.go | 187 +
.../x/net/ipv6/control_rfc2292_unix.go | 48 +
.../x/net/ipv6/control_rfc3542_unix.go | 94 +
vendor/golang.org/x/net/ipv6/control_stub.go | 13 +
vendor/golang.org/x/net/ipv6/control_test.go | 21 +
vendor/golang.org/x/net/ipv6/control_unix.go | 55 +
.../golang.org/x/net/ipv6/control_windows.go | 16 +
vendor/golang.org/x/net/ipv6/defs_darwin.go | 112 +
.../golang.org/x/net/ipv6/defs_dragonfly.go | 84 +
vendor/golang.org/x/net/ipv6/defs_freebsd.go | 105 +
vendor/golang.org/x/net/ipv6/defs_linux.go | 147 +
vendor/golang.org/x/net/ipv6/defs_netbsd.go | 80 +
vendor/golang.org/x/net/ipv6/defs_openbsd.go | 89 +
vendor/golang.org/x/net/ipv6/defs_solaris.go | 114 +
vendor/golang.org/x/net/ipv6/dgramopt.go | 302 +
vendor/golang.org/x/net/ipv6/doc.go | 243 +
vendor/golang.org/x/net/ipv6/endpoint.go | 128 +
vendor/golang.org/x/net/ipv6/example_test.go | 216 +
vendor/golang.org/x/net/ipv6/gen.go | 199 +
vendor/golang.org/x/net/ipv6/genericopt.go | 58 +
vendor/golang.org/x/net/ipv6/header.go | 55 +
vendor/golang.org/x/net/ipv6/header_test.go | 55 +
vendor/golang.org/x/net/ipv6/helper.go | 57 +
vendor/golang.org/x/net/ipv6/iana.go | 86 +
vendor/golang.org/x/net/ipv6/icmp.go | 60 +
vendor/golang.org/x/net/ipv6/icmp_bsd.go | 29 +
vendor/golang.org/x/net/ipv6/icmp_linux.go | 27 +
vendor/golang.org/x/net/ipv6/icmp_solaris.go | 27 +
vendor/golang.org/x/net/ipv6/icmp_stub.go | 23 +
vendor/golang.org/x/net/ipv6/icmp_test.go | 96 +
vendor/golang.org/x/net/ipv6/icmp_windows.go | 22 +
.../x/net/ipv6/mocktransponder_test.go | 32 +
.../golang.org/x/net/ipv6/multicast_test.go | 264 +
.../x/net/ipv6/multicastlistener_test.go | 261 +
.../x/net/ipv6/multicastsockopt_test.go | 157 +
vendor/golang.org/x/net/ipv6/payload.go | 23 +
vendor/golang.org/x/net/ipv6/payload_cmsg.go | 35 +
.../x/net/ipv6/payload_cmsg_go1_8.go | 55 +
.../x/net/ipv6/payload_cmsg_go1_9.go | 57 +
.../golang.org/x/net/ipv6/payload_nocmsg.go | 41 +
.../x/net/ipv6/readwrite_go1_8_test.go | 242 +
.../x/net/ipv6/readwrite_go1_9_test.go | 373 +
.../golang.org/x/net/ipv6/readwrite_test.go | 148 +
vendor/golang.org/x/net/ipv6/sockopt.go | 43 +
vendor/golang.org/x/net/ipv6/sockopt_posix.go | 87 +
vendor/golang.org/x/net/ipv6/sockopt_stub.go | 46 +
vendor/golang.org/x/net/ipv6/sockopt_test.go | 133 +
vendor/golang.org/x/net/ipv6/sys_asmreq.go | 24 +
.../golang.org/x/net/ipv6/sys_asmreq_stub.go | 17 +
vendor/golang.org/x/net/ipv6/sys_bpf.go | 23 +
vendor/golang.org/x/net/ipv6/sys_bpf_stub.go | 16 +
vendor/golang.org/x/net/ipv6/sys_bsd.go | 57 +
vendor/golang.org/x/net/ipv6/sys_darwin.go | 106 +
vendor/golang.org/x/net/ipv6/sys_freebsd.go | 92 +
vendor/golang.org/x/net/ipv6/sys_linux.go | 74 +
vendor/golang.org/x/net/ipv6/sys_solaris.go | 74 +
vendor/golang.org/x/net/ipv6/sys_ssmreq.go | 54 +
.../golang.org/x/net/ipv6/sys_ssmreq_stub.go | 21 +
vendor/golang.org/x/net/ipv6/sys_stub.go | 13 +
vendor/golang.org/x/net/ipv6/sys_windows.go | 75 +
vendor/golang.org/x/net/ipv6/unicast_test.go | 184 +
.../x/net/ipv6/unicastsockopt_test.go | 120 +
vendor/golang.org/x/net/ipv6/zsys_darwin.go | 131 +
.../golang.org/x/net/ipv6/zsys_dragonfly.go | 88 +
.../golang.org/x/net/ipv6/zsys_freebsd_386.go | 122 +
.../x/net/ipv6/zsys_freebsd_amd64.go | 124 +
.../golang.org/x/net/ipv6/zsys_freebsd_arm.go | 124 +
.../golang.org/x/net/ipv6/zsys_linux_386.go | 170 +
.../golang.org/x/net/ipv6/zsys_linux_amd64.go | 172 +
.../golang.org/x/net/ipv6/zsys_linux_arm.go | 170 +
.../golang.org/x/net/ipv6/zsys_linux_arm64.go | 172 +
.../golang.org/x/net/ipv6/zsys_linux_mips.go | 170 +
.../x/net/ipv6/zsys_linux_mips64.go | 172 +
.../x/net/ipv6/zsys_linux_mips64le.go | 172 +
.../x/net/ipv6/zsys_linux_mipsle.go | 170 +
.../golang.org/x/net/ipv6/zsys_linux_ppc.go | 170 +
.../golang.org/x/net/ipv6/zsys_linux_ppc64.go | 172 +
.../x/net/ipv6/zsys_linux_ppc64le.go | 172 +
.../golang.org/x/net/ipv6/zsys_linux_s390x.go | 172 +
vendor/golang.org/x/net/ipv6/zsys_netbsd.go | 84 +
vendor/golang.org/x/net/ipv6/zsys_openbsd.go | 93 +
vendor/golang.org/x/net/ipv6/zsys_solaris.go | 131 +
.../golang.org/x/net/lex/httplex/httplex.go | 351 +
.../x/net/lex/httplex/httplex_test.go | 119 +
vendor/golang.org/x/net/lif/address.go | 105 +
vendor/golang.org/x/net/lif/address_test.go | 123 +
vendor/golang.org/x/net/lif/binary.go | 115 +
vendor/golang.org/x/net/lif/defs_solaris.go | 90 +
vendor/golang.org/x/net/lif/lif.go | 43 +
vendor/golang.org/x/net/lif/link.go | 126 +
vendor/golang.org/x/net/lif/link_test.go | 63 +
vendor/golang.org/x/net/lif/sys.go | 21 +
.../golang.org/x/net/lif/sys_solaris_amd64.s | 8 +
vendor/golang.org/x/net/lif/syscall.go | 28 +
.../x/net/lif/zsys_solaris_amd64.go | 103 +
vendor/golang.org/x/net/nettest/conntest.go | 456 +
.../golang.org/x/net/nettest/conntest_go16.go | 24 +
.../golang.org/x/net/nettest/conntest_go17.go | 24 +
.../golang.org/x/net/nettest/conntest_test.go | 76 +
vendor/golang.org/x/net/netutil/listen.go | 74 +
.../golang.org/x/net/netutil/listen_test.go | 147 +
vendor/golang.org/x/net/proxy/direct.go | 18 +
vendor/golang.org/x/net/proxy/per_host.go | 140 +
.../golang.org/x/net/proxy/per_host_test.go | 55 +
vendor/golang.org/x/net/proxy/proxy.go | 134 +
vendor/golang.org/x/net/proxy/proxy_test.go | 123 +
vendor/golang.org/x/net/proxy/socks5.go | 36 +
vendor/golang.org/x/net/publicsuffix/gen.go | 713 +
vendor/golang.org/x/net/publicsuffix/list.go | 135 +
.../x/net/publicsuffix/list_test.go | 416 +
vendor/golang.org/x/net/publicsuffix/table.go | 9534 +++++++++
.../x/net/publicsuffix/table_test.go | 16959 ++++++++++++++++
vendor/golang.org/x/net/route/address.go | 425 +
.../x/net/route/address_darwin_test.go | 63 +
vendor/golang.org/x/net/route/address_test.go | 103 +
vendor/golang.org/x/net/route/binary.go | 90 +
vendor/golang.org/x/net/route/defs_darwin.go | 114 +
.../golang.org/x/net/route/defs_dragonfly.go | 113 +
vendor/golang.org/x/net/route/defs_freebsd.go | 337 +
vendor/golang.org/x/net/route/defs_netbsd.go | 112 +
vendor/golang.org/x/net/route/defs_openbsd.go | 116 +
vendor/golang.org/x/net/route/interface.go | 64 +
.../x/net/route/interface_announce.go | 32 +
.../x/net/route/interface_classic.go | 66 +
.../x/net/route/interface_freebsd.go | 78 +
.../x/net/route/interface_multicast.go | 30 +
.../x/net/route/interface_openbsd.go | 90 +
vendor/golang.org/x/net/route/message.go | 72 +
.../x/net/route/message_darwin_test.go | 34 +
.../x/net/route/message_freebsd_test.go | 92 +
vendor/golang.org/x/net/route/message_test.go | 239 +
vendor/golang.org/x/net/route/route.go | 123 +
.../golang.org/x/net/route/route_classic.go | 75 +
.../golang.org/x/net/route/route_openbsd.go | 65 +
vendor/golang.org/x/net/route/route_test.go | 390 +
vendor/golang.org/x/net/route/sys.go | 39 +
vendor/golang.org/x/net/route/sys_darwin.go | 87 +
.../golang.org/x/net/route/sys_dragonfly.go | 76 +
vendor/golang.org/x/net/route/sys_freebsd.go | 155 +
vendor/golang.org/x/net/route/sys_netbsd.go | 71 +
vendor/golang.org/x/net/route/sys_openbsd.go | 80 +
vendor/golang.org/x/net/route/syscall.go | 28 +
vendor/golang.org/x/net/route/zsys_darwin.go | 99 +
.../golang.org/x/net/route/zsys_dragonfly.go | 98 +
.../x/net/route/zsys_freebsd_386.go | 126 +
.../x/net/route/zsys_freebsd_amd64.go | 123 +
.../x/net/route/zsys_freebsd_arm.go | 123 +
vendor/golang.org/x/net/route/zsys_netbsd.go | 97 +
vendor/golang.org/x/net/route/zsys_openbsd.go | 101 +
vendor/golang.org/x/net/trace/events.go | 532 +
vendor/golang.org/x/net/trace/histogram.go | 365 +
.../golang.org/x/net/trace/histogram_test.go | 325 +
vendor/golang.org/x/net/trace/trace.go | 1103 +
vendor/golang.org/x/net/trace/trace_go16.go | 21 +
vendor/golang.org/x/net/trace/trace_go17.go | 21 +
vendor/golang.org/x/net/trace/trace_test.go | 178 +
vendor/golang.org/x/net/webdav/file.go | 796 +
vendor/golang.org/x/net/webdav/file_go1.6.go | 17 +
vendor/golang.org/x/net/webdav/file_go1.7.go | 16 +
vendor/golang.org/x/net/webdav/file_test.go | 1184 ++
vendor/golang.org/x/net/webdav/if.go | 173 +
vendor/golang.org/x/net/webdav/if_test.go | 322 +
.../x/net/webdav/internal/xml/README | 11 +
.../x/net/webdav/internal/xml/atom_test.go | 56 +
.../x/net/webdav/internal/xml/example_test.go | 151 +
.../x/net/webdav/internal/xml/marshal.go | 1223 ++
.../x/net/webdav/internal/xml/marshal_test.go | 1939 ++
.../x/net/webdav/internal/xml/read.go | 692 +
.../x/net/webdav/internal/xml/read_test.go | 744 +
.../x/net/webdav/internal/xml/typeinfo.go | 371 +
.../x/net/webdav/internal/xml/xml.go | 1998 ++
.../x/net/webdav/internal/xml/xml_test.go | 752 +
.../x/net/webdav/litmus_test_server.go | 94 +
vendor/golang.org/x/net/webdav/lock.go | 445 +
vendor/golang.org/x/net/webdav/lock_test.go | 731 +
vendor/golang.org/x/net/webdav/prop.go | 418 +
vendor/golang.org/x/net/webdav/prop_test.go | 613 +
vendor/golang.org/x/net/webdav/webdav.go | 702 +
vendor/golang.org/x/net/webdav/webdav_test.go | 344 +
vendor/golang.org/x/net/webdav/xml.go | 519 +
vendor/golang.org/x/net/webdav/xml_test.go | 906 +
vendor/golang.org/x/net/websocket/client.go | 106 +
vendor/golang.org/x/net/websocket/dial.go | 24 +
.../golang.org/x/net/websocket/dial_test.go | 43 +
.../x/net/websocket/exampledial_test.go | 31 +
.../x/net/websocket/examplehandler_test.go | 26 +
vendor/golang.org/x/net/websocket/hybi.go | 583 +
.../golang.org/x/net/websocket/hybi_test.go | 608 +
vendor/golang.org/x/net/websocket/server.go | 113 +
.../golang.org/x/net/websocket/websocket.go | 448 +
.../x/net/websocket/websocket_test.go | 665 +
vendor/golang.org/x/net/xsrftoken/xsrf.go | 94 +
.../golang.org/x/net/xsrftoken/xsrf_test.go | 83 +
vendor/golang.org/x/sys/.gitattributes | 10 +
vendor/golang.org/x/sys/.gitignore | 2 +
vendor/golang.org/x/sys/AUTHORS | 3 +
vendor/golang.org/x/sys/CONTRIBUTING.md | 26 +
vendor/golang.org/x/sys/CONTRIBUTORS | 3 +
vendor/golang.org/x/sys/LICENSE | 27 +
vendor/golang.org/x/sys/PATENTS | 22 +
vendor/golang.org/x/sys/README.md | 18 +
vendor/golang.org/x/sys/codereview.cfg | 1 +
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 | 138 +
vendor/golang.org/x/sys/plan9/mkerrors.sh | 246 +
vendor/golang.org/x/sys/plan9/mksyscall.pl | 319 +
.../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 | 77 +
.../golang.org/x/sys/plan9/syscall_plan9.go | 349 +
vendor/golang.org/x/sys/plan9/syscall_test.go | 33 +
.../x/sys/plan9/zsyscall_plan9_386.go | 292 +
.../x/sys/plan9/zsyscall_plan9_amd64.go | 292 +
.../x/sys/plan9/zsyscall_plan9_arm.go | 284 +
.../golang.org/x/sys/plan9/zsysnum_plan9.go | 49 +
vendor/golang.org/x/sys/unix/.gitignore | 2 +
vendor/golang.org/x/sys/unix/README.md | 173 +
.../golang.org/x/sys/unix/affinity_linux.go | 124 +
vendor/golang.org/x/sys/unix/asm_darwin_386.s | 29 +
.../golang.org/x/sys/unix/asm_darwin_amd64.s | 29 +
vendor/golang.org/x/sys/unix/asm_darwin_arm.s | 30 +
.../golang.org/x/sys/unix/asm_darwin_arm64.s | 30 +
.../x/sys/unix/asm_dragonfly_amd64.s | 29 +
.../golang.org/x/sys/unix/asm_freebsd_386.s | 29 +
.../golang.org/x/sys/unix/asm_freebsd_amd64.s | 29 +
.../golang.org/x/sys/unix/asm_freebsd_arm.s | 29 +
vendor/golang.org/x/sys/unix/asm_linux_386.s | 65 +
.../golang.org/x/sys/unix/asm_linux_amd64.s | 57 +
vendor/golang.org/x/sys/unix/asm_linux_arm.s | 56 +
.../golang.org/x/sys/unix/asm_linux_arm64.s | 52 +
.../golang.org/x/sys/unix/asm_linux_mips64x.s | 56 +
.../golang.org/x/sys/unix/asm_linux_mipsx.s | 54 +
.../golang.org/x/sys/unix/asm_linux_ppc64x.s | 56 +
.../golang.org/x/sys/unix/asm_linux_s390x.s | 56 +
vendor/golang.org/x/sys/unix/asm_netbsd_386.s | 29 +
.../golang.org/x/sys/unix/asm_netbsd_amd64.s | 29 +
vendor/golang.org/x/sys/unix/asm_netbsd_arm.s | 29 +
.../golang.org/x/sys/unix/asm_openbsd_386.s | 29 +
.../golang.org/x/sys/unix/asm_openbsd_amd64.s | 29 +
.../golang.org/x/sys/unix/asm_openbsd_arm.s | 29 +
.../golang.org/x/sys/unix/asm_solaris_amd64.s | 17 +
.../golang.org/x/sys/unix/bluetooth_linux.go | 35 +
vendor/golang.org/x/sys/unix/cap_freebsd.go | 195 +
vendor/golang.org/x/sys/unix/constants.go | 13 +
vendor/golang.org/x/sys/unix/creds_test.go | 149 +
vendor/golang.org/x/sys/unix/dev_darwin.go | 24 +
.../golang.org/x/sys/unix/dev_darwin_test.go | 51 +
vendor/golang.org/x/sys/unix/dev_dragonfly.go | 30 +
.../x/sys/unix/dev_dragonfly_test.go | 50 +
vendor/golang.org/x/sys/unix/dev_freebsd.go | 30 +
vendor/golang.org/x/sys/unix/dev_linux.go | 42 +
.../golang.org/x/sys/unix/dev_linux_test.go | 53 +
vendor/golang.org/x/sys/unix/dev_netbsd.go | 29 +
.../golang.org/x/sys/unix/dev_netbsd_test.go | 50 +
vendor/golang.org/x/sys/unix/dev_openbsd.go | 29 +
.../golang.org/x/sys/unix/dev_openbsd_test.go | 54 +
.../golang.org/x/sys/unix/dev_solaris_test.go | 51 +
vendor/golang.org/x/sys/unix/dirent.go | 17 +
vendor/golang.org/x/sys/unix/endian_big.go | 9 +
vendor/golang.org/x/sys/unix/endian_little.go | 9 +
vendor/golang.org/x/sys/unix/env_unix.go | 31 +
.../x/sys/unix/errors_freebsd_386.go | 227 +
.../x/sys/unix/errors_freebsd_amd64.go | 227 +
.../x/sys/unix/errors_freebsd_arm.go | 226 +
vendor/golang.org/x/sys/unix/example_test.go | 19 +
vendor/golang.org/x/sys/unix/export_test.go | 9 +
vendor/golang.org/x/sys/unix/fcntl.go | 28 +
.../x/sys/unix/fcntl_linux_32bit.go | 13 +
vendor/golang.org/x/sys/unix/gccgo.go | 61 +
vendor/golang.org/x/sys/unix/gccgo_c.c | 47 +
.../x/sys/unix/gccgo_linux_amd64.go | 20 +
vendor/golang.org/x/sys/unix/linux/Dockerfile | 52 +
vendor/golang.org/x/sys/unix/linux/mkall.go | 750 +
.../golang.org/x/sys/unix/linux/mksysnum.pl | 85 +
vendor/golang.org/x/sys/unix/linux/types.go | 974 +
vendor/golang.org/x/sys/unix/mkall.sh | 188 +
vendor/golang.org/x/sys/unix/mkerrors.sh | 583 +
vendor/golang.org/x/sys/unix/mkpost.go | 98 +
vendor/golang.org/x/sys/unix/mksyscall.pl | 341 +
.../x/sys/unix/mksyscall_solaris.pl | 289 +
.../golang.org/x/sys/unix/mksysctl_openbsd.pl | 264 +
.../golang.org/x/sys/unix/mksysnum_darwin.pl | 39 +
.../x/sys/unix/mksysnum_dragonfly.pl | 50 +
.../golang.org/x/sys/unix/mksysnum_freebsd.pl | 50 +
.../golang.org/x/sys/unix/mksysnum_netbsd.pl | 58 +
.../golang.org/x/sys/unix/mksysnum_openbsd.pl | 50 +
.../golang.org/x/sys/unix/mmap_unix_test.go | 35 +
.../golang.org/x/sys/unix/openbsd_pledge.go | 38 +
vendor/golang.org/x/sys/unix/openbsd_test.go | 113 +
vendor/golang.org/x/sys/unix/pagesize_unix.go | 15 +
vendor/golang.org/x/sys/unix/race.go | 30 +
vendor/golang.org/x/sys/unix/race0.go | 25 +
.../golang.org/x/sys/unix/sockcmsg_linux.go | 36 +
vendor/golang.org/x/sys/unix/sockcmsg_unix.go | 104 +
vendor/golang.org/x/sys/unix/str.go | 26 +
vendor/golang.org/x/sys/unix/syscall.go | 54 +
vendor/golang.org/x/sys/unix/syscall_bsd.go | 624 +
.../golang.org/x/sys/unix/syscall_bsd_test.go | 93 +
.../golang.org/x/sys/unix/syscall_darwin.go | 602 +
.../x/sys/unix/syscall_darwin_386.go | 68 +
.../x/sys/unix/syscall_darwin_amd64.go | 68 +
.../x/sys/unix/syscall_darwin_arm.go | 66 +
.../x/sys/unix/syscall_darwin_arm64.go | 68 +
.../x/sys/unix/syscall_dragonfly.go | 523 +
.../x/sys/unix/syscall_dragonfly_amd64.go | 52 +
.../golang.org/x/sys/unix/syscall_freebsd.go | 756 +
.../x/sys/unix/syscall_freebsd_386.go | 52 +
.../x/sys/unix/syscall_freebsd_amd64.go | 52 +
.../x/sys/unix/syscall_freebsd_arm.go | 52 +
.../x/sys/unix/syscall_freebsd_test.go | 297 +
vendor/golang.org/x/sys/unix/syscall_linux.go | 1474 ++
.../x/sys/unix/syscall_linux_386.go | 391 +
.../x/sys/unix/syscall_linux_amd64.go | 144 +
.../x/sys/unix/syscall_linux_amd64_gc.go | 13 +
.../x/sys/unix/syscall_linux_arm.go | 255 +
.../x/sys/unix/syscall_linux_arm64.go | 190 +
.../golang.org/x/sys/unix/syscall_linux_gc.go | 14 +
.../x/sys/unix/syscall_linux_gccgo.go | 21 +
.../x/sys/unix/syscall_linux_mips64x.go | 210 +
.../x/sys/unix/syscall_linux_mipsx.go | 232 +
.../x/sys/unix/syscall_linux_ppc64x.go | 128 +
.../x/sys/unix/syscall_linux_s390x.go | 320 +
.../x/sys/unix/syscall_linux_sparc64.go | 144 +
.../x/sys/unix/syscall_linux_test.go | 373 +
.../golang.org/x/sys/unix/syscall_netbsd.go | 567 +
.../x/sys/unix/syscall_netbsd_386.go | 33 +
.../x/sys/unix/syscall_netbsd_amd64.go | 33 +
.../x/sys/unix/syscall_netbsd_arm.go | 33 +
.../golang.org/x/sys/unix/syscall_openbsd.go | 367 +
.../x/sys/unix/syscall_openbsd_386.go | 33 +
.../x/sys/unix/syscall_openbsd_amd64.go | 33 +
.../x/sys/unix/syscall_openbsd_arm.go | 33 +
.../golang.org/x/sys/unix/syscall_solaris.go | 725 +
.../x/sys/unix/syscall_solaris_amd64.go | 23 +
.../x/sys/unix/syscall_solaris_test.go | 55 +
vendor/golang.org/x/sys/unix/syscall_test.go | 60 +
vendor/golang.org/x/sys/unix/syscall_unix.go | 371 +
.../golang.org/x/sys/unix/syscall_unix_gc.go | 15 +
.../x/sys/unix/syscall_unix_test.go | 575 +
vendor/golang.org/x/sys/unix/timestruct.go | 82 +
.../golang.org/x/sys/unix/timestruct_test.go | 54 +
vendor/golang.org/x/sys/unix/types_darwin.go | 277 +
.../golang.org/x/sys/unix/types_dragonfly.go | 280 +
vendor/golang.org/x/sys/unix/types_freebsd.go | 402 +
vendor/golang.org/x/sys/unix/types_netbsd.go | 281 +
vendor/golang.org/x/sys/unix/types_openbsd.go | 282 +
vendor/golang.org/x/sys/unix/types_solaris.go | 283 +
.../x/sys/unix/zerrors_darwin_386.go | 1769 ++
.../x/sys/unix/zerrors_darwin_amd64.go | 1769 ++
.../x/sys/unix/zerrors_darwin_arm.go | 1769 ++
.../x/sys/unix/zerrors_darwin_arm64.go | 1769 ++
.../x/sys/unix/zerrors_dragonfly_amd64.go | 1578 ++
.../x/sys/unix/zerrors_freebsd_386.go | 1756 ++
.../x/sys/unix/zerrors_freebsd_amd64.go | 1757 ++
.../x/sys/unix/zerrors_freebsd_arm.go | 1765 ++
.../x/sys/unix/zerrors_linux_386.go | 2438 +++
.../x/sys/unix/zerrors_linux_amd64.go | 2439 +++
.../x/sys/unix/zerrors_linux_arm.go | 2446 +++
.../x/sys/unix/zerrors_linux_arm64.go | 2429 +++
.../x/sys/unix/zerrors_linux_mips.go | 2448 +++
.../x/sys/unix/zerrors_linux_mips64.go | 2448 +++
.../x/sys/unix/zerrors_linux_mips64le.go | 2448 +++
.../x/sys/unix/zerrors_linux_mipsle.go | 2448 +++
.../x/sys/unix/zerrors_linux_ppc64.go | 2501 +++
.../x/sys/unix/zerrors_linux_ppc64le.go | 2501 +++
.../x/sys/unix/zerrors_linux_s390x.go | 2500 +++
.../x/sys/unix/zerrors_linux_sparc64.go | 2142 ++
.../x/sys/unix/zerrors_netbsd_386.go | 1720 ++
.../x/sys/unix/zerrors_netbsd_amd64.go | 1710 ++
.../x/sys/unix/zerrors_netbsd_arm.go | 1699 ++
.../x/sys/unix/zerrors_openbsd_386.go | 1592 ++
.../x/sys/unix/zerrors_openbsd_amd64.go | 1591 ++
.../x/sys/unix/zerrors_openbsd_arm.go | 1594 ++
.../x/sys/unix/zerrors_solaris_amd64.go | 1489 ++
.../golang.org/x/sys/unix/zptrace386_linux.go | 80 +
.../golang.org/x/sys/unix/zptracearm_linux.go | 41 +
.../x/sys/unix/zptracemips_linux.go | 50 +
.../x/sys/unix/zptracemipsle_linux.go | 50 +
.../x/sys/unix/zsyscall_darwin_386.go | 1635 ++
.../x/sys/unix/zsyscall_darwin_amd64.go | 1635 ++
.../x/sys/unix/zsyscall_darwin_arm.go | 1635 ++
.../x/sys/unix/zsyscall_darwin_arm64.go | 1635 ++
.../x/sys/unix/zsyscall_dragonfly_amd64.go | 1508 ++
.../x/sys/unix/zsyscall_freebsd_386.go | 1937 ++
.../x/sys/unix/zsyscall_freebsd_amd64.go | 1937 ++
.../x/sys/unix/zsyscall_freebsd_arm.go | 1937 ++
.../x/sys/unix/zsyscall_linux_386.go | 2005 ++
.../x/sys/unix/zsyscall_linux_amd64.go | 2198 ++
.../x/sys/unix/zsyscall_linux_arm.go | 2107 ++
.../x/sys/unix/zsyscall_linux_arm64.go | 2065 ++
.../x/sys/unix/zsyscall_linux_mips.go | 2173 ++
.../x/sys/unix/zsyscall_linux_mips64.go | 2156 ++
.../x/sys/unix/zsyscall_linux_mips64le.go | 2156 ++
.../x/sys/unix/zsyscall_linux_mipsle.go | 2173 ++
.../x/sys/unix/zsyscall_linux_ppc64.go | 2219 ++
.../x/sys/unix/zsyscall_linux_ppc64le.go | 2219 ++
.../x/sys/unix/zsyscall_linux_s390x.go | 1989 ++
.../x/sys/unix/zsyscall_linux_sparc64.go | 1843 ++
.../x/sys/unix/zsyscall_netbsd_386.go | 1424 ++
.../x/sys/unix/zsyscall_netbsd_amd64.go | 1424 ++
.../x/sys/unix/zsyscall_netbsd_arm.go | 1424 ++
.../x/sys/unix/zsyscall_openbsd_386.go | 1493 ++
.../x/sys/unix/zsyscall_openbsd_amd64.go | 1493 ++
.../x/sys/unix/zsyscall_openbsd_arm.go | 1493 ++
.../x/sys/unix/zsyscall_solaris_amd64.go | 1681 ++
.../x/sys/unix/zsysctl_openbsd_386.go | 270 +
.../x/sys/unix/zsysctl_openbsd_amd64.go | 270 +
.../x/sys/unix/zsysctl_openbsd_arm.go | 270 +
.../x/sys/unix/zsysnum_darwin_386.go | 436 +
.../x/sys/unix/zsysnum_darwin_amd64.go | 436 +
.../x/sys/unix/zsysnum_darwin_arm.go | 436 +
.../x/sys/unix/zsysnum_darwin_arm64.go | 436 +
.../x/sys/unix/zsysnum_dragonfly_amd64.go | 315 +
.../x/sys/unix/zsysnum_freebsd_386.go | 353 +
.../x/sys/unix/zsysnum_freebsd_amd64.go | 353 +
.../x/sys/unix/zsysnum_freebsd_arm.go | 353 +
.../x/sys/unix/zsysnum_linux_386.go | 390 +
.../x/sys/unix/zsysnum_linux_amd64.go | 342 +
.../x/sys/unix/zsysnum_linux_arm.go | 362 +
.../x/sys/unix/zsysnum_linux_arm64.go | 286 +
.../x/sys/unix/zsysnum_linux_mips.go | 375 +
.../x/sys/unix/zsysnum_linux_mips64.go | 335 +
.../x/sys/unix/zsysnum_linux_mips64le.go | 335 +
.../x/sys/unix/zsysnum_linux_mipsle.go | 375 +
.../x/sys/unix/zsysnum_linux_ppc64.go | 373 +
.../x/sys/unix/zsysnum_linux_ppc64le.go | 373 +
.../x/sys/unix/zsysnum_linux_s390x.go | 334 +
.../x/sys/unix/zsysnum_linux_sparc64.go | 348 +
.../x/sys/unix/zsysnum_netbsd_386.go | 274 +
.../x/sys/unix/zsysnum_netbsd_amd64.go | 274 +
.../x/sys/unix/zsysnum_netbsd_arm.go | 274 +
.../x/sys/unix/zsysnum_openbsd_386.go | 207 +
.../x/sys/unix/zsysnum_openbsd_amd64.go | 207 +
.../x/sys/unix/zsysnum_openbsd_arm.go | 213 +
.../x/sys/unix/ztypes_darwin_386.go | 489 +
.../x/sys/unix/ztypes_darwin_amd64.go | 499 +
.../x/sys/unix/ztypes_darwin_arm.go | 490 +
.../x/sys/unix/ztypes_darwin_arm64.go | 499 +
.../x/sys/unix/ztypes_dragonfly_amd64.go | 486 +
.../x/sys/unix/ztypes_freebsd_386.go | 553 +
.../x/sys/unix/ztypes_freebsd_amd64.go | 556 +
.../x/sys/unix/ztypes_freebsd_arm.go | 556 +
.../golang.org/x/sys/unix/ztypes_linux_386.go | 1246 ++
.../x/sys/unix/ztypes_linux_amd64.go | 1265 ++
.../golang.org/x/sys/unix/ztypes_linux_arm.go | 1235 ++
.../x/sys/unix/ztypes_linux_arm64.go | 1244 ++
.../x/sys/unix/ztypes_linux_mips.go | 1240 ++
.../x/sys/unix/ztypes_linux_mips64.go | 1246 ++
.../x/sys/unix/ztypes_linux_mips64le.go | 1246 ++
.../x/sys/unix/ztypes_linux_mipsle.go | 1240 ++
.../x/sys/unix/ztypes_linux_ppc64.go | 1254 ++
.../x/sys/unix/ztypes_linux_ppc64le.go | 1254 ++
.../x/sys/unix/ztypes_linux_s390x.go | 1271 ++
.../x/sys/unix/ztypes_linux_sparc64.go | 690 +
.../x/sys/unix/ztypes_netbsd_386.go | 448 +
.../x/sys/unix/ztypes_netbsd_amd64.go | 455 +
.../x/sys/unix/ztypes_netbsd_arm.go | 453 +
.../x/sys/unix/ztypes_openbsd_386.go | 484 +
.../x/sys/unix/ztypes_openbsd_amd64.go | 491 +
.../x/sys/unix/ztypes_openbsd_arm.go | 477 +
.../x/sys/unix/ztypes_solaris_amd64.go | 459 +
.../x/sys/windows/asm_windows_386.s | 13 +
.../x/sys/windows/asm_windows_amd64.s | 13 +
.../golang.org/x/sys/windows/dll_windows.go | 378 +
.../golang.org/x/sys/windows/env_windows.go | 29 +
vendor/golang.org/x/sys/windows/eventlog.go | 20 +
.../golang.org/x/sys/windows/exec_windows.go | 97 +
.../x/sys/windows/memory_windows.go | 26 +
vendor/golang.org/x/sys/windows/mksyscall.go | 7 +
vendor/golang.org/x/sys/windows/race.go | 30 +
vendor/golang.org/x/sys/windows/race0.go | 25 +
.../x/sys/windows/registry/export_test.go | 11 +
.../golang.org/x/sys/windows/registry/key.go | 198 +
.../x/sys/windows/registry/mksyscall.go | 7 +
.../x/sys/windows/registry/registry_test.go | 756 +
.../x/sys/windows/registry/syscall.go | 32 +
.../x/sys/windows/registry/value.go | 384 +
.../sys/windows/registry/zsyscall_windows.go | 120 +
.../x/sys/windows/security_windows.go | 476 +
vendor/golang.org/x/sys/windows/service.go | 164 +
vendor/golang.org/x/sys/windows/str.go | 22 +
.../golang.org/x/sys/windows/svc/debug/log.go | 56 +
.../x/sys/windows/svc/debug/service.go | 45 +
vendor/golang.org/x/sys/windows/svc/event.go | 48 +
.../x/sys/windows/svc/eventlog/install.go | 80 +
.../x/sys/windows/svc/eventlog/log.go | 70 +
.../x/sys/windows/svc/eventlog/log_test.go | 51 +
.../x/sys/windows/svc/example/beep.go | 22 +
.../x/sys/windows/svc/example/install.go | 92 +
.../x/sys/windows/svc/example/main.go | 76 +
.../x/sys/windows/svc/example/manage.go | 62 +
.../x/sys/windows/svc/example/service.go | 82 +
vendor/golang.org/x/sys/windows/svc/go12.c | 24 +
vendor/golang.org/x/sys/windows/svc/go12.go | 11 +
vendor/golang.org/x/sys/windows/svc/go13.go | 31 +
.../x/sys/windows/svc/mgr/config.go | 139 +
.../golang.org/x/sys/windows/svc/mgr/mgr.go | 162 +
.../x/sys/windows/svc/mgr/mgr_test.go | 169 +
.../x/sys/windows/svc/mgr/service.go | 72 +
.../golang.org/x/sys/windows/svc/security.go | 62 +
.../golang.org/x/sys/windows/svc/service.go | 363 +
.../golang.org/x/sys/windows/svc/svc_test.go | 118 +
vendor/golang.org/x/sys/windows/svc/sys_386.s | 68 +
.../golang.org/x/sys/windows/svc/sys_amd64.s | 42 +
vendor/golang.org/x/sys/windows/syscall.go | 74 +
.../golang.org/x/sys/windows/syscall_test.go | 53 +
.../x/sys/windows/syscall_windows.go | 1153 ++
.../x/sys/windows/syscall_windows_test.go | 107 +
.../golang.org/x/sys/windows/types_windows.go | 1333 ++
.../x/sys/windows/types_windows_386.go | 22 +
.../x/sys/windows/types_windows_amd64.go | 22 +
.../x/sys/windows/zsyscall_windows.go | 2687 +++
1216 files changed, 364997 insertions(+), 49 deletions(-)
create mode 100644 pkg/cache/cache.go
create mode 100644 pkg/gocui/attribute.go
create mode 100644 pkg/gocui/edit.go
create mode 100644 pkg/gocui/escape.go
create mode 100644 pkg/gocui/gocui.go
create mode 100644 pkg/gocui/keybinding.go
create mode 100644 pkg/gocui/view.go
create mode 100644 pkg/slice/slice.go
create mode 100644 vendor/github.com/BurntSushi/toml/.gitignore
create mode 100644 vendor/github.com/BurntSushi/toml/.travis.yml
create mode 100644 vendor/github.com/BurntSushi/toml/COMPATIBLE
create mode 100644 vendor/github.com/BurntSushi/toml/COPYING
create mode 100644 vendor/github.com/BurntSushi/toml/Makefile
create mode 100644 vendor/github.com/BurntSushi/toml/README.md
create mode 100644 vendor/github.com/BurntSushi/toml/_examples/example.go
create mode 100644 vendor/github.com/BurntSushi/toml/_examples/example.toml
create mode 100644 vendor/github.com/BurntSushi/toml/_examples/hard.toml
create mode 100644 vendor/github.com/BurntSushi/toml/_examples/implicit.toml
create mode 100644 vendor/github.com/BurntSushi/toml/_examples/invalid-apples.toml
create mode 100644 vendor/github.com/BurntSushi/toml/_examples/invalid.toml
create mode 100644 vendor/github.com/BurntSushi/toml/_examples/readme1.toml
create mode 100644 vendor/github.com/BurntSushi/toml/_examples/readme2.toml
create mode 100644 vendor/github.com/BurntSushi/toml/cmd/toml-test-decoder/COPYING
create mode 100644 vendor/github.com/BurntSushi/toml/cmd/toml-test-decoder/README.md
create mode 100644 vendor/github.com/BurntSushi/toml/cmd/toml-test-decoder/main.go
create mode 100644 vendor/github.com/BurntSushi/toml/cmd/toml-test-encoder/COPYING
create mode 100644 vendor/github.com/BurntSushi/toml/cmd/toml-test-encoder/README.md
create mode 100644 vendor/github.com/BurntSushi/toml/cmd/toml-test-encoder/main.go
create mode 100644 vendor/github.com/BurntSushi/toml/cmd/tomlv/COPYING
create mode 100644 vendor/github.com/BurntSushi/toml/cmd/tomlv/README.md
create mode 100644 vendor/github.com/BurntSushi/toml/cmd/tomlv/main.go
create mode 100644 vendor/github.com/BurntSushi/toml/decode.go
create mode 100644 vendor/github.com/BurntSushi/toml/decode_meta.go
create mode 100644 vendor/github.com/BurntSushi/toml/decode_test.go
create mode 100644 vendor/github.com/BurntSushi/toml/doc.go
create mode 100644 vendor/github.com/BurntSushi/toml/encode.go
create mode 100644 vendor/github.com/BurntSushi/toml/encode_test.go
create mode 100644 vendor/github.com/BurntSushi/toml/encoding_types.go
create mode 100644 vendor/github.com/BurntSushi/toml/encoding_types_1.1.go
create mode 100644 vendor/github.com/BurntSushi/toml/lex.go
create mode 100644 vendor/github.com/BurntSushi/toml/parse.go
create mode 100644 vendor/github.com/BurntSushi/toml/session.vim
create mode 100644 vendor/github.com/BurntSushi/toml/type_check.go
create mode 100644 vendor/github.com/BurntSushi/toml/type_fields.go
create mode 100644 vendor/github.com/anaskhan96/soup/.gitignore
create mode 100644 vendor/github.com/anaskhan96/soup/.travis.yml
create mode 100644 vendor/github.com/anaskhan96/soup/CHANGELOG.md
create mode 100644 vendor/github.com/anaskhan96/soup/README.md
create mode 100644 vendor/github.com/anaskhan96/soup/examples/weather/weather.go
create mode 100644 vendor/github.com/anaskhan96/soup/examples/xkcdextract/xkcdextract.go
create mode 100644 vendor/github.com/anaskhan96/soup/license
create mode 100644 vendor/github.com/anaskhan96/soup/soup.go
create mode 100644 vendor/github.com/anaskhan96/soup/soup_test.go
create mode 100644 vendor/github.com/fatih/color/.travis.yml
create mode 100644 vendor/github.com/fatih/color/Gopkg.lock
create mode 100644 vendor/github.com/fatih/color/Gopkg.toml
create mode 100644 vendor/github.com/fatih/color/LICENSE.md
create mode 100644 vendor/github.com/fatih/color/README.md
create mode 100644 vendor/github.com/fatih/color/color.go
create mode 100644 vendor/github.com/fatih/color/color_test.go
create mode 100644 vendor/github.com/fatih/color/doc.go
create mode 100644 vendor/github.com/mattn/go-colorable/.travis.yml
create mode 100644 vendor/github.com/mattn/go-colorable/LICENSE
create mode 100644 vendor/github.com/mattn/go-colorable/README.md
create mode 100644 vendor/github.com/mattn/go-colorable/_example/escape-seq/main.go
create mode 100644 vendor/github.com/mattn/go-colorable/_example/logrus/main.go
create mode 100644 vendor/github.com/mattn/go-colorable/_example/title/main.go
create mode 100644 vendor/github.com/mattn/go-colorable/colorable_appengine.go
create mode 100644 vendor/github.com/mattn/go-colorable/colorable_others.go
create mode 100644 vendor/github.com/mattn/go-colorable/colorable_test.go
create mode 100644 vendor/github.com/mattn/go-colorable/colorable_windows.go
create mode 100644 vendor/github.com/mattn/go-colorable/noncolorable.go
create mode 100644 vendor/github.com/mattn/go-isatty/.travis.yml
create mode 100644 vendor/github.com/mattn/go-isatty/LICENSE
create mode 100644 vendor/github.com/mattn/go-isatty/README.md
create mode 100644 vendor/github.com/mattn/go-isatty/doc.go
create mode 100644 vendor/github.com/mattn/go-isatty/example_test.go
create mode 100644 vendor/github.com/mattn/go-isatty/isatty_appengine.go
create mode 100644 vendor/github.com/mattn/go-isatty/isatty_bsd.go
create mode 100644 vendor/github.com/mattn/go-isatty/isatty_linux.go
create mode 100644 vendor/github.com/mattn/go-isatty/isatty_linux_ppc64x.go
create mode 100644 vendor/github.com/mattn/go-isatty/isatty_others.go
create mode 100644 vendor/github.com/mattn/go-isatty/isatty_others_test.go
create mode 100644 vendor/github.com/mattn/go-isatty/isatty_solaris.go
create mode 100644 vendor/github.com/mattn/go-isatty/isatty_windows.go
create mode 100644 vendor/github.com/mattn/go-isatty/isatty_windows_test.go
create mode 100644 vendor/github.com/mattn/go-runewidth/.travis.yml
create mode 100644 vendor/github.com/mattn/go-runewidth/LICENSE
create mode 100644 vendor/github.com/mattn/go-runewidth/README.mkd
create mode 100644 vendor/github.com/mattn/go-runewidth/runewidth.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_test.go
create mode 100644 vendor/github.com/mattn/go-runewidth/runewidth_windows.go
create mode 100644 vendor/github.com/miguelmota/go-coinmarketcap/.gitignore
create mode 100644 vendor/github.com/miguelmota/go-coinmarketcap/.travis.yml
create mode 100644 vendor/github.com/miguelmota/go-coinmarketcap/Gopkg.lock
create mode 100644 vendor/github.com/miguelmota/go-coinmarketcap/Gopkg.toml
create mode 100755 vendor/github.com/miguelmota/go-coinmarketcap/LICENSE.md
create mode 100644 vendor/github.com/miguelmota/go-coinmarketcap/Makefile
create mode 100755 vendor/github.com/miguelmota/go-coinmarketcap/README.md
create mode 100644 vendor/github.com/miguelmota/go-coinmarketcap/coinmarketcap.go
create mode 100644 vendor/github.com/miguelmota/go-coinmarketcap/coinmarketcap_test.go
create mode 100644 vendor/github.com/miguelmota/go-coinmarketcap/example/all_coins.go
create mode 100644 vendor/github.com/miguelmota/go-coinmarketcap/example/coin.go
create mode 100644 vendor/github.com/miguelmota/go-coinmarketcap/example/coin_graph.go
create mode 100644 vendor/github.com/miguelmota/go-coinmarketcap/example/global_market.go
create mode 100644 vendor/github.com/miguelmota/go-coinmarketcap/types.go
create mode 100644 vendor/github.com/nsf/termbox-go/AUTHORS
create mode 100644 vendor/github.com/nsf/termbox-go/LICENSE
create mode 100644 vendor/github.com/nsf/termbox-go/README.md
create mode 100644 vendor/github.com/nsf/termbox-go/_demos/editbox.go
create mode 100644 vendor/github.com/nsf/termbox-go/_demos/interrupt.go
create mode 100644 vendor/github.com/nsf/termbox-go/_demos/keyboard.go
create mode 100644 vendor/github.com/nsf/termbox-go/_demos/output.go
create mode 100644 vendor/github.com/nsf/termbox-go/_demos/paint.go
create mode 100644 vendor/github.com/nsf/termbox-go/_demos/random_output.go
create mode 100644 vendor/github.com/nsf/termbox-go/_demos/raw_input.go
create mode 100644 vendor/github.com/nsf/termbox-go/api.go
create mode 100644 vendor/github.com/nsf/termbox-go/api_common.go
create mode 100644 vendor/github.com/nsf/termbox-go/api_windows.go
create mode 100755 vendor/github.com/nsf/termbox-go/collect_terminfo.py
create mode 100644 vendor/github.com/nsf/termbox-go/escwait.go
create mode 100644 vendor/github.com/nsf/termbox-go/escwait_darwin.go
create mode 100644 vendor/github.com/nsf/termbox-go/syscalls.go
create mode 100644 vendor/github.com/nsf/termbox-go/syscalls_darwin.go
create mode 100644 vendor/github.com/nsf/termbox-go/syscalls_darwin_amd64.go
create mode 100644 vendor/github.com/nsf/termbox-go/syscalls_dragonfly.go
create mode 100644 vendor/github.com/nsf/termbox-go/syscalls_freebsd.go
create mode 100644 vendor/github.com/nsf/termbox-go/syscalls_linux.go
create mode 100644 vendor/github.com/nsf/termbox-go/syscalls_netbsd.go
create mode 100644 vendor/github.com/nsf/termbox-go/syscalls_openbsd.go
create mode 100644 vendor/github.com/nsf/termbox-go/syscalls_windows.go
create mode 100644 vendor/github.com/nsf/termbox-go/termbox.go
create mode 100644 vendor/github.com/nsf/termbox-go/termbox_common.go
create mode 100644 vendor/github.com/nsf/termbox-go/termbox_windows.go
create mode 100644 vendor/github.com/nsf/termbox-go/terminfo.go
create mode 100644 vendor/github.com/nsf/termbox-go/terminfo_builtin.go
create mode 100644 vendor/go4.org/.gitignore
create mode 100644 vendor/go4.org/.travis.yml
create mode 100644 vendor/go4.org/AUTHORS
create mode 100644 vendor/go4.org/LICENSE
create mode 100644 vendor/go4.org/README.md
create mode 100644 vendor/go4.org/bytereplacer/bytereplacer.go
create mode 100644 vendor/go4.org/bytereplacer/bytereplacer_test.go
create mode 100644 vendor/go4.org/cloud/cloudlaunch/cloudlaunch.go
create mode 100644 vendor/go4.org/cloud/google/gceutil/gceutil.go
create mode 100644 vendor/go4.org/cloud/google/gcsutil/storage.go
create mode 100644 vendor/go4.org/ctxutil/ctxutil.go
create mode 100644 vendor/go4.org/errorutil/highlight.go
create mode 100644 vendor/go4.org/fault/fault.go
create mode 100644 vendor/go4.org/go4test/cloudlaunch/serve_on_cloud.go
create mode 100644 vendor/go4.org/jsonconfig/eval.go
create mode 100644 vendor/go4.org/jsonconfig/jsonconfig.go
create mode 100644 vendor/go4.org/jsonconfig/jsonconfig_test.go
create mode 100644 vendor/go4.org/jsonconfig/testdata/boolenv.json
create mode 100644 vendor/go4.org/jsonconfig/testdata/include1.json
create mode 100644 vendor/go4.org/jsonconfig/testdata/include1bis.json
create mode 100644 vendor/go4.org/jsonconfig/testdata/include2.json
create mode 100644 vendor/go4.org/jsonconfig/testdata/listexpand.json
create mode 100644 vendor/go4.org/jsonconfig/testdata/loop1.json
create mode 100644 vendor/go4.org/jsonconfig/testdata/loop2.json
create mode 100644 vendor/go4.org/legal/legal.go
create mode 100644 vendor/go4.org/legal/legal_test.go
create mode 100644 vendor/go4.org/lock/.gitignore
create mode 100644 vendor/go4.org/lock/lock.go
create mode 100644 vendor/go4.org/lock/lock_appengine.go
create mode 100644 vendor/go4.org/lock/lock_plan9.go
create mode 100644 vendor/go4.org/lock/lock_sigzero.go
create mode 100644 vendor/go4.org/lock/lock_test.go
create mode 100644 vendor/go4.org/lock/lock_unix.go
create mode 100644 vendor/go4.org/lock/lock_windows.go
create mode 100644 vendor/go4.org/media/heif/bmff/bmff.go
create mode 100644 vendor/go4.org/media/heif/dumpheif/dumpheif.go
create mode 100644 vendor/go4.org/media/heif/heif.go
create mode 100644 vendor/go4.org/media/heif/heif_test.go
create mode 100644 vendor/go4.org/media/heif/testdata/park.heic
create mode 100644 vendor/go4.org/media/heif/testdata/rotate.heic
create mode 100644 vendor/go4.org/net/throttle/throttle.go
create mode 100644 vendor/go4.org/oauthutil/oauth.go
create mode 100644 vendor/go4.org/osutil/exec_plan9.go
create mode 100644 vendor/go4.org/osutil/exec_procfs.go
create mode 100644 vendor/go4.org/osutil/exec_solaris_amd64.go
create mode 100644 vendor/go4.org/osutil/exec_sysctl.go
create mode 100644 vendor/go4.org/osutil/exec_test.go
create mode 100644 vendor/go4.org/osutil/exec_windows.go
create mode 100644 vendor/go4.org/osutil/osutil.go
create mode 100644 vendor/go4.org/readerutil/bufreaderat.go
create mode 100644 vendor/go4.org/readerutil/bufreaderat_test.go
create mode 100644 vendor/go4.org/readerutil/countingreader.go
create mode 100644 vendor/go4.org/readerutil/fakeseeker.go
create mode 100644 vendor/go4.org/readerutil/fakeseeker_test.go
create mode 100644 vendor/go4.org/readerutil/multireaderat.go
create mode 100644 vendor/go4.org/readerutil/multireaderat_test.go
create mode 100644 vendor/go4.org/readerutil/readersize.go
create mode 100644 vendor/go4.org/readerutil/readersize_test.go
create mode 100644 vendor/go4.org/readerutil/readerutil.go
create mode 100644 vendor/go4.org/readerutil/readerutil_test.go
create mode 100644 vendor/go4.org/readerutil/singlereader/opener.go
create mode 100644 vendor/go4.org/readerutil/singlereader/opener_test.go
create mode 100644 vendor/go4.org/reflectutil/asm_b.s
create mode 100644 vendor/go4.org/reflectutil/asm_b_14.s
create mode 100644 vendor/go4.org/reflectutil/asm_jmp.s
create mode 100644 vendor/go4.org/reflectutil/asm_jmp_14.s
create mode 100644 vendor/go4.org/reflectutil/reflectutil.go
create mode 100644 vendor/go4.org/reflectutil/reflectutil_test.go
create mode 100644 vendor/go4.org/reflectutil/swapper.go
create mode 100644 vendor/go4.org/reflectutil/swapper_safe.go
create mode 100644 vendor/go4.org/reflectutil/swapper_test.go
create mode 100644 vendor/go4.org/reflectutil/swapper_unsafe.go
create mode 100644 vendor/go4.org/reflectutil/swapper_unsafe_14.go
create mode 100644 vendor/go4.org/reflectutil/swapper_unsafe_15.go
create mode 100644 vendor/go4.org/sort/example_interface_test.go
create mode 100644 vendor/go4.org/sort/example_keys_test.go
create mode 100644 vendor/go4.org/sort/example_multi_test.go
create mode 100644 vendor/go4.org/sort/example_slice_test.go
create mode 100644 vendor/go4.org/sort/example_test.go
create mode 100644 vendor/go4.org/sort/example_wrapper_test.go
create mode 100644 vendor/go4.org/sort/export_test.go
create mode 100644 vendor/go4.org/sort/genzfunc.go
create mode 100644 vendor/go4.org/sort/search.go
create mode 100644 vendor/go4.org/sort/search_test.go
create mode 100644 vendor/go4.org/sort/sort.go
create mode 100644 vendor/go4.org/sort/sort_test.go
create mode 100644 vendor/go4.org/sort/zfuncversion.go
create mode 100644 vendor/go4.org/strutil/intern.go
create mode 100644 vendor/go4.org/strutil/strconv.go
create mode 100644 vendor/go4.org/strutil/strutil.go
create mode 100644 vendor/go4.org/strutil/strutil_test.go
create mode 100644 vendor/go4.org/syncutil/gate.go
create mode 100644 vendor/go4.org/syncutil/group.go
create mode 100644 vendor/go4.org/syncutil/once.go
create mode 100644 vendor/go4.org/syncutil/once_test.go
create mode 100644 vendor/go4.org/syncutil/sem.go
create mode 100644 vendor/go4.org/syncutil/sem_test.go
create mode 100644 vendor/go4.org/syncutil/singleflight/singleflight.go
create mode 100644 vendor/go4.org/syncutil/singleflight/singleflight_test.go
create mode 100644 vendor/go4.org/syncutil/syncdebug/syncdebug.go
create mode 100644 vendor/go4.org/syncutil/syncdebug/syncdebug_test.go
create mode 100644 vendor/go4.org/syncutil/syncutil.go
create mode 100644 vendor/go4.org/testing/functest/functest.go
create mode 100644 vendor/go4.org/testing/functest/functest_test.go
create mode 100644 vendor/go4.org/types/types.go
create mode 100644 vendor/go4.org/types/types_test.go
create mode 100644 vendor/go4.org/wkfs/gcs/gcs.go
create mode 100644 vendor/go4.org/wkfs/gcs/gcs_test.go
create mode 100644 vendor/go4.org/wkfs/wkfs.go
create mode 100644 vendor/go4.org/writerutil/writerutil.go
create mode 100644 vendor/go4.org/writerutil/writerutil_test.go
create mode 100644 vendor/go4.org/xdgdir/example_test.go
create mode 100644 vendor/go4.org/xdgdir/xdgdir.go
create mode 100644 vendor/go4.org/xdgdir/xdgdir_test.go
create mode 100644 vendor/golang.org/x/net/.gitattributes
create mode 100644 vendor/golang.org/x/net/.gitignore
create mode 100644 vendor/golang.org/x/net/AUTHORS
create mode 100644 vendor/golang.org/x/net/CONTRIBUTING.md
create mode 100644 vendor/golang.org/x/net/CONTRIBUTORS
create mode 100644 vendor/golang.org/x/net/LICENSE
create mode 100644 vendor/golang.org/x/net/PATENTS
create mode 100644 vendor/golang.org/x/net/README.md
create mode 100644 vendor/golang.org/x/net/bpf/asm.go
create mode 100644 vendor/golang.org/x/net/bpf/constants.go
create mode 100644 vendor/golang.org/x/net/bpf/doc.go
create mode 100644 vendor/golang.org/x/net/bpf/instructions.go
create mode 100644 vendor/golang.org/x/net/bpf/instructions_test.go
create mode 100644 vendor/golang.org/x/net/bpf/setter.go
create mode 100644 vendor/golang.org/x/net/bpf/testdata/all_instructions.bpf
create mode 100644 vendor/golang.org/x/net/bpf/testdata/all_instructions.txt
create mode 100644 vendor/golang.org/x/net/bpf/vm.go
create mode 100644 vendor/golang.org/x/net/bpf/vm_aluop_test.go
create mode 100644 vendor/golang.org/x/net/bpf/vm_bpf_test.go
create mode 100644 vendor/golang.org/x/net/bpf/vm_extension_test.go
create mode 100644 vendor/golang.org/x/net/bpf/vm_instructions.go
create mode 100644 vendor/golang.org/x/net/bpf/vm_jump_test.go
create mode 100644 vendor/golang.org/x/net/bpf/vm_load_test.go
create mode 100644 vendor/golang.org/x/net/bpf/vm_ret_test.go
create mode 100644 vendor/golang.org/x/net/bpf/vm_scratch_test.go
create mode 100644 vendor/golang.org/x/net/bpf/vm_test.go
create mode 100644 vendor/golang.org/x/net/codereview.cfg
create mode 100644 vendor/golang.org/x/net/context/context.go
create mode 100644 vendor/golang.org/x/net/context/context_test.go
create mode 100644 vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go
create mode 100644 vendor/golang.org/x/net/context/ctxhttp/ctxhttp_17_test.go
create mode 100644 vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go
create mode 100644 vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17_test.go
create mode 100644 vendor/golang.org/x/net/context/ctxhttp/ctxhttp_test.go
create mode 100644 vendor/golang.org/x/net/context/go17.go
create mode 100644 vendor/golang.org/x/net/context/go19.go
create mode 100644 vendor/golang.org/x/net/context/pre_go17.go
create mode 100644 vendor/golang.org/x/net/context/pre_go19.go
create mode 100644 vendor/golang.org/x/net/context/withtimeout_test.go
create mode 100644 vendor/golang.org/x/net/dict/dict.go
create mode 100644 vendor/golang.org/x/net/dns/dnsmessage/example_test.go
create mode 100644 vendor/golang.org/x/net/dns/dnsmessage/message.go
create mode 100644 vendor/golang.org/x/net/dns/dnsmessage/message_test.go
create mode 100644 vendor/golang.org/x/net/html/atom/atom.go
create mode 100644 vendor/golang.org/x/net/html/atom/atom_test.go
create mode 100644 vendor/golang.org/x/net/html/atom/gen.go
create mode 100644 vendor/golang.org/x/net/html/atom/table.go
create mode 100644 vendor/golang.org/x/net/html/atom/table_test.go
create mode 100644 vendor/golang.org/x/net/html/charset/charset.go
create mode 100644 vendor/golang.org/x/net/html/charset/charset_test.go
create mode 100644 vendor/golang.org/x/net/html/charset/testdata/HTTP-charset.html
create mode 100644 vendor/golang.org/x/net/html/charset/testdata/HTTP-vs-UTF-8-BOM.html
create mode 100644 vendor/golang.org/x/net/html/charset/testdata/HTTP-vs-meta-charset.html
create mode 100644 vendor/golang.org/x/net/html/charset/testdata/HTTP-vs-meta-content.html
create mode 100644 vendor/golang.org/x/net/html/charset/testdata/No-encoding-declaration.html
create mode 100644 vendor/golang.org/x/net/html/charset/testdata/README
create mode 100644 vendor/golang.org/x/net/html/charset/testdata/UTF-16BE-BOM.html
create mode 100644 vendor/golang.org/x/net/html/charset/testdata/UTF-16LE-BOM.html
create mode 100644 vendor/golang.org/x/net/html/charset/testdata/UTF-8-BOM-vs-meta-charset.html
create mode 100644 vendor/golang.org/x/net/html/charset/testdata/UTF-8-BOM-vs-meta-content.html
create mode 100644 vendor/golang.org/x/net/html/charset/testdata/meta-charset-attribute.html
create mode 100644 vendor/golang.org/x/net/html/charset/testdata/meta-content-attribute.html
create mode 100644 vendor/golang.org/x/net/html/const.go
create mode 100644 vendor/golang.org/x/net/html/doc.go
create mode 100644 vendor/golang.org/x/net/html/doctype.go
create mode 100644 vendor/golang.org/x/net/html/entity.go
create mode 100644 vendor/golang.org/x/net/html/entity_test.go
create mode 100644 vendor/golang.org/x/net/html/escape.go
create mode 100644 vendor/golang.org/x/net/html/escape_test.go
create mode 100644 vendor/golang.org/x/net/html/example_test.go
create mode 100644 vendor/golang.org/x/net/html/foreign.go
create mode 100644 vendor/golang.org/x/net/html/node.go
create mode 100644 vendor/golang.org/x/net/html/node_test.go
create mode 100644 vendor/golang.org/x/net/html/parse.go
create mode 100644 vendor/golang.org/x/net/html/parse_test.go
create mode 100644 vendor/golang.org/x/net/html/render.go
create mode 100644 vendor/golang.org/x/net/html/render_test.go
create mode 100644 vendor/golang.org/x/net/html/testdata/go1.html
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/README
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/adoption01.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/adoption02.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/comments01.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/doctype01.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/entities01.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/entities02.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/html5test-com.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/inbody01.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/isindex.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/pending-spec-changes-plain-text-unsafe.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/pending-spec-changes.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/plain-text-unsafe.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/ruby.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/scriptdata01.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/scripted/adoption01.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/scripted/webkit01.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tables01.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/template.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests1.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests10.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests11.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests12.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests14.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests15.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests16.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests17.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests18.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests19.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests2.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests20.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests21.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests22.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests23.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests24.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests25.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests26.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests3.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests4.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests5.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests6.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests7.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests8.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests9.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tests_innerHTML_1.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/tricky01.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/webkit01.dat
create mode 100644 vendor/golang.org/x/net/html/testdata/webkit/webkit02.dat
create mode 100644 vendor/golang.org/x/net/html/token.go
create mode 100644 vendor/golang.org/x/net/html/token_test.go
create mode 100644 vendor/golang.org/x/net/http/httpguts/guts.go
create mode 100644 vendor/golang.org/x/net/http/httpproxy/export_test.go
create mode 100644 vendor/golang.org/x/net/http/httpproxy/go19_test.go
create mode 100644 vendor/golang.org/x/net/http/httpproxy/proxy.go
create mode 100644 vendor/golang.org/x/net/http/httpproxy/proxy_test.go
create mode 100644 vendor/golang.org/x/net/http2/.gitignore
create mode 100644 vendor/golang.org/x/net/http2/Dockerfile
create mode 100644 vendor/golang.org/x/net/http2/Makefile
create mode 100644 vendor/golang.org/x/net/http2/README
create mode 100644 vendor/golang.org/x/net/http2/ciphers.go
create mode 100644 vendor/golang.org/x/net/http2/ciphers_test.go
create mode 100644 vendor/golang.org/x/net/http2/client_conn_pool.go
create mode 100644 vendor/golang.org/x/net/http2/configure_transport.go
create mode 100644 vendor/golang.org/x/net/http2/databuffer.go
create mode 100644 vendor/golang.org/x/net/http2/databuffer_test.go
create mode 100644 vendor/golang.org/x/net/http2/errors.go
create mode 100644 vendor/golang.org/x/net/http2/errors_test.go
create mode 100644 vendor/golang.org/x/net/http2/flow.go
create mode 100644 vendor/golang.org/x/net/http2/flow_test.go
create mode 100644 vendor/golang.org/x/net/http2/frame.go
create mode 100644 vendor/golang.org/x/net/http2/frame_test.go
create mode 100644 vendor/golang.org/x/net/http2/go16.go
create mode 100644 vendor/golang.org/x/net/http2/go17.go
create mode 100644 vendor/golang.org/x/net/http2/go17_not18.go
create mode 100644 vendor/golang.org/x/net/http2/go18.go
create mode 100644 vendor/golang.org/x/net/http2/go18_test.go
create mode 100644 vendor/golang.org/x/net/http2/go19.go
create mode 100644 vendor/golang.org/x/net/http2/go19_test.go
create mode 100644 vendor/golang.org/x/net/http2/gotrack.go
create mode 100644 vendor/golang.org/x/net/http2/gotrack_test.go
create mode 100644 vendor/golang.org/x/net/http2/h2demo/.gitignore
create mode 100644 vendor/golang.org/x/net/http2/h2demo/Dockerfile
create mode 100644 vendor/golang.org/x/net/http2/h2demo/Dockerfile.0
create mode 100644 vendor/golang.org/x/net/http2/h2demo/Makefile
create mode 100644 vendor/golang.org/x/net/http2/h2demo/README
create mode 100644 vendor/golang.org/x/net/http2/h2demo/deployment-prod.yaml
create mode 100644 vendor/golang.org/x/net/http2/h2demo/h2demo.go
create mode 100644 vendor/golang.org/x/net/http2/h2demo/launch.go
create mode 100644 vendor/golang.org/x/net/http2/h2demo/rootCA.key
create mode 100644 vendor/golang.org/x/net/http2/h2demo/rootCA.pem
create mode 100644 vendor/golang.org/x/net/http2/h2demo/rootCA.srl
create mode 100644 vendor/golang.org/x/net/http2/h2demo/server.crt
create mode 100644 vendor/golang.org/x/net/http2/h2demo/server.key
create mode 100644 vendor/golang.org/x/net/http2/h2demo/service.yaml
create mode 100644 vendor/golang.org/x/net/http2/h2demo/tmpl.go
create mode 100644 vendor/golang.org/x/net/http2/h2i/README.md
create mode 100644 vendor/golang.org/x/net/http2/h2i/h2i.go
create mode 100644 vendor/golang.org/x/net/http2/headermap.go
create mode 100644 vendor/golang.org/x/net/http2/hpack/encode.go
create mode 100644 vendor/golang.org/x/net/http2/hpack/encode_test.go
create mode 100644 vendor/golang.org/x/net/http2/hpack/hpack.go
create mode 100644 vendor/golang.org/x/net/http2/hpack/hpack_test.go
create mode 100644 vendor/golang.org/x/net/http2/hpack/huffman.go
create mode 100644 vendor/golang.org/x/net/http2/hpack/tables.go
create mode 100644 vendor/golang.org/x/net/http2/hpack/tables_test.go
create mode 100644 vendor/golang.org/x/net/http2/http2.go
create mode 100644 vendor/golang.org/x/net/http2/http2_test.go
create mode 100644 vendor/golang.org/x/net/http2/not_go16.go
create mode 100644 vendor/golang.org/x/net/http2/not_go17.go
create mode 100644 vendor/golang.org/x/net/http2/not_go18.go
create mode 100644 vendor/golang.org/x/net/http2/not_go19.go
create mode 100644 vendor/golang.org/x/net/http2/pipe.go
create mode 100644 vendor/golang.org/x/net/http2/pipe_test.go
create mode 100644 vendor/golang.org/x/net/http2/server.go
create mode 100644 vendor/golang.org/x/net/http2/server_push_test.go
create mode 100644 vendor/golang.org/x/net/http2/server_test.go
create mode 100644 vendor/golang.org/x/net/http2/testdata/draft-ietf-httpbis-http2.xml
create mode 100644 vendor/golang.org/x/net/http2/transport.go
create mode 100644 vendor/golang.org/x/net/http2/transport_test.go
create mode 100644 vendor/golang.org/x/net/http2/write.go
create mode 100644 vendor/golang.org/x/net/http2/writesched.go
create mode 100644 vendor/golang.org/x/net/http2/writesched_priority.go
create mode 100644 vendor/golang.org/x/net/http2/writesched_priority_test.go
create mode 100644 vendor/golang.org/x/net/http2/writesched_random.go
create mode 100644 vendor/golang.org/x/net/http2/writesched_random_test.go
create mode 100644 vendor/golang.org/x/net/http2/writesched_test.go
create mode 100644 vendor/golang.org/x/net/http2/z_spec_test.go
create mode 100644 vendor/golang.org/x/net/icmp/diag_test.go
create mode 100644 vendor/golang.org/x/net/icmp/dstunreach.go
create mode 100644 vendor/golang.org/x/net/icmp/echo.go
create mode 100644 vendor/golang.org/x/net/icmp/endpoint.go
create mode 100644 vendor/golang.org/x/net/icmp/example_test.go
create mode 100644 vendor/golang.org/x/net/icmp/extension.go
create mode 100644 vendor/golang.org/x/net/icmp/extension_test.go
create mode 100644 vendor/golang.org/x/net/icmp/helper_posix.go
create mode 100644 vendor/golang.org/x/net/icmp/interface.go
create mode 100644 vendor/golang.org/x/net/icmp/ipv4.go
create mode 100644 vendor/golang.org/x/net/icmp/ipv4_test.go
create mode 100644 vendor/golang.org/x/net/icmp/ipv6.go
create mode 100644 vendor/golang.org/x/net/icmp/listen_posix.go
create mode 100644 vendor/golang.org/x/net/icmp/listen_stub.go
create mode 100644 vendor/golang.org/x/net/icmp/message.go
create mode 100644 vendor/golang.org/x/net/icmp/message_test.go
create mode 100644 vendor/golang.org/x/net/icmp/messagebody.go
create mode 100644 vendor/golang.org/x/net/icmp/mpls.go
create mode 100644 vendor/golang.org/x/net/icmp/multipart.go
create mode 100644 vendor/golang.org/x/net/icmp/multipart_test.go
create mode 100644 vendor/golang.org/x/net/icmp/packettoobig.go
create mode 100644 vendor/golang.org/x/net/icmp/paramprob.go
create mode 100644 vendor/golang.org/x/net/icmp/sys_freebsd.go
create mode 100644 vendor/golang.org/x/net/icmp/timeexceeded.go
create mode 100644 vendor/golang.org/x/net/idna/example_test.go
create mode 100644 vendor/golang.org/x/net/idna/idna.go
create mode 100644 vendor/golang.org/x/net/idna/idna_test.go
create mode 100644 vendor/golang.org/x/net/idna/punycode.go
create mode 100644 vendor/golang.org/x/net/idna/punycode_test.go
create mode 100644 vendor/golang.org/x/net/idna/tables.go
create mode 100644 vendor/golang.org/x/net/idna/trie.go
create mode 100644 vendor/golang.org/x/net/idna/trieval.go
create mode 100644 vendor/golang.org/x/net/internal/iana/const.go
create mode 100644 vendor/golang.org/x/net/internal/iana/gen.go
create mode 100644 vendor/golang.org/x/net/internal/nettest/helper_bsd.go
create mode 100644 vendor/golang.org/x/net/internal/nettest/helper_nobsd.go
create mode 100644 vendor/golang.org/x/net/internal/nettest/helper_posix.go
create mode 100644 vendor/golang.org/x/net/internal/nettest/helper_stub.go
create mode 100644 vendor/golang.org/x/net/internal/nettest/helper_unix.go
create mode 100644 vendor/golang.org/x/net/internal/nettest/helper_windows.go
create mode 100644 vendor/golang.org/x/net/internal/nettest/interface.go
create mode 100644 vendor/golang.org/x/net/internal/nettest/rlimit.go
create mode 100644 vendor/golang.org/x/net/internal/nettest/stack.go
create mode 100644 vendor/golang.org/x/net/internal/socket/cmsghdr.go
create mode 100644 vendor/golang.org/x/net/internal/socket/cmsghdr_bsd.go
create mode 100644 vendor/golang.org/x/net/internal/socket/cmsghdr_linux_32bit.go
create mode 100644 vendor/golang.org/x/net/internal/socket/cmsghdr_linux_64bit.go
create mode 100644 vendor/golang.org/x/net/internal/socket/cmsghdr_solaris_64bit.go
create mode 100644 vendor/golang.org/x/net/internal/socket/cmsghdr_stub.go
create mode 100644 vendor/golang.org/x/net/internal/socket/defs_darwin.go
create mode 100644 vendor/golang.org/x/net/internal/socket/defs_dragonfly.go
create mode 100644 vendor/golang.org/x/net/internal/socket/defs_freebsd.go
create mode 100644 vendor/golang.org/x/net/internal/socket/defs_linux.go
create mode 100644 vendor/golang.org/x/net/internal/socket/defs_netbsd.go
create mode 100644 vendor/golang.org/x/net/internal/socket/defs_openbsd.go
create mode 100644 vendor/golang.org/x/net/internal/socket/defs_solaris.go
create mode 100644 vendor/golang.org/x/net/internal/socket/error_unix.go
create mode 100644 vendor/golang.org/x/net/internal/socket/error_windows.go
create mode 100644 vendor/golang.org/x/net/internal/socket/iovec_32bit.go
create mode 100644 vendor/golang.org/x/net/internal/socket/iovec_64bit.go
create mode 100644 vendor/golang.org/x/net/internal/socket/iovec_solaris_64bit.go
create mode 100644 vendor/golang.org/x/net/internal/socket/iovec_stub.go
create mode 100644 vendor/golang.org/x/net/internal/socket/mmsghdr_stub.go
create mode 100644 vendor/golang.org/x/net/internal/socket/mmsghdr_unix.go
create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_bsd.go
create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_bsdvar.go
create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_linux.go
create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_linux_32bit.go
create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_linux_64bit.go
create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_openbsd.go
create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_solaris_64bit.go
create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_stub.go
create mode 100644 vendor/golang.org/x/net/internal/socket/rawconn.go
create mode 100644 vendor/golang.org/x/net/internal/socket/rawconn_mmsg.go
create mode 100644 vendor/golang.org/x/net/internal/socket/rawconn_msg.go
create mode 100644 vendor/golang.org/x/net/internal/socket/rawconn_nommsg.go
create mode 100644 vendor/golang.org/x/net/internal/socket/rawconn_nomsg.go
create mode 100644 vendor/golang.org/x/net/internal/socket/rawconn_stub.go
create mode 100644 vendor/golang.org/x/net/internal/socket/reflect.go
create mode 100644 vendor/golang.org/x/net/internal/socket/socket.go
create mode 100644 vendor/golang.org/x/net/internal/socket/socket_go1_9_test.go
create mode 100644 vendor/golang.org/x/net/internal/socket/socket_test.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_bsd.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_bsdvar.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_darwin.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_dragonfly.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_386.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_386.s
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_amd64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_arm.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_arm64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_mips.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_mips64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_mips64le.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_mipsle.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_ppc64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_ppc64le.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_s390x.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_s390x.s
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_netbsd.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_posix.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_solaris.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_solaris_amd64.s
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_stub.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_unix.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_windows.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_darwin_386.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_darwin_amd64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_darwin_arm.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_darwin_arm64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_dragonfly_amd64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_freebsd_386.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_freebsd_amd64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_freebsd_arm.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_386.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_amd64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_arm.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_arm64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_mips.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_mips64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_mips64le.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_mipsle.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_ppc64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_ppc64le.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_s390x.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_netbsd_386.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_netbsd_amd64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_netbsd_arm.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_openbsd_386.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_openbsd_amd64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_openbsd_arm.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_solaris_amd64.go
create mode 100644 vendor/golang.org/x/net/internal/socks/client.go
create mode 100644 vendor/golang.org/x/net/internal/socks/dial_test.go
create mode 100644 vendor/golang.org/x/net/internal/socks/socks.go
create mode 100644 vendor/golang.org/x/net/internal/sockstest/server.go
create mode 100644 vendor/golang.org/x/net/internal/sockstest/server_test.go
create mode 100644 vendor/golang.org/x/net/internal/timeseries/timeseries.go
create mode 100644 vendor/golang.org/x/net/internal/timeseries/timeseries_test.go
create mode 100644 vendor/golang.org/x/net/ipv4/batch.go
create mode 100644 vendor/golang.org/x/net/ipv4/bpf_test.go
create mode 100644 vendor/golang.org/x/net/ipv4/control.go
create mode 100644 vendor/golang.org/x/net/ipv4/control_bsd.go
create mode 100644 vendor/golang.org/x/net/ipv4/control_pktinfo.go
create mode 100644 vendor/golang.org/x/net/ipv4/control_stub.go
create mode 100644 vendor/golang.org/x/net/ipv4/control_test.go
create mode 100644 vendor/golang.org/x/net/ipv4/control_unix.go
create mode 100644 vendor/golang.org/x/net/ipv4/control_windows.go
create mode 100644 vendor/golang.org/x/net/ipv4/defs_darwin.go
create mode 100644 vendor/golang.org/x/net/ipv4/defs_dragonfly.go
create mode 100644 vendor/golang.org/x/net/ipv4/defs_freebsd.go
create mode 100644 vendor/golang.org/x/net/ipv4/defs_linux.go
create mode 100644 vendor/golang.org/x/net/ipv4/defs_netbsd.go
create mode 100644 vendor/golang.org/x/net/ipv4/defs_openbsd.go
create mode 100644 vendor/golang.org/x/net/ipv4/defs_solaris.go
create mode 100644 vendor/golang.org/x/net/ipv4/dgramopt.go
create mode 100644 vendor/golang.org/x/net/ipv4/doc.go
create mode 100644 vendor/golang.org/x/net/ipv4/endpoint.go
create mode 100644 vendor/golang.org/x/net/ipv4/example_test.go
create mode 100644 vendor/golang.org/x/net/ipv4/gen.go
create mode 100644 vendor/golang.org/x/net/ipv4/genericopt.go
create mode 100644 vendor/golang.org/x/net/ipv4/header.go
create mode 100644 vendor/golang.org/x/net/ipv4/header_test.go
create mode 100644 vendor/golang.org/x/net/ipv4/helper.go
create mode 100644 vendor/golang.org/x/net/ipv4/iana.go
create mode 100644 vendor/golang.org/x/net/ipv4/icmp.go
create mode 100644 vendor/golang.org/x/net/ipv4/icmp_linux.go
create mode 100644 vendor/golang.org/x/net/ipv4/icmp_stub.go
create mode 100644 vendor/golang.org/x/net/ipv4/icmp_test.go
create mode 100644 vendor/golang.org/x/net/ipv4/multicast_test.go
create mode 100644 vendor/golang.org/x/net/ipv4/multicastlistener_test.go
create mode 100644 vendor/golang.org/x/net/ipv4/multicastsockopt_test.go
create mode 100644 vendor/golang.org/x/net/ipv4/packet.go
create mode 100644 vendor/golang.org/x/net/ipv4/packet_go1_8.go
create mode 100644 vendor/golang.org/x/net/ipv4/packet_go1_9.go
create mode 100644 vendor/golang.org/x/net/ipv4/payload.go
create mode 100644 vendor/golang.org/x/net/ipv4/payload_cmsg.go
create mode 100644 vendor/golang.org/x/net/ipv4/payload_cmsg_go1_8.go
create mode 100644 vendor/golang.org/x/net/ipv4/payload_cmsg_go1_9.go
create mode 100644 vendor/golang.org/x/net/ipv4/payload_nocmsg.go
create mode 100644 vendor/golang.org/x/net/ipv4/readwrite_go1_8_test.go
create mode 100644 vendor/golang.org/x/net/ipv4/readwrite_go1_9_test.go
create mode 100644 vendor/golang.org/x/net/ipv4/readwrite_test.go
create mode 100644 vendor/golang.org/x/net/ipv4/sockopt.go
create mode 100644 vendor/golang.org/x/net/ipv4/sockopt_posix.go
create mode 100644 vendor/golang.org/x/net/ipv4/sockopt_stub.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_asmreq.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_asmreq_stub.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_asmreqn.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_asmreqn_stub.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_bpf.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_bpf_stub.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_bsd.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_darwin.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_dragonfly.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_freebsd.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_linux.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_solaris.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_ssmreq.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_ssmreq_stub.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_stub.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_windows.go
create mode 100644 vendor/golang.org/x/net/ipv4/unicast_test.go
create mode 100644 vendor/golang.org/x/net/ipv4/unicastsockopt_test.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_darwin.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_dragonfly.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_freebsd_386.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_freebsd_amd64.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_freebsd_arm.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_386.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_amd64.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_arm.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_arm64.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_mips.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_mips64.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_mips64le.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_mipsle.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_ppc.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_ppc64.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_ppc64le.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_s390x.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_netbsd.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_openbsd.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_solaris.go
create mode 100644 vendor/golang.org/x/net/ipv6/batch.go
create mode 100644 vendor/golang.org/x/net/ipv6/bpf_test.go
create mode 100644 vendor/golang.org/x/net/ipv6/control.go
create mode 100644 vendor/golang.org/x/net/ipv6/control_rfc2292_unix.go
create mode 100644 vendor/golang.org/x/net/ipv6/control_rfc3542_unix.go
create mode 100644 vendor/golang.org/x/net/ipv6/control_stub.go
create mode 100644 vendor/golang.org/x/net/ipv6/control_test.go
create mode 100644 vendor/golang.org/x/net/ipv6/control_unix.go
create mode 100644 vendor/golang.org/x/net/ipv6/control_windows.go
create mode 100644 vendor/golang.org/x/net/ipv6/defs_darwin.go
create mode 100644 vendor/golang.org/x/net/ipv6/defs_dragonfly.go
create mode 100644 vendor/golang.org/x/net/ipv6/defs_freebsd.go
create mode 100644 vendor/golang.org/x/net/ipv6/defs_linux.go
create mode 100644 vendor/golang.org/x/net/ipv6/defs_netbsd.go
create mode 100644 vendor/golang.org/x/net/ipv6/defs_openbsd.go
create mode 100644 vendor/golang.org/x/net/ipv6/defs_solaris.go
create mode 100644 vendor/golang.org/x/net/ipv6/dgramopt.go
create mode 100644 vendor/golang.org/x/net/ipv6/doc.go
create mode 100644 vendor/golang.org/x/net/ipv6/endpoint.go
create mode 100644 vendor/golang.org/x/net/ipv6/example_test.go
create mode 100644 vendor/golang.org/x/net/ipv6/gen.go
create mode 100644 vendor/golang.org/x/net/ipv6/genericopt.go
create mode 100644 vendor/golang.org/x/net/ipv6/header.go
create mode 100644 vendor/golang.org/x/net/ipv6/header_test.go
create mode 100644 vendor/golang.org/x/net/ipv6/helper.go
create mode 100644 vendor/golang.org/x/net/ipv6/iana.go
create mode 100644 vendor/golang.org/x/net/ipv6/icmp.go
create mode 100644 vendor/golang.org/x/net/ipv6/icmp_bsd.go
create mode 100644 vendor/golang.org/x/net/ipv6/icmp_linux.go
create mode 100644 vendor/golang.org/x/net/ipv6/icmp_solaris.go
create mode 100644 vendor/golang.org/x/net/ipv6/icmp_stub.go
create mode 100644 vendor/golang.org/x/net/ipv6/icmp_test.go
create mode 100644 vendor/golang.org/x/net/ipv6/icmp_windows.go
create mode 100644 vendor/golang.org/x/net/ipv6/mocktransponder_test.go
create mode 100644 vendor/golang.org/x/net/ipv6/multicast_test.go
create mode 100644 vendor/golang.org/x/net/ipv6/multicastlistener_test.go
create mode 100644 vendor/golang.org/x/net/ipv6/multicastsockopt_test.go
create mode 100644 vendor/golang.org/x/net/ipv6/payload.go
create mode 100644 vendor/golang.org/x/net/ipv6/payload_cmsg.go
create mode 100644 vendor/golang.org/x/net/ipv6/payload_cmsg_go1_8.go
create mode 100644 vendor/golang.org/x/net/ipv6/payload_cmsg_go1_9.go
create mode 100644 vendor/golang.org/x/net/ipv6/payload_nocmsg.go
create mode 100644 vendor/golang.org/x/net/ipv6/readwrite_go1_8_test.go
create mode 100644 vendor/golang.org/x/net/ipv6/readwrite_go1_9_test.go
create mode 100644 vendor/golang.org/x/net/ipv6/readwrite_test.go
create mode 100644 vendor/golang.org/x/net/ipv6/sockopt.go
create mode 100644 vendor/golang.org/x/net/ipv6/sockopt_posix.go
create mode 100644 vendor/golang.org/x/net/ipv6/sockopt_stub.go
create mode 100644 vendor/golang.org/x/net/ipv6/sockopt_test.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_asmreq.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_asmreq_stub.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_bpf.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_bpf_stub.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_bsd.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_darwin.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_freebsd.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_linux.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_solaris.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_ssmreq.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_ssmreq_stub.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_stub.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_windows.go
create mode 100644 vendor/golang.org/x/net/ipv6/unicast_test.go
create mode 100644 vendor/golang.org/x/net/ipv6/unicastsockopt_test.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_darwin.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_dragonfly.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_freebsd_386.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_freebsd_amd64.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_freebsd_arm.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_386.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_amd64.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_arm.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_arm64.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_mips.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_mips64.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_mips64le.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_mipsle.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_ppc.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_ppc64.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_ppc64le.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_s390x.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_netbsd.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_openbsd.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_solaris.go
create mode 100644 vendor/golang.org/x/net/lex/httplex/httplex.go
create mode 100644 vendor/golang.org/x/net/lex/httplex/httplex_test.go
create mode 100644 vendor/golang.org/x/net/lif/address.go
create mode 100644 vendor/golang.org/x/net/lif/address_test.go
create mode 100644 vendor/golang.org/x/net/lif/binary.go
create mode 100644 vendor/golang.org/x/net/lif/defs_solaris.go
create mode 100644 vendor/golang.org/x/net/lif/lif.go
create mode 100644 vendor/golang.org/x/net/lif/link.go
create mode 100644 vendor/golang.org/x/net/lif/link_test.go
create mode 100644 vendor/golang.org/x/net/lif/sys.go
create mode 100644 vendor/golang.org/x/net/lif/sys_solaris_amd64.s
create mode 100644 vendor/golang.org/x/net/lif/syscall.go
create mode 100644 vendor/golang.org/x/net/lif/zsys_solaris_amd64.go
create mode 100644 vendor/golang.org/x/net/nettest/conntest.go
create mode 100644 vendor/golang.org/x/net/nettest/conntest_go16.go
create mode 100644 vendor/golang.org/x/net/nettest/conntest_go17.go
create mode 100644 vendor/golang.org/x/net/nettest/conntest_test.go
create mode 100644 vendor/golang.org/x/net/netutil/listen.go
create mode 100644 vendor/golang.org/x/net/netutil/listen_test.go
create mode 100644 vendor/golang.org/x/net/proxy/direct.go
create mode 100644 vendor/golang.org/x/net/proxy/per_host.go
create mode 100644 vendor/golang.org/x/net/proxy/per_host_test.go
create mode 100644 vendor/golang.org/x/net/proxy/proxy.go
create mode 100644 vendor/golang.org/x/net/proxy/proxy_test.go
create mode 100644 vendor/golang.org/x/net/proxy/socks5.go
create mode 100644 vendor/golang.org/x/net/publicsuffix/gen.go
create mode 100644 vendor/golang.org/x/net/publicsuffix/list.go
create mode 100644 vendor/golang.org/x/net/publicsuffix/list_test.go
create mode 100644 vendor/golang.org/x/net/publicsuffix/table.go
create mode 100644 vendor/golang.org/x/net/publicsuffix/table_test.go
create mode 100644 vendor/golang.org/x/net/route/address.go
create mode 100644 vendor/golang.org/x/net/route/address_darwin_test.go
create mode 100644 vendor/golang.org/x/net/route/address_test.go
create mode 100644 vendor/golang.org/x/net/route/binary.go
create mode 100644 vendor/golang.org/x/net/route/defs_darwin.go
create mode 100644 vendor/golang.org/x/net/route/defs_dragonfly.go
create mode 100644 vendor/golang.org/x/net/route/defs_freebsd.go
create mode 100644 vendor/golang.org/x/net/route/defs_netbsd.go
create mode 100644 vendor/golang.org/x/net/route/defs_openbsd.go
create mode 100644 vendor/golang.org/x/net/route/interface.go
create mode 100644 vendor/golang.org/x/net/route/interface_announce.go
create mode 100644 vendor/golang.org/x/net/route/interface_classic.go
create mode 100644 vendor/golang.org/x/net/route/interface_freebsd.go
create mode 100644 vendor/golang.org/x/net/route/interface_multicast.go
create mode 100644 vendor/golang.org/x/net/route/interface_openbsd.go
create mode 100644 vendor/golang.org/x/net/route/message.go
create mode 100644 vendor/golang.org/x/net/route/message_darwin_test.go
create mode 100644 vendor/golang.org/x/net/route/message_freebsd_test.go
create mode 100644 vendor/golang.org/x/net/route/message_test.go
create mode 100644 vendor/golang.org/x/net/route/route.go
create mode 100644 vendor/golang.org/x/net/route/route_classic.go
create mode 100644 vendor/golang.org/x/net/route/route_openbsd.go
create mode 100644 vendor/golang.org/x/net/route/route_test.go
create mode 100644 vendor/golang.org/x/net/route/sys.go
create mode 100644 vendor/golang.org/x/net/route/sys_darwin.go
create mode 100644 vendor/golang.org/x/net/route/sys_dragonfly.go
create mode 100644 vendor/golang.org/x/net/route/sys_freebsd.go
create mode 100644 vendor/golang.org/x/net/route/sys_netbsd.go
create mode 100644 vendor/golang.org/x/net/route/sys_openbsd.go
create mode 100644 vendor/golang.org/x/net/route/syscall.go
create mode 100644 vendor/golang.org/x/net/route/zsys_darwin.go
create mode 100644 vendor/golang.org/x/net/route/zsys_dragonfly.go
create mode 100644 vendor/golang.org/x/net/route/zsys_freebsd_386.go
create mode 100644 vendor/golang.org/x/net/route/zsys_freebsd_amd64.go
create mode 100644 vendor/golang.org/x/net/route/zsys_freebsd_arm.go
create mode 100644 vendor/golang.org/x/net/route/zsys_netbsd.go
create mode 100644 vendor/golang.org/x/net/route/zsys_openbsd.go
create mode 100644 vendor/golang.org/x/net/trace/events.go
create mode 100644 vendor/golang.org/x/net/trace/histogram.go
create mode 100644 vendor/golang.org/x/net/trace/histogram_test.go
create mode 100644 vendor/golang.org/x/net/trace/trace.go
create mode 100644 vendor/golang.org/x/net/trace/trace_go16.go
create mode 100644 vendor/golang.org/x/net/trace/trace_go17.go
create mode 100644 vendor/golang.org/x/net/trace/trace_test.go
create mode 100644 vendor/golang.org/x/net/webdav/file.go
create mode 100644 vendor/golang.org/x/net/webdav/file_go1.6.go
create mode 100644 vendor/golang.org/x/net/webdav/file_go1.7.go
create mode 100644 vendor/golang.org/x/net/webdav/file_test.go
create mode 100644 vendor/golang.org/x/net/webdav/if.go
create mode 100644 vendor/golang.org/x/net/webdav/if_test.go
create mode 100644 vendor/golang.org/x/net/webdav/internal/xml/README
create mode 100644 vendor/golang.org/x/net/webdav/internal/xml/atom_test.go
create mode 100644 vendor/golang.org/x/net/webdav/internal/xml/example_test.go
create mode 100644 vendor/golang.org/x/net/webdav/internal/xml/marshal.go
create mode 100644 vendor/golang.org/x/net/webdav/internal/xml/marshal_test.go
create mode 100644 vendor/golang.org/x/net/webdav/internal/xml/read.go
create mode 100644 vendor/golang.org/x/net/webdav/internal/xml/read_test.go
create mode 100644 vendor/golang.org/x/net/webdav/internal/xml/typeinfo.go
create mode 100644 vendor/golang.org/x/net/webdav/internal/xml/xml.go
create mode 100644 vendor/golang.org/x/net/webdav/internal/xml/xml_test.go
create mode 100644 vendor/golang.org/x/net/webdav/litmus_test_server.go
create mode 100644 vendor/golang.org/x/net/webdav/lock.go
create mode 100644 vendor/golang.org/x/net/webdav/lock_test.go
create mode 100644 vendor/golang.org/x/net/webdav/prop.go
create mode 100644 vendor/golang.org/x/net/webdav/prop_test.go
create mode 100644 vendor/golang.org/x/net/webdav/webdav.go
create mode 100644 vendor/golang.org/x/net/webdav/webdav_test.go
create mode 100644 vendor/golang.org/x/net/webdav/xml.go
create mode 100644 vendor/golang.org/x/net/webdav/xml_test.go
create mode 100644 vendor/golang.org/x/net/websocket/client.go
create mode 100644 vendor/golang.org/x/net/websocket/dial.go
create mode 100644 vendor/golang.org/x/net/websocket/dial_test.go
create mode 100644 vendor/golang.org/x/net/websocket/exampledial_test.go
create mode 100644 vendor/golang.org/x/net/websocket/examplehandler_test.go
create mode 100644 vendor/golang.org/x/net/websocket/hybi.go
create mode 100644 vendor/golang.org/x/net/websocket/hybi_test.go
create mode 100644 vendor/golang.org/x/net/websocket/server.go
create mode 100644 vendor/golang.org/x/net/websocket/websocket.go
create mode 100644 vendor/golang.org/x/net/websocket/websocket_test.go
create mode 100644 vendor/golang.org/x/net/xsrftoken/xsrf.go
create mode 100644 vendor/golang.org/x/net/xsrftoken/xsrf_test.go
create mode 100644 vendor/golang.org/x/sys/.gitattributes
create mode 100644 vendor/golang.org/x/sys/.gitignore
create mode 100644 vendor/golang.org/x/sys/AUTHORS
create mode 100644 vendor/golang.org/x/sys/CONTRIBUTING.md
create mode 100644 vendor/golang.org/x/sys/CONTRIBUTORS
create mode 100644 vendor/golang.org/x/sys/LICENSE
create mode 100644 vendor/golang.org/x/sys/PATENTS
create mode 100644 vendor/golang.org/x/sys/README.md
create mode 100644 vendor/golang.org/x/sys/codereview.cfg
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 100755 vendor/golang.org/x/sys/plan9/mkall.sh
create mode 100755 vendor/golang.org/x/sys/plan9/mkerrors.sh
create mode 100755 vendor/golang.org/x/sys/plan9/mksyscall.pl
create mode 100755 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/syscall_test.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/sys/unix/.gitignore
create mode 100644 vendor/golang.org/x/sys/unix/README.md
create mode 100644 vendor/golang.org/x/sys/unix/affinity_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/asm_darwin_386.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_darwin_amd64.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_darwin_arm.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_darwin_arm64.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_freebsd_386.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_freebsd_amd64.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_freebsd_arm.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_386.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_amd64.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_arm.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_arm64.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_mips64x.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_mipsx.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_s390x.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_netbsd_386.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_netbsd_amd64.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_netbsd_arm.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_openbsd_386.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_openbsd_amd64.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_openbsd_arm.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_solaris_amd64.s
create mode 100644 vendor/golang.org/x/sys/unix/bluetooth_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/cap_freebsd.go
create mode 100644 vendor/golang.org/x/sys/unix/constants.go
create mode 100644 vendor/golang.org/x/sys/unix/creds_test.go
create mode 100644 vendor/golang.org/x/sys/unix/dev_darwin.go
create mode 100644 vendor/golang.org/x/sys/unix/dev_darwin_test.go
create mode 100644 vendor/golang.org/x/sys/unix/dev_dragonfly.go
create mode 100644 vendor/golang.org/x/sys/unix/dev_dragonfly_test.go
create mode 100644 vendor/golang.org/x/sys/unix/dev_freebsd.go
create mode 100644 vendor/golang.org/x/sys/unix/dev_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/dev_linux_test.go
create mode 100644 vendor/golang.org/x/sys/unix/dev_netbsd.go
create mode 100644 vendor/golang.org/x/sys/unix/dev_netbsd_test.go
create mode 100644 vendor/golang.org/x/sys/unix/dev_openbsd.go
create mode 100644 vendor/golang.org/x/sys/unix/dev_openbsd_test.go
create mode 100644 vendor/golang.org/x/sys/unix/dev_solaris_test.go
create mode 100644 vendor/golang.org/x/sys/unix/dirent.go
create mode 100644 vendor/golang.org/x/sys/unix/endian_big.go
create mode 100644 vendor/golang.org/x/sys/unix/endian_little.go
create mode 100644 vendor/golang.org/x/sys/unix/env_unix.go
create mode 100644 vendor/golang.org/x/sys/unix/errors_freebsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/errors_freebsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/errors_freebsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/example_test.go
create mode 100644 vendor/golang.org/x/sys/unix/export_test.go
create mode 100644 vendor/golang.org/x/sys/unix/fcntl.go
create mode 100644 vendor/golang.org/x/sys/unix/fcntl_linux_32bit.go
create mode 100644 vendor/golang.org/x/sys/unix/gccgo.go
create mode 100644 vendor/golang.org/x/sys/unix/gccgo_c.c
create mode 100644 vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/linux/Dockerfile
create mode 100644 vendor/golang.org/x/sys/unix/linux/mkall.go
create mode 100755 vendor/golang.org/x/sys/unix/linux/mksysnum.pl
create mode 100644 vendor/golang.org/x/sys/unix/linux/types.go
create mode 100755 vendor/golang.org/x/sys/unix/mkall.sh
create mode 100755 vendor/golang.org/x/sys/unix/mkerrors.sh
create mode 100644 vendor/golang.org/x/sys/unix/mkpost.go
create mode 100755 vendor/golang.org/x/sys/unix/mksyscall.pl
create mode 100755 vendor/golang.org/x/sys/unix/mksyscall_solaris.pl
create mode 100755 vendor/golang.org/x/sys/unix/mksysctl_openbsd.pl
create mode 100755 vendor/golang.org/x/sys/unix/mksysnum_darwin.pl
create mode 100755 vendor/golang.org/x/sys/unix/mksysnum_dragonfly.pl
create mode 100755 vendor/golang.org/x/sys/unix/mksysnum_freebsd.pl
create mode 100755 vendor/golang.org/x/sys/unix/mksysnum_netbsd.pl
create mode 100755 vendor/golang.org/x/sys/unix/mksysnum_openbsd.pl
create mode 100644 vendor/golang.org/x/sys/unix/mmap_unix_test.go
create mode 100644 vendor/golang.org/x/sys/unix/openbsd_pledge.go
create mode 100644 vendor/golang.org/x/sys/unix/openbsd_test.go
create mode 100644 vendor/golang.org/x/sys/unix/pagesize_unix.go
create mode 100644 vendor/golang.org/x/sys/unix/race.go
create mode 100644 vendor/golang.org/x/sys/unix/race0.go
create mode 100644 vendor/golang.org/x/sys/unix/sockcmsg_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/sockcmsg_unix.go
create mode 100644 vendor/golang.org/x/sys/unix/str.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_bsd.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_bsd_test.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin_386.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_dragonfly.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_dragonfly_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_freebsd.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_freebsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_freebsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_freebsd_test.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_386.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_amd64_gc.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_gc.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_gccgo.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_s390x.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_test.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_netbsd.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_netbsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_netbsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_netbsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_solaris.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_solaris_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_solaris_test.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_test.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_unix.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_unix_gc.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_unix_test.go
create mode 100644 vendor/golang.org/x/sys/unix/timestruct.go
create mode 100644 vendor/golang.org/x/sys/unix/timestruct_test.go
create mode 100644 vendor/golang.org/x/sys/unix/types_darwin.go
create mode 100644 vendor/golang.org/x/sys/unix/types_dragonfly.go
create mode 100644 vendor/golang.org/x/sys/unix/types_freebsd.go
create mode 100644 vendor/golang.org/x/sys/unix/types_netbsd.go
create mode 100644 vendor/golang.org/x/sys/unix/types_openbsd.go
create mode 100644 vendor/golang.org/x/sys/unix/types_solaris.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_darwin_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_darwin_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_dragonfly_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_netbsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_netbsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_netbsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_openbsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_openbsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_openbsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_solaris_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zptrace386_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/zptracearm_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/zptracemips_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/zptracemipsle_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysctl_openbsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysctl_openbsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysctl_openbsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_darwin_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_darwin_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_darwin_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_darwin_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_dragonfly_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_freebsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_freebsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_netbsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_netbsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_openbsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_openbsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_openbsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_darwin_386.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_386.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_mips.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_solaris_amd64.go
create mode 100644 vendor/golang.org/x/sys/windows/asm_windows_386.s
create mode 100644 vendor/golang.org/x/sys/windows/asm_windows_amd64.s
create mode 100644 vendor/golang.org/x/sys/windows/dll_windows.go
create mode 100644 vendor/golang.org/x/sys/windows/env_windows.go
create mode 100644 vendor/golang.org/x/sys/windows/eventlog.go
create mode 100644 vendor/golang.org/x/sys/windows/exec_windows.go
create mode 100644 vendor/golang.org/x/sys/windows/memory_windows.go
create mode 100644 vendor/golang.org/x/sys/windows/mksyscall.go
create mode 100644 vendor/golang.org/x/sys/windows/race.go
create mode 100644 vendor/golang.org/x/sys/windows/race0.go
create mode 100644 vendor/golang.org/x/sys/windows/registry/export_test.go
create mode 100644 vendor/golang.org/x/sys/windows/registry/key.go
create mode 100644 vendor/golang.org/x/sys/windows/registry/mksyscall.go
create mode 100644 vendor/golang.org/x/sys/windows/registry/registry_test.go
create mode 100644 vendor/golang.org/x/sys/windows/registry/syscall.go
create mode 100644 vendor/golang.org/x/sys/windows/registry/value.go
create mode 100644 vendor/golang.org/x/sys/windows/registry/zsyscall_windows.go
create mode 100644 vendor/golang.org/x/sys/windows/security_windows.go
create mode 100644 vendor/golang.org/x/sys/windows/service.go
create mode 100644 vendor/golang.org/x/sys/windows/str.go
create mode 100644 vendor/golang.org/x/sys/windows/svc/debug/log.go
create mode 100644 vendor/golang.org/x/sys/windows/svc/debug/service.go
create mode 100644 vendor/golang.org/x/sys/windows/svc/event.go
create mode 100644 vendor/golang.org/x/sys/windows/svc/eventlog/install.go
create mode 100644 vendor/golang.org/x/sys/windows/svc/eventlog/log.go
create mode 100644 vendor/golang.org/x/sys/windows/svc/eventlog/log_test.go
create mode 100644 vendor/golang.org/x/sys/windows/svc/example/beep.go
create mode 100644 vendor/golang.org/x/sys/windows/svc/example/install.go
create mode 100644 vendor/golang.org/x/sys/windows/svc/example/main.go
create mode 100644 vendor/golang.org/x/sys/windows/svc/example/manage.go
create mode 100644 vendor/golang.org/x/sys/windows/svc/example/service.go
create mode 100644 vendor/golang.org/x/sys/windows/svc/go12.c
create mode 100644 vendor/golang.org/x/sys/windows/svc/go12.go
create mode 100644 vendor/golang.org/x/sys/windows/svc/go13.go
create mode 100644 vendor/golang.org/x/sys/windows/svc/mgr/config.go
create mode 100644 vendor/golang.org/x/sys/windows/svc/mgr/mgr.go
create mode 100644 vendor/golang.org/x/sys/windows/svc/mgr/mgr_test.go
create mode 100644 vendor/golang.org/x/sys/windows/svc/mgr/service.go
create mode 100644 vendor/golang.org/x/sys/windows/svc/security.go
create mode 100644 vendor/golang.org/x/sys/windows/svc/service.go
create mode 100644 vendor/golang.org/x/sys/windows/svc/svc_test.go
create mode 100644 vendor/golang.org/x/sys/windows/svc/sys_386.s
create mode 100644 vendor/golang.org/x/sys/windows/svc/sys_amd64.s
create mode 100644 vendor/golang.org/x/sys/windows/syscall.go
create mode 100644 vendor/golang.org/x/sys/windows/syscall_test.go
create mode 100644 vendor/golang.org/x/sys/windows/syscall_windows.go
create mode 100644 vendor/golang.org/x/sys/windows/syscall_windows_test.go
create mode 100644 vendor/golang.org/x/sys/windows/types_windows.go
create mode 100644 vendor/golang.org/x/sys/windows/types_windows_386.go
create mode 100644 vendor/golang.org/x/sys/windows/types_windows_amd64.go
create mode 100644 vendor/golang.org/x/sys/windows/zsyscall_windows.go
diff --git a/.gitignore b/.gitignore
index d9a4482..53e2fed 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,4 +21,3 @@ stage
*.snap
*bfg-report*
*bfg-report
-vendor
diff --git a/Gopkg.lock b/Gopkg.lock
index bae54ed..11e681f 100644
--- a/Gopkg.lock
+++ b/Gopkg.lock
@@ -13,24 +13,12 @@
revision = "cd07662ec9300d16d2ece1c24b0b29ad89f65ff4"
version = "v1.1"
-[[projects]]
- branch = "master"
- name = "github.com/bradfitz/slice"
- packages = ["."]
- revision = "d9036e2120b5ddfa53f3ebccd618c4af275f47da"
-
[[projects]]
name = "github.com/fatih/color"
packages = ["."]
revision = "507f6050b8568533fb3f5504de8e5205fa62a114"
version = "v1.6.0"
-[[projects]]
- branch = "master"
- name = "github.com/jroimartin/gocui"
- packages = ["."]
- revision = "c055c87ae801372cd74a0839b972db4f7697ae5f"
-
[[projects]]
name = "github.com/mattn/go-colorable"
packages = ["."]
@@ -53,19 +41,13 @@
branch = "master"
name = "github.com/miguelmota/go-coinmarketcap"
packages = ["."]
- revision = "824d58bf0ced24a3c5211695d1da4751c179ab64"
+ revision = "42269f499a7031e0affa526258909fa73f2914cd"
[[projects]]
branch = "master"
name = "github.com/nsf/termbox-go"
packages = ["."]
- revision = "3e24a7b6661e09b87a9f49d693034219f81602fa"
-
-[[projects]]
- name = "github.com/patrickmn/go-cache"
- packages = ["."]
- revision = "a3647f8e31d79543b2d0f0ae2fe5c379d72cedc0"
- version = "v2.1.0"
+ revision = "7cbfaac9e282b3ea0cefeddc67b2c3ed3aaf97bc"
[[projects]]
branch = "master"
@@ -80,17 +62,17 @@
"html",
"html/atom"
]
- revision = "84348c2dc81a524fe94aaea3e3d9f967135338ef"
+ revision = "5f9ae10d9af5b1c89ae6904293b14b064d4ada23"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
- revision = "b126b21c05a91c856b027c16779c12e3bf236954"
+ revision = "bb9c189858d91f42db229b04d45a4c3d23a7662a"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
- inputs-digest = "a379741758ab87277a2159f17b7f9741ece58d2f94b1c959191189f9100a6f29"
+ inputs-digest = "f8fa24cf45636d4d6991f0a805aba5b6ad13ce7807be80cc3baf17909e6b855b"
solver-name = "gps-cdcl"
solver-version = 1
diff --git a/Gopkg.toml b/Gopkg.toml
index 5218fdc..8738f07 100644
--- a/Gopkg.toml
+++ b/Gopkg.toml
@@ -25,30 +25,12 @@
# unused-packages = true
-[[constraint]]
- branch = "master"
- name = "github.com/bradfitz/slice"
[[constraint]]
name = "github.com/fatih/color"
version = "1.6.0"
-[[constraint]]
- name = "github.com/gizak/termui"
- version = "2.2.0"
-
-[[constraint]]
- name = "github.com/jroimartin/gocui"
- branch = "master"
-
[[constraint]]
branch = "master"
name = "github.com/miguelmota/go-coinmarketcap"
-[prune]
- go-tests = true
- unused-packages = true
-
-[[constraint]]
- name = "github.com/patrickmn/go-cache"
- version = "2.1.0"
diff --git a/cointop/cointop.go b/cointop/cointop.go
index fb7c5da..26f2fde 100644
--- a/cointop/cointop.go
+++ b/cointop/cointop.go
@@ -6,11 +6,11 @@ import (
"sync"
"time"
- "github.com/jroimartin/gocui"
"github.com/miguelmota/cointop/pkg/api"
+ "github.com/miguelmota/cointop/pkg/cache"
+ "github.com/miguelmota/cointop/pkg/gocui"
"github.com/miguelmota/cointop/pkg/table"
"github.com/miguelmota/cointop/pkg/termui"
- "github.com/patrickmn/go-cache"
)
// Cointop cointop
diff --git a/cointop/keybindings.go b/cointop/keybindings.go
index 1188d6e..51acc87 100644
--- a/cointop/keybindings.go
+++ b/cointop/keybindings.go
@@ -3,7 +3,7 @@ package cointop
import (
"strings"
- "github.com/jroimartin/gocui"
+ "github.com/miguelmota/cointop/pkg/gocui"
)
func (ct *Cointop) parseKeys(s string) (interface{}, gocui.Modifier) {
diff --git a/cointop/layout.go b/cointop/layout.go
index 098e562..d7a9333 100644
--- a/cointop/layout.go
+++ b/cointop/layout.go
@@ -3,7 +3,7 @@ package cointop
import (
"fmt"
- "github.com/jroimartin/gocui"
+ "github.com/miguelmota/cointop/pkg/gocui"
)
func (ct *Cointop) layout(g *gocui.Gui) error {
diff --git a/cointop/sort.go b/cointop/sort.go
index de506a6..8053340 100644
--- a/cointop/sort.go
+++ b/cointop/sort.go
@@ -1,8 +1,8 @@
package cointop
import (
- "github.com/bradfitz/slice"
- "github.com/jroimartin/gocui"
+ "github.com/miguelmota/cointop/pkg/gocui"
+ "github.com/miguelmota/cointop/pkg/slice"
)
var colorder = []string{
diff --git a/cointop/update.go b/cointop/update.go
index 049a3c9..9e81ca2 100644
--- a/cointop/update.go
+++ b/cointop/update.go
@@ -1,6 +1,6 @@
package cointop
-import "github.com/jroimartin/gocui"
+import "github.com/miguelmota/cointop/pkg/gocui"
// update update view
func (ct *Cointop) update(f func()) {
diff --git a/pkg/cache/cache.go b/pkg/cache/cache.go
new file mode 100644
index 0000000..db88d2f
--- /dev/null
+++ b/pkg/cache/cache.go
@@ -0,0 +1,1161 @@
+package cache
+
+import (
+ "encoding/gob"
+ "fmt"
+ "io"
+ "os"
+ "runtime"
+ "sync"
+ "time"
+)
+
+type Item struct {
+ Object interface{}
+ Expiration int64
+}
+
+// Returns true if the item has expired.
+func (item Item) Expired() bool {
+ if item.Expiration == 0 {
+ return false
+ }
+ return time.Now().UnixNano() > item.Expiration
+}
+
+const (
+ // For use with functions that take an expiration time.
+ NoExpiration time.Duration = -1
+ // For use with functions that take an expiration time. Equivalent to
+ // passing in the same expiration duration as was given to New() or
+ // NewFrom() when the cache was created (e.g. 5 minutes.)
+ DefaultExpiration time.Duration = 0
+)
+
+type Cache struct {
+ *cache
+ // If this is confusing, see the comment at the bottom of New()
+}
+
+type cache struct {
+ defaultExpiration time.Duration
+ items map[string]Item
+ mu sync.RWMutex
+ onEvicted func(string, interface{})
+ janitor *janitor
+}
+
+// Add an item to the cache, replacing any existing item. If the duration is 0
+// (DefaultExpiration), the cache's default expiration time is used. If it is -1
+// (NoExpiration), the item never expires.
+func (c *cache) Set(k string, x interface{}, d time.Duration) {
+ // "Inlining" of set
+ var e int64
+ if d == DefaultExpiration {
+ d = c.defaultExpiration
+ }
+ if d > 0 {
+ e = time.Now().Add(d).UnixNano()
+ }
+ c.mu.Lock()
+ c.items[k] = Item{
+ Object: x,
+ Expiration: e,
+ }
+ // TODO: Calls to mu.Unlock are currently not deferred because defer
+ // adds ~200 ns (as of go1.)
+ c.mu.Unlock()
+}
+
+func (c *cache) set(k string, x interface{}, d time.Duration) {
+ var e int64
+ if d == DefaultExpiration {
+ d = c.defaultExpiration
+ }
+ if d > 0 {
+ e = time.Now().Add(d).UnixNano()
+ }
+ c.items[k] = Item{
+ Object: x,
+ Expiration: e,
+ }
+}
+
+// Add an item to the cache, replacing any existing item, using the default
+// expiration.
+func (c *cache) SetDefault(k string, x interface{}) {
+ c.Set(k, x, DefaultExpiration)
+}
+
+// Add an item to the cache only if an item doesn't already exist for the given
+// key, or if the existing item has expired. Returns an error otherwise.
+func (c *cache) Add(k string, x interface{}, d time.Duration) error {
+ c.mu.Lock()
+ _, found := c.get(k)
+ if found {
+ c.mu.Unlock()
+ return fmt.Errorf("Item %s already exists", k)
+ }
+ c.set(k, x, d)
+ c.mu.Unlock()
+ return nil
+}
+
+// Set a new value for the cache key only if it already exists, and the existing
+// item hasn't expired. Returns an error otherwise.
+func (c *cache) Replace(k string, x interface{}, d time.Duration) error {
+ c.mu.Lock()
+ _, found := c.get(k)
+ if !found {
+ c.mu.Unlock()
+ return fmt.Errorf("Item %s doesn't exist", k)
+ }
+ c.set(k, x, d)
+ c.mu.Unlock()
+ return nil
+}
+
+// Get an item from the cache. Returns the item or nil, and a bool indicating
+// whether the key was found.
+func (c *cache) Get(k string) (interface{}, bool) {
+ c.mu.RLock()
+ // "Inlining" of get and Expired
+ item, found := c.items[k]
+ if !found {
+ c.mu.RUnlock()
+ return nil, false
+ }
+ if item.Expiration > 0 {
+ if time.Now().UnixNano() > item.Expiration {
+ c.mu.RUnlock()
+ return nil, false
+ }
+ }
+ c.mu.RUnlock()
+ return item.Object, true
+}
+
+// GetWithExpiration returns an item and its expiration time from the cache.
+// It returns the item or nil, the expiration time if one is set (if the item
+// never expires a zero value for time.Time is returned), and a bool indicating
+// whether the key was found.
+func (c *cache) GetWithExpiration(k string) (interface{}, time.Time, bool) {
+ c.mu.RLock()
+ // "Inlining" of get and Expired
+ item, found := c.items[k]
+ if !found {
+ c.mu.RUnlock()
+ return nil, time.Time{}, false
+ }
+
+ if item.Expiration > 0 {
+ if time.Now().UnixNano() > item.Expiration {
+ c.mu.RUnlock()
+ return nil, time.Time{}, false
+ }
+
+ // Return the item and the expiration time
+ c.mu.RUnlock()
+ return item.Object, time.Unix(0, item.Expiration), true
+ }
+
+ // If expiration <= 0 (i.e. no expiration time set) then return the item
+ // and a zeroed time.Time
+ c.mu.RUnlock()
+ return item.Object, time.Time{}, true
+}
+
+func (c *cache) get(k string) (interface{}, bool) {
+ item, found := c.items[k]
+ if !found {
+ return nil, false
+ }
+ // "Inlining" of Expired
+ if item.Expiration > 0 {
+ if time.Now().UnixNano() > item.Expiration {
+ return nil, false
+ }
+ }
+ return item.Object, true
+}
+
+// Increment an item of type int, int8, int16, int32, int64, uintptr, uint,
+// uint8, uint32, or uint64, float32 or float64 by n. Returns an error if the
+// item's value is not an integer, if it was not found, or if it is not
+// possible to increment it by n. To retrieve the incremented value, use one
+// of the specialized methods, e.g. IncrementInt64.
+func (c *cache) Increment(k string, n int64) error {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return fmt.Errorf("Item %s not found", k)
+ }
+ switch v.Object.(type) {
+ case int:
+ v.Object = v.Object.(int) + int(n)
+ case int8:
+ v.Object = v.Object.(int8) + int8(n)
+ case int16:
+ v.Object = v.Object.(int16) + int16(n)
+ case int32:
+ v.Object = v.Object.(int32) + int32(n)
+ case int64:
+ v.Object = v.Object.(int64) + n
+ case uint:
+ v.Object = v.Object.(uint) + uint(n)
+ case uintptr:
+ v.Object = v.Object.(uintptr) + uintptr(n)
+ case uint8:
+ v.Object = v.Object.(uint8) + uint8(n)
+ case uint16:
+ v.Object = v.Object.(uint16) + uint16(n)
+ case uint32:
+ v.Object = v.Object.(uint32) + uint32(n)
+ case uint64:
+ v.Object = v.Object.(uint64) + uint64(n)
+ case float32:
+ v.Object = v.Object.(float32) + float32(n)
+ case float64:
+ v.Object = v.Object.(float64) + float64(n)
+ default:
+ c.mu.Unlock()
+ return fmt.Errorf("The value for %s is not an integer", k)
+ }
+ c.items[k] = v
+ c.mu.Unlock()
+ return nil
+}
+
+// Increment an item of type float32 or float64 by n. Returns an error if the
+// item's value is not floating point, if it was not found, or if it is not
+// possible to increment it by n. Pass a negative number to decrement the
+// value. To retrieve the incremented value, use one of the specialized methods,
+// e.g. IncrementFloat64.
+func (c *cache) IncrementFloat(k string, n float64) error {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return fmt.Errorf("Item %s not found", k)
+ }
+ switch v.Object.(type) {
+ case float32:
+ v.Object = v.Object.(float32) + float32(n)
+ case float64:
+ v.Object = v.Object.(float64) + n
+ default:
+ c.mu.Unlock()
+ return fmt.Errorf("The value for %s does not have type float32 or float64", k)
+ }
+ c.items[k] = v
+ c.mu.Unlock()
+ return nil
+}
+
+// Increment an item of type int by n. Returns an error if the item's value is
+// not an int, or if it was not found. If there is no error, the incremented
+// value is returned.
+func (c *cache) IncrementInt(k string, n int) (int, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(int)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an int", k)
+ }
+ nv := rv + n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Increment an item of type int8 by n. Returns an error if the item's value is
+// not an int8, or if it was not found. If there is no error, the incremented
+// value is returned.
+func (c *cache) IncrementInt8(k string, n int8) (int8, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(int8)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an int8", k)
+ }
+ nv := rv + n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Increment an item of type int16 by n. Returns an error if the item's value is
+// not an int16, or if it was not found. If there is no error, the incremented
+// value is returned.
+func (c *cache) IncrementInt16(k string, n int16) (int16, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(int16)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an int16", k)
+ }
+ nv := rv + n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Increment an item of type int32 by n. Returns an error if the item's value is
+// not an int32, or if it was not found. If there is no error, the incremented
+// value is returned.
+func (c *cache) IncrementInt32(k string, n int32) (int32, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(int32)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an int32", k)
+ }
+ nv := rv + n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Increment an item of type int64 by n. Returns an error if the item's value is
+// not an int64, or if it was not found. If there is no error, the incremented
+// value is returned.
+func (c *cache) IncrementInt64(k string, n int64) (int64, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(int64)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an int64", k)
+ }
+ nv := rv + n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Increment an item of type uint by n. Returns an error if the item's value is
+// not an uint, or if it was not found. If there is no error, the incremented
+// value is returned.
+func (c *cache) IncrementUint(k string, n uint) (uint, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(uint)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an uint", k)
+ }
+ nv := rv + n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Increment an item of type uintptr by n. Returns an error if the item's value
+// is not an uintptr, or if it was not found. If there is no error, the
+// incremented value is returned.
+func (c *cache) IncrementUintptr(k string, n uintptr) (uintptr, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(uintptr)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an uintptr", k)
+ }
+ nv := rv + n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Increment an item of type uint8 by n. Returns an error if the item's value
+// is not an uint8, or if it was not found. If there is no error, the
+// incremented value is returned.
+func (c *cache) IncrementUint8(k string, n uint8) (uint8, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(uint8)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an uint8", k)
+ }
+ nv := rv + n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Increment an item of type uint16 by n. Returns an error if the item's value
+// is not an uint16, or if it was not found. If there is no error, the
+// incremented value is returned.
+func (c *cache) IncrementUint16(k string, n uint16) (uint16, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(uint16)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an uint16", k)
+ }
+ nv := rv + n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Increment an item of type uint32 by n. Returns an error if the item's value
+// is not an uint32, or if it was not found. If there is no error, the
+// incremented value is returned.
+func (c *cache) IncrementUint32(k string, n uint32) (uint32, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(uint32)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an uint32", k)
+ }
+ nv := rv + n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Increment an item of type uint64 by n. Returns an error if the item's value
+// is not an uint64, or if it was not found. If there is no error, the
+// incremented value is returned.
+func (c *cache) IncrementUint64(k string, n uint64) (uint64, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(uint64)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an uint64", k)
+ }
+ nv := rv + n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Increment an item of type float32 by n. Returns an error if the item's value
+// is not an float32, or if it was not found. If there is no error, the
+// incremented value is returned.
+func (c *cache) IncrementFloat32(k string, n float32) (float32, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(float32)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an float32", k)
+ }
+ nv := rv + n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Increment an item of type float64 by n. Returns an error if the item's value
+// is not an float64, or if it was not found. If there is no error, the
+// incremented value is returned.
+func (c *cache) IncrementFloat64(k string, n float64) (float64, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(float64)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an float64", k)
+ }
+ nv := rv + n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Decrement an item of type int, int8, int16, int32, int64, uintptr, uint,
+// uint8, uint32, or uint64, float32 or float64 by n. Returns an error if the
+// item's value is not an integer, if it was not found, or if it is not
+// possible to decrement it by n. To retrieve the decremented value, use one
+// of the specialized methods, e.g. DecrementInt64.
+func (c *cache) Decrement(k string, n int64) error {
+ // TODO: Implement Increment and Decrement more cleanly.
+ // (Cannot do Increment(k, n*-1) for uints.)
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return fmt.Errorf("Item not found")
+ }
+ switch v.Object.(type) {
+ case int:
+ v.Object = v.Object.(int) - int(n)
+ case int8:
+ v.Object = v.Object.(int8) - int8(n)
+ case int16:
+ v.Object = v.Object.(int16) - int16(n)
+ case int32:
+ v.Object = v.Object.(int32) - int32(n)
+ case int64:
+ v.Object = v.Object.(int64) - n
+ case uint:
+ v.Object = v.Object.(uint) - uint(n)
+ case uintptr:
+ v.Object = v.Object.(uintptr) - uintptr(n)
+ case uint8:
+ v.Object = v.Object.(uint8) - uint8(n)
+ case uint16:
+ v.Object = v.Object.(uint16) - uint16(n)
+ case uint32:
+ v.Object = v.Object.(uint32) - uint32(n)
+ case uint64:
+ v.Object = v.Object.(uint64) - uint64(n)
+ case float32:
+ v.Object = v.Object.(float32) - float32(n)
+ case float64:
+ v.Object = v.Object.(float64) - float64(n)
+ default:
+ c.mu.Unlock()
+ return fmt.Errorf("The value for %s is not an integer", k)
+ }
+ c.items[k] = v
+ c.mu.Unlock()
+ return nil
+}
+
+// Decrement an item of type float32 or float64 by n. Returns an error if the
+// item's value is not floating point, if it was not found, or if it is not
+// possible to decrement it by n. Pass a negative number to decrement the
+// value. To retrieve the decremented value, use one of the specialized methods,
+// e.g. DecrementFloat64.
+func (c *cache) DecrementFloat(k string, n float64) error {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return fmt.Errorf("Item %s not found", k)
+ }
+ switch v.Object.(type) {
+ case float32:
+ v.Object = v.Object.(float32) - float32(n)
+ case float64:
+ v.Object = v.Object.(float64) - n
+ default:
+ c.mu.Unlock()
+ return fmt.Errorf("The value for %s does not have type float32 or float64", k)
+ }
+ c.items[k] = v
+ c.mu.Unlock()
+ return nil
+}
+
+// Decrement an item of type int by n. Returns an error if the item's value is
+// not an int, or if it was not found. If there is no error, the decremented
+// value is returned.
+func (c *cache) DecrementInt(k string, n int) (int, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(int)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an int", k)
+ }
+ nv := rv - n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Decrement an item of type int8 by n. Returns an error if the item's value is
+// not an int8, or if it was not found. If there is no error, the decremented
+// value is returned.
+func (c *cache) DecrementInt8(k string, n int8) (int8, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(int8)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an int8", k)
+ }
+ nv := rv - n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Decrement an item of type int16 by n. Returns an error if the item's value is
+// not an int16, or if it was not found. If there is no error, the decremented
+// value is returned.
+func (c *cache) DecrementInt16(k string, n int16) (int16, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(int16)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an int16", k)
+ }
+ nv := rv - n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Decrement an item of type int32 by n. Returns an error if the item's value is
+// not an int32, or if it was not found. If there is no error, the decremented
+// value is returned.
+func (c *cache) DecrementInt32(k string, n int32) (int32, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(int32)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an int32", k)
+ }
+ nv := rv - n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Decrement an item of type int64 by n. Returns an error if the item's value is
+// not an int64, or if it was not found. If there is no error, the decremented
+// value is returned.
+func (c *cache) DecrementInt64(k string, n int64) (int64, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(int64)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an int64", k)
+ }
+ nv := rv - n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Decrement an item of type uint by n. Returns an error if the item's value is
+// not an uint, or if it was not found. If there is no error, the decremented
+// value is returned.
+func (c *cache) DecrementUint(k string, n uint) (uint, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(uint)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an uint", k)
+ }
+ nv := rv - n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Decrement an item of type uintptr by n. Returns an error if the item's value
+// is not an uintptr, or if it was not found. If there is no error, the
+// decremented value is returned.
+func (c *cache) DecrementUintptr(k string, n uintptr) (uintptr, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(uintptr)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an uintptr", k)
+ }
+ nv := rv - n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Decrement an item of type uint8 by n. Returns an error if the item's value is
+// not an uint8, or if it was not found. If there is no error, the decremented
+// value is returned.
+func (c *cache) DecrementUint8(k string, n uint8) (uint8, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(uint8)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an uint8", k)
+ }
+ nv := rv - n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Decrement an item of type uint16 by n. Returns an error if the item's value
+// is not an uint16, or if it was not found. If there is no error, the
+// decremented value is returned.
+func (c *cache) DecrementUint16(k string, n uint16) (uint16, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(uint16)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an uint16", k)
+ }
+ nv := rv - n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Decrement an item of type uint32 by n. Returns an error if the item's value
+// is not an uint32, or if it was not found. If there is no error, the
+// decremented value is returned.
+func (c *cache) DecrementUint32(k string, n uint32) (uint32, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(uint32)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an uint32", k)
+ }
+ nv := rv - n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Decrement an item of type uint64 by n. Returns an error if the item's value
+// is not an uint64, or if it was not found. If there is no error, the
+// decremented value is returned.
+func (c *cache) DecrementUint64(k string, n uint64) (uint64, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(uint64)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an uint64", k)
+ }
+ nv := rv - n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Decrement an item of type float32 by n. Returns an error if the item's value
+// is not an float32, or if it was not found. If there is no error, the
+// decremented value is returned.
+func (c *cache) DecrementFloat32(k string, n float32) (float32, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(float32)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an float32", k)
+ }
+ nv := rv - n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Decrement an item of type float64 by n. Returns an error if the item's value
+// is not an float64, or if it was not found. If there is no error, the
+// decremented value is returned.
+func (c *cache) DecrementFloat64(k string, n float64) (float64, error) {
+ c.mu.Lock()
+ v, found := c.items[k]
+ if !found || v.Expired() {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("Item %s not found", k)
+ }
+ rv, ok := v.Object.(float64)
+ if !ok {
+ c.mu.Unlock()
+ return 0, fmt.Errorf("The value for %s is not an float64", k)
+ }
+ nv := rv - n
+ v.Object = nv
+ c.items[k] = v
+ c.mu.Unlock()
+ return nv, nil
+}
+
+// Delete an item from the cache. Does nothing if the key is not in the cache.
+func (c *cache) Delete(k string) {
+ c.mu.Lock()
+ v, evicted := c.delete(k)
+ c.mu.Unlock()
+ if evicted {
+ c.onEvicted(k, v)
+ }
+}
+
+func (c *cache) delete(k string) (interface{}, bool) {
+ if c.onEvicted != nil {
+ if v, found := c.items[k]; found {
+ delete(c.items, k)
+ return v.Object, true
+ }
+ }
+ delete(c.items, k)
+ return nil, false
+}
+
+type keyAndValue struct {
+ key string
+ value interface{}
+}
+
+// Delete all expired items from the cache.
+func (c *cache) DeleteExpired() {
+ var evictedItems []keyAndValue
+ now := time.Now().UnixNano()
+ c.mu.Lock()
+ for k, v := range c.items {
+ // "Inlining" of expired
+ if v.Expiration > 0 && now > v.Expiration {
+ ov, evicted := c.delete(k)
+ if evicted {
+ evictedItems = append(evictedItems, keyAndValue{k, ov})
+ }
+ }
+ }
+ c.mu.Unlock()
+ for _, v := range evictedItems {
+ c.onEvicted(v.key, v.value)
+ }
+}
+
+// Sets an (optional) function that is called with the key and value when an
+// item is evicted from the cache. (Including when it is deleted manually, but
+// not when it is overwritten.) Set to nil to disable.
+func (c *cache) OnEvicted(f func(string, interface{})) {
+ c.mu.Lock()
+ c.onEvicted = f
+ c.mu.Unlock()
+}
+
+// Write the cache's items (using Gob) to an io.Writer.
+//
+// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
+// documentation for NewFrom().)
+func (c *cache) Save(w io.Writer) (err error) {
+ enc := gob.NewEncoder(w)
+ defer func() {
+ if x := recover(); x != nil {
+ err = fmt.Errorf("Error registering item types with Gob library")
+ }
+ }()
+ c.mu.RLock()
+ defer c.mu.RUnlock()
+ for _, v := range c.items {
+ gob.Register(v.Object)
+ }
+ err = enc.Encode(&c.items)
+ return
+}
+
+// Save the cache's items to the given filename, creating the file if it
+// doesn't exist, and overwriting it if it does.
+//
+// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
+// documentation for NewFrom().)
+func (c *cache) SaveFile(fname string) error {
+ fp, err := os.Create(fname)
+ if err != nil {
+ return err
+ }
+ err = c.Save(fp)
+ if err != nil {
+ fp.Close()
+ return err
+ }
+ return fp.Close()
+}
+
+// Add (Gob-serialized) cache items from an io.Reader, excluding any items with
+// keys that already exist (and haven't expired) in the current cache.
+//
+// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
+// documentation for NewFrom().)
+func (c *cache) Load(r io.Reader) error {
+ dec := gob.NewDecoder(r)
+ items := map[string]Item{}
+ err := dec.Decode(&items)
+ if err == nil {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ for k, v := range items {
+ ov, found := c.items[k]
+ if !found || ov.Expired() {
+ c.items[k] = v
+ }
+ }
+ }
+ return err
+}
+
+// Load and add cache items from the given filename, excluding any items with
+// keys that already exist in the current cache.
+//
+// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
+// documentation for NewFrom().)
+func (c *cache) LoadFile(fname string) error {
+ fp, err := os.Open(fname)
+ if err != nil {
+ return err
+ }
+ err = c.Load(fp)
+ if err != nil {
+ fp.Close()
+ return err
+ }
+ return fp.Close()
+}
+
+// Copies all unexpired items in the cache into a new map and returns it.
+func (c *cache) Items() map[string]Item {
+ c.mu.RLock()
+ defer c.mu.RUnlock()
+ m := make(map[string]Item, len(c.items))
+ now := time.Now().UnixNano()
+ for k, v := range c.items {
+ // "Inlining" of Expired
+ if v.Expiration > 0 {
+ if now > v.Expiration {
+ continue
+ }
+ }
+ m[k] = v
+ }
+ return m
+}
+
+// Returns the number of items in the cache. This may include items that have
+// expired, but have not yet been cleaned up.
+func (c *cache) ItemCount() int {
+ c.mu.RLock()
+ n := len(c.items)
+ c.mu.RUnlock()
+ return n
+}
+
+// Delete all items from the cache.
+func (c *cache) Flush() {
+ c.mu.Lock()
+ c.items = map[string]Item{}
+ c.mu.Unlock()
+}
+
+type janitor struct {
+ Interval time.Duration
+ stop chan bool
+}
+
+func (j *janitor) Run(c *cache) {
+ ticker := time.NewTicker(j.Interval)
+ for {
+ select {
+ case <-ticker.C:
+ c.DeleteExpired()
+ case <-j.stop:
+ ticker.Stop()
+ return
+ }
+ }
+}
+
+func stopJanitor(c *Cache) {
+ c.janitor.stop <- true
+}
+
+func runJanitor(c *cache, ci time.Duration) {
+ j := &janitor{
+ Interval: ci,
+ stop: make(chan bool),
+ }
+ c.janitor = j
+ go j.Run(c)
+}
+
+func newCache(de time.Duration, m map[string]Item) *cache {
+ if de == 0 {
+ de = -1
+ }
+ c := &cache{
+ defaultExpiration: de,
+ items: m,
+ }
+ return c
+}
+
+func newCacheWithJanitor(de time.Duration, ci time.Duration, m map[string]Item) *Cache {
+ c := newCache(de, m)
+ // This trick ensures that the janitor goroutine (which--granted it
+ // was enabled--is running DeleteExpired on c forever) does not keep
+ // the returned C object from being garbage collected. When it is
+ // garbage collected, the finalizer stops the janitor goroutine, after
+ // which c can be collected.
+ C := &Cache{c}
+ if ci > 0 {
+ runJanitor(c, ci)
+ runtime.SetFinalizer(C, stopJanitor)
+ }
+ return C
+}
+
+// Return a new cache with a given default expiration duration and cleanup
+// interval. If the expiration duration is less than one (or NoExpiration),
+// the items in the cache never expire (by default), and must be deleted
+// manually. If the cleanup interval is less than one, expired items are not
+// deleted from the cache before calling c.DeleteExpired().
+func New(defaultExpiration, cleanupInterval time.Duration) *Cache {
+ items := make(map[string]Item)
+ return newCacheWithJanitor(defaultExpiration, cleanupInterval, items)
+}
+
+// Return a new cache with a given default expiration duration and cleanup
+// interval. If the expiration duration is less than one (or NoExpiration),
+// the items in the cache never expire (by default), and must be deleted
+// manually. If the cleanup interval is less than one, expired items are not
+// deleted from the cache before calling c.DeleteExpired().
+//
+// NewFrom() also accepts an items map which will serve as the underlying map
+// for the cache. This is useful for starting from a deserialized cache
+// (serialized using e.g. gob.Encode() on c.Items()), or passing in e.g.
+// make(map[string]Item, 500) to improve startup performance when the cache
+// is expected to reach a certain minimum size.
+//
+// Only the cache's methods synchronize access to this map, so it is not
+// recommended to keep any references to the map around after creating a cache.
+// If need be, the map can be accessed at a later point using c.Items() (subject
+// to the same caveat.)
+//
+// Note regarding serialization: When using e.g. gob, make sure to
+// gob.Register() the individual types stored in the cache before encoding a
+// map retrieved with c.Items(), and to register those same types before
+// decoding a blob containing an items map.
+func NewFrom(defaultExpiration, cleanupInterval time.Duration, items map[string]Item) *Cache {
+ return newCacheWithJanitor(defaultExpiration, cleanupInterval, items)
+}
diff --git a/pkg/gocui/attribute.go b/pkg/gocui/attribute.go
new file mode 100644
index 0000000..bad758a
--- /dev/null
+++ b/pkg/gocui/attribute.go
@@ -0,0 +1,32 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gocui
+
+import "github.com/nsf/termbox-go"
+
+// Attribute represents a terminal attribute, like color, font style, etc. They
+// can be combined using bitwise OR (|). Note that it is not possible to
+// combine multiple color attributes.
+type Attribute termbox.Attribute
+
+// Color attributes.
+const (
+ ColorDefault Attribute = Attribute(termbox.ColorDefault)
+ ColorBlack = Attribute(termbox.ColorBlack)
+ ColorRed = Attribute(termbox.ColorRed)
+ ColorGreen = Attribute(termbox.ColorGreen)
+ ColorYellow = Attribute(termbox.ColorYellow)
+ ColorBlue = Attribute(termbox.ColorBlue)
+ ColorMagenta = Attribute(termbox.ColorMagenta)
+ ColorCyan = Attribute(termbox.ColorCyan)
+ ColorWhite = Attribute(termbox.ColorWhite)
+)
+
+// Text style attributes.
+const (
+ AttrBold Attribute = Attribute(termbox.AttrBold)
+ AttrUnderline = Attribute(termbox.AttrUnderline)
+ AttrReverse = Attribute(termbox.AttrReverse)
+)
diff --git a/pkg/gocui/edit.go b/pkg/gocui/edit.go
new file mode 100644
index 0000000..e1b19c2
--- /dev/null
+++ b/pkg/gocui/edit.go
@@ -0,0 +1,344 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gocui
+
+import "errors"
+
+const maxInt = int(^uint(0) >> 1)
+
+// Editor interface must be satisfied by gocui editors.
+type Editor interface {
+ Edit(v *View, key Key, ch rune, mod Modifier)
+}
+
+// The EditorFunc type is an adapter to allow the use of ordinary functions as
+// Editors. If f is a function with the appropriate signature, EditorFunc(f)
+// is an Editor object that calls f.
+type EditorFunc func(v *View, key Key, ch rune, mod Modifier)
+
+// Edit calls f(v, key, ch, mod)
+func (f EditorFunc) Edit(v *View, key Key, ch rune, mod Modifier) {
+ f(v, key, ch, mod)
+}
+
+// DefaultEditor is the default editor.
+var DefaultEditor Editor = EditorFunc(simpleEditor)
+
+// simpleEditor is used as the default gocui editor.
+func simpleEditor(v *View, key Key, ch rune, mod Modifier) {
+ switch {
+ case ch != 0 && mod == 0:
+ v.EditWrite(ch)
+ case key == KeySpace:
+ v.EditWrite(' ')
+ case key == KeyBackspace || key == KeyBackspace2:
+ v.EditDelete(true)
+ case key == KeyDelete:
+ v.EditDelete(false)
+ case key == KeyInsert:
+ v.Overwrite = !v.Overwrite
+ case key == KeyEnter:
+ v.EditNewLine()
+ case key == KeyArrowDown:
+ v.MoveCursor(0, 1, false)
+ case key == KeyArrowUp:
+ v.MoveCursor(0, -1, false)
+ case key == KeyArrowLeft:
+ v.MoveCursor(-1, 0, false)
+ case key == KeyArrowRight:
+ v.MoveCursor(1, 0, false)
+ }
+}
+
+// EditWrite writes a rune at the cursor position.
+func (v *View) EditWrite(ch rune) {
+ v.writeRune(v.cx, v.cy, ch)
+ v.MoveCursor(1, 0, true)
+}
+
+// EditDelete deletes a rune at the cursor position. back determines the
+// direction.
+func (v *View) EditDelete(back bool) {
+ x, y := v.ox+v.cx, v.oy+v.cy
+ if y < 0 {
+ return
+ } else if y >= len(v.viewLines) {
+ v.MoveCursor(-1, 0, true)
+ return
+ }
+
+ maxX, _ := v.Size()
+ if back {
+ if x == 0 { // start of the line
+ if y < 1 {
+ return
+ }
+
+ var maxPrevWidth int
+ if v.Wrap {
+ maxPrevWidth = maxX
+ } else {
+ maxPrevWidth = maxInt
+ }
+
+ if v.viewLines[y].linesX == 0 { // regular line
+ v.mergeLines(v.cy - 1)
+ if len(v.viewLines[y-1].line) < maxPrevWidth {
+ v.MoveCursor(-1, 0, true)
+ }
+ } else { // wrapped line
+ v.deleteRune(len(v.viewLines[y-1].line)-1, v.cy-1)
+ v.MoveCursor(-1, 0, true)
+ }
+ } else { // middle/end of the line
+ v.deleteRune(v.cx-1, v.cy)
+ v.MoveCursor(-1, 0, true)
+ }
+ } else {
+ if x == len(v.viewLines[y].line) { // end of the line
+ v.mergeLines(v.cy)
+ } else { // start/middle of the line
+ v.deleteRune(v.cx, v.cy)
+ }
+ }
+}
+
+// EditNewLine inserts a new line under the cursor.
+func (v *View) EditNewLine() {
+ v.breakLine(v.cx, v.cy)
+ v.ox = 0
+ v.cx = 0
+ v.MoveCursor(0, 1, true)
+}
+
+// MoveCursor moves the cursor taking into account the width of the line/view,
+// displacing the origin if necessary.
+func (v *View) MoveCursor(dx, dy int, writeMode bool) {
+ maxX, maxY := v.Size()
+ cx, cy := v.cx+dx, v.cy+dy
+ x, y := v.ox+cx, v.oy+cy
+
+ var curLineWidth, prevLineWidth int
+ // get the width of the current line
+ if writeMode {
+ if v.Wrap {
+ curLineWidth = maxX - 1
+ } else {
+ curLineWidth = maxInt
+ }
+ } else {
+ if y >= 0 && y < len(v.viewLines) {
+ curLineWidth = len(v.viewLines[y].line)
+ if v.Wrap && curLineWidth >= maxX {
+ curLineWidth = maxX - 1
+ }
+ } else {
+ curLineWidth = 0
+ }
+ }
+ // get the width of the previous line
+ if y-1 >= 0 && y-1 < len(v.viewLines) {
+ prevLineWidth = len(v.viewLines[y-1].line)
+ } else {
+ prevLineWidth = 0
+ }
+
+ // adjust cursor's x position and view's x origin
+ if x > curLineWidth { // move to next line
+ if dx > 0 { // horizontal movement
+ cy++
+ if writeMode || v.oy+cy < len(v.viewLines) {
+ if !v.Wrap {
+ v.ox = 0
+ }
+ v.cx = 0
+ }
+ } else { // vertical movement
+ if curLineWidth > 0 { // move cursor to the EOL
+ if v.Wrap {
+ v.cx = curLineWidth
+ } else {
+ ncx := curLineWidth - v.ox
+ if ncx < 0 {
+ v.ox += ncx
+ if v.ox < 0 {
+ v.ox = 0
+ }
+ v.cx = 0
+ } else {
+ v.cx = ncx
+ }
+ }
+ } else {
+ if writeMode || v.oy+cy < len(v.viewLines) {
+ if !v.Wrap {
+ v.ox = 0
+ }
+ v.cx = 0
+ }
+ }
+ }
+ } else if cx < 0 {
+ if !v.Wrap && v.ox > 0 { // move origin to the left
+ v.ox += cx
+ v.cx = 0
+ } else { // move to previous line
+ cy--
+ if prevLineWidth > 0 {
+ if !v.Wrap { // set origin so the EOL is visible
+ nox := prevLineWidth - maxX + 1
+ if nox < 0 {
+ v.ox = 0
+ } else {
+ v.ox = nox
+ }
+ }
+ v.cx = prevLineWidth
+ } else {
+ if !v.Wrap {
+ v.ox = 0
+ }
+ v.cx = 0
+ }
+ }
+ } else { // stay on the same line
+ if v.Wrap {
+ v.cx = cx
+ } else {
+ if cx >= maxX {
+ v.ox += cx - maxX + 1
+ v.cx = maxX
+ } else {
+ v.cx = cx
+ }
+ }
+ }
+
+ // adjust cursor's y position and view's y origin
+ if cy < 0 {
+ if v.oy > 0 {
+ v.oy--
+ }
+ } else if writeMode || v.oy+cy < len(v.viewLines) {
+ if cy >= maxY {
+ v.oy++
+ } else {
+ v.cy = cy
+ }
+ }
+}
+
+// writeRune writes a rune into the view's internal buffer, at the
+// position corresponding to the point (x, y). The length of the internal
+// buffer is increased if the point is out of bounds. Overwrite mode is
+// governed by the value of View.overwrite.
+func (v *View) writeRune(x, y int, ch rune) error {
+ v.tainted = true
+
+ x, y, err := v.realPosition(x, y)
+ if err != nil {
+ return err
+ }
+
+ if x < 0 || y < 0 {
+ return errors.New("invalid point")
+ }
+
+ if y >= len(v.lines) {
+ s := make([][]cell, y-len(v.lines)+1)
+ v.lines = append(v.lines, s...)
+ }
+
+ olen := len(v.lines[y])
+
+ var s []cell
+ if x >= len(v.lines[y]) {
+ s = make([]cell, x-len(v.lines[y])+1)
+ } else if !v.Overwrite {
+ s = make([]cell, 1)
+ }
+ v.lines[y] = append(v.lines[y], s...)
+
+ if !v.Overwrite || (v.Overwrite && x >= olen-1) {
+ copy(v.lines[y][x+1:], v.lines[y][x:])
+ }
+ v.lines[y][x] = cell{
+ fgColor: v.FgColor,
+ bgColor: v.BgColor,
+ chr: ch,
+ }
+
+ return nil
+}
+
+// deleteRune removes a rune from the view's internal buffer, at the
+// position corresponding to the point (x, y).
+func (v *View) deleteRune(x, y int) error {
+ v.tainted = true
+
+ x, y, err := v.realPosition(x, y)
+ if err != nil {
+ return err
+ }
+
+ if x < 0 || y < 0 || y >= len(v.lines) || x >= len(v.lines[y]) {
+ return errors.New("invalid point")
+ }
+ v.lines[y] = append(v.lines[y][:x], v.lines[y][x+1:]...)
+ return nil
+}
+
+// mergeLines merges the lines "y" and "y+1" if possible.
+func (v *View) mergeLines(y int) error {
+ v.tainted = true
+
+ _, y, err := v.realPosition(0, y)
+ if err != nil {
+ return err
+ }
+
+ if y < 0 || y >= len(v.lines) {
+ return errors.New("invalid point")
+ }
+
+ if y < len(v.lines)-1 { // otherwise we don't need to merge anything
+ v.lines[y] = append(v.lines[y], v.lines[y+1]...)
+ v.lines = append(v.lines[:y+1], v.lines[y+2:]...)
+ }
+ return nil
+}
+
+// breakLine breaks a line of the internal buffer at the position corresponding
+// to the point (x, y).
+func (v *View) breakLine(x, y int) error {
+ v.tainted = true
+
+ x, y, err := v.realPosition(x, y)
+ if err != nil {
+ return err
+ }
+
+ if y < 0 || y >= len(v.lines) {
+ return errors.New("invalid point")
+ }
+
+ var left, right []cell
+ if x < len(v.lines[y]) { // break line
+ left = make([]cell, len(v.lines[y][:x]))
+ copy(left, v.lines[y][:x])
+ right = make([]cell, len(v.lines[y][x:]))
+ copy(right, v.lines[y][x:])
+ } else { // new empty line
+ left = v.lines[y]
+ }
+
+ lines := make([][]cell, len(v.lines)+1)
+ lines[y] = left
+ lines[y+1] = right
+ copy(lines, v.lines[:y])
+ copy(lines[y+2:], v.lines[y+1:])
+ v.lines = lines
+ return nil
+}
diff --git a/pkg/gocui/escape.go b/pkg/gocui/escape.go
new file mode 100644
index 0000000..ec31bbe
--- /dev/null
+++ b/pkg/gocui/escape.go
@@ -0,0 +1,229 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gocui
+
+import (
+ "errors"
+ "strconv"
+)
+
+type escapeInterpreter struct {
+ state escapeState
+ curch rune
+ csiParam []string
+ curFgColor, curBgColor Attribute
+ mode OutputMode
+}
+
+type escapeState int
+
+const (
+ stateNone escapeState = iota
+ stateEscape
+ stateCSI
+ stateParams
+)
+
+var (
+ errNotCSI = errors.New("Not a CSI escape sequence")
+ errCSIParseError = errors.New("CSI escape sequence parsing error")
+ errCSITooLong = errors.New("CSI escape sequence is too long")
+)
+
+// runes in case of error will output the non-parsed runes as a string.
+func (ei *escapeInterpreter) runes() []rune {
+ switch ei.state {
+ case stateNone:
+ return []rune{0x1b}
+ case stateEscape:
+ return []rune{0x1b, ei.curch}
+ case stateCSI:
+ return []rune{0x1b, '[', ei.curch}
+ case stateParams:
+ ret := []rune{0x1b, '['}
+ for _, s := range ei.csiParam {
+ ret = append(ret, []rune(s)...)
+ ret = append(ret, ';')
+ }
+ return append(ret, ei.curch)
+ }
+ return nil
+}
+
+// newEscapeInterpreter returns an escapeInterpreter that will be able to parse
+// terminal escape sequences.
+func newEscapeInterpreter(mode OutputMode) *escapeInterpreter {
+ ei := &escapeInterpreter{
+ state: stateNone,
+ curFgColor: ColorDefault,
+ curBgColor: ColorDefault,
+ mode: mode,
+ }
+ return ei
+}
+
+// reset sets the escapeInterpreter in initial state.
+func (ei *escapeInterpreter) reset() {
+ ei.state = stateNone
+ ei.curFgColor = ColorDefault
+ ei.curBgColor = ColorDefault
+ ei.csiParam = nil
+}
+
+// parseOne parses a rune. If isEscape is true, it means that the rune is part
+// of an escape sequence, and as such should not be printed verbatim. Otherwise,
+// it's not an escape sequence.
+func (ei *escapeInterpreter) parseOne(ch rune) (isEscape bool, err error) {
+ // Sanity checks
+ if len(ei.csiParam) > 20 {
+ return false, errCSITooLong
+ }
+ if len(ei.csiParam) > 0 && len(ei.csiParam[len(ei.csiParam)-1]) > 255 {
+ return false, errCSITooLong
+ }
+
+ ei.curch = ch
+
+ switch ei.state {
+ case stateNone:
+ if ch == 0x1b {
+ ei.state = stateEscape
+ return true, nil
+ }
+ return false, nil
+ case stateEscape:
+ if ch == '[' {
+ ei.state = stateCSI
+ return true, nil
+ }
+ return false, errNotCSI
+ case stateCSI:
+ switch {
+ case ch >= '0' && ch <= '9':
+ ei.csiParam = append(ei.csiParam, "")
+ case ch == 'm':
+ ei.csiParam = append(ei.csiParam, "0")
+ default:
+ return false, errCSIParseError
+ }
+ ei.state = stateParams
+ fallthrough
+ case stateParams:
+ switch {
+ case ch >= '0' && ch <= '9':
+ ei.csiParam[len(ei.csiParam)-1] += string(ch)
+ return true, nil
+ case ch == ';':
+ ei.csiParam = append(ei.csiParam, "")
+ return true, nil
+ case ch == 'm':
+ var err error
+ switch ei.mode {
+ case OutputNormal:
+ err = ei.outputNormal()
+ case Output256:
+ err = ei.output256()
+ }
+ if err != nil {
+ return false, errCSIParseError
+ }
+
+ ei.state = stateNone
+ ei.csiParam = nil
+ return true, nil
+ default:
+ return false, errCSIParseError
+ }
+ }
+ return false, nil
+}
+
+// outputNormal provides 8 different colors:
+// black, red, green, yellow, blue, magenta, cyan, white
+func (ei *escapeInterpreter) outputNormal() error {
+ for _, param := range ei.csiParam {
+ p, err := strconv.Atoi(param)
+ if err != nil {
+ return errCSIParseError
+ }
+
+ switch {
+ case p >= 30 && p <= 37:
+ ei.curFgColor = Attribute(p - 30 + 1)
+ case p == 39:
+ ei.curFgColor = ColorDefault
+ case p >= 40 && p <= 47:
+ ei.curBgColor = Attribute(p - 40 + 1)
+ case p == 49:
+ ei.curBgColor = ColorDefault
+ case p == 1:
+ ei.curFgColor |= AttrBold
+ case p == 4:
+ ei.curFgColor |= AttrUnderline
+ case p == 7:
+ ei.curFgColor |= AttrReverse
+ case p == 0:
+ ei.curFgColor = ColorDefault
+ ei.curBgColor = ColorDefault
+ }
+ }
+
+ return nil
+}
+
+// output256 allows you to leverage the 256-colors terminal mode:
+// 0x01 - 0x08: the 8 colors as in OutputNormal
+// 0x09 - 0x10: Color* | AttrBold
+// 0x11 - 0xe8: 216 different colors
+// 0xe9 - 0x1ff: 24 different shades of grey
+func (ei *escapeInterpreter) output256() error {
+ if len(ei.csiParam) < 3 {
+ return ei.outputNormal()
+ }
+
+ mode, err := strconv.Atoi(ei.csiParam[1])
+ if err != nil {
+ return errCSIParseError
+ }
+ if mode != 5 {
+ return ei.outputNormal()
+ }
+
+ fgbg, err := strconv.Atoi(ei.csiParam[0])
+ if err != nil {
+ return errCSIParseError
+ }
+ color, err := strconv.Atoi(ei.csiParam[2])
+ if err != nil {
+ return errCSIParseError
+ }
+
+ switch fgbg {
+ case 38:
+ ei.curFgColor = Attribute(color + 1)
+
+ for _, param := range ei.csiParam[3:] {
+ p, err := strconv.Atoi(param)
+ if err != nil {
+ return errCSIParseError
+ }
+
+ switch {
+ case p == 1:
+ ei.curFgColor |= AttrBold
+ case p == 4:
+ ei.curFgColor |= AttrUnderline
+ case p == 7:
+ ei.curFgColor |= AttrReverse
+ }
+ }
+ case 48:
+ ei.curBgColor = Attribute(color + 1)
+ default:
+ return errCSIParseError
+ }
+
+ return nil
+}
diff --git a/pkg/gocui/gocui.go b/pkg/gocui/gocui.go
new file mode 100644
index 0000000..9499d3c
--- /dev/null
+++ b/pkg/gocui/gocui.go
@@ -0,0 +1,636 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gocui
+
+import (
+ "errors"
+
+ "github.com/nsf/termbox-go"
+)
+
+var (
+ // ErrQuit is used to decide if the MainLoop finished successfully.
+ ErrQuit = errors.New("quit")
+
+ // ErrUnknownView allows to assert if a View must be initialized.
+ ErrUnknownView = errors.New("unknown view")
+)
+
+// OutputMode represents the terminal's output mode (8 or 256 colors).
+type OutputMode termbox.OutputMode
+
+const (
+ // OutputNormal provides 8-colors terminal mode.
+ OutputNormal = OutputMode(termbox.OutputNormal)
+
+ // Output256 provides 256-colors terminal mode.
+ Output256 = OutputMode(termbox.Output256)
+)
+
+// Gui represents the whole User Interface, including the views, layouts
+// and keybindings.
+type Gui struct {
+ tbEvents chan termbox.Event
+ userEvents chan userEvent
+ views []*View
+ currentView *View
+ managers []Manager
+ keybindings []*keybinding
+ maxX, maxY int
+ outputMode OutputMode
+
+ // BgColor and FgColor allow to configure the background and foreground
+ // colors of the GUI.
+ BgColor, FgColor Attribute
+
+ // SelBgColor and SelFgColor allow to configure the background and
+ // foreground colors of the frame of the current view.
+ SelBgColor, SelFgColor Attribute
+
+ // If Highlight is true, Sel{Bg,Fg}Colors will be used to draw the
+ // frame of the current view.
+ Highlight bool
+
+ // If Cursor is true then the cursor is enabled.
+ Cursor bool
+
+ // If Mouse is true then mouse events will be enabled.
+ Mouse bool
+
+ // If InputEsc is true, when ESC sequence is in the buffer and it doesn't
+ // match any known sequence, ESC means KeyEsc.
+ InputEsc bool
+
+ // If ASCII is true then use ASCII instead of unicode to draw the
+ // interface. Using ASCII is more portable.
+ ASCII bool
+}
+
+// NewGui returns a new Gui object with a given output mode.
+func NewGui(mode OutputMode) (*Gui, error) {
+ if err := termbox.Init(); err != nil {
+ return nil, err
+ }
+
+ g := &Gui{}
+
+ g.outputMode = mode
+ termbox.SetOutputMode(termbox.OutputMode(mode))
+
+ g.tbEvents = make(chan termbox.Event, 20)
+ g.userEvents = make(chan userEvent, 20)
+
+ g.maxX, g.maxY = termbox.Size()
+
+ g.BgColor, g.FgColor = ColorDefault, ColorDefault
+ g.SelBgColor, g.SelFgColor = ColorDefault, ColorDefault
+
+ return g, nil
+}
+
+// Close finalizes the library. It should be called after a successful
+// initialization and when gocui is not needed anymore.
+func (g *Gui) Close() {
+ termbox.Close()
+}
+
+// Size returns the terminal's size.
+func (g *Gui) Size() (x, y int) {
+ return g.maxX, g.maxY
+}
+
+// SetRune writes a rune at the given point, relative to the top-left
+// corner of the terminal. It checks if the position is valid and applies
+// the given colors.
+func (g *Gui) SetRune(x, y int, ch rune, fgColor, bgColor Attribute) error {
+ if x < 0 || y < 0 || x >= g.maxX || y >= g.maxY {
+ return errors.New("invalid point")
+ }
+ termbox.SetCell(x, y, ch, termbox.Attribute(fgColor), termbox.Attribute(bgColor))
+ return nil
+}
+
+// Rune returns the rune contained in the cell at the given position.
+// It checks if the position is valid.
+func (g *Gui) Rune(x, y int) (rune, error) {
+ if x < 0 || y < 0 || x >= g.maxX || y >= g.maxY {
+ return ' ', errors.New("invalid point")
+ }
+ c := termbox.CellBuffer()[y*g.maxX+x]
+ return c.Ch, nil
+}
+
+// SetView creates a new view with its top-left corner at (x0, y0)
+// and the bottom-right one at (x1, y1). If a view with the same name
+// already exists, its dimensions are updated; otherwise, the error
+// ErrUnknownView is returned, which allows to assert if the View must
+// be initialized. It checks if the position is valid.
+func (g *Gui) SetView(name string, x0, y0, x1, y1 int) (*View, error) {
+ if x0 >= x1 || y0 >= y1 {
+ return nil, errors.New("invalid dimensions")
+ }
+ if name == "" {
+ return nil, errors.New("invalid name")
+ }
+
+ if v, err := g.View(name); err == nil {
+ v.x0 = x0
+ v.y0 = y0
+ v.x1 = x1
+ v.y1 = y1
+ v.tainted = true
+ return v, nil
+ }
+
+ v := newView(name, x0, y0, x1, y1, g.outputMode)
+ v.BgColor, v.FgColor = g.BgColor, g.FgColor
+ v.SelBgColor, v.SelFgColor = g.SelBgColor, g.SelFgColor
+ g.views = append(g.views, v)
+ return v, ErrUnknownView
+}
+
+// SetViewOnTop sets the given view on top of the existing ones.
+func (g *Gui) SetViewOnTop(name string) (*View, error) {
+ for i, v := range g.views {
+ if v.name == name {
+ s := append(g.views[:i], g.views[i+1:]...)
+ g.views = append(s, v)
+ return v, nil
+ }
+ }
+ return nil, ErrUnknownView
+}
+
+// SetViewOnBottom sets the given view on bottom of the existing ones.
+func (g *Gui) SetViewOnBottom(name string) (*View, error) {
+ for i, v := range g.views {
+ if v.name == name {
+ s := append(g.views[:i], g.views[i+1:]...)
+ g.views = append([]*View{v}, s...)
+ return v, nil
+ }
+ }
+ return nil, ErrUnknownView
+}
+
+// Views returns all the views in the GUI.
+func (g *Gui) Views() []*View {
+ return g.views
+}
+
+// View returns a pointer to the view with the given name, or error
+// ErrUnknownView if a view with that name does not exist.
+func (g *Gui) View(name string) (*View, error) {
+ for _, v := range g.views {
+ if v.name == name {
+ return v, nil
+ }
+ }
+ return nil, ErrUnknownView
+}
+
+// ViewByPosition returns a pointer to a view matching the given position, or
+// error ErrUnknownView if a view in that position does not exist.
+func (g *Gui) ViewByPosition(x, y int) (*View, error) {
+ // traverse views in reverse order checking top views first
+ for i := len(g.views); i > 0; i-- {
+ v := g.views[i-1]
+ if x > v.x0 && x < v.x1 && y > v.y0 && y < v.y1 {
+ return v, nil
+ }
+ }
+ return nil, ErrUnknownView
+}
+
+// ViewPosition returns the coordinates of the view with the given name, or
+// error ErrUnknownView if a view with that name does not exist.
+func (g *Gui) ViewPosition(name string) (x0, y0, x1, y1 int, err error) {
+ for _, v := range g.views {
+ if v.name == name {
+ return v.x0, v.y0, v.x1, v.y1, nil
+ }
+ }
+ return 0, 0, 0, 0, ErrUnknownView
+}
+
+// DeleteView deletes a view by name.
+func (g *Gui) DeleteView(name string) error {
+ for i, v := range g.views {
+ if v.name == name {
+ g.views = append(g.views[:i], g.views[i+1:]...)
+ return nil
+ }
+ }
+ return ErrUnknownView
+}
+
+// SetCurrentView gives the focus to a given view.
+func (g *Gui) SetCurrentView(name string) (*View, error) {
+ for _, v := range g.views {
+ if v.name == name {
+ g.currentView = v
+ return v, nil
+ }
+ }
+ return nil, ErrUnknownView
+}
+
+// CurrentView returns the currently focused view, or nil if no view
+// owns the focus.
+func (g *Gui) CurrentView() *View {
+ return g.currentView
+}
+
+// SetKeybinding creates a new keybinding. If viewname equals to ""
+// (empty string) then the keybinding will apply to all views. key must
+// be a rune or a Key.
+func (g *Gui) SetKeybinding(viewname string, key interface{}, mod Modifier, handler func(*Gui, *View) error) error {
+ var kb *keybinding
+
+ k, ch, err := getKey(key)
+ if err != nil {
+ return err
+ }
+ kb = newKeybinding(viewname, k, ch, mod, handler)
+ g.keybindings = append(g.keybindings, kb)
+ return nil
+}
+
+// DeleteKeybinding deletes a keybinding.
+func (g *Gui) DeleteKeybinding(viewname string, key interface{}, mod Modifier) error {
+ k, ch, err := getKey(key)
+ if err != nil {
+ return err
+ }
+
+ for i, kb := range g.keybindings {
+ if kb.viewName == viewname && kb.ch == ch && kb.key == k && kb.mod == mod {
+ g.keybindings = append(g.keybindings[:i], g.keybindings[i+1:]...)
+ return nil
+ }
+ }
+ return errors.New("keybinding not found")
+}
+
+// DeleteKeybindings deletes all keybindings of view.
+func (g *Gui) DeleteKeybindings(viewname string) {
+ var s []*keybinding
+ for _, kb := range g.keybindings {
+ if kb.viewName != viewname {
+ s = append(s, kb)
+ }
+ }
+ g.keybindings = s
+}
+
+// getKey takes an empty interface with a key and returns the corresponding
+// typed Key or rune.
+func getKey(key interface{}) (Key, rune, error) {
+ switch t := key.(type) {
+ case Key:
+ return t, 0, nil
+ case rune:
+ return 0, t, nil
+ default:
+ return 0, 0, errors.New("unknown type")
+ }
+}
+
+// userEvent represents an event triggered by the user.
+type userEvent struct {
+ f func(*Gui) error
+}
+
+// Update executes the passed function. This method can be called safely from a
+// goroutine in order to update the GUI. It is important to note that the
+// passed function won't be executed immediately, instead it will be added to
+// the user events queue. Given that Update spawns a goroutine, the order in
+// which the user events will be handled is not guaranteed.
+func (g *Gui) Update(f func(*Gui) error) {
+ go func() { g.userEvents <- userEvent{f: f} }()
+}
+
+// A Manager is in charge of GUI's layout and can be used to build widgets.
+type Manager interface {
+ // Layout is called every time the GUI is redrawn, it must contain the
+ // base views and its initializations.
+ Layout(*Gui) error
+}
+
+// The ManagerFunc type is an adapter to allow the use of ordinary functions as
+// Managers. If f is a function with the appropriate signature, ManagerFunc(f)
+// is an Manager object that calls f.
+type ManagerFunc func(*Gui) error
+
+// Layout calls f(g)
+func (f ManagerFunc) Layout(g *Gui) error {
+ return f(g)
+}
+
+// SetManager sets the given GUI managers. It deletes all views and
+// keybindings.
+func (g *Gui) SetManager(managers ...Manager) {
+ g.managers = managers
+ g.currentView = nil
+ g.views = nil
+ g.keybindings = nil
+
+ go func() { g.tbEvents <- termbox.Event{Type: termbox.EventResize} }()
+}
+
+// SetManagerFunc sets the given manager function. It deletes all views and
+// keybindings.
+func (g *Gui) SetManagerFunc(manager func(*Gui) error) {
+ g.SetManager(ManagerFunc(manager))
+}
+
+// MainLoop runs the main loop until an error is returned. A successful
+// finish should return ErrQuit.
+func (g *Gui) MainLoop() error {
+ go func() {
+ for {
+ g.tbEvents <- termbox.PollEvent()
+ }
+ }()
+
+ inputMode := termbox.InputAlt
+ if g.InputEsc {
+ inputMode = termbox.InputEsc
+ }
+ if g.Mouse {
+ inputMode |= termbox.InputMouse
+ }
+ termbox.SetInputMode(inputMode)
+
+ if err := g.flush(); err != nil {
+ return err
+ }
+ for {
+ select {
+ case ev := <-g.tbEvents:
+ if err := g.handleEvent(&ev); err != nil {
+ return err
+ }
+ case ev := <-g.userEvents:
+ if err := ev.f(g); err != nil {
+ return err
+ }
+ }
+ if err := g.consumeevents(); err != nil {
+ return err
+ }
+ if err := g.flush(); err != nil {
+ return err
+ }
+ }
+}
+
+// consumeevents handles the remaining events in the events pool.
+func (g *Gui) consumeevents() error {
+ for {
+ select {
+ case ev := <-g.tbEvents:
+ if err := g.handleEvent(&ev); err != nil {
+ return err
+ }
+ case ev := <-g.userEvents:
+ if err := ev.f(g); err != nil {
+ return err
+ }
+ default:
+ return nil
+ }
+ }
+}
+
+// handleEvent handles an event, based on its type (key-press, error,
+// etc.)
+func (g *Gui) handleEvent(ev *termbox.Event) error {
+ switch ev.Type {
+ case termbox.EventKey, termbox.EventMouse:
+ return g.onKey(ev)
+ case termbox.EventError:
+ return ev.Err
+ default:
+ return nil
+ }
+}
+
+// flush updates the gui, re-drawing frames and buffers.
+func (g *Gui) flush() error {
+ termbox.Clear(termbox.Attribute(g.FgColor), termbox.Attribute(g.BgColor))
+
+ maxX, maxY := termbox.Size()
+ // if GUI's size has changed, we need to redraw all views
+ if maxX != g.maxX || maxY != g.maxY {
+ for _, v := range g.views {
+ v.tainted = true
+ }
+ }
+ g.maxX, g.maxY = maxX, maxY
+
+ for _, m := range g.managers {
+ if err := m.Layout(g); err != nil {
+ return err
+ }
+ }
+ for _, v := range g.views {
+ if v.Frame {
+ var fgColor, bgColor Attribute
+ if g.Highlight && v == g.currentView {
+ fgColor = g.SelFgColor
+ bgColor = g.SelBgColor
+ } else {
+ fgColor = g.FgColor
+ bgColor = g.BgColor
+ }
+
+ if err := g.drawFrameEdges(v, fgColor, bgColor); err != nil {
+ return err
+ }
+ if err := g.drawFrameCorners(v, fgColor, bgColor); err != nil {
+ return err
+ }
+ if v.Title != "" {
+ if err := g.drawTitle(v, fgColor, bgColor); err != nil {
+ return err
+ }
+ }
+ }
+ if err := g.draw(v); err != nil {
+ return err
+ }
+ }
+ termbox.Flush()
+ return nil
+}
+
+// drawFrameEdges draws the horizontal and vertical edges of a view.
+func (g *Gui) drawFrameEdges(v *View, fgColor, bgColor Attribute) error {
+ runeH, runeV := '─', '│'
+ if g.ASCII {
+ runeH, runeV = '-', '|'
+ }
+
+ for x := v.x0 + 1; x < v.x1 && x < g.maxX; x++ {
+ if x < 0 {
+ continue
+ }
+ if v.y0 > -1 && v.y0 < g.maxY {
+ if err := g.SetRune(x, v.y0, runeH, fgColor, bgColor); err != nil {
+ return err
+ }
+ }
+ if v.y1 > -1 && v.y1 < g.maxY {
+ if err := g.SetRune(x, v.y1, runeH, fgColor, bgColor); err != nil {
+ return err
+ }
+ }
+ }
+ for y := v.y0 + 1; y < v.y1 && y < g.maxY; y++ {
+ if y < 0 {
+ continue
+ }
+ if v.x0 > -1 && v.x0 < g.maxX {
+ if err := g.SetRune(v.x0, y, runeV, fgColor, bgColor); err != nil {
+ return err
+ }
+ }
+ if v.x1 > -1 && v.x1 < g.maxX {
+ if err := g.SetRune(v.x1, y, runeV, fgColor, bgColor); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+// drawFrameCorners draws the corners of the view.
+func (g *Gui) drawFrameCorners(v *View, fgColor, bgColor Attribute) error {
+ runeTL, runeTR, runeBL, runeBR := '┌', '┐', '└', '┘'
+ if g.ASCII {
+ runeTL, runeTR, runeBL, runeBR = '+', '+', '+', '+'
+ }
+
+ corners := []struct {
+ x, y int
+ ch rune
+ }{{v.x0, v.y0, runeTL}, {v.x1, v.y0, runeTR}, {v.x0, v.y1, runeBL}, {v.x1, v.y1, runeBR}}
+
+ for _, c := range corners {
+ if c.x >= 0 && c.y >= 0 && c.x < g.maxX && c.y < g.maxY {
+ if err := g.SetRune(c.x, c.y, c.ch, fgColor, bgColor); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+// drawTitle draws the title of the view.
+func (g *Gui) drawTitle(v *View, fgColor, bgColor Attribute) error {
+ if v.y0 < 0 || v.y0 >= g.maxY {
+ return nil
+ }
+
+ for i, ch := range v.Title {
+ x := v.x0 + i + 2
+ if x < 0 {
+ continue
+ } else if x > v.x1-2 || x >= g.maxX {
+ break
+ }
+ if err := g.SetRune(x, v.y0, ch, fgColor, bgColor); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// draw manages the cursor and calls the draw function of a view.
+func (g *Gui) draw(v *View) error {
+ if g.Cursor {
+ if curview := g.currentView; curview != nil {
+ vMaxX, vMaxY := curview.Size()
+ if curview.cx < 0 {
+ curview.cx = 0
+ } else if curview.cx >= vMaxX {
+ curview.cx = vMaxX - 1
+ }
+ if curview.cy < 0 {
+ curview.cy = 0
+ } else if curview.cy >= vMaxY {
+ curview.cy = vMaxY - 1
+ }
+
+ gMaxX, gMaxY := g.Size()
+ cx, cy := curview.x0+curview.cx+1, curview.y0+curview.cy+1
+ if cx >= 0 && cx < gMaxX && cy >= 0 && cy < gMaxY {
+ termbox.SetCursor(cx, cy)
+ } else {
+ termbox.HideCursor()
+ }
+ }
+ } else {
+ termbox.HideCursor()
+ }
+
+ v.clearRunes()
+ if err := v.draw(); err != nil {
+ return err
+ }
+ return nil
+}
+
+// onKey manages key-press events. A keybinding handler is called when
+// a key-press or mouse event satisfies a configured keybinding. Furthermore,
+// currentView's internal buffer is modified if currentView.Editable is true.
+func (g *Gui) onKey(ev *termbox.Event) error {
+ switch ev.Type {
+ case termbox.EventKey:
+ matched, err := g.execKeybindings(g.currentView, ev)
+ if err != nil {
+ return err
+ }
+ if matched {
+ break
+ }
+ if g.currentView != nil && g.currentView.Editable && g.currentView.Editor != nil {
+ g.currentView.Editor.Edit(g.currentView, Key(ev.Key), ev.Ch, Modifier(ev.Mod))
+ }
+ case termbox.EventMouse:
+ mx, my := ev.MouseX, ev.MouseY
+ v, err := g.ViewByPosition(mx, my)
+ if err != nil {
+ break
+ }
+ if err := v.SetCursor(mx-v.x0-1, my-v.y0-1); err != nil {
+ return err
+ }
+ if _, err := g.execKeybindings(v, ev); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+// execKeybindings executes the keybinding handlers that match the passed view
+// and event. The value of matched is true if there is a match and no errors.
+func (g *Gui) execKeybindings(v *View, ev *termbox.Event) (matched bool, err error) {
+ matched = false
+ for _, kb := range g.keybindings {
+ if kb.handler == nil {
+ continue
+ }
+ if kb.matchKeypress(Key(ev.Key), ev.Ch, Modifier(ev.Mod)) && kb.matchView(v) {
+ if err := kb.handler(g, v); err != nil {
+ return false, err
+ }
+ matched = true
+ }
+ }
+ return matched, nil
+}
diff --git a/pkg/gocui/keybinding.go b/pkg/gocui/keybinding.go
new file mode 100644
index 0000000..03fe677
--- /dev/null
+++ b/pkg/gocui/keybinding.go
@@ -0,0 +1,137 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gocui
+
+import "github.com/nsf/termbox-go"
+
+// Keybidings are used to link a given key-press event with a handler.
+type keybinding struct {
+ viewName string
+ key Key
+ ch rune
+ mod Modifier
+ handler func(*Gui, *View) error
+}
+
+// newKeybinding returns a new Keybinding object.
+func newKeybinding(viewname string, key Key, ch rune, mod Modifier, handler func(*Gui, *View) error) (kb *keybinding) {
+ kb = &keybinding{
+ viewName: viewname,
+ key: key,
+ ch: ch,
+ mod: mod,
+ handler: handler,
+ }
+ return kb
+}
+
+// matchKeypress returns if the keybinding matches the keypress.
+func (kb *keybinding) matchKeypress(key Key, ch rune, mod Modifier) bool {
+ return kb.key == key && kb.ch == ch && kb.mod == mod
+}
+
+// matchView returns if the keybinding matches the current view.
+func (kb *keybinding) matchView(v *View) bool {
+ if kb.viewName == "" {
+ return true
+ }
+ return v != nil && kb.viewName == v.name
+}
+
+// Key represents special keys or keys combinations.
+type Key termbox.Key
+
+// Special keys.
+const (
+ KeyF1 Key = Key(termbox.KeyF1)
+ KeyF2 = Key(termbox.KeyF2)
+ KeyF3 = Key(termbox.KeyF3)
+ KeyF4 = Key(termbox.KeyF4)
+ KeyF5 = Key(termbox.KeyF5)
+ KeyF6 = Key(termbox.KeyF6)
+ KeyF7 = Key(termbox.KeyF7)
+ KeyF8 = Key(termbox.KeyF8)
+ KeyF9 = Key(termbox.KeyF9)
+ KeyF10 = Key(termbox.KeyF10)
+ KeyF11 = Key(termbox.KeyF11)
+ KeyF12 = Key(termbox.KeyF12)
+ KeyInsert = Key(termbox.KeyInsert)
+ KeyDelete = Key(termbox.KeyDelete)
+ KeyHome = Key(termbox.KeyHome)
+ KeyEnd = Key(termbox.KeyEnd)
+ KeyPgup = Key(termbox.KeyPgup)
+ KeyPgdn = Key(termbox.KeyPgdn)
+ KeyArrowUp = Key(termbox.KeyArrowUp)
+ KeyArrowDown = Key(termbox.KeyArrowDown)
+ KeyArrowLeft = Key(termbox.KeyArrowLeft)
+ KeyArrowRight = Key(termbox.KeyArrowRight)
+
+ MouseLeft = Key(termbox.MouseLeft)
+ MouseMiddle = Key(termbox.MouseMiddle)
+ MouseRight = Key(termbox.MouseRight)
+ MouseRelease = Key(termbox.MouseRelease)
+ MouseWheelUp = Key(termbox.MouseWheelUp)
+ MouseWheelDown = Key(termbox.MouseWheelDown)
+)
+
+// Keys combinations.
+const (
+ KeyCtrlTilde Key = Key(termbox.KeyCtrlTilde)
+ KeyCtrl2 = Key(termbox.KeyCtrl2)
+ KeyCtrlSpace = Key(termbox.KeyCtrlSpace)
+ KeyCtrlA = Key(termbox.KeyCtrlA)
+ KeyCtrlB = Key(termbox.KeyCtrlB)
+ KeyCtrlC = Key(termbox.KeyCtrlC)
+ KeyCtrlD = Key(termbox.KeyCtrlD)
+ KeyCtrlE = Key(termbox.KeyCtrlE)
+ KeyCtrlF = Key(termbox.KeyCtrlF)
+ KeyCtrlG = Key(termbox.KeyCtrlG)
+ KeyBackspace = Key(termbox.KeyBackspace)
+ KeyCtrlH = Key(termbox.KeyCtrlH)
+ KeyTab = Key(termbox.KeyTab)
+ KeyCtrlI = Key(termbox.KeyCtrlI)
+ KeyCtrlJ = Key(termbox.KeyCtrlJ)
+ KeyCtrlK = Key(termbox.KeyCtrlK)
+ KeyCtrlL = Key(termbox.KeyCtrlL)
+ KeyEnter = Key(termbox.KeyEnter)
+ KeyCtrlM = Key(termbox.KeyCtrlM)
+ KeyCtrlN = Key(termbox.KeyCtrlN)
+ KeyCtrlO = Key(termbox.KeyCtrlO)
+ KeyCtrlP = Key(termbox.KeyCtrlP)
+ KeyCtrlQ = Key(termbox.KeyCtrlQ)
+ KeyCtrlR = Key(termbox.KeyCtrlR)
+ KeyCtrlS = Key(termbox.KeyCtrlS)
+ KeyCtrlT = Key(termbox.KeyCtrlT)
+ KeyCtrlU = Key(termbox.KeyCtrlU)
+ KeyCtrlV = Key(termbox.KeyCtrlV)
+ KeyCtrlW = Key(termbox.KeyCtrlW)
+ KeyCtrlX = Key(termbox.KeyCtrlX)
+ KeyCtrlY = Key(termbox.KeyCtrlY)
+ KeyCtrlZ = Key(termbox.KeyCtrlZ)
+ KeyEsc = Key(termbox.KeyEsc)
+ KeyCtrlLsqBracket = Key(termbox.KeyCtrlLsqBracket)
+ KeyCtrl3 = Key(termbox.KeyCtrl3)
+ KeyCtrl4 = Key(termbox.KeyCtrl4)
+ KeyCtrlBackslash = Key(termbox.KeyCtrlBackslash)
+ KeyCtrl5 = Key(termbox.KeyCtrl5)
+ KeyCtrlRsqBracket = Key(termbox.KeyCtrlRsqBracket)
+ KeyCtrl6 = Key(termbox.KeyCtrl6)
+ KeyCtrl7 = Key(termbox.KeyCtrl7)
+ KeyCtrlSlash = Key(termbox.KeyCtrlSlash)
+ KeyCtrlUnderscore = Key(termbox.KeyCtrlUnderscore)
+ KeySpace = Key(termbox.KeySpace)
+ KeyBackspace2 = Key(termbox.KeyBackspace2)
+ KeyCtrl8 = Key(termbox.KeyCtrl8)
+)
+
+// Modifier allows to define special keys combinations. They can be used
+// in combination with Keys or Runes when a new keybinding is defined.
+type Modifier termbox.Modifier
+
+// Modifiers.
+const (
+ ModNone Modifier = Modifier(0)
+ ModAlt = Modifier(termbox.ModAlt)
+)
diff --git a/pkg/gocui/view.go b/pkg/gocui/view.go
new file mode 100644
index 0000000..42082f8
--- /dev/null
+++ b/pkg/gocui/view.go
@@ -0,0 +1,503 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gocui
+
+import (
+ "bytes"
+ "errors"
+ "io"
+ "strings"
+
+ "github.com/nsf/termbox-go"
+)
+
+// A View is a window. It maintains its own internal buffer and cursor
+// position.
+type View struct {
+ name string
+ x0, y0, x1, y1 int
+ ox, oy int
+ cx, cy int
+ lines [][]cell
+ readOffset int
+ readCache string
+
+ tainted bool // marks if the viewBuffer must be updated
+ viewLines []viewLine // internal representation of the view's buffer
+
+ ei *escapeInterpreter // used to decode ESC sequences on Write
+
+ // BgColor and FgColor allow to configure the background and foreground
+ // colors of the View.
+ BgColor, FgColor Attribute
+
+ // SelBgColor and SelFgColor are used to configure the background and
+ // foreground colors of the selected line, when it is highlighted.
+ SelBgColor, SelFgColor Attribute
+
+ // If Editable is true, keystrokes will be added to the view's internal
+ // buffer at the cursor position.
+ Editable bool
+
+ // Editor allows to define the editor that manages the edition mode,
+ // including keybindings or cursor behaviour. DefaultEditor is used by
+ // default.
+ Editor Editor
+
+ // Overwrite enables or disables the overwrite mode of the view.
+ Overwrite bool
+
+ // If Highlight is true, Sel{Bg,Fg}Colors will be used
+ // for the line under the cursor position.
+ Highlight bool
+
+ // If Frame is true, a border will be drawn around the view.
+ Frame bool
+
+ // If Wrap is true, the content that is written to this View is
+ // automatically wrapped when it is longer than its width. If true the
+ // view's x-origin will be ignored.
+ Wrap bool
+
+ // If Autoscroll is true, the View will automatically scroll down when the
+ // text overflows. If true the view's y-origin will be ignored.
+ Autoscroll bool
+
+ // If Frame is true, Title allows to configure a title for the view.
+ Title string
+
+ // If Mask is true, the View will display the mask instead of the real
+ // content
+ Mask rune
+}
+
+type viewLine struct {
+ linesX, linesY int // coordinates relative to v.lines
+ line []cell
+}
+
+type cell struct {
+ chr rune
+ bgColor, fgColor Attribute
+}
+
+type lineType []cell
+
+// String returns a string from a given cell slice.
+func (l lineType) String() string {
+ str := ""
+ for _, c := range l {
+ str += string(c.chr)
+ }
+ return str
+}
+
+// newView returns a new View object.
+func newView(name string, x0, y0, x1, y1 int, mode OutputMode) *View {
+ v := &View{
+ name: name,
+ x0: x0,
+ y0: y0,
+ x1: x1,
+ y1: y1,
+ Frame: true,
+ Editor: DefaultEditor,
+ tainted: true,
+ ei: newEscapeInterpreter(mode),
+ }
+ return v
+}
+
+// Size returns the number of visible columns and rows in the View.
+func (v *View) Size() (x, y int) {
+ return v.x1 - v.x0 - 1, v.y1 - v.y0 - 1
+}
+
+// Name returns the name of the view.
+func (v *View) Name() string {
+ return v.name
+}
+
+// setRune sets a rune at the given point relative to the view. It applies the
+// specified colors, taking into account if the cell must be highlighted. Also,
+// it checks if the position is valid.
+func (v *View) setRune(x, y int, ch rune, fgColor, bgColor Attribute) error {
+ maxX, maxY := v.Size()
+ if x < 0 || x >= maxX || y < 0 || y >= maxY {
+ return errors.New("invalid point")
+ }
+
+ var (
+ ry, rcy int
+ err error
+ )
+ if v.Highlight {
+ _, ry, err = v.realPosition(x, y)
+ if err != nil {
+ return err
+ }
+ _, rcy, err = v.realPosition(v.cx, v.cy)
+ if err != nil {
+ return err
+ }
+ }
+
+ if v.Mask != 0 {
+ fgColor = v.FgColor
+ bgColor = v.BgColor
+ ch = v.Mask
+ } else if v.Highlight && ry == rcy {
+ fgColor = v.SelFgColor
+ bgColor = v.SelBgColor
+ }
+
+ termbox.SetCell(v.x0+x+1, v.y0+y+1, ch,
+ termbox.Attribute(fgColor), termbox.Attribute(bgColor))
+
+ return nil
+}
+
+// SetCursor sets the cursor position of the view at the given point,
+// relative to the view. It checks if the position is valid.
+func (v *View) SetCursor(x, y int) error {
+ maxX, maxY := v.Size()
+ if x < 0 || x >= maxX || y < 0 || y >= maxY {
+ return errors.New("invalid point")
+ }
+ v.cx = x
+ v.cy = y
+ return nil
+}
+
+// Cursor returns the cursor position of the view.
+func (v *View) Cursor() (x, y int) {
+ return v.cx, v.cy
+}
+
+// SetOrigin sets the origin position of the view's internal buffer,
+// so the buffer starts to be printed from this point, which means that
+// it is linked with the origin point of view. It can be used to
+// implement Horizontal and Vertical scrolling with just incrementing
+// or decrementing ox and oy.
+func (v *View) SetOrigin(x, y int) error {
+ if x < 0 || y < 0 {
+ return errors.New("invalid point")
+ }
+ v.ox = x
+ v.oy = y
+ return nil
+}
+
+// Origin returns the origin position of the view.
+func (v *View) Origin() (x, y int) {
+ return v.ox, v.oy
+}
+
+// Write appends a byte slice into the view's internal buffer. Because
+// View implements the io.Writer interface, it can be passed as parameter
+// of functions like fmt.Fprintf, fmt.Fprintln, io.Copy, etc. Clear must
+// be called to clear the view's buffer.
+func (v *View) Write(p []byte) (n int, err error) {
+ v.tainted = true
+
+ for _, ch := range bytes.Runes(p) {
+ switch ch {
+ case '\n':
+ v.lines = append(v.lines, nil)
+ case '\r':
+ nl := len(v.lines)
+ if nl > 0 {
+ v.lines[nl-1] = nil
+ } else {
+ v.lines = make([][]cell, 1)
+ }
+ default:
+ cells := v.parseInput(ch)
+ if cells == nil {
+ continue
+ }
+
+ nl := len(v.lines)
+ if nl > 0 {
+ v.lines[nl-1] = append(v.lines[nl-1], cells...)
+ } else {
+ v.lines = append(v.lines, cells)
+ }
+ }
+ }
+ return len(p), nil
+}
+
+// parseInput parses char by char the input written to the View. It returns nil
+// while processing ESC sequences. Otherwise, it returns a cell slice that
+// contains the processed data.
+func (v *View) parseInput(ch rune) []cell {
+ cells := []cell{}
+
+ isEscape, err := v.ei.parseOne(ch)
+ if err != nil {
+ for _, r := range v.ei.runes() {
+ c := cell{
+ fgColor: v.FgColor,
+ bgColor: v.BgColor,
+ chr: r,
+ }
+ cells = append(cells, c)
+ }
+ v.ei.reset()
+ } else {
+ if isEscape {
+ return nil
+ }
+ c := cell{
+ fgColor: v.ei.curFgColor,
+ bgColor: v.ei.curBgColor,
+ chr: ch,
+ }
+ cells = append(cells, c)
+ }
+
+ return cells
+}
+
+// Read reads data into p. It returns the number of bytes read into p.
+// At EOF, err will be io.EOF. Calling Read() after Rewind() makes the
+// cache to be refreshed with the contents of the view.
+func (v *View) Read(p []byte) (n int, err error) {
+ if v.readOffset == 0 {
+ v.readCache = v.Buffer()
+ }
+ if v.readOffset < len(v.readCache) {
+ n = copy(p, v.readCache[v.readOffset:])
+ v.readOffset += n
+ } else {
+ err = io.EOF
+ }
+ return
+}
+
+// Rewind sets the offset for the next Read to 0, which also refresh the
+// read cache.
+func (v *View) Rewind() {
+ v.readOffset = 0
+}
+
+// draw re-draws the view's contents.
+func (v *View) draw() error {
+ maxX, maxY := v.Size()
+
+ if v.Wrap {
+ if maxX == 0 {
+ return errors.New("X size of the view cannot be 0")
+ }
+ v.ox = 0
+ }
+ if v.tainted {
+ v.viewLines = nil
+ for i, line := range v.lines {
+ if v.Wrap {
+ if len(line) < maxX {
+ vline := viewLine{linesX: 0, linesY: i, line: line}
+ v.viewLines = append(v.viewLines, vline)
+ continue
+ } else {
+ for n := 0; n <= len(line); n += maxX {
+ if len(line[n:]) <= maxX {
+ vline := viewLine{linesX: n, linesY: i, line: line[n:]}
+ v.viewLines = append(v.viewLines, vline)
+ } else {
+ vline := viewLine{linesX: n, linesY: i, line: line[n : n+maxX]}
+ v.viewLines = append(v.viewLines, vline)
+ }
+ }
+ }
+ } else {
+ vline := viewLine{linesX: 0, linesY: i, line: line}
+ v.viewLines = append(v.viewLines, vline)
+ }
+ }
+ v.tainted = false
+ }
+
+ if v.Autoscroll && len(v.viewLines) > maxY {
+ v.oy = len(v.viewLines) - maxY
+ }
+ y := 0
+ for i, vline := range v.viewLines {
+ if i < v.oy {
+ continue
+ }
+ if y >= maxY {
+ break
+ }
+ x := 0
+ for j, c := range vline.line {
+ if j < v.ox {
+ continue
+ }
+ if x >= maxX {
+ break
+ }
+
+ fgColor := c.fgColor
+ if fgColor == ColorDefault {
+ fgColor = v.FgColor
+ }
+ bgColor := c.bgColor
+ if bgColor == ColorDefault {
+ bgColor = v.BgColor
+ }
+
+ if err := v.setRune(x, y, c.chr, fgColor, bgColor); err != nil {
+ return err
+ }
+ x++
+ }
+ y++
+ }
+ return nil
+}
+
+// realPosition returns the position in the internal buffer corresponding to the
+// point (x, y) of the view.
+func (v *View) realPosition(vx, vy int) (x, y int, err error) {
+ vx = v.ox + vx
+ vy = v.oy + vy
+
+ if vx < 0 || vy < 0 {
+ return 0, 0, errors.New("invalid point")
+ }
+
+ if len(v.viewLines) == 0 {
+ return vx, vy, nil
+ }
+
+ if vy < len(v.viewLines) {
+ vline := v.viewLines[vy]
+ x = vline.linesX + vx
+ y = vline.linesY
+ } else {
+ vline := v.viewLines[len(v.viewLines)-1]
+ x = vx
+ y = vline.linesY + vy - len(v.viewLines) + 1
+ }
+
+ return x, y, nil
+}
+
+// Clear empties the view's internal buffer.
+func (v *View) Clear() {
+ v.tainted = true
+
+ v.lines = nil
+ v.viewLines = nil
+ v.readOffset = 0
+ v.clearRunes()
+}
+
+// clearRunes erases all the cells in the view.
+func (v *View) clearRunes() {
+ maxX, maxY := v.Size()
+ for x := 0; x < maxX; x++ {
+ for y := 0; y < maxY; y++ {
+ termbox.SetCell(v.x0+x+1, v.y0+y+1, ' ',
+ termbox.Attribute(v.FgColor), termbox.Attribute(v.BgColor))
+ }
+ }
+}
+
+// BufferLines returns the lines in the view's internal
+// buffer.
+func (v *View) BufferLines() []string {
+ lines := make([]string, len(v.lines))
+ for i, l := range v.lines {
+ str := lineType(l).String()
+ str = strings.Replace(str, "\x00", " ", -1)
+ lines[i] = str
+ }
+ return lines
+}
+
+// Buffer returns a string with the contents of the view's internal
+// buffer.
+func (v *View) Buffer() string {
+ str := ""
+ for _, l := range v.lines {
+ str += lineType(l).String() + "\n"
+ }
+ return strings.Replace(str, "\x00", " ", -1)
+}
+
+// ViewBufferLines returns the lines in the view's internal
+// buffer that is shown to the user.
+func (v *View) ViewBufferLines() []string {
+ lines := make([]string, len(v.viewLines))
+ for i, l := range v.viewLines {
+ str := lineType(l.line).String()
+ str = strings.Replace(str, "\x00", " ", -1)
+ lines[i] = str
+ }
+ return lines
+}
+
+// ViewBuffer returns a string with the contents of the view's buffer that is
+// shown to the user.
+func (v *View) ViewBuffer() string {
+ str := ""
+ for _, l := range v.viewLines {
+ str += lineType(l.line).String() + "\n"
+ }
+ return strings.Replace(str, "\x00", " ", -1)
+}
+
+// Line returns a string with the line of the view's internal buffer
+// at the position corresponding to the point (x, y).
+func (v *View) Line(y int) (string, error) {
+ _, y, err := v.realPosition(0, y)
+ if err != nil {
+ return "", err
+ }
+
+ if y < 0 || y >= len(v.lines) {
+ return "", errors.New("invalid point")
+ }
+
+ return lineType(v.lines[y]).String(), nil
+}
+
+// Word returns a string with the word of the view's internal buffer
+// at the position corresponding to the point (x, y).
+func (v *View) Word(x, y int) (string, error) {
+ x, y, err := v.realPosition(x, y)
+ if err != nil {
+ return "", err
+ }
+
+ if x < 0 || y < 0 || y >= len(v.lines) || x >= len(v.lines[y]) {
+ return "", errors.New("invalid point")
+ }
+
+ str := lineType(v.lines[y]).String()
+
+ nl := strings.LastIndexFunc(str[:x], indexFunc)
+ if nl == -1 {
+ nl = 0
+ } else {
+ nl = nl + 1
+ }
+ nr := strings.IndexFunc(str[x:], indexFunc)
+ if nr == -1 {
+ nr = len(str)
+ } else {
+ nr = nr + x
+ }
+ return string(str[nl:nr]), nil
+}
+
+// indexFunc allows to split lines by words taking into account spaces
+// and 0.
+func indexFunc(r rune) bool {
+ return r == ' ' || r == 0
+}
diff --git a/pkg/slice/slice.go b/pkg/slice/slice.go
new file mode 100644
index 0000000..150d38a
--- /dev/null
+++ b/pkg/slice/slice.go
@@ -0,0 +1,40 @@
+// Package slice provides a slice sorting function.
+package slice
+
+import (
+ "fmt"
+ "reflect"
+ "sort"
+
+ "go4.org/reflectutil"
+)
+
+// Sort sorts the provided slice using the function less.
+// If slice is not a slice, Sort panics.
+func Sort(slice interface{}, less func(i, j int) bool) {
+ sort.Sort(SortInterface(slice, less))
+}
+
+// SortInterface returns a sort.Interface to sort the provided slice
+// using the function less.
+func SortInterface(slice interface{}, less func(i, j int) bool) sort.Interface {
+ sv := reflect.ValueOf(slice)
+ if sv.Kind() != reflect.Slice {
+ panic(fmt.Sprintf("slice.Sort called with non-slice value of type %T", slice))
+ }
+ return &funcs{
+ length: sv.Len(),
+ less: less,
+ swap: reflectutil.Swapper(slice),
+ }
+}
+
+type funcs struct {
+ length int
+ less func(i, j int) bool
+ swap func(i, j int)
+}
+
+func (f *funcs) Len() int { return f.length }
+func (f *funcs) Less(i, j int) bool { return f.less(i, j) }
+func (f *funcs) Swap(i, j int) { f.swap(i, j) }
diff --git a/vendor/github.com/BurntSushi/toml/.gitignore b/vendor/github.com/BurntSushi/toml/.gitignore
new file mode 100644
index 0000000..0cd3800
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/.gitignore
@@ -0,0 +1,5 @@
+TAGS
+tags
+.*.swp
+tomlcheck/tomlcheck
+toml.test
diff --git a/vendor/github.com/BurntSushi/toml/.travis.yml b/vendor/github.com/BurntSushi/toml/.travis.yml
new file mode 100644
index 0000000..8b8afc4
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/.travis.yml
@@ -0,0 +1,15 @@
+language: go
+go:
+ - 1.1
+ - 1.2
+ - 1.3
+ - 1.4
+ - 1.5
+ - 1.6
+ - tip
+install:
+ - go install ./...
+ - go get github.com/BurntSushi/toml-test
+script:
+ - export PATH="$PATH:$HOME/gopath/bin"
+ - make test
diff --git a/vendor/github.com/BurntSushi/toml/COMPATIBLE b/vendor/github.com/BurntSushi/toml/COMPATIBLE
new file mode 100644
index 0000000..6efcfd0
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/COMPATIBLE
@@ -0,0 +1,3 @@
+Compatible with TOML version
+[v0.4.0](https://github.com/toml-lang/toml/blob/v0.4.0/versions/en/toml-v0.4.0.md)
+
diff --git a/vendor/github.com/BurntSushi/toml/COPYING b/vendor/github.com/BurntSushi/toml/COPYING
new file mode 100644
index 0000000..5a8e332
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/COPYING
@@ -0,0 +1,14 @@
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ Version 2, December 2004
+
+ Copyright (C) 2004 Sam Hocevar
+
+ Everyone is permitted to copy and distribute verbatim or modified
+ copies of this license document, and changing it is allowed as long
+ as the name is changed.
+
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
+
diff --git a/vendor/github.com/BurntSushi/toml/Makefile b/vendor/github.com/BurntSushi/toml/Makefile
new file mode 100644
index 0000000..3600848
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/Makefile
@@ -0,0 +1,19 @@
+install:
+ go install ./...
+
+test: install
+ go test -v
+ toml-test toml-test-decoder
+ toml-test -encoder toml-test-encoder
+
+fmt:
+ gofmt -w *.go */*.go
+ colcheck *.go */*.go
+
+tags:
+ find ./ -name '*.go' -print0 | xargs -0 gotags > TAGS
+
+push:
+ git push origin master
+ git push github master
+
diff --git a/vendor/github.com/BurntSushi/toml/README.md b/vendor/github.com/BurntSushi/toml/README.md
new file mode 100644
index 0000000..7c1b37e
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/README.md
@@ -0,0 +1,218 @@
+## TOML parser and encoder for Go with reflection
+
+TOML stands for Tom's Obvious, Minimal Language. This Go package provides a
+reflection interface similar to Go's standard library `json` and `xml`
+packages. This package also supports the `encoding.TextUnmarshaler` and
+`encoding.TextMarshaler` interfaces so that you can define custom data
+representations. (There is an example of this below.)
+
+Spec: https://github.com/toml-lang/toml
+
+Compatible with TOML version
+[v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md)
+
+Documentation: https://godoc.org/github.com/BurntSushi/toml
+
+Installation:
+
+```bash
+go get github.com/BurntSushi/toml
+```
+
+Try the toml validator:
+
+```bash
+go get github.com/BurntSushi/toml/cmd/tomlv
+tomlv some-toml-file.toml
+```
+
+[![Build Status](https://travis-ci.org/BurntSushi/toml.svg?branch=master)](https://travis-ci.org/BurntSushi/toml) [![GoDoc](https://godoc.org/github.com/BurntSushi/toml?status.svg)](https://godoc.org/github.com/BurntSushi/toml)
+
+### Testing
+
+This package passes all tests in
+[toml-test](https://github.com/BurntSushi/toml-test) for both the decoder
+and the encoder.
+
+### Examples
+
+This package works similarly to how the Go standard library handles `XML`
+and `JSON`. Namely, data is loaded into Go values via reflection.
+
+For the simplest example, consider some TOML file as just a list of keys
+and values:
+
+```toml
+Age = 25
+Cats = [ "Cauchy", "Plato" ]
+Pi = 3.14
+Perfection = [ 6, 28, 496, 8128 ]
+DOB = 1987-07-05T05:45:00Z
+```
+
+Which could be defined in Go as:
+
+```go
+type Config struct {
+ Age int
+ Cats []string
+ Pi float64
+ Perfection []int
+ DOB time.Time // requires `import time`
+}
+```
+
+And then decoded with:
+
+```go
+var conf Config
+if _, err := toml.Decode(tomlData, &conf); err != nil {
+ // handle error
+}
+```
+
+You can also use struct tags if your struct field name doesn't map to a TOML
+key value directly:
+
+```toml
+some_key_NAME = "wat"
+```
+
+```go
+type TOML struct {
+ ObscureKey string `toml:"some_key_NAME"`
+}
+```
+
+### Using the `encoding.TextUnmarshaler` interface
+
+Here's an example that automatically parses duration strings into
+`time.Duration` values:
+
+```toml
+[[song]]
+name = "Thunder Road"
+duration = "4m49s"
+
+[[song]]
+name = "Stairway to Heaven"
+duration = "8m03s"
+```
+
+Which can be decoded with:
+
+```go
+type song struct {
+ Name string
+ Duration duration
+}
+type songs struct {
+ Song []song
+}
+var favorites songs
+if _, err := toml.Decode(blob, &favorites); err != nil {
+ log.Fatal(err)
+}
+
+for _, s := range favorites.Song {
+ fmt.Printf("%s (%s)\n", s.Name, s.Duration)
+}
+```
+
+And you'll also need a `duration` type that satisfies the
+`encoding.TextUnmarshaler` interface:
+
+```go
+type duration struct {
+ time.Duration
+}
+
+func (d *duration) UnmarshalText(text []byte) error {
+ var err error
+ d.Duration, err = time.ParseDuration(string(text))
+ return err
+}
+```
+
+### More complex usage
+
+Here's an example of how to load the example from the official spec page:
+
+```toml
+# This is a TOML document. Boom.
+
+title = "TOML Example"
+
+[owner]
+name = "Tom Preston-Werner"
+organization = "GitHub"
+bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
+dob = 1979-05-27T07:32:00Z # First class dates? Why not?
+
+[database]
+server = "192.168.1.1"
+ports = [ 8001, 8001, 8002 ]
+connection_max = 5000
+enabled = true
+
+[servers]
+
+ # You can indent as you please. Tabs or spaces. TOML don't care.
+ [servers.alpha]
+ ip = "10.0.0.1"
+ dc = "eqdc10"
+
+ [servers.beta]
+ ip = "10.0.0.2"
+ dc = "eqdc10"
+
+[clients]
+data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it
+
+# Line breaks are OK when inside arrays
+hosts = [
+ "alpha",
+ "omega"
+]
+```
+
+And the corresponding Go types are:
+
+```go
+type tomlConfig struct {
+ Title string
+ Owner ownerInfo
+ DB database `toml:"database"`
+ Servers map[string]server
+ Clients clients
+}
+
+type ownerInfo struct {
+ Name string
+ Org string `toml:"organization"`
+ Bio string
+ DOB time.Time
+}
+
+type database struct {
+ Server string
+ Ports []int
+ ConnMax int `toml:"connection_max"`
+ Enabled bool
+}
+
+type server struct {
+ IP string
+ DC string
+}
+
+type clients struct {
+ Data [][]interface{}
+ Hosts []string
+}
+```
+
+Note that a case insensitive match will be tried if an exact match can't be
+found.
+
+A working example of the above can be found in `_examples/example.{go,toml}`.
diff --git a/vendor/github.com/BurntSushi/toml/_examples/example.go b/vendor/github.com/BurntSushi/toml/_examples/example.go
new file mode 100644
index 0000000..79f31f2
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/_examples/example.go
@@ -0,0 +1,61 @@
+package main
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/BurntSushi/toml"
+)
+
+type tomlConfig struct {
+ Title string
+ Owner ownerInfo
+ DB database `toml:"database"`
+ Servers map[string]server
+ Clients clients
+}
+
+type ownerInfo struct {
+ Name string
+ Org string `toml:"organization"`
+ Bio string
+ DOB time.Time
+}
+
+type database struct {
+ Server string
+ Ports []int
+ ConnMax int `toml:"connection_max"`
+ Enabled bool
+}
+
+type server struct {
+ IP string
+ DC string
+}
+
+type clients struct {
+ Data [][]interface{}
+ Hosts []string
+}
+
+func main() {
+ var config tomlConfig
+ if _, err := toml.DecodeFile("example.toml", &config); err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ fmt.Printf("Title: %s\n", config.Title)
+ fmt.Printf("Owner: %s (%s, %s), Born: %s\n",
+ config.Owner.Name, config.Owner.Org, config.Owner.Bio,
+ config.Owner.DOB)
+ fmt.Printf("Database: %s %v (Max conn. %d), Enabled? %v\n",
+ config.DB.Server, config.DB.Ports, config.DB.ConnMax,
+ config.DB.Enabled)
+ for serverName, server := range config.Servers {
+ fmt.Printf("Server: %s (%s, %s)\n", serverName, server.IP, server.DC)
+ }
+ fmt.Printf("Client data: %v\n", config.Clients.Data)
+ fmt.Printf("Client hosts: %v\n", config.Clients.Hosts)
+}
diff --git a/vendor/github.com/BurntSushi/toml/_examples/example.toml b/vendor/github.com/BurntSushi/toml/_examples/example.toml
new file mode 100644
index 0000000..32c7a4f
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/_examples/example.toml
@@ -0,0 +1,35 @@
+# This is a TOML document. Boom.
+
+title = "TOML Example"
+
+[owner]
+name = "Tom Preston-Werner"
+organization = "GitHub"
+bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
+dob = 1979-05-27T07:32:00Z # First class dates? Why not?
+
+[database]
+server = "192.168.1.1"
+ports = [ 8001, 8001, 8002 ]
+connection_max = 5000
+enabled = true
+
+[servers]
+
+ # You can indent as you please. Tabs or spaces. TOML don't care.
+ [servers.alpha]
+ ip = "10.0.0.1"
+ dc = "eqdc10"
+
+ [servers.beta]
+ ip = "10.0.0.2"
+ dc = "eqdc10"
+
+[clients]
+data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it
+
+# Line breaks are OK when inside arrays
+hosts = [
+ "alpha",
+ "omega"
+]
diff --git a/vendor/github.com/BurntSushi/toml/_examples/hard.toml b/vendor/github.com/BurntSushi/toml/_examples/hard.toml
new file mode 100644
index 0000000..26145d2
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/_examples/hard.toml
@@ -0,0 +1,22 @@
+# Test file for TOML
+# Only this one tries to emulate a TOML file written by a user of the kind of parser writers probably hate
+# This part you'll really hate
+
+[the]
+test_string = "You'll hate me after this - #" # " Annoying, isn't it?
+
+ [the.hard]
+ test_array = [ "] ", " # "] # ] There you go, parse this!
+ test_array2 = [ "Test #11 ]proved that", "Experiment #9 was a success" ]
+ # You didn't think it'd as easy as chucking out the last #, did you?
+ another_test_string = " Same thing, but with a string #"
+ harder_test_string = " And when \"'s are in the string, along with # \"" # "and comments are there too"
+ # Things will get harder
+
+ [the.hard.bit#]
+ what? = "You don't think some user won't do that?"
+ multi_line_array = [
+ "]",
+ # ] Oh yes I did
+ ]
+
diff --git a/vendor/github.com/BurntSushi/toml/_examples/implicit.toml b/vendor/github.com/BurntSushi/toml/_examples/implicit.toml
new file mode 100644
index 0000000..1dea5ce
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/_examples/implicit.toml
@@ -0,0 +1,4 @@
+# [x] you
+# [x.y] don't
+# [x.y.z] need these
+[x.y.z.w] # for this to work
diff --git a/vendor/github.com/BurntSushi/toml/_examples/invalid-apples.toml b/vendor/github.com/BurntSushi/toml/_examples/invalid-apples.toml
new file mode 100644
index 0000000..74e9e33
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/_examples/invalid-apples.toml
@@ -0,0 +1,6 @@
+# DO NOT WANT
+[fruit]
+type = "apple"
+
+[fruit.type]
+apple = "yes"
diff --git a/vendor/github.com/BurntSushi/toml/_examples/invalid.toml b/vendor/github.com/BurntSushi/toml/_examples/invalid.toml
new file mode 100644
index 0000000..beb1dba
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/_examples/invalid.toml
@@ -0,0 +1,35 @@
+# This is an INVALID TOML document. Boom.
+# Can you spot the error without help?
+
+title = "TOML Example"
+
+[owner]
+name = "Tom Preston-Werner"
+organization = "GitHub"
+bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
+dob = 1979-05-27T7:32:00Z # First class dates? Why not?
+
+[database]
+server = "192.168.1.1"
+ports = [ 8001, 8001, 8002 ]
+connection_max = 5000
+enabled = true
+
+[servers]
+ # You can indent as you please. Tabs or spaces. TOML don't care.
+ [servers.alpha]
+ ip = "10.0.0.1"
+ dc = "eqdc10"
+
+ [servers.beta]
+ ip = "10.0.0.2"
+ dc = "eqdc10"
+
+[clients]
+data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it
+
+# Line breaks are OK when inside arrays
+hosts = [
+ "alpha",
+ "omega"
+]
diff --git a/vendor/github.com/BurntSushi/toml/_examples/readme1.toml b/vendor/github.com/BurntSushi/toml/_examples/readme1.toml
new file mode 100644
index 0000000..3e1261d
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/_examples/readme1.toml
@@ -0,0 +1,5 @@
+Age = 25
+Cats = [ "Cauchy", "Plato" ]
+Pi = 3.14
+Perfection = [ 6, 28, 496, 8128 ]
+DOB = 1987-07-05T05:45:00Z
diff --git a/vendor/github.com/BurntSushi/toml/_examples/readme2.toml b/vendor/github.com/BurntSushi/toml/_examples/readme2.toml
new file mode 100644
index 0000000..b51cd93
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/_examples/readme2.toml
@@ -0,0 +1 @@
+some_key_NAME = "wat"
diff --git a/vendor/github.com/BurntSushi/toml/cmd/toml-test-decoder/COPYING b/vendor/github.com/BurntSushi/toml/cmd/toml-test-decoder/COPYING
new file mode 100644
index 0000000..5a8e332
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/cmd/toml-test-decoder/COPYING
@@ -0,0 +1,14 @@
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ Version 2, December 2004
+
+ Copyright (C) 2004 Sam Hocevar
+
+ Everyone is permitted to copy and distribute verbatim or modified
+ copies of this license document, and changing it is allowed as long
+ as the name is changed.
+
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
+
diff --git a/vendor/github.com/BurntSushi/toml/cmd/toml-test-decoder/README.md b/vendor/github.com/BurntSushi/toml/cmd/toml-test-decoder/README.md
new file mode 100644
index 0000000..93f4e3a
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/cmd/toml-test-decoder/README.md
@@ -0,0 +1,13 @@
+# Implements the TOML test suite interface
+
+This is an implementation of the interface expected by
+[toml-test](https://github.com/BurntSushi/toml-test) for my
+[toml parser written in Go](https://github.com/BurntSushi/toml).
+In particular, it maps TOML data on `stdin` to a JSON format on `stdout`.
+
+
+Compatible with TOML version
+[v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md)
+
+Compatible with `toml-test` version
+[v0.2.0](https://github.com/BurntSushi/toml-test/tree/v0.2.0)
diff --git a/vendor/github.com/BurntSushi/toml/cmd/toml-test-decoder/main.go b/vendor/github.com/BurntSushi/toml/cmd/toml-test-decoder/main.go
new file mode 100644
index 0000000..14e7557
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/cmd/toml-test-decoder/main.go
@@ -0,0 +1,90 @@
+// Command toml-test-decoder satisfies the toml-test interface for testing
+// TOML decoders. Namely, it accepts TOML on stdin and outputs JSON on stdout.
+package main
+
+import (
+ "encoding/json"
+ "flag"
+ "fmt"
+ "log"
+ "os"
+ "path"
+ "time"
+
+ "github.com/BurntSushi/toml"
+)
+
+func init() {
+ log.SetFlags(0)
+
+ flag.Usage = usage
+ flag.Parse()
+}
+
+func usage() {
+ log.Printf("Usage: %s < toml-file\n", path.Base(os.Args[0]))
+ flag.PrintDefaults()
+
+ os.Exit(1)
+}
+
+func main() {
+ if flag.NArg() != 0 {
+ flag.Usage()
+ }
+
+ var tmp interface{}
+ if _, err := toml.DecodeReader(os.Stdin, &tmp); err != nil {
+ log.Fatalf("Error decoding TOML: %s", err)
+ }
+
+ typedTmp := translate(tmp)
+ if err := json.NewEncoder(os.Stdout).Encode(typedTmp); err != nil {
+ log.Fatalf("Error encoding JSON: %s", err)
+ }
+}
+
+func translate(tomlData interface{}) interface{} {
+ switch orig := tomlData.(type) {
+ case map[string]interface{}:
+ typed := make(map[string]interface{}, len(orig))
+ for k, v := range orig {
+ typed[k] = translate(v)
+ }
+ return typed
+ case []map[string]interface{}:
+ typed := make([]map[string]interface{}, len(orig))
+ for i, v := range orig {
+ typed[i] = translate(v).(map[string]interface{})
+ }
+ return typed
+ case []interface{}:
+ typed := make([]interface{}, len(orig))
+ for i, v := range orig {
+ typed[i] = translate(v)
+ }
+
+ // We don't really need to tag arrays, but let's be future proof.
+ // (If TOML ever supports tuples, we'll need this.)
+ return tag("array", typed)
+ case time.Time:
+ return tag("datetime", orig.Format("2006-01-02T15:04:05Z"))
+ case bool:
+ return tag("bool", fmt.Sprintf("%v", orig))
+ case int64:
+ return tag("integer", fmt.Sprintf("%d", orig))
+ case float64:
+ return tag("float", fmt.Sprintf("%v", orig))
+ case string:
+ return tag("string", orig)
+ }
+
+ panic(fmt.Sprintf("Unknown type: %T", tomlData))
+}
+
+func tag(typeName string, data interface{}) map[string]interface{} {
+ return map[string]interface{}{
+ "type": typeName,
+ "value": data,
+ }
+}
diff --git a/vendor/github.com/BurntSushi/toml/cmd/toml-test-encoder/COPYING b/vendor/github.com/BurntSushi/toml/cmd/toml-test-encoder/COPYING
new file mode 100644
index 0000000..5a8e332
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/cmd/toml-test-encoder/COPYING
@@ -0,0 +1,14 @@
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ Version 2, December 2004
+
+ Copyright (C) 2004 Sam Hocevar
+
+ Everyone is permitted to copy and distribute verbatim or modified
+ copies of this license document, and changing it is allowed as long
+ as the name is changed.
+
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
+
diff --git a/vendor/github.com/BurntSushi/toml/cmd/toml-test-encoder/README.md b/vendor/github.com/BurntSushi/toml/cmd/toml-test-encoder/README.md
new file mode 100644
index 0000000..a45bd4d
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/cmd/toml-test-encoder/README.md
@@ -0,0 +1,13 @@
+# Implements the TOML test suite interface for TOML encoders
+
+This is an implementation of the interface expected by
+[toml-test](https://github.com/BurntSushi/toml-test) for the
+[TOML encoder](https://github.com/BurntSushi/toml).
+In particular, it maps JSON data on `stdin` to a TOML format on `stdout`.
+
+
+Compatible with TOML version
+[v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md)
+
+Compatible with `toml-test` version
+[v0.2.0](https://github.com/BurntSushi/toml-test/tree/v0.2.0)
diff --git a/vendor/github.com/BurntSushi/toml/cmd/toml-test-encoder/main.go b/vendor/github.com/BurntSushi/toml/cmd/toml-test-encoder/main.go
new file mode 100644
index 0000000..092cc68
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/cmd/toml-test-encoder/main.go
@@ -0,0 +1,131 @@
+// Command toml-test-encoder satisfies the toml-test interface for testing
+// TOML encoders. Namely, it accepts JSON on stdin and outputs TOML on stdout.
+package main
+
+import (
+ "encoding/json"
+ "flag"
+ "log"
+ "os"
+ "path"
+ "strconv"
+ "time"
+
+ "github.com/BurntSushi/toml"
+)
+
+func init() {
+ log.SetFlags(0)
+
+ flag.Usage = usage
+ flag.Parse()
+}
+
+func usage() {
+ log.Printf("Usage: %s < json-file\n", path.Base(os.Args[0]))
+ flag.PrintDefaults()
+
+ os.Exit(1)
+}
+
+func main() {
+ if flag.NArg() != 0 {
+ flag.Usage()
+ }
+
+ var tmp interface{}
+ if err := json.NewDecoder(os.Stdin).Decode(&tmp); err != nil {
+ log.Fatalf("Error decoding JSON: %s", err)
+ }
+
+ tomlData := translate(tmp)
+ if err := toml.NewEncoder(os.Stdout).Encode(tomlData); err != nil {
+ log.Fatalf("Error encoding TOML: %s", err)
+ }
+}
+
+func translate(typedJson interface{}) interface{} {
+ switch v := typedJson.(type) {
+ case map[string]interface{}:
+ if len(v) == 2 && in("type", v) && in("value", v) {
+ return untag(v)
+ }
+ m := make(map[string]interface{}, len(v))
+ for k, v2 := range v {
+ m[k] = translate(v2)
+ }
+ return m
+ case []interface{}:
+ tabArray := make([]map[string]interface{}, len(v))
+ for i := range v {
+ if m, ok := translate(v[i]).(map[string]interface{}); ok {
+ tabArray[i] = m
+ } else {
+ log.Fatalf("JSON arrays may only contain objects. This " +
+ "corresponds to only tables being allowed in " +
+ "TOML table arrays.")
+ }
+ }
+ return tabArray
+ }
+ log.Fatalf("Unrecognized JSON format '%T'.", typedJson)
+ panic("unreachable")
+}
+
+func untag(typed map[string]interface{}) interface{} {
+ t := typed["type"].(string)
+ v := typed["value"]
+ switch t {
+ case "string":
+ return v.(string)
+ case "integer":
+ v := v.(string)
+ n, err := strconv.Atoi(v)
+ if err != nil {
+ log.Fatalf("Could not parse '%s' as integer: %s", v, err)
+ }
+ return n
+ case "float":
+ v := v.(string)
+ f, err := strconv.ParseFloat(v, 64)
+ if err != nil {
+ log.Fatalf("Could not parse '%s' as float64: %s", v, err)
+ }
+ return f
+ case "datetime":
+ v := v.(string)
+ t, err := time.Parse("2006-01-02T15:04:05Z", v)
+ if err != nil {
+ log.Fatalf("Could not parse '%s' as a datetime: %s", v, err)
+ }
+ return t
+ case "bool":
+ v := v.(string)
+ switch v {
+ case "true":
+ return true
+ case "false":
+ return false
+ }
+ log.Fatalf("Could not parse '%s' as a boolean.", v)
+ case "array":
+ v := v.([]interface{})
+ array := make([]interface{}, len(v))
+ for i := range v {
+ if m, ok := v[i].(map[string]interface{}); ok {
+ array[i] = untag(m)
+ } else {
+ log.Fatalf("Arrays may only contain other arrays or "+
+ "primitive values, but found a '%T'.", m)
+ }
+ }
+ return array
+ }
+ log.Fatalf("Unrecognized tag type '%s'.", t)
+ panic("unreachable")
+}
+
+func in(key string, m map[string]interface{}) bool {
+ _, ok := m[key]
+ return ok
+}
diff --git a/vendor/github.com/BurntSushi/toml/cmd/tomlv/COPYING b/vendor/github.com/BurntSushi/toml/cmd/tomlv/COPYING
new file mode 100644
index 0000000..5a8e332
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/cmd/tomlv/COPYING
@@ -0,0 +1,14 @@
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ Version 2, December 2004
+
+ Copyright (C) 2004 Sam Hocevar
+
+ Everyone is permitted to copy and distribute verbatim or modified
+ copies of this license document, and changing it is allowed as long
+ as the name is changed.
+
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
+
diff --git a/vendor/github.com/BurntSushi/toml/cmd/tomlv/README.md b/vendor/github.com/BurntSushi/toml/cmd/tomlv/README.md
new file mode 100644
index 0000000..51231e2
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/cmd/tomlv/README.md
@@ -0,0 +1,21 @@
+# TOML Validator
+
+If Go is installed, it's simple to try it out:
+
+```bash
+go get github.com/BurntSushi/toml/cmd/tomlv
+tomlv some-toml-file.toml
+```
+
+You can see the types of every key in a TOML file with:
+
+```bash
+tomlv -types some-toml-file.toml
+```
+
+At the moment, only one error message is reported at a time. Error messages
+include line numbers. No output means that the files given are valid TOML, or
+there is a bug in `tomlv`.
+
+Compatible with TOML version
+[v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md)
diff --git a/vendor/github.com/BurntSushi/toml/cmd/tomlv/main.go b/vendor/github.com/BurntSushi/toml/cmd/tomlv/main.go
new file mode 100644
index 0000000..c7d689a
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/cmd/tomlv/main.go
@@ -0,0 +1,61 @@
+// Command tomlv validates TOML documents and prints each key's type.
+package main
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "os"
+ "path"
+ "strings"
+ "text/tabwriter"
+
+ "github.com/BurntSushi/toml"
+)
+
+var (
+ flagTypes = false
+)
+
+func init() {
+ log.SetFlags(0)
+
+ flag.BoolVar(&flagTypes, "types", flagTypes,
+ "When set, the types of every defined key will be shown.")
+
+ flag.Usage = usage
+ flag.Parse()
+}
+
+func usage() {
+ log.Printf("Usage: %s toml-file [ toml-file ... ]\n",
+ path.Base(os.Args[0]))
+ flag.PrintDefaults()
+
+ os.Exit(1)
+}
+
+func main() {
+ if flag.NArg() < 1 {
+ flag.Usage()
+ }
+ for _, f := range flag.Args() {
+ var tmp interface{}
+ md, err := toml.DecodeFile(f, &tmp)
+ if err != nil {
+ log.Fatalf("Error in '%s': %s", f, err)
+ }
+ if flagTypes {
+ printTypes(md)
+ }
+ }
+}
+
+func printTypes(md toml.MetaData) {
+ tabw := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
+ for _, key := range md.Keys() {
+ fmt.Fprintf(tabw, "%s%s\t%s\n",
+ strings.Repeat(" ", len(key)-1), key, md.Type(key...))
+ }
+ tabw.Flush()
+}
diff --git a/vendor/github.com/BurntSushi/toml/decode.go b/vendor/github.com/BurntSushi/toml/decode.go
new file mode 100644
index 0000000..b0fd51d
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/decode.go
@@ -0,0 +1,509 @@
+package toml
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "math"
+ "reflect"
+ "strings"
+ "time"
+)
+
+func e(format string, args ...interface{}) error {
+ return fmt.Errorf("toml: "+format, args...)
+}
+
+// Unmarshaler is the interface implemented by objects that can unmarshal a
+// TOML description of themselves.
+type Unmarshaler interface {
+ UnmarshalTOML(interface{}) error
+}
+
+// Unmarshal decodes the contents of `p` in TOML format into a pointer `v`.
+func Unmarshal(p []byte, v interface{}) error {
+ _, err := Decode(string(p), v)
+ return err
+}
+
+// Primitive is a TOML value that hasn't been decoded into a Go value.
+// When using the various `Decode*` functions, the type `Primitive` may
+// be given to any value, and its decoding will be delayed.
+//
+// A `Primitive` value can be decoded using the `PrimitiveDecode` function.
+//
+// The underlying representation of a `Primitive` value is subject to change.
+// Do not rely on it.
+//
+// N.B. Primitive values are still parsed, so using them will only avoid
+// the overhead of reflection. They can be useful when you don't know the
+// exact type of TOML data until run time.
+type Primitive struct {
+ undecoded interface{}
+ context Key
+}
+
+// DEPRECATED!
+//
+// Use MetaData.PrimitiveDecode instead.
+func PrimitiveDecode(primValue Primitive, v interface{}) error {
+ md := MetaData{decoded: make(map[string]bool)}
+ return md.unify(primValue.undecoded, rvalue(v))
+}
+
+// PrimitiveDecode is just like the other `Decode*` functions, except it
+// decodes a TOML value that has already been parsed. Valid primitive values
+// can *only* be obtained from values filled by the decoder functions,
+// including this method. (i.e., `v` may contain more `Primitive`
+// values.)
+//
+// Meta data for primitive values is included in the meta data returned by
+// the `Decode*` functions with one exception: keys returned by the Undecoded
+// method will only reflect keys that were decoded. Namely, any keys hidden
+// behind a Primitive will be considered undecoded. Executing this method will
+// update the undecoded keys in the meta data. (See the example.)
+func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error {
+ md.context = primValue.context
+ defer func() { md.context = nil }()
+ return md.unify(primValue.undecoded, rvalue(v))
+}
+
+// Decode will decode the contents of `data` in TOML format into a pointer
+// `v`.
+//
+// TOML hashes correspond to Go structs or maps. (Dealer's choice. They can be
+// used interchangeably.)
+//
+// TOML arrays of tables correspond to either a slice of structs or a slice
+// of maps.
+//
+// TOML datetimes correspond to Go `time.Time` values.
+//
+// All other TOML types (float, string, int, bool and array) correspond
+// to the obvious Go types.
+//
+// An exception to the above rules is if a type implements the
+// encoding.TextUnmarshaler interface. In this case, any primitive TOML value
+// (floats, strings, integers, booleans and datetimes) will be converted to
+// a byte string and given to the value's UnmarshalText method. See the
+// Unmarshaler example for a demonstration with time duration strings.
+//
+// Key mapping
+//
+// TOML keys can map to either keys in a Go map or field names in a Go
+// struct. The special `toml` struct tag may be used to map TOML keys to
+// struct fields that don't match the key name exactly. (See the example.)
+// A case insensitive match to struct names will be tried if an exact match
+// can't be found.
+//
+// The mapping between TOML values and Go values is loose. That is, there
+// may exist TOML values that cannot be placed into your representation, and
+// there may be parts of your representation that do not correspond to
+// TOML values. This loose mapping can be made stricter by using the IsDefined
+// and/or Undecoded methods on the MetaData returned.
+//
+// This decoder will not handle cyclic types. If a cyclic type is passed,
+// `Decode` will not terminate.
+func Decode(data string, v interface{}) (MetaData, error) {
+ rv := reflect.ValueOf(v)
+ if rv.Kind() != reflect.Ptr {
+ return MetaData{}, e("Decode of non-pointer %s", reflect.TypeOf(v))
+ }
+ if rv.IsNil() {
+ return MetaData{}, e("Decode of nil %s", reflect.TypeOf(v))
+ }
+ p, err := parse(data)
+ if err != nil {
+ return MetaData{}, err
+ }
+ md := MetaData{
+ p.mapping, p.types, p.ordered,
+ make(map[string]bool, len(p.ordered)), nil,
+ }
+ return md, md.unify(p.mapping, indirect(rv))
+}
+
+// DecodeFile is just like Decode, except it will automatically read the
+// contents of the file at `fpath` and decode it for you.
+func DecodeFile(fpath string, v interface{}) (MetaData, error) {
+ bs, err := ioutil.ReadFile(fpath)
+ if err != nil {
+ return MetaData{}, err
+ }
+ return Decode(string(bs), v)
+}
+
+// DecodeReader is just like Decode, except it will consume all bytes
+// from the reader and decode it for you.
+func DecodeReader(r io.Reader, v interface{}) (MetaData, error) {
+ bs, err := ioutil.ReadAll(r)
+ if err != nil {
+ return MetaData{}, err
+ }
+ return Decode(string(bs), v)
+}
+
+// unify performs a sort of type unification based on the structure of `rv`,
+// which is the client representation.
+//
+// Any type mismatch produces an error. Finding a type that we don't know
+// how to handle produces an unsupported type error.
+func (md *MetaData) unify(data interface{}, rv reflect.Value) error {
+
+ // Special case. Look for a `Primitive` value.
+ if rv.Type() == reflect.TypeOf((*Primitive)(nil)).Elem() {
+ // Save the undecoded data and the key context into the primitive
+ // value.
+ context := make(Key, len(md.context))
+ copy(context, md.context)
+ rv.Set(reflect.ValueOf(Primitive{
+ undecoded: data,
+ context: context,
+ }))
+ return nil
+ }
+
+ // Special case. Unmarshaler Interface support.
+ if rv.CanAddr() {
+ if v, ok := rv.Addr().Interface().(Unmarshaler); ok {
+ return v.UnmarshalTOML(data)
+ }
+ }
+
+ // Special case. Handle time.Time values specifically.
+ // TODO: Remove this code when we decide to drop support for Go 1.1.
+ // This isn't necessary in Go 1.2 because time.Time satisfies the encoding
+ // interfaces.
+ if rv.Type().AssignableTo(rvalue(time.Time{}).Type()) {
+ return md.unifyDatetime(data, rv)
+ }
+
+ // Special case. Look for a value satisfying the TextUnmarshaler interface.
+ if v, ok := rv.Interface().(TextUnmarshaler); ok {
+ return md.unifyText(data, v)
+ }
+ // BUG(burntsushi)
+ // The behavior here is incorrect whenever a Go type satisfies the
+ // encoding.TextUnmarshaler interface but also corresponds to a TOML
+ // hash or array. In particular, the unmarshaler should only be applied
+ // to primitive TOML values. But at this point, it will be applied to
+ // all kinds of values and produce an incorrect error whenever those values
+ // are hashes or arrays (including arrays of tables).
+
+ k := rv.Kind()
+
+ // laziness
+ if k >= reflect.Int && k <= reflect.Uint64 {
+ return md.unifyInt(data, rv)
+ }
+ switch k {
+ case reflect.Ptr:
+ elem := reflect.New(rv.Type().Elem())
+ err := md.unify(data, reflect.Indirect(elem))
+ if err != nil {
+ return err
+ }
+ rv.Set(elem)
+ return nil
+ case reflect.Struct:
+ return md.unifyStruct(data, rv)
+ case reflect.Map:
+ return md.unifyMap(data, rv)
+ case reflect.Array:
+ return md.unifyArray(data, rv)
+ case reflect.Slice:
+ return md.unifySlice(data, rv)
+ case reflect.String:
+ return md.unifyString(data, rv)
+ case reflect.Bool:
+ return md.unifyBool(data, rv)
+ case reflect.Interface:
+ // we only support empty interfaces.
+ if rv.NumMethod() > 0 {
+ return e("unsupported type %s", rv.Type())
+ }
+ return md.unifyAnything(data, rv)
+ case reflect.Float32:
+ fallthrough
+ case reflect.Float64:
+ return md.unifyFloat64(data, rv)
+ }
+ return e("unsupported type %s", rv.Kind())
+}
+
+func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error {
+ tmap, ok := mapping.(map[string]interface{})
+ if !ok {
+ if mapping == nil {
+ return nil
+ }
+ return e("type mismatch for %s: expected table but found %T",
+ rv.Type().String(), mapping)
+ }
+
+ for key, datum := range tmap {
+ var f *field
+ fields := cachedTypeFields(rv.Type())
+ for i := range fields {
+ ff := &fields[i]
+ if ff.name == key {
+ f = ff
+ break
+ }
+ if f == nil && strings.EqualFold(ff.name, key) {
+ f = ff
+ }
+ }
+ if f != nil {
+ subv := rv
+ for _, i := range f.index {
+ subv = indirect(subv.Field(i))
+ }
+ if isUnifiable(subv) {
+ md.decoded[md.context.add(key).String()] = true
+ md.context = append(md.context, key)
+ if err := md.unify(datum, subv); err != nil {
+ return err
+ }
+ md.context = md.context[0 : len(md.context)-1]
+ } else if f.name != "" {
+ // Bad user! No soup for you!
+ return e("cannot write unexported field %s.%s",
+ rv.Type().String(), f.name)
+ }
+ }
+ }
+ return nil
+}
+
+func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error {
+ tmap, ok := mapping.(map[string]interface{})
+ if !ok {
+ if tmap == nil {
+ return nil
+ }
+ return badtype("map", mapping)
+ }
+ if rv.IsNil() {
+ rv.Set(reflect.MakeMap(rv.Type()))
+ }
+ for k, v := range tmap {
+ md.decoded[md.context.add(k).String()] = true
+ md.context = append(md.context, k)
+
+ rvkey := indirect(reflect.New(rv.Type().Key()))
+ rvval := reflect.Indirect(reflect.New(rv.Type().Elem()))
+ if err := md.unify(v, rvval); err != nil {
+ return err
+ }
+ md.context = md.context[0 : len(md.context)-1]
+
+ rvkey.SetString(k)
+ rv.SetMapIndex(rvkey, rvval)
+ }
+ return nil
+}
+
+func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error {
+ datav := reflect.ValueOf(data)
+ if datav.Kind() != reflect.Slice {
+ if !datav.IsValid() {
+ return nil
+ }
+ return badtype("slice", data)
+ }
+ sliceLen := datav.Len()
+ if sliceLen != rv.Len() {
+ return e("expected array length %d; got TOML array of length %d",
+ rv.Len(), sliceLen)
+ }
+ return md.unifySliceArray(datav, rv)
+}
+
+func (md *MetaData) unifySlice(data interface{}, rv reflect.Value) error {
+ datav := reflect.ValueOf(data)
+ if datav.Kind() != reflect.Slice {
+ if !datav.IsValid() {
+ return nil
+ }
+ return badtype("slice", data)
+ }
+ n := datav.Len()
+ if rv.IsNil() || rv.Cap() < n {
+ rv.Set(reflect.MakeSlice(rv.Type(), n, n))
+ }
+ rv.SetLen(n)
+ return md.unifySliceArray(datav, rv)
+}
+
+func (md *MetaData) unifySliceArray(data, rv reflect.Value) error {
+ sliceLen := data.Len()
+ for i := 0; i < sliceLen; i++ {
+ v := data.Index(i).Interface()
+ sliceval := indirect(rv.Index(i))
+ if err := md.unify(v, sliceval); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (md *MetaData) unifyDatetime(data interface{}, rv reflect.Value) error {
+ if _, ok := data.(time.Time); ok {
+ rv.Set(reflect.ValueOf(data))
+ return nil
+ }
+ return badtype("time.Time", data)
+}
+
+func (md *MetaData) unifyString(data interface{}, rv reflect.Value) error {
+ if s, ok := data.(string); ok {
+ rv.SetString(s)
+ return nil
+ }
+ return badtype("string", data)
+}
+
+func (md *MetaData) unifyFloat64(data interface{}, rv reflect.Value) error {
+ if num, ok := data.(float64); ok {
+ switch rv.Kind() {
+ case reflect.Float32:
+ fallthrough
+ case reflect.Float64:
+ rv.SetFloat(num)
+ default:
+ panic("bug")
+ }
+ return nil
+ }
+ return badtype("float", data)
+}
+
+func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error {
+ if num, ok := data.(int64); ok {
+ if rv.Kind() >= reflect.Int && rv.Kind() <= reflect.Int64 {
+ switch rv.Kind() {
+ case reflect.Int, reflect.Int64:
+ // No bounds checking necessary.
+ case reflect.Int8:
+ if num < math.MinInt8 || num > math.MaxInt8 {
+ return e("value %d is out of range for int8", num)
+ }
+ case reflect.Int16:
+ if num < math.MinInt16 || num > math.MaxInt16 {
+ return e("value %d is out of range for int16", num)
+ }
+ case reflect.Int32:
+ if num < math.MinInt32 || num > math.MaxInt32 {
+ return e("value %d is out of range for int32", num)
+ }
+ }
+ rv.SetInt(num)
+ } else if rv.Kind() >= reflect.Uint && rv.Kind() <= reflect.Uint64 {
+ unum := uint64(num)
+ switch rv.Kind() {
+ case reflect.Uint, reflect.Uint64:
+ // No bounds checking necessary.
+ case reflect.Uint8:
+ if num < 0 || unum > math.MaxUint8 {
+ return e("value %d is out of range for uint8", num)
+ }
+ case reflect.Uint16:
+ if num < 0 || unum > math.MaxUint16 {
+ return e("value %d is out of range for uint16", num)
+ }
+ case reflect.Uint32:
+ if num < 0 || unum > math.MaxUint32 {
+ return e("value %d is out of range for uint32", num)
+ }
+ }
+ rv.SetUint(unum)
+ } else {
+ panic("unreachable")
+ }
+ return nil
+ }
+ return badtype("integer", data)
+}
+
+func (md *MetaData) unifyBool(data interface{}, rv reflect.Value) error {
+ if b, ok := data.(bool); ok {
+ rv.SetBool(b)
+ return nil
+ }
+ return badtype("boolean", data)
+}
+
+func (md *MetaData) unifyAnything(data interface{}, rv reflect.Value) error {
+ rv.Set(reflect.ValueOf(data))
+ return nil
+}
+
+func (md *MetaData) unifyText(data interface{}, v TextUnmarshaler) error {
+ var s string
+ switch sdata := data.(type) {
+ case TextMarshaler:
+ text, err := sdata.MarshalText()
+ if err != nil {
+ return err
+ }
+ s = string(text)
+ case fmt.Stringer:
+ s = sdata.String()
+ case string:
+ s = sdata
+ case bool:
+ s = fmt.Sprintf("%v", sdata)
+ case int64:
+ s = fmt.Sprintf("%d", sdata)
+ case float64:
+ s = fmt.Sprintf("%f", sdata)
+ default:
+ return badtype("primitive (string-like)", data)
+ }
+ if err := v.UnmarshalText([]byte(s)); err != nil {
+ return err
+ }
+ return nil
+}
+
+// rvalue returns a reflect.Value of `v`. All pointers are resolved.
+func rvalue(v interface{}) reflect.Value {
+ return indirect(reflect.ValueOf(v))
+}
+
+// indirect returns the value pointed to by a pointer.
+// Pointers are followed until the value is not a pointer.
+// New values are allocated for each nil pointer.
+//
+// An exception to this rule is if the value satisfies an interface of
+// interest to us (like encoding.TextUnmarshaler).
+func indirect(v reflect.Value) reflect.Value {
+ if v.Kind() != reflect.Ptr {
+ if v.CanSet() {
+ pv := v.Addr()
+ if _, ok := pv.Interface().(TextUnmarshaler); ok {
+ return pv
+ }
+ }
+ return v
+ }
+ if v.IsNil() {
+ v.Set(reflect.New(v.Type().Elem()))
+ }
+ return indirect(reflect.Indirect(v))
+}
+
+func isUnifiable(rv reflect.Value) bool {
+ if rv.CanSet() {
+ return true
+ }
+ if _, ok := rv.Interface().(TextUnmarshaler); ok {
+ return true
+ }
+ return false
+}
+
+func badtype(expected string, data interface{}) error {
+ return e("cannot load TOML value of type %T into a Go %s", data, expected)
+}
diff --git a/vendor/github.com/BurntSushi/toml/decode_meta.go b/vendor/github.com/BurntSushi/toml/decode_meta.go
new file mode 100644
index 0000000..b9914a6
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/decode_meta.go
@@ -0,0 +1,121 @@
+package toml
+
+import "strings"
+
+// MetaData allows access to meta information about TOML data that may not
+// be inferrable via reflection. In particular, whether a key has been defined
+// and the TOML type of a key.
+type MetaData struct {
+ mapping map[string]interface{}
+ types map[string]tomlType
+ keys []Key
+ decoded map[string]bool
+ context Key // Used only during decoding.
+}
+
+// IsDefined returns true if the key given exists in the TOML data. The key
+// should be specified hierarchially. e.g.,
+//
+// // access the TOML key 'a.b.c'
+// IsDefined("a", "b", "c")
+//
+// IsDefined will return false if an empty key given. Keys are case sensitive.
+func (md *MetaData) IsDefined(key ...string) bool {
+ if len(key) == 0 {
+ return false
+ }
+
+ var hash map[string]interface{}
+ var ok bool
+ var hashOrVal interface{} = md.mapping
+ for _, k := range key {
+ if hash, ok = hashOrVal.(map[string]interface{}); !ok {
+ return false
+ }
+ if hashOrVal, ok = hash[k]; !ok {
+ return false
+ }
+ }
+ return true
+}
+
+// Type returns a string representation of the type of the key specified.
+//
+// Type will return the empty string if given an empty key or a key that
+// does not exist. Keys are case sensitive.
+func (md *MetaData) Type(key ...string) string {
+ fullkey := strings.Join(key, ".")
+ if typ, ok := md.types[fullkey]; ok {
+ return typ.typeString()
+ }
+ return ""
+}
+
+// Key is the type of any TOML key, including key groups. Use (MetaData).Keys
+// to get values of this type.
+type Key []string
+
+func (k Key) String() string {
+ return strings.Join(k, ".")
+}
+
+func (k Key) maybeQuotedAll() string {
+ var ss []string
+ for i := range k {
+ ss = append(ss, k.maybeQuoted(i))
+ }
+ return strings.Join(ss, ".")
+}
+
+func (k Key) maybeQuoted(i int) string {
+ quote := false
+ for _, c := range k[i] {
+ if !isBareKeyChar(c) {
+ quote = true
+ break
+ }
+ }
+ if quote {
+ return "\"" + strings.Replace(k[i], "\"", "\\\"", -1) + "\""
+ }
+ return k[i]
+}
+
+func (k Key) add(piece string) Key {
+ newKey := make(Key, len(k)+1)
+ copy(newKey, k)
+ newKey[len(k)] = piece
+ return newKey
+}
+
+// Keys returns a slice of every key in the TOML data, including key groups.
+// Each key is itself a slice, where the first element is the top of the
+// hierarchy and the last is the most specific.
+//
+// The list will have the same order as the keys appeared in the TOML data.
+//
+// All keys returned are non-empty.
+func (md *MetaData) Keys() []Key {
+ return md.keys
+}
+
+// Undecoded returns all keys that have not been decoded in the order in which
+// they appear in the original TOML document.
+//
+// This includes keys that haven't been decoded because of a Primitive value.
+// Once the Primitive value is decoded, the keys will be considered decoded.
+//
+// Also note that decoding into an empty interface will result in no decoding,
+// and so no keys will be considered decoded.
+//
+// In this sense, the Undecoded keys correspond to keys in the TOML document
+// that do not have a concrete type in your representation.
+func (md *MetaData) Undecoded() []Key {
+ undecoded := make([]Key, 0, len(md.keys))
+ for _, key := range md.keys {
+ if !md.decoded[key.String()] {
+ undecoded = append(undecoded, key)
+ }
+ }
+ return undecoded
+}
diff --git a/vendor/github.com/BurntSushi/toml/decode_test.go b/vendor/github.com/BurntSushi/toml/decode_test.go
new file mode 100644
index 0000000..0c36b33
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/decode_test.go
@@ -0,0 +1,1447 @@
+package toml
+
+import (
+ "fmt"
+ "log"
+ "math"
+ "reflect"
+ "strings"
+ "testing"
+ "time"
+)
+
+func TestDecodeSimple(t *testing.T) {
+ var testSimple = `
+age = 250
+andrew = "gallant"
+kait = "brady"
+now = 1987-07-05T05:45:00Z
+yesOrNo = true
+pi = 3.14
+colors = [
+ ["red", "green", "blue"],
+ ["cyan", "magenta", "yellow", "black"],
+]
+
+[My.Cats]
+plato = "cat 1"
+cauchy = "cat 2"
+`
+
+ type cats struct {
+ Plato string
+ Cauchy string
+ }
+ type simple struct {
+ Age int
+ Colors [][]string
+ Pi float64
+ YesOrNo bool
+ Now time.Time
+ Andrew string
+ Kait string
+ My map[string]cats
+ }
+
+ var val simple
+ _, err := Decode(testSimple, &val)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ now, err := time.Parse("2006-01-02T15:04:05", "1987-07-05T05:45:00")
+ if err != nil {
+ panic(err)
+ }
+ var answer = simple{
+ Age: 250,
+ Andrew: "gallant",
+ Kait: "brady",
+ Now: now,
+ YesOrNo: true,
+ Pi: 3.14,
+ Colors: [][]string{
+ {"red", "green", "blue"},
+ {"cyan", "magenta", "yellow", "black"},
+ },
+ My: map[string]cats{
+ "Cats": {Plato: "cat 1", Cauchy: "cat 2"},
+ },
+ }
+ if !reflect.DeepEqual(val, answer) {
+ t.Fatalf("Expected\n-----\n%#v\n-----\nbut got\n-----\n%#v\n",
+ answer, val)
+ }
+}
+
+func TestDecodeEmbedded(t *testing.T) {
+ type Dog struct{ Name string }
+ type Age int
+ type cat struct{ Name string }
+
+ for _, test := range []struct {
+ label string
+ input string
+ decodeInto interface{}
+ wantDecoded interface{}
+ }{
+ {
+ label: "embedded struct",
+ input: `Name = "milton"`,
+ decodeInto: &struct{ Dog }{},
+ wantDecoded: &struct{ Dog }{Dog{"milton"}},
+ },
+ {
+ label: "embedded non-nil pointer to struct",
+ input: `Name = "milton"`,
+ decodeInto: &struct{ *Dog }{},
+ wantDecoded: &struct{ *Dog }{&Dog{"milton"}},
+ },
+ {
+ label: "embedded nil pointer to struct",
+ input: ``,
+ decodeInto: &struct{ *Dog }{},
+ wantDecoded: &struct{ *Dog }{nil},
+ },
+ {
+ label: "unexported embedded struct",
+ input: `Name = "socks"`,
+ decodeInto: &struct{ cat }{},
+ wantDecoded: &struct{ cat }{cat{"socks"}},
+ },
+ {
+ label: "embedded int",
+ input: `Age = -5`,
+ decodeInto: &struct{ Age }{},
+ wantDecoded: &struct{ Age }{-5},
+ },
+ } {
+ _, err := Decode(test.input, test.decodeInto)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(test.wantDecoded, test.decodeInto) {
+ t.Errorf("%s: want decoded == %+v, got %+v",
+ test.label, test.wantDecoded, test.decodeInto)
+ }
+ }
+}
+
+func TestDecodeIgnoredFields(t *testing.T) {
+ type simple struct {
+ Number int `toml:"-"`
+ }
+ const input = `
+Number = 123
+- = 234
+`
+ var s simple
+ if _, err := Decode(input, &s); err != nil {
+ t.Fatal(err)
+ }
+ if s.Number != 0 {
+ t.Errorf("got: %d; want 0", s.Number)
+ }
+}
+
+func TestTableArrays(t *testing.T) {
+ var tomlTableArrays = `
+[[albums]]
+name = "Born to Run"
+
+ [[albums.songs]]
+ name = "Jungleland"
+
+ [[albums.songs]]
+ name = "Meeting Across the River"
+
+[[albums]]
+name = "Born in the USA"
+
+ [[albums.songs]]
+ name = "Glory Days"
+
+ [[albums.songs]]
+ name = "Dancing in the Dark"
+`
+
+ type Song struct {
+ Name string
+ }
+
+ type Album struct {
+ Name string
+ Songs []Song
+ }
+
+ type Music struct {
+ Albums []Album
+ }
+
+ expected := Music{[]Album{
+ {"Born to Run", []Song{{"Jungleland"}, {"Meeting Across the River"}}},
+ {"Born in the USA", []Song{{"Glory Days"}, {"Dancing in the Dark"}}},
+ }}
+ var got Music
+ if _, err := Decode(tomlTableArrays, &got); err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(expected, got) {
+ t.Fatalf("\n%#v\n!=\n%#v\n", expected, got)
+ }
+}
+
+func TestTableNesting(t *testing.T) {
+ for _, tt := range []struct {
+ t string
+ want []string
+ }{
+ {"[a.b.c]", []string{"a", "b", "c"}},
+ {`[a."b.c"]`, []string{"a", "b.c"}},
+ {`[a.'b.c']`, []string{"a", "b.c"}},
+ {`[a.' b ']`, []string{"a", " b "}},
+ {"[ d.e.f ]", []string{"d", "e", "f"}},
+ {"[ g . h . i ]", []string{"g", "h", "i"}},
+ {`[ j . "ʞ" . 'l' ]`, []string{"j", "ʞ", "l"}},
+ } {
+ var m map[string]interface{}
+ if _, err := Decode(tt.t, &m); err != nil {
+ t.Errorf("Decode(%q): got error: %s", tt.t, err)
+ continue
+ }
+ if keys := extractNestedKeys(m); !reflect.DeepEqual(keys, tt.want) {
+ t.Errorf("Decode(%q): got nested keys %#v; want %#v",
+ tt.t, keys, tt.want)
+ }
+ }
+}
+
+func extractNestedKeys(v map[string]interface{}) []string {
+ var result []string
+ for {
+ if len(v) != 1 {
+ return result
+ }
+ for k, m := range v {
+ result = append(result, k)
+ var ok bool
+ v, ok = m.(map[string]interface{})
+ if !ok {
+ return result
+ }
+ }
+
+ }
+}
+
+// Case insensitive matching tests.
+// A bit more comprehensive than needed given the current implementation,
+// but implementations change.
+// Probably still missing demonstrations of some ugly corner cases regarding
+// case insensitive matching and multiple fields.
+func TestCase(t *testing.T) {
+ var caseToml = `
+tOpString = "string"
+tOpInt = 1
+tOpFloat = 1.1
+tOpBool = true
+tOpdate = 2006-01-02T15:04:05Z
+tOparray = [ "array" ]
+Match = "i should be in Match only"
+MatcH = "i should be in MatcH only"
+once = "just once"
+[nEst.eD]
+nEstedString = "another string"
+`
+
+ type InsensitiveEd struct {
+ NestedString string
+ }
+
+ type InsensitiveNest struct {
+ Ed InsensitiveEd
+ }
+
+ type Insensitive struct {
+ TopString string
+ TopInt int
+ TopFloat float64
+ TopBool bool
+ TopDate time.Time
+ TopArray []string
+ Match string
+ MatcH string
+ Once string
+ OncE string
+ Nest InsensitiveNest
+ }
+
+ tme, err := time.Parse(time.RFC3339, time.RFC3339[:len(time.RFC3339)-5])
+ if err != nil {
+ panic(err)
+ }
+ expected := Insensitive{
+ TopString: "string",
+ TopInt: 1,
+ TopFloat: 1.1,
+ TopBool: true,
+ TopDate: tme,
+ TopArray: []string{"array"},
+ MatcH: "i should be in MatcH only",
+ Match: "i should be in Match only",
+ Once: "just once",
+ OncE: "",
+ Nest: InsensitiveNest{
+ Ed: InsensitiveEd{NestedString: "another string"},
+ },
+ }
+ var got Insensitive
+ if _, err := Decode(caseToml, &got); err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(expected, got) {
+ t.Fatalf("\n%#v\n!=\n%#v\n", expected, got)
+ }
+}
+
+func TestPointers(t *testing.T) {
+ type Object struct {
+ Type string
+ Description string
+ }
+
+ type Dict struct {
+ NamedObject map[string]*Object
+ BaseObject *Object
+ Strptr *string
+ Strptrs []*string
+ }
+ s1, s2, s3 := "blah", "abc", "def"
+ expected := &Dict{
+ Strptr: &s1,
+ Strptrs: []*string{&s2, &s3},
+ NamedObject: map[string]*Object{
+ "foo": {"FOO", "fooooo!!!"},
+ "bar": {"BAR", "ba-ba-ba-ba-barrrr!!!"},
+ },
+ BaseObject: &Object{"BASE", "da base"},
+ }
+
+ ex1 := `
+Strptr = "blah"
+Strptrs = ["abc", "def"]
+
+[NamedObject.foo]
+Type = "FOO"
+Description = "fooooo!!!"
+
+[NamedObject.bar]
+Type = "BAR"
+Description = "ba-ba-ba-ba-barrrr!!!"
+
+[BaseObject]
+Type = "BASE"
+Description = "da base"
+`
+ dict := new(Dict)
+ _, err := Decode(ex1, dict)
+ if err != nil {
+ t.Errorf("Decode error: %v", err)
+ }
+ if !reflect.DeepEqual(expected, dict) {
+ t.Fatalf("\n%#v\n!=\n%#v\n", expected, dict)
+ }
+}
+
+func TestDecodeDatetime(t *testing.T) {
+ const noTimestamp = "2006-01-02T15:04:05"
+ for _, tt := range []struct {
+ s string
+ t string
+ format string
+ }{
+ {"1979-05-27T07:32:00Z", "1979-05-27T07:32:00Z", time.RFC3339},
+ {"1979-05-27T00:32:00-07:00", "1979-05-27T00:32:00-07:00", time.RFC3339},
+ {
+ "1979-05-27T00:32:00.999999-07:00",
+ "1979-05-27T00:32:00.999999-07:00",
+ time.RFC3339,
+ },
+ {"1979-05-27T07:32:00", "1979-05-27T07:32:00", noTimestamp},
+ {
+ "1979-05-27T00:32:00.999999",
+ "1979-05-27T00:32:00.999999",
+ noTimestamp,
+ },
+ {"1979-05-27", "1979-05-27T00:00:00", noTimestamp},
+ } {
+ var x struct{ D time.Time }
+ input := "d = " + tt.s
+ if _, err := Decode(input, &x); err != nil {
+ t.Errorf("Decode(%q): got error: %s", input, err)
+ continue
+ }
+ want, err := time.ParseInLocation(tt.format, tt.t, time.Local)
+ if err != nil {
+ panic(err)
+ }
+ if !x.D.Equal(want) {
+ t.Errorf("Decode(%q): got %s; want %s", input, x.D, want)
+ }
+ }
+}
+
+func TestDecodeBadDatetime(t *testing.T) {
+ var x struct{ T time.Time }
+ for _, s := range []string{
+ "123",
+ "2006-01-50T00:00:00Z",
+ "2006-01-30T00:00",
+ "2006-01-30T",
+ } {
+ input := "T = " + s
+ if _, err := Decode(input, &x); err == nil {
+ t.Errorf("Expected invalid DateTime error for %q", s)
+ }
+ }
+}
+
+func TestDecodeMultilineStrings(t *testing.T) {
+ var x struct {
+ S string
+ }
+ const s0 = `s = """
+a b \n c
+d e f
+"""`
+ if _, err := Decode(s0, &x); err != nil {
+ t.Fatal(err)
+ }
+ if want := "a b \n c\nd e f\n"; x.S != want {
+ t.Errorf("got: %q; want: %q", x.S, want)
+ }
+ const s1 = `s = """a b c\
+"""`
+ if _, err := Decode(s1, &x); err != nil {
+ t.Fatal(err)
+ }
+ if want := "a b c"; x.S != want {
+ t.Errorf("got: %q; want: %q", x.S, want)
+ }
+}
+
+type sphere struct {
+ Center [3]float64
+ Radius float64
+}
+
+func TestDecodeSimpleArray(t *testing.T) {
+ var s1 sphere
+ if _, err := Decode(`center = [0.0, 1.5, 0.0]`, &s1); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestDecodeArrayWrongSize(t *testing.T) {
+ var s1 sphere
+ if _, err := Decode(`center = [0.1, 2.3]`, &s1); err == nil {
+ t.Fatal("Expected array type mismatch error")
+ }
+}
+
+func TestDecodeLargeIntoSmallInt(t *testing.T) {
+ type table struct {
+ Value int8
+ }
+ var tab table
+ if _, err := Decode(`value = 500`, &tab); err == nil {
+ t.Fatal("Expected integer out-of-bounds error.")
+ }
+}
+
+func TestDecodeSizedInts(t *testing.T) {
+ type table struct {
+ U8 uint8
+ U16 uint16
+ U32 uint32
+ U64 uint64
+ U uint
+ I8 int8
+ I16 int16
+ I32 int32
+ I64 int64
+ I int
+ }
+ answer := table{1, 1, 1, 1, 1, -1, -1, -1, -1, -1}
+ toml := `
+ u8 = 1
+ u16 = 1
+ u32 = 1
+ u64 = 1
+ u = 1
+ i8 = -1
+ i16 = -1
+ i32 = -1
+ i64 = -1
+ i = -1
+ `
+ var tab table
+ if _, err := Decode(toml, &tab); err != nil {
+ t.Fatal(err.Error())
+ }
+ if answer != tab {
+ t.Fatalf("Expected %#v but got %#v", answer, tab)
+ }
+}
+
+func TestDecodeInts(t *testing.T) {
+ for _, tt := range []struct {
+ s string
+ want int64
+ }{
+ {"0", 0},
+ {"+99", 99},
+ {"-10", -10},
+ {"1_234_567", 1234567},
+ {"1_2_3_4", 1234},
+ {"-9_223_372_036_854_775_808", math.MinInt64},
+ {"9_223_372_036_854_775_807", math.MaxInt64},
+ } {
+ var x struct{ N int64 }
+ input := "n = " + tt.s
+ if _, err := Decode(input, &x); err != nil {
+ t.Errorf("Decode(%q): got error: %s", input, err)
+ continue
+ }
+ if x.N != tt.want {
+ t.Errorf("Decode(%q): got %d; want %d", input, x.N, tt.want)
+ }
+ }
+}
+
+func TestDecodeFloats(t *testing.T) {
+ for _, tt := range []struct {
+ s string
+ want float64
+ }{
+ {"+1.0", 1},
+ {"3.1415", 3.1415},
+ {"-0.01", -0.01},
+ {"5e+22", 5e22},
+ {"1e6", 1e6},
+ {"-2E-2", -2e-2},
+ {"6.626e-34", 6.626e-34},
+ {"9_224_617.445_991_228_313", 9224617.445991228313},
+ {"9_876.54_32e1_0", 9876.5432e10},
+ } {
+ var x struct{ N float64 }
+ input := "n = " + tt.s
+ if _, err := Decode(input, &x); err != nil {
+ t.Errorf("Decode(%q): got error: %s", input, err)
+ continue
+ }
+ if x.N != tt.want {
+ t.Errorf("Decode(%q): got %f; want %f", input, x.N, tt.want)
+ }
+ }
+}
+
+func TestDecodeMalformedNumbers(t *testing.T) {
+ for _, tt := range []struct {
+ s string
+ want string
+ }{
+ {"++99", "expected a digit"},
+ {"0..1", "must be followed by one or more digits"},
+ {"0.1.2", "Invalid float value"},
+ {"1e2.3", "Invalid float value"},
+ {"1e2e3", "Invalid float value"},
+ {"_123", "expected value"},
+ {"123_", "surrounded by digits"},
+ {"1._23", "surrounded by digits"},
+ {"1e__23", "surrounded by digits"},
+ {"123.", "must be followed by one or more digits"},
+ {"1.e2", "must be followed by one or more digits"},
+ } {
+ var x struct{ N interface{} }
+ input := "n = " + tt.s
+ _, err := Decode(input, &x)
+ if err == nil {
+ t.Errorf("Decode(%q): got nil, want error containing %q",
+ input, tt.want)
+ continue
+ }
+ if !strings.Contains(err.Error(), tt.want) {
+ t.Errorf("Decode(%q): got %q, want error containing %q",
+ input, err, tt.want)
+ }
+ }
+}
+
+func TestDecodeBadValues(t *testing.T) {
+ for _, tt := range []struct {
+ v interface{}
+ want string
+ }{
+ {3, "non-pointer int"},
+ {(*int)(nil), "nil"},
+ } {
+ _, err := Decode(`x = 3`, tt.v)
+ if err == nil {
+ t.Errorf("Decode(%v): got nil; want error containing %q",
+ tt.v, tt.want)
+ continue
+ }
+ if !strings.Contains(err.Error(), tt.want) {
+ t.Errorf("Decode(%v): got %q; want error containing %q",
+ tt.v, err, tt.want)
+ }
+ }
+}
+
+func TestUnmarshaler(t *testing.T) {
+
+ var tomlBlob = `
+[dishes.hamboogie]
+name = "Hamboogie with fries"
+price = 10.99
+
+[[dishes.hamboogie.ingredients]]
+name = "Bread Bun"
+
+[[dishes.hamboogie.ingredients]]
+name = "Lettuce"
+
+[[dishes.hamboogie.ingredients]]
+name = "Real Beef Patty"
+
+[[dishes.hamboogie.ingredients]]
+name = "Tomato"
+
+[dishes.eggsalad]
+name = "Egg Salad with rice"
+price = 3.99
+
+[[dishes.eggsalad.ingredients]]
+name = "Egg"
+
+[[dishes.eggsalad.ingredients]]
+name = "Mayo"
+
+[[dishes.eggsalad.ingredients]]
+name = "Rice"
+`
+ m := &menu{}
+ if _, err := Decode(tomlBlob, m); err != nil {
+ t.Fatal(err)
+ }
+
+ if len(m.Dishes) != 2 {
+ t.Log("two dishes should be loaded with UnmarshalTOML()")
+ t.Errorf("expected %d but got %d", 2, len(m.Dishes))
+ }
+
+ eggSalad := m.Dishes["eggsalad"]
+ if _, ok := interface{}(eggSalad).(dish); !ok {
+ t.Errorf("expected a dish")
+ }
+
+ if eggSalad.Name != "Egg Salad with rice" {
+ t.Errorf("expected the dish to be named 'Egg Salad with rice'")
+ }
+
+ if len(eggSalad.Ingredients) != 3 {
+ t.Log("dish should be loaded with UnmarshalTOML()")
+ t.Errorf("expected %d but got %d", 3, len(eggSalad.Ingredients))
+ }
+
+ found := false
+ for _, i := range eggSalad.Ingredients {
+ if i.Name == "Rice" {
+ found = true
+ break
+ }
+ }
+ if !found {
+ t.Error("Rice was not loaded in UnmarshalTOML()")
+ }
+
+ // test on a value - must be passed as *
+ o := menu{}
+ if _, err := Decode(tomlBlob, &o); err != nil {
+ t.Fatal(err)
+ }
+
+}
+
+func TestDecodeInlineTable(t *testing.T) {
+ input := `
+[CookieJar]
+Types = {Chocolate = "yummy", Oatmeal = "best ever"}
+
+[Seasons]
+Locations = {NY = {Temp = "not cold", Rating = 4}, MI = {Temp = "freezing", Rating = 9}}
+`
+ type cookieJar struct {
+ Types map[string]string
+ }
+ type properties struct {
+ Temp string
+ Rating int
+ }
+ type seasons struct {
+ Locations map[string]properties
+ }
+ type wrapper struct {
+ CookieJar cookieJar
+ Seasons seasons
+ }
+ var got wrapper
+
+ meta, err := Decode(input, &got)
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := wrapper{
+ CookieJar: cookieJar{
+ Types: map[string]string{
+ "Chocolate": "yummy",
+ "Oatmeal": "best ever",
+ },
+ },
+ Seasons: seasons{
+ Locations: map[string]properties{
+ "NY": {
+ Temp: "not cold",
+ Rating: 4,
+ },
+ "MI": {
+ Temp: "freezing",
+ Rating: 9,
+ },
+ },
+ },
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Fatalf("after decode, got:\n\n%#v\n\nwant:\n\n%#v", got, want)
+ }
+ if len(meta.keys) != 12 {
+ t.Errorf("after decode, got %d meta keys; want 12", len(meta.keys))
+ }
+ if len(meta.types) != 12 {
+ t.Errorf("after decode, got %d meta types; want 12", len(meta.types))
+ }
+}
+
+func TestDecodeInlineTableArray(t *testing.T) {
+ type point struct {
+ X, Y, Z int
+ }
+ var got struct {
+ Points []point
+ }
+ // Example inline table array from the spec.
+ const in = `
+points = [ { x = 1, y = 2, z = 3 },
+ { x = 7, y = 8, z = 9 },
+ { x = 2, y = 4, z = 8 } ]
+
+`
+ if _, err := Decode(in, &got); err != nil {
+ t.Fatal(err)
+ }
+ want := []point{
+ {X: 1, Y: 2, Z: 3},
+ {X: 7, Y: 8, Z: 9},
+ {X: 2, Y: 4, Z: 8},
+ }
+ if !reflect.DeepEqual(got.Points, want) {
+ t.Errorf("got %#v; want %#v", got.Points, want)
+ }
+}
+
+func TestDecodeMalformedInlineTable(t *testing.T) {
+ for _, tt := range []struct {
+ s string
+ want string
+ }{
+ {"{,}", "unexpected comma"},
+ {"{x = 3 y = 4}", "expected a comma or an inline table terminator"},
+ {"{x=3,,y=4}", "unexpected comma"},
+ {"{x=3,\ny=4}", "newlines not allowed"},
+ {"{x=3\n,y=4}", "newlines not allowed"},
+ } {
+ var x struct{ A map[string]int }
+ input := "a = " + tt.s
+ _, err := Decode(input, &x)
+ if err == nil {
+ t.Errorf("Decode(%q): got nil, want error containing %q",
+ input, tt.want)
+ continue
+ }
+ if !strings.Contains(err.Error(), tt.want) {
+ t.Errorf("Decode(%q): got %q, want error containing %q",
+ input, err, tt.want)
+ }
+ }
+}
+
+type menu struct {
+ Dishes map[string]dish
+}
+
+func (m *menu) UnmarshalTOML(p interface{}) error {
+ m.Dishes = make(map[string]dish)
+ data, _ := p.(map[string]interface{})
+ dishes := data["dishes"].(map[string]interface{})
+ for n, v := range dishes {
+ if d, ok := v.(map[string]interface{}); ok {
+ nd := dish{}
+ nd.UnmarshalTOML(d)
+ m.Dishes[n] = nd
+ } else {
+ return fmt.Errorf("not a dish")
+ }
+ }
+ return nil
+}
+
+type dish struct {
+ Name string
+ Price float32
+ Ingredients []ingredient
+}
+
+func (d *dish) UnmarshalTOML(p interface{}) error {
+ data, _ := p.(map[string]interface{})
+ d.Name, _ = data["name"].(string)
+ d.Price, _ = data["price"].(float32)
+ ingredients, _ := data["ingredients"].([]map[string]interface{})
+ for _, e := range ingredients {
+ n, _ := interface{}(e).(map[string]interface{})
+ name, _ := n["name"].(string)
+ i := ingredient{name}
+ d.Ingredients = append(d.Ingredients, i)
+ }
+ return nil
+}
+
+type ingredient struct {
+ Name string
+}
+
+func TestDecodeSlices(t *testing.T) {
+ type T struct {
+ S []string
+ }
+ for i, tt := range []struct {
+ v T
+ input string
+ want T
+ }{
+ {T{}, "", T{}},
+ {T{[]string{}}, "", T{[]string{}}},
+ {T{[]string{"a", "b"}}, "", T{[]string{"a", "b"}}},
+ {T{}, "S = []", T{[]string{}}},
+ {T{[]string{}}, "S = []", T{[]string{}}},
+ {T{[]string{"a", "b"}}, "S = []", T{[]string{}}},
+ {T{}, `S = ["x"]`, T{[]string{"x"}}},
+ {T{[]string{}}, `S = ["x"]`, T{[]string{"x"}}},
+ {T{[]string{"a", "b"}}, `S = ["x"]`, T{[]string{"x"}}},
+ } {
+ if _, err := Decode(tt.input, &tt.v); err != nil {
+ t.Errorf("[%d] %s", i, err)
+ continue
+ }
+ if !reflect.DeepEqual(tt.v, tt.want) {
+ t.Errorf("[%d] got %#v; want %#v", i, tt.v, tt.want)
+ }
+ }
+}
+
+func TestDecodePrimitive(t *testing.T) {
+ type S struct {
+ P Primitive
+ }
+ type T struct {
+ S []int
+ }
+ slicep := func(s []int) *[]int { return &s }
+ arrayp := func(a [2]int) *[2]int { return &a }
+ mapp := func(m map[string]int) *map[string]int { return &m }
+ for i, tt := range []struct {
+ v interface{}
+ input string
+ want interface{}
+ }{
+ // slices
+ {slicep(nil), "", slicep(nil)},
+ {slicep([]int{}), "", slicep([]int{})},
+ {slicep([]int{1, 2, 3}), "", slicep([]int{1, 2, 3})},
+ {slicep(nil), "P = [1,2]", slicep([]int{1, 2})},
+ {slicep([]int{}), "P = [1,2]", slicep([]int{1, 2})},
+ {slicep([]int{1, 2, 3}), "P = [1,2]", slicep([]int{1, 2})},
+
+ // arrays
+ {arrayp([2]int{2, 3}), "", arrayp([2]int{2, 3})},
+ {arrayp([2]int{2, 3}), "P = [3,4]", arrayp([2]int{3, 4})},
+
+ // maps
+ {mapp(nil), "", mapp(nil)},
+ {mapp(map[string]int{}), "", mapp(map[string]int{})},
+ {mapp(map[string]int{"a": 1}), "", mapp(map[string]int{"a": 1})},
+ {mapp(nil), "[P]\na = 2", mapp(map[string]int{"a": 2})},
+ {mapp(map[string]int{}), "[P]\na = 2", mapp(map[string]int{"a": 2})},
+ {mapp(map[string]int{"a": 1, "b": 3}), "[P]\na = 2", mapp(map[string]int{"a": 2, "b": 3})},
+
+ // structs
+ {&T{nil}, "[P]", &T{nil}},
+ {&T{[]int{}}, "[P]", &T{[]int{}}},
+ {&T{[]int{1, 2, 3}}, "[P]", &T{[]int{1, 2, 3}}},
+ {&T{nil}, "[P]\nS = [1,2]", &T{[]int{1, 2}}},
+ {&T{[]int{}}, "[P]\nS = [1,2]", &T{[]int{1, 2}}},
+ {&T{[]int{1, 2, 3}}, "[P]\nS = [1,2]", &T{[]int{1, 2}}},
+ } {
+ var s S
+ md, err := Decode(tt.input, &s)
+ if err != nil {
+ t.Errorf("[%d] Decode error: %s", i, err)
+ continue
+ }
+ if err := md.PrimitiveDecode(s.P, tt.v); err != nil {
+ t.Errorf("[%d] PrimitiveDecode error: %s", i, err)
+ continue
+ }
+ if !reflect.DeepEqual(tt.v, tt.want) {
+ t.Errorf("[%d] got %#v; want %#v", i, tt.v, tt.want)
+ }
+ }
+}
+
+func TestDecodeErrors(t *testing.T) {
+ for _, s := range []string{
+ `x="`,
+ `x='`,
+ `x='''`,
+
+ // Cases found by fuzzing in
+ // https://github.com/BurntSushi/toml/issues/155.
+ `""�`, // used to panic with index out of range
+ `e="""`, // used to hang
+ } {
+ var x struct{}
+ _, err := Decode(s, &x)
+ if err == nil {
+ t.Errorf("Decode(%q): got nil error", s)
+ }
+ }
+}
+
+// Test for https://github.com/BurntSushi/toml/pull/166.
+func TestDecodeBoolArray(t *testing.T) {
+ for _, tt := range []struct {
+ s string
+ got interface{}
+ want interface{}
+ }{
+ {
+ "a = [true, false]",
+ &struct{ A []bool }{},
+ &struct{ A []bool }{[]bool{true, false}},
+ },
+ {
+ "a = {a = true, b = false}",
+ &struct{ A map[string]bool }{},
+ &struct{ A map[string]bool }{map[string]bool{"a": true, "b": false}},
+ },
+ } {
+ if _, err := Decode(tt.s, tt.got); err != nil {
+ t.Errorf("Decode(%q): %s", tt.s, err)
+ continue
+ }
+ if !reflect.DeepEqual(tt.got, tt.want) {
+ t.Errorf("Decode(%q): got %#v; want %#v", tt.s, tt.got, tt.want)
+ }
+ }
+}
+
+func ExampleMetaData_PrimitiveDecode() {
+ var md MetaData
+ var err error
+
+ var tomlBlob = `
+ranking = ["Springsteen", "J Geils"]
+
+[bands.Springsteen]
+started = 1973
+albums = ["Greetings", "WIESS", "Born to Run", "Darkness"]
+
+[bands."J Geils"]
+started = 1970
+albums = ["The J. Geils Band", "Full House", "Blow Your Face Out"]
+`
+
+ type band struct {
+ Started int
+ Albums []string
+ }
+ type classics struct {
+ Ranking []string
+ Bands map[string]Primitive
+ }
+
+ // Do the initial decode. Reflection is delayed on Primitive values.
+ var music classics
+ if md, err = Decode(tomlBlob, &music); err != nil {
+ log.Fatal(err)
+ }
+
+ // MetaData still includes information on Primitive values.
+ fmt.Printf("Is `bands.Springsteen` defined? %v\n",
+ md.IsDefined("bands", "Springsteen"))
+
+ // Decode primitive data into Go values.
+ for _, artist := range music.Ranking {
+ // A band is a primitive value, so we need to decode it to get a
+ // real `band` value.
+ primValue := music.Bands[artist]
+
+ var aBand band
+ if err = md.PrimitiveDecode(primValue, &aBand); err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("%s started in %d.\n", artist, aBand.Started)
+ }
+ // Check to see if there were any fields left undecoded.
+ // Note that this won't be empty before decoding the Primitive value!
+ fmt.Printf("Undecoded: %q\n", md.Undecoded())
+
+ // Output:
+ // Is `bands.Springsteen` defined? true
+ // Springsteen started in 1973.
+ // J Geils started in 1970.
+ // Undecoded: []
+}
+
+func ExampleDecode() {
+ var tomlBlob = `
+# Some comments.
+[alpha]
+ip = "10.0.0.1"
+
+ [alpha.config]
+ Ports = [ 8001, 8002 ]
+ Location = "Toronto"
+ Created = 1987-07-05T05:45:00Z
+
+[beta]
+ip = "10.0.0.2"
+
+ [beta.config]
+ Ports = [ 9001, 9002 ]
+ Location = "New Jersey"
+ Created = 1887-01-05T05:55:00Z
+`
+
+ type serverConfig struct {
+ Ports []int
+ Location string
+ Created time.Time
+ }
+
+ type server struct {
+ IP string `toml:"ip,omitempty"`
+ Config serverConfig `toml:"config"`
+ }
+
+ type servers map[string]server
+
+ var config servers
+ if _, err := Decode(tomlBlob, &config); err != nil {
+ log.Fatal(err)
+ }
+
+ for _, name := range []string{"alpha", "beta"} {
+ s := config[name]
+ fmt.Printf("Server: %s (ip: %s) in %s created on %s\n",
+ name, s.IP, s.Config.Location,
+ s.Config.Created.Format("2006-01-02"))
+ fmt.Printf("Ports: %v\n", s.Config.Ports)
+ }
+
+ // Output:
+ // Server: alpha (ip: 10.0.0.1) in Toronto created on 1987-07-05
+ // Ports: [8001 8002]
+ // Server: beta (ip: 10.0.0.2) in New Jersey created on 1887-01-05
+ // Ports: [9001 9002]
+}
+
+type duration struct {
+ time.Duration
+}
+
+func (d *duration) UnmarshalText(text []byte) error {
+ var err error
+ d.Duration, err = time.ParseDuration(string(text))
+ return err
+}
+
+// Example Unmarshaler shows how to decode TOML strings into your own
+// custom data type.
+func Example_unmarshaler() {
+ blob := `
+[[song]]
+name = "Thunder Road"
+duration = "4m49s"
+
+[[song]]
+name = "Stairway to Heaven"
+duration = "8m03s"
+`
+ type song struct {
+ Name string
+ Duration duration
+ }
+ type songs struct {
+ Song []song
+ }
+ var favorites songs
+ if _, err := Decode(blob, &favorites); err != nil {
+ log.Fatal(err)
+ }
+
+ // Code to implement the TextUnmarshaler interface for `duration`:
+ //
+ // type duration struct {
+ // time.Duration
+ // }
+ //
+ // func (d *duration) UnmarshalText(text []byte) error {
+ // var err error
+ // d.Duration, err = time.ParseDuration(string(text))
+ // return err
+ // }
+
+ for _, s := range favorites.Song {
+ fmt.Printf("%s (%s)\n", s.Name, s.Duration)
+ }
+ // Output:
+ // Thunder Road (4m49s)
+ // Stairway to Heaven (8m3s)
+}
+
+// Example StrictDecoding shows how to detect whether there are keys in the
+// TOML document that weren't decoded into the value given. This is useful
+// for returning an error to the user if they've included extraneous fields
+// in their configuration.
+func Example_strictDecoding() {
+ var blob = `
+key1 = "value1"
+key2 = "value2"
+key3 = "value3"
+`
+ type config struct {
+ Key1 string
+ Key3 string
+ }
+
+ var conf config
+ md, err := Decode(blob, &conf)
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("Undecoded keys: %q\n", md.Undecoded())
+ // Output:
+ // Undecoded keys: ["key2"]
+}
+
+// Example UnmarshalTOML shows how to implement a struct type that knows how to
+// unmarshal itself. The struct must take full responsibility for mapping the
+// values passed into the struct. The method may be used with interfaces in a
+// struct in cases where the actual type is not known until the data is
+// examined.
+func Example_unmarshalTOML() {
+
+ var blob = `
+[[parts]]
+type = "valve"
+id = "valve-1"
+size = 1.2
+rating = 4
+
+[[parts]]
+type = "valve"
+id = "valve-2"
+size = 2.1
+rating = 5
+
+[[parts]]
+type = "pipe"
+id = "pipe-1"
+length = 2.1
+diameter = 12
+
+[[parts]]
+type = "cable"
+id = "cable-1"
+length = 12
+rating = 3.1
+`
+ o := &order{}
+ err := Unmarshal([]byte(blob), o)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Println(len(o.parts))
+
+ for _, part := range o.parts {
+ fmt.Println(part.Name())
+ }
+
+ // Code to implement UmarshalJSON.
+
+ // type order struct {
+ // // NOTE `order.parts` is a private slice of type `part` which is an
+ // // interface and may only be loaded from toml using the
+ // // UnmarshalTOML() method of the Umarshaler interface.
+ // parts parts
+ // }
+
+ // func (o *order) UnmarshalTOML(data interface{}) error {
+
+ // // NOTE the example below contains detailed type casting to show how
+ // // the 'data' is retrieved. In operational use, a type cast wrapper
+ // // may be preferred e.g.
+ // //
+ // // func AsMap(v interface{}) (map[string]interface{}, error) {
+ // // return v.(map[string]interface{})
+ // // }
+ // //
+ // // resulting in:
+ // // d, _ := AsMap(data)
+ // //
+
+ // d, _ := data.(map[string]interface{})
+ // parts, _ := d["parts"].([]map[string]interface{})
+
+ // for _, p := range parts {
+
+ // typ, _ := p["type"].(string)
+ // id, _ := p["id"].(string)
+
+ // // detect the type of part and handle each case
+ // switch p["type"] {
+ // case "valve":
+
+ // size := float32(p["size"].(float64))
+ // rating := int(p["rating"].(int64))
+
+ // valve := &valve{
+ // Type: typ,
+ // ID: id,
+ // Size: size,
+ // Rating: rating,
+ // }
+
+ // o.parts = append(o.parts, valve)
+
+ // case "pipe":
+
+ // length := float32(p["length"].(float64))
+ // diameter := int(p["diameter"].(int64))
+
+ // pipe := &pipe{
+ // Type: typ,
+ // ID: id,
+ // Length: length,
+ // Diameter: diameter,
+ // }
+
+ // o.parts = append(o.parts, pipe)
+
+ // case "cable":
+
+ // length := int(p["length"].(int64))
+ // rating := float32(p["rating"].(float64))
+
+ // cable := &cable{
+ // Type: typ,
+ // ID: id,
+ // Length: length,
+ // Rating: rating,
+ // }
+
+ // o.parts = append(o.parts, cable)
+
+ // }
+ // }
+
+ // return nil
+ // }
+
+ // type parts []part
+
+ // type part interface {
+ // Name() string
+ // }
+
+ // type valve struct {
+ // Type string
+ // ID string
+ // Size float32
+ // Rating int
+ // }
+
+ // func (v *valve) Name() string {
+ // return fmt.Sprintf("VALVE: %s", v.ID)
+ // }
+
+ // type pipe struct {
+ // Type string
+ // ID string
+ // Length float32
+ // Diameter int
+ // }
+
+ // func (p *pipe) Name() string {
+ // return fmt.Sprintf("PIPE: %s", p.ID)
+ // }
+
+ // type cable struct {
+ // Type string
+ // ID string
+ // Length int
+ // Rating float32
+ // }
+
+ // func (c *cable) Name() string {
+ // return fmt.Sprintf("CABLE: %s", c.ID)
+ // }
+
+ // Output:
+ // 4
+ // VALVE: valve-1
+ // VALVE: valve-2
+ // PIPE: pipe-1
+ // CABLE: cable-1
+
+}
+
+type order struct {
+ // NOTE `order.parts` is a private slice of type `part` which is an
+ // interface and may only be loaded from toml using the UnmarshalTOML()
+ // method of the Umarshaler interface.
+ parts parts
+}
+
+func (o *order) UnmarshalTOML(data interface{}) error {
+
+ // NOTE the example below contains detailed type casting to show how
+ // the 'data' is retrieved. In operational use, a type cast wrapper
+ // may be preferred e.g.
+ //
+ // func AsMap(v interface{}) (map[string]interface{}, error) {
+ // return v.(map[string]interface{})
+ // }
+ //
+ // resulting in:
+ // d, _ := AsMap(data)
+ //
+
+ d, _ := data.(map[string]interface{})
+ parts, _ := d["parts"].([]map[string]interface{})
+
+ for _, p := range parts {
+
+ typ, _ := p["type"].(string)
+ id, _ := p["id"].(string)
+
+ // detect the type of part and handle each case
+ switch p["type"] {
+ case "valve":
+
+ size := float32(p["size"].(float64))
+ rating := int(p["rating"].(int64))
+
+ valve := &valve{
+ Type: typ,
+ ID: id,
+ Size: size,
+ Rating: rating,
+ }
+
+ o.parts = append(o.parts, valve)
+
+ case "pipe":
+
+ length := float32(p["length"].(float64))
+ diameter := int(p["diameter"].(int64))
+
+ pipe := &pipe{
+ Type: typ,
+ ID: id,
+ Length: length,
+ Diameter: diameter,
+ }
+
+ o.parts = append(o.parts, pipe)
+
+ case "cable":
+
+ length := int(p["length"].(int64))
+ rating := float32(p["rating"].(float64))
+
+ cable := &cable{
+ Type: typ,
+ ID: id,
+ Length: length,
+ Rating: rating,
+ }
+
+ o.parts = append(o.parts, cable)
+
+ }
+ }
+
+ return nil
+}
+
+type parts []part
+
+type part interface {
+ Name() string
+}
+
+type valve struct {
+ Type string
+ ID string
+ Size float32
+ Rating int
+}
+
+func (v *valve) Name() string {
+ return fmt.Sprintf("VALVE: %s", v.ID)
+}
+
+type pipe struct {
+ Type string
+ ID string
+ Length float32
+ Diameter int
+}
+
+func (p *pipe) Name() string {
+ return fmt.Sprintf("PIPE: %s", p.ID)
+}
+
+type cable struct {
+ Type string
+ ID string
+ Length int
+ Rating float32
+}
+
+func (c *cable) Name() string {
+ return fmt.Sprintf("CABLE: %s", c.ID)
+}
diff --git a/vendor/github.com/BurntSushi/toml/doc.go b/vendor/github.com/BurntSushi/toml/doc.go
new file mode 100644
index 0000000..b371f39
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/doc.go
@@ -0,0 +1,27 @@
+/*
+Package toml provides facilities for decoding and encoding TOML configuration
+files via reflection. There is also support for delaying decoding with
+the Primitive type, and querying the set of keys in a TOML document with the
+MetaData type.
+
+The specification implemented: https://github.com/toml-lang/toml
+
+The sub-command github.com/BurntSushi/toml/cmd/tomlv can be used to verify
+whether a file is a valid TOML document. It can also be used to print the
+type of each key in a TOML document.
+
+Testing
+
+There are two important types of tests used for this package. The first is
+contained inside '*_test.go' files and uses the standard Go unit testing
+framework. These tests are primarily devoted to holistically testing the
+decoder and encoder.
+
+The second type of testing is used to verify the implementation's adherence
+to the TOML specification. These tests have been factored into their own
+project: https://github.com/BurntSushi/toml-test
+
+The reason the tests are in a separate project is so that they can be used by
+any implementation of TOML. Namely, it is language agnostic.
+*/
+package toml
diff --git a/vendor/github.com/BurntSushi/toml/encode.go b/vendor/github.com/BurntSushi/toml/encode.go
new file mode 100644
index 0000000..d905c21
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/encode.go
@@ -0,0 +1,568 @@
+package toml
+
+import (
+ "bufio"
+ "errors"
+ "fmt"
+ "io"
+ "reflect"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+)
+
+type tomlEncodeError struct{ error }
+
+var (
+ errArrayMixedElementTypes = errors.New(
+ "toml: cannot encode array with mixed element types")
+ errArrayNilElement = errors.New(
+ "toml: cannot encode array with nil element")
+ errNonString = errors.New(
+ "toml: cannot encode a map with non-string key type")
+ errAnonNonStruct = errors.New(
+ "toml: cannot encode an anonymous field that is not a struct")
+ errArrayNoTable = errors.New(
+ "toml: TOML array element cannot contain a table")
+ errNoKey = errors.New(
+ "toml: top-level values must be Go maps or structs")
+ errAnything = errors.New("") // used in testing
+)
+
+var quotedReplacer = strings.NewReplacer(
+ "\t", "\\t",
+ "\n", "\\n",
+ "\r", "\\r",
+ "\"", "\\\"",
+ "\\", "\\\\",
+)
+
+// Encoder controls the encoding of Go values to a TOML document to some
+// io.Writer.
+//
+// The indentation level can be controlled with the Indent field.
+type Encoder struct {
+ // A single indentation level. By default it is two spaces.
+ Indent string
+
+ // hasWritten is whether we have written any output to w yet.
+ hasWritten bool
+ w *bufio.Writer
+}
+
+// NewEncoder returns a TOML encoder that encodes Go values to the io.Writer
+// given. By default, a single indentation level is 2 spaces.
+func NewEncoder(w io.Writer) *Encoder {
+ return &Encoder{
+ w: bufio.NewWriter(w),
+ Indent: " ",
+ }
+}
+
+// Encode writes a TOML representation of the Go value to the underlying
+// io.Writer. If the value given cannot be encoded to a valid TOML document,
+// then an error is returned.
+//
+// The mapping between Go values and TOML values should be precisely the same
+// as for the Decode* functions. Similarly, the TextMarshaler interface is
+// supported by encoding the resulting bytes as strings. (If you want to write
+// arbitrary binary data then you will need to use something like base64 since
+// TOML does not have any binary types.)
+//
+// When encoding TOML hashes (i.e., Go maps or structs), keys without any
+// sub-hashes are encoded first.
+//
+// If a Go map is encoded, then its keys are sorted alphabetically for
+// deterministic output. More control over this behavior may be provided if
+// there is demand for it.
+//
+// Encoding Go values without a corresponding TOML representation---like map
+// types with non-string keys---will cause an error to be returned. Similarly
+// for mixed arrays/slices, arrays/slices with nil elements, embedded
+// non-struct types and nested slices containing maps or structs.
+// (e.g., [][]map[string]string is not allowed but []map[string]string is OK
+// and so is []map[string][]string.)
+func (enc *Encoder) Encode(v interface{}) error {
+ rv := eindirect(reflect.ValueOf(v))
+ if err := enc.safeEncode(Key([]string{}), rv); err != nil {
+ return err
+ }
+ return enc.w.Flush()
+}
+
+func (enc *Encoder) safeEncode(key Key, rv reflect.Value) (err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ if terr, ok := r.(tomlEncodeError); ok {
+ err = terr.error
+ return
+ }
+ panic(r)
+ }
+ }()
+ enc.encode(key, rv)
+ return nil
+}
+
+func (enc *Encoder) encode(key Key, rv reflect.Value) {
+ // Special case. Time needs to be in ISO8601 format.
+ // Special case. If we can marshal the type to text, then we used that.
+ // Basically, this prevents the encoder for handling these types as
+ // generic structs (or whatever the underlying type of a TextMarshaler is).
+ switch rv.Interface().(type) {
+ case time.Time, TextMarshaler:
+ enc.keyEqElement(key, rv)
+ return
+ }
+
+ k := rv.Kind()
+ switch k {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
+ reflect.Int64,
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
+ reflect.Uint64,
+ reflect.Float32, reflect.Float64, reflect.String, reflect.Bool:
+ enc.keyEqElement(key, rv)
+ case reflect.Array, reflect.Slice:
+ if typeEqual(tomlArrayHash, tomlTypeOfGo(rv)) {
+ enc.eArrayOfTables(key, rv)
+ } else {
+ enc.keyEqElement(key, rv)
+ }
+ case reflect.Interface:
+ if rv.IsNil() {
+ return
+ }
+ enc.encode(key, rv.Elem())
+ case reflect.Map:
+ if rv.IsNil() {
+ return
+ }
+ enc.eTable(key, rv)
+ case reflect.Ptr:
+ if rv.IsNil() {
+ return
+ }
+ enc.encode(key, rv.Elem())
+ case reflect.Struct:
+ enc.eTable(key, rv)
+ default:
+ panic(e("unsupported type for key '%s': %s", key, k))
+ }
+}
+
+// eElement encodes any value that can be an array element (primitives and
+// arrays).
+func (enc *Encoder) eElement(rv reflect.Value) {
+ switch v := rv.Interface().(type) {
+ case time.Time:
+ // Special case time.Time as a primitive. Has to come before
+ // TextMarshaler below because time.Time implements
+ // encoding.TextMarshaler, but we need to always use UTC.
+ enc.wf(v.UTC().Format("2006-01-02T15:04:05Z"))
+ return
+ case TextMarshaler:
+ // Special case. Use text marshaler if it's available for this value.
+ if s, err := v.MarshalText(); err != nil {
+ encPanic(err)
+ } else {
+ enc.writeQuoted(string(s))
+ }
+ return
+ }
+ switch rv.Kind() {
+ case reflect.Bool:
+ enc.wf(strconv.FormatBool(rv.Bool()))
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
+ reflect.Int64:
+ enc.wf(strconv.FormatInt(rv.Int(), 10))
+ case reflect.Uint, reflect.Uint8, reflect.Uint16,
+ reflect.Uint32, reflect.Uint64:
+ enc.wf(strconv.FormatUint(rv.Uint(), 10))
+ case reflect.Float32:
+ enc.wf(floatAddDecimal(strconv.FormatFloat(rv.Float(), 'f', -1, 32)))
+ case reflect.Float64:
+ enc.wf(floatAddDecimal(strconv.FormatFloat(rv.Float(), 'f', -1, 64)))
+ case reflect.Array, reflect.Slice:
+ enc.eArrayOrSliceElement(rv)
+ case reflect.Interface:
+ enc.eElement(rv.Elem())
+ case reflect.String:
+ enc.writeQuoted(rv.String())
+ default:
+ panic(e("unexpected primitive type: %s", rv.Kind()))
+ }
+}
+
+// By the TOML spec, all floats must have a decimal with at least one
+// number on either side.
+func floatAddDecimal(fstr string) string {
+ if !strings.Contains(fstr, ".") {
+ return fstr + ".0"
+ }
+ return fstr
+}
+
+func (enc *Encoder) writeQuoted(s string) {
+ enc.wf("\"%s\"", quotedReplacer.Replace(s))
+}
+
+func (enc *Encoder) eArrayOrSliceElement(rv reflect.Value) {
+ length := rv.Len()
+ enc.wf("[")
+ for i := 0; i < length; i++ {
+ elem := rv.Index(i)
+ enc.eElement(elem)
+ if i != length-1 {
+ enc.wf(", ")
+ }
+ }
+ enc.wf("]")
+}
+
+func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) {
+ if len(key) == 0 {
+ encPanic(errNoKey)
+ }
+ for i := 0; i < rv.Len(); i++ {
+ trv := rv.Index(i)
+ if isNil(trv) {
+ continue
+ }
+ panicIfInvalidKey(key)
+ enc.newline()
+ enc.wf("%s[[%s]]", enc.indentStr(key), key.maybeQuotedAll())
+ enc.newline()
+ enc.eMapOrStruct(key, trv)
+ }
+}
+
+func (enc *Encoder) eTable(key Key, rv reflect.Value) {
+ panicIfInvalidKey(key)
+ if len(key) == 1 {
+ // Output an extra newline between top-level tables.
+ // (The newline isn't written if nothing else has been written though.)
+ enc.newline()
+ }
+ if len(key) > 0 {
+ enc.wf("%s[%s]", enc.indentStr(key), key.maybeQuotedAll())
+ enc.newline()
+ }
+ enc.eMapOrStruct(key, rv)
+}
+
+func (enc *Encoder) eMapOrStruct(key Key, rv reflect.Value) {
+ switch rv := eindirect(rv); rv.Kind() {
+ case reflect.Map:
+ enc.eMap(key, rv)
+ case reflect.Struct:
+ enc.eStruct(key, rv)
+ default:
+ panic("eTable: unhandled reflect.Value Kind: " + rv.Kind().String())
+ }
+}
+
+func (enc *Encoder) eMap(key Key, rv reflect.Value) {
+ rt := rv.Type()
+ if rt.Key().Kind() != reflect.String {
+ encPanic(errNonString)
+ }
+
+ // Sort keys so that we have deterministic output. And write keys directly
+ // underneath this key first, before writing sub-structs or sub-maps.
+ var mapKeysDirect, mapKeysSub []string
+ for _, mapKey := range rv.MapKeys() {
+ k := mapKey.String()
+ if typeIsHash(tomlTypeOfGo(rv.MapIndex(mapKey))) {
+ mapKeysSub = append(mapKeysSub, k)
+ } else {
+ mapKeysDirect = append(mapKeysDirect, k)
+ }
+ }
+
+ var writeMapKeys = func(mapKeys []string) {
+ sort.Strings(mapKeys)
+ for _, mapKey := range mapKeys {
+ mrv := rv.MapIndex(reflect.ValueOf(mapKey))
+ if isNil(mrv) {
+ // Don't write anything for nil fields.
+ continue
+ }
+ enc.encode(key.add(mapKey), mrv)
+ }
+ }
+ writeMapKeys(mapKeysDirect)
+ writeMapKeys(mapKeysSub)
+}
+
+func (enc *Encoder) eStruct(key Key, rv reflect.Value) {
+ // Write keys for fields directly under this key first, because if we write
+ // a field that creates a new table, then all keys under it will be in that
+ // table (not the one we're writing here).
+ rt := rv.Type()
+ var fieldsDirect, fieldsSub [][]int
+ var addFields func(rt reflect.Type, rv reflect.Value, start []int)
+ addFields = func(rt reflect.Type, rv reflect.Value, start []int) {
+ for i := 0; i < rt.NumField(); i++ {
+ f := rt.Field(i)
+ // skip unexported fields
+ if f.PkgPath != "" && !f.Anonymous {
+ continue
+ }
+ frv := rv.Field(i)
+ if f.Anonymous {
+ t := f.Type
+ switch t.Kind() {
+ case reflect.Struct:
+ // Treat anonymous struct fields with
+ // tag names as though they are not
+ // anonymous, like encoding/json does.
+ if getOptions(f.Tag).name == "" {
+ addFields(t, frv, f.Index)
+ continue
+ }
+ case reflect.Ptr:
+ if t.Elem().Kind() == reflect.Struct &&
+ getOptions(f.Tag).name == "" {
+ if !frv.IsNil() {
+ addFields(t.Elem(), frv.Elem(), f.Index)
+ }
+ continue
+ }
+ // Fall through to the normal field encoding logic below
+ // for non-struct anonymous fields.
+ }
+ }
+
+ if typeIsHash(tomlTypeOfGo(frv)) {
+ fieldsSub = append(fieldsSub, append(start, f.Index...))
+ } else {
+ fieldsDirect = append(fieldsDirect, append(start, f.Index...))
+ }
+ }
+ }
+ addFields(rt, rv, nil)
+
+ var writeFields = func(fields [][]int) {
+ for _, fieldIndex := range fields {
+ sft := rt.FieldByIndex(fieldIndex)
+ sf := rv.FieldByIndex(fieldIndex)
+ if isNil(sf) {
+ // Don't write anything for nil fields.
+ continue
+ }
+
+ opts := getOptions(sft.Tag)
+ if opts.skip {
+ continue
+ }
+ keyName := sft.Name
+ if opts.name != "" {
+ keyName = opts.name
+ }
+ if opts.omitempty && isEmpty(sf) {
+ continue
+ }
+ if opts.omitzero && isZero(sf) {
+ continue
+ }
+
+ enc.encode(key.add(keyName), sf)
+ }
+ }
+ writeFields(fieldsDirect)
+ writeFields(fieldsSub)
+}
+
+// tomlTypeName returns the TOML type name of the Go value's type. It is
+// used to determine whether the types of array elements are mixed (which is
+// forbidden). If the Go value is nil, then it is illegal for it to be an array
+// element, and valueIsNil is returned as true.
+
+// Returns the TOML type of a Go value. The type may be `nil`, which means
+// no concrete TOML type could be found.
+func tomlTypeOfGo(rv reflect.Value) tomlType {
+ if isNil(rv) || !rv.IsValid() {
+ return nil
+ }
+ switch rv.Kind() {
+ case reflect.Bool:
+ return tomlBool
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
+ reflect.Int64,
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
+ reflect.Uint64:
+ return tomlInteger
+ case reflect.Float32, reflect.Float64:
+ return tomlFloat
+ case reflect.Array, reflect.Slice:
+ if typeEqual(tomlHash, tomlArrayType(rv)) {
+ return tomlArrayHash
+ }
+ return tomlArray
+ case reflect.Ptr, reflect.Interface:
+ return tomlTypeOfGo(rv.Elem())
+ case reflect.String:
+ return tomlString
+ case reflect.Map:
+ return tomlHash
+ case reflect.Struct:
+ switch rv.Interface().(type) {
+ case time.Time:
+ return tomlDatetime
+ case TextMarshaler:
+ return tomlString
+ default:
+ return tomlHash
+ }
+ default:
+ panic("unexpected reflect.Kind: " + rv.Kind().String())
+ }
+}
+
+// tomlArrayType returns the element type of a TOML array. The type returned
+// may be nil if it cannot be determined (e.g., a nil slice or a zero length
+// slize). This function may also panic if it finds a type that cannot be
+// expressed in TOML (such as nil elements, heterogeneous arrays or directly
+// nested arrays of tables).
+func tomlArrayType(rv reflect.Value) tomlType {
+ if isNil(rv) || !rv.IsValid() || rv.Len() == 0 {
+ return nil
+ }
+ firstType := tomlTypeOfGo(rv.Index(0))
+ if firstType == nil {
+ encPanic(errArrayNilElement)
+ }
+
+ rvlen := rv.Len()
+ for i := 1; i < rvlen; i++ {
+ elem := rv.Index(i)
+ switch elemType := tomlTypeOfGo(elem); {
+ case elemType == nil:
+ encPanic(errArrayNilElement)
+ case !typeEqual(firstType, elemType):
+ encPanic(errArrayMixedElementTypes)
+ }
+ }
+ // If we have a nested array, then we must make sure that the nested
+ // array contains ONLY primitives.
+ // This checks arbitrarily nested arrays.
+ if typeEqual(firstType, tomlArray) || typeEqual(firstType, tomlArrayHash) {
+ nest := tomlArrayType(eindirect(rv.Index(0)))
+ if typeEqual(nest, tomlHash) || typeEqual(nest, tomlArrayHash) {
+ encPanic(errArrayNoTable)
+ }
+ }
+ return firstType
+}
+
+type tagOptions struct {
+ skip bool // "-"
+ name string
+ omitempty bool
+ omitzero bool
+}
+
+func getOptions(tag reflect.StructTag) tagOptions {
+ t := tag.Get("toml")
+ if t == "-" {
+ return tagOptions{skip: true}
+ }
+ var opts tagOptions
+ parts := strings.Split(t, ",")
+ opts.name = parts[0]
+ for _, s := range parts[1:] {
+ switch s {
+ case "omitempty":
+ opts.omitempty = true
+ case "omitzero":
+ opts.omitzero = true
+ }
+ }
+ return opts
+}
+
+func isZero(rv reflect.Value) bool {
+ switch rv.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return rv.Int() == 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ return rv.Uint() == 0
+ case reflect.Float32, reflect.Float64:
+ return rv.Float() == 0.0
+ }
+ return false
+}
+
+func isEmpty(rv reflect.Value) bool {
+ switch rv.Kind() {
+ case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
+ return rv.Len() == 0
+ case reflect.Bool:
+ return !rv.Bool()
+ }
+ return false
+}
+
+func (enc *Encoder) newline() {
+ if enc.hasWritten {
+ enc.wf("\n")
+ }
+}
+
+func (enc *Encoder) keyEqElement(key Key, val reflect.Value) {
+ if len(key) == 0 {
+ encPanic(errNoKey)
+ }
+ panicIfInvalidKey(key)
+ enc.wf("%s%s = ", enc.indentStr(key), key.maybeQuoted(len(key)-1))
+ enc.eElement(val)
+ enc.newline()
+}
+
+func (enc *Encoder) wf(format string, v ...interface{}) {
+ if _, err := fmt.Fprintf(enc.w, format, v...); err != nil {
+ encPanic(err)
+ }
+ enc.hasWritten = true
+}
+
+func (enc *Encoder) indentStr(key Key) string {
+ return strings.Repeat(enc.Indent, len(key)-1)
+}
+
+func encPanic(err error) {
+ panic(tomlEncodeError{err})
+}
+
+func eindirect(v reflect.Value) reflect.Value {
+ switch v.Kind() {
+ case reflect.Ptr, reflect.Interface:
+ return eindirect(v.Elem())
+ default:
+ return v
+ }
+}
+
+func isNil(rv reflect.Value) bool {
+ switch rv.Kind() {
+ case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
+ return rv.IsNil()
+ default:
+ return false
+ }
+}
+
+func panicIfInvalidKey(key Key) {
+ for _, k := range key {
+ if len(k) == 0 {
+ encPanic(e("Key '%s' is not a valid table name. Key names "+
+ "cannot be empty.", key.maybeQuotedAll()))
+ }
+ }
+}
+
+func isValidKeyName(s string) bool {
+ return len(s) != 0
+}
diff --git a/vendor/github.com/BurntSushi/toml/encode_test.go b/vendor/github.com/BurntSushi/toml/encode_test.go
new file mode 100644
index 0000000..673b7b0
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/encode_test.go
@@ -0,0 +1,615 @@
+package toml
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ "net"
+ "testing"
+ "time"
+)
+
+func TestEncodeRoundTrip(t *testing.T) {
+ type Config struct {
+ Age int
+ Cats []string
+ Pi float64
+ Perfection []int
+ DOB time.Time
+ Ipaddress net.IP
+ }
+
+ var inputs = Config{
+ 13,
+ []string{"one", "two", "three"},
+ 3.145,
+ []int{11, 2, 3, 4},
+ time.Now(),
+ net.ParseIP("192.168.59.254"),
+ }
+
+ var firstBuffer bytes.Buffer
+ e := NewEncoder(&firstBuffer)
+ err := e.Encode(inputs)
+ if err != nil {
+ t.Fatal(err)
+ }
+ var outputs Config
+ if _, err := Decode(firstBuffer.String(), &outputs); err != nil {
+ t.Logf("Could not decode:\n-----\n%s\n-----\n",
+ firstBuffer.String())
+ t.Fatal(err)
+ }
+
+ // could test each value individually, but I'm lazy
+ var secondBuffer bytes.Buffer
+ e2 := NewEncoder(&secondBuffer)
+ err = e2.Encode(outputs)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if firstBuffer.String() != secondBuffer.String() {
+ t.Error(
+ firstBuffer.String(),
+ "\n\n is not identical to\n\n",
+ secondBuffer.String())
+ }
+}
+
+// XXX(burntsushi)
+// I think these tests probably should be removed. They are good, but they
+// ought to be obsolete by toml-test.
+func TestEncode(t *testing.T) {
+ type Embedded struct {
+ Int int `toml:"_int"`
+ }
+ type NonStruct int
+
+ date := time.Date(2014, 5, 11, 20, 30, 40, 0, time.FixedZone("IST", 3600))
+ dateStr := "2014-05-11T19:30:40Z"
+
+ tests := map[string]struct {
+ input interface{}
+ wantOutput string
+ wantError error
+ }{
+ "bool field": {
+ input: struct {
+ BoolTrue bool
+ BoolFalse bool
+ }{true, false},
+ wantOutput: "BoolTrue = true\nBoolFalse = false\n",
+ },
+ "int fields": {
+ input: struct {
+ Int int
+ Int8 int8
+ Int16 int16
+ Int32 int32
+ Int64 int64
+ }{1, 2, 3, 4, 5},
+ wantOutput: "Int = 1\nInt8 = 2\nInt16 = 3\nInt32 = 4\nInt64 = 5\n",
+ },
+ "uint fields": {
+ input: struct {
+ Uint uint
+ Uint8 uint8
+ Uint16 uint16
+ Uint32 uint32
+ Uint64 uint64
+ }{1, 2, 3, 4, 5},
+ wantOutput: "Uint = 1\nUint8 = 2\nUint16 = 3\nUint32 = 4" +
+ "\nUint64 = 5\n",
+ },
+ "float fields": {
+ input: struct {
+ Float32 float32
+ Float64 float64
+ }{1.5, 2.5},
+ wantOutput: "Float32 = 1.5\nFloat64 = 2.5\n",
+ },
+ "string field": {
+ input: struct{ String string }{"foo"},
+ wantOutput: "String = \"foo\"\n",
+ },
+ "string field and unexported field": {
+ input: struct {
+ String string
+ unexported int
+ }{"foo", 0},
+ wantOutput: "String = \"foo\"\n",
+ },
+ "datetime field in UTC": {
+ input: struct{ Date time.Time }{date},
+ wantOutput: fmt.Sprintf("Date = %s\n", dateStr),
+ },
+ "datetime field as primitive": {
+ // Using a map here to fail if isStructOrMap() returns true for
+ // time.Time.
+ input: map[string]interface{}{
+ "Date": date,
+ "Int": 1,
+ },
+ wantOutput: fmt.Sprintf("Date = %s\nInt = 1\n", dateStr),
+ },
+ "array fields": {
+ input: struct {
+ IntArray0 [0]int
+ IntArray3 [3]int
+ }{[0]int{}, [3]int{1, 2, 3}},
+ wantOutput: "IntArray0 = []\nIntArray3 = [1, 2, 3]\n",
+ },
+ "slice fields": {
+ input: struct{ IntSliceNil, IntSlice0, IntSlice3 []int }{
+ nil, []int{}, []int{1, 2, 3},
+ },
+ wantOutput: "IntSlice0 = []\nIntSlice3 = [1, 2, 3]\n",
+ },
+ "datetime slices": {
+ input: struct{ DatetimeSlice []time.Time }{
+ []time.Time{date, date},
+ },
+ wantOutput: fmt.Sprintf("DatetimeSlice = [%s, %s]\n",
+ dateStr, dateStr),
+ },
+ "nested arrays and slices": {
+ input: struct {
+ SliceOfArrays [][2]int
+ ArrayOfSlices [2][]int
+ SliceOfArraysOfSlices [][2][]int
+ ArrayOfSlicesOfArrays [2][][2]int
+ SliceOfMixedArrays [][2]interface{}
+ ArrayOfMixedSlices [2][]interface{}
+ }{
+ [][2]int{{1, 2}, {3, 4}},
+ [2][]int{{1, 2}, {3, 4}},
+ [][2][]int{
+ {
+ {1, 2}, {3, 4},
+ },
+ {
+ {5, 6}, {7, 8},
+ },
+ },
+ [2][][2]int{
+ {
+ {1, 2}, {3, 4},
+ },
+ {
+ {5, 6}, {7, 8},
+ },
+ },
+ [][2]interface{}{
+ {1, 2}, {"a", "b"},
+ },
+ [2][]interface{}{
+ {1, 2}, {"a", "b"},
+ },
+ },
+ wantOutput: `SliceOfArrays = [[1, 2], [3, 4]]
+ArrayOfSlices = [[1, 2], [3, 4]]
+SliceOfArraysOfSlices = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
+ArrayOfSlicesOfArrays = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
+SliceOfMixedArrays = [[1, 2], ["a", "b"]]
+ArrayOfMixedSlices = [[1, 2], ["a", "b"]]
+`,
+ },
+ "empty slice": {
+ input: struct{ Empty []interface{} }{[]interface{}{}},
+ wantOutput: "Empty = []\n",
+ },
+ "(error) slice with element type mismatch (string and integer)": {
+ input: struct{ Mixed []interface{} }{[]interface{}{1, "a"}},
+ wantError: errArrayMixedElementTypes,
+ },
+ "(error) slice with element type mismatch (integer and float)": {
+ input: struct{ Mixed []interface{} }{[]interface{}{1, 2.5}},
+ wantError: errArrayMixedElementTypes,
+ },
+ "slice with elems of differing Go types, same TOML types": {
+ input: struct {
+ MixedInts []interface{}
+ MixedFloats []interface{}
+ }{
+ []interface{}{
+ int(1), int8(2), int16(3), int32(4), int64(5),
+ uint(1), uint8(2), uint16(3), uint32(4), uint64(5),
+ },
+ []interface{}{float32(1.5), float64(2.5)},
+ },
+ wantOutput: "MixedInts = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]\n" +
+ "MixedFloats = [1.5, 2.5]\n",
+ },
+ "(error) slice w/ element type mismatch (one is nested array)": {
+ input: struct{ Mixed []interface{} }{
+ []interface{}{1, []interface{}{2}},
+ },
+ wantError: errArrayMixedElementTypes,
+ },
+ "(error) slice with 1 nil element": {
+ input: struct{ NilElement1 []interface{} }{[]interface{}{nil}},
+ wantError: errArrayNilElement,
+ },
+ "(error) slice with 1 nil element (and other non-nil elements)": {
+ input: struct{ NilElement []interface{} }{
+ []interface{}{1, nil},
+ },
+ wantError: errArrayNilElement,
+ },
+ "simple map": {
+ input: map[string]int{"a": 1, "b": 2},
+ wantOutput: "a = 1\nb = 2\n",
+ },
+ "map with interface{} value type": {
+ input: map[string]interface{}{"a": 1, "b": "c"},
+ wantOutput: "a = 1\nb = \"c\"\n",
+ },
+ "map with interface{} value type, some of which are structs": {
+ input: map[string]interface{}{
+ "a": struct{ Int int }{2},
+ "b": 1,
+ },
+ wantOutput: "b = 1\n\n[a]\n Int = 2\n",
+ },
+ "nested map": {
+ input: map[string]map[string]int{
+ "a": {"b": 1},
+ "c": {"d": 2},
+ },
+ wantOutput: "[a]\n b = 1\n\n[c]\n d = 2\n",
+ },
+ "nested struct": {
+ input: struct{ Struct struct{ Int int } }{
+ struct{ Int int }{1},
+ },
+ wantOutput: "[Struct]\n Int = 1\n",
+ },
+ "nested struct and non-struct field": {
+ input: struct {
+ Struct struct{ Int int }
+ Bool bool
+ }{struct{ Int int }{1}, true},
+ wantOutput: "Bool = true\n\n[Struct]\n Int = 1\n",
+ },
+ "2 nested structs": {
+ input: struct{ Struct1, Struct2 struct{ Int int } }{
+ struct{ Int int }{1}, struct{ Int int }{2},
+ },
+ wantOutput: "[Struct1]\n Int = 1\n\n[Struct2]\n Int = 2\n",
+ },
+ "deeply nested structs": {
+ input: struct {
+ Struct1, Struct2 struct{ Struct3 *struct{ Int int } }
+ }{
+ struct{ Struct3 *struct{ Int int } }{&struct{ Int int }{1}},
+ struct{ Struct3 *struct{ Int int } }{nil},
+ },
+ wantOutput: "[Struct1]\n [Struct1.Struct3]\n Int = 1" +
+ "\n\n[Struct2]\n",
+ },
+ "nested struct with nil struct elem": {
+ input: struct {
+ Struct struct{ Inner *struct{ Int int } }
+ }{
+ struct{ Inner *struct{ Int int } }{nil},
+ },
+ wantOutput: "[Struct]\n",
+ },
+ "nested struct with no fields": {
+ input: struct {
+ Struct struct{ Inner struct{} }
+ }{
+ struct{ Inner struct{} }{struct{}{}},
+ },
+ wantOutput: "[Struct]\n [Struct.Inner]\n",
+ },
+ "struct with tags": {
+ input: struct {
+ Struct struct {
+ Int int `toml:"_int"`
+ } `toml:"_struct"`
+ Bool bool `toml:"_bool"`
+ }{
+ struct {
+ Int int `toml:"_int"`
+ }{1}, true,
+ },
+ wantOutput: "_bool = true\n\n[_struct]\n _int = 1\n",
+ },
+ "embedded struct": {
+ input: struct{ Embedded }{Embedded{1}},
+ wantOutput: "_int = 1\n",
+ },
+ "embedded *struct": {
+ input: struct{ *Embedded }{&Embedded{1}},
+ wantOutput: "_int = 1\n",
+ },
+ "nested embedded struct": {
+ input: struct {
+ Struct struct{ Embedded } `toml:"_struct"`
+ }{struct{ Embedded }{Embedded{1}}},
+ wantOutput: "[_struct]\n _int = 1\n",
+ },
+ "nested embedded *struct": {
+ input: struct {
+ Struct struct{ *Embedded } `toml:"_struct"`
+ }{struct{ *Embedded }{&Embedded{1}}},
+ wantOutput: "[_struct]\n _int = 1\n",
+ },
+ "embedded non-struct": {
+ input: struct{ NonStruct }{5},
+ wantOutput: "NonStruct = 5\n",
+ },
+ "array of tables": {
+ input: struct {
+ Structs []*struct{ Int int } `toml:"struct"`
+ }{
+ []*struct{ Int int }{{1}, {3}},
+ },
+ wantOutput: "[[struct]]\n Int = 1\n\n[[struct]]\n Int = 3\n",
+ },
+ "array of tables order": {
+ input: map[string]interface{}{
+ "map": map[string]interface{}{
+ "zero": 5,
+ "arr": []map[string]int{
+ {
+ "friend": 5,
+ },
+ },
+ },
+ },
+ wantOutput: "[map]\n zero = 5\n\n [[map.arr]]\n friend = 5\n",
+ },
+ "(error) top-level slice": {
+ input: []struct{ Int int }{{1}, {2}, {3}},
+ wantError: errNoKey,
+ },
+ "(error) slice of slice": {
+ input: struct {
+ Slices [][]struct{ Int int }
+ }{
+ [][]struct{ Int int }{{{1}}, {{2}}, {{3}}},
+ },
+ wantError: errArrayNoTable,
+ },
+ "(error) map no string key": {
+ input: map[int]string{1: ""},
+ wantError: errNonString,
+ },
+ "(error) empty key name": {
+ input: map[string]int{"": 1},
+ wantError: errAnything,
+ },
+ "(error) empty map name": {
+ input: map[string]interface{}{
+ "": map[string]int{"v": 1},
+ },
+ wantError: errAnything,
+ },
+ }
+ for label, test := range tests {
+ encodeExpected(t, label, test.input, test.wantOutput, test.wantError)
+ }
+}
+
+func TestEncodeNestedTableArrays(t *testing.T) {
+ type song struct {
+ Name string `toml:"name"`
+ }
+ type album struct {
+ Name string `toml:"name"`
+ Songs []song `toml:"songs"`
+ }
+ type springsteen struct {
+ Albums []album `toml:"albums"`
+ }
+ value := springsteen{
+ []album{
+ {"Born to Run",
+ []song{{"Jungleland"}, {"Meeting Across the River"}}},
+ {"Born in the USA",
+ []song{{"Glory Days"}, {"Dancing in the Dark"}}},
+ },
+ }
+ expected := `[[albums]]
+ name = "Born to Run"
+
+ [[albums.songs]]
+ name = "Jungleland"
+
+ [[albums.songs]]
+ name = "Meeting Across the River"
+
+[[albums]]
+ name = "Born in the USA"
+
+ [[albums.songs]]
+ name = "Glory Days"
+
+ [[albums.songs]]
+ name = "Dancing in the Dark"
+`
+ encodeExpected(t, "nested table arrays", value, expected, nil)
+}
+
+func TestEncodeArrayHashWithNormalHashOrder(t *testing.T) {
+ type Alpha struct {
+ V int
+ }
+ type Beta struct {
+ V int
+ }
+ type Conf struct {
+ V int
+ A Alpha
+ B []Beta
+ }
+
+ val := Conf{
+ V: 1,
+ A: Alpha{2},
+ B: []Beta{{3}},
+ }
+ expected := "V = 1\n\n[A]\n V = 2\n\n[[B]]\n V = 3\n"
+ encodeExpected(t, "array hash with normal hash order", val, expected, nil)
+}
+
+func TestEncodeWithOmitEmpty(t *testing.T) {
+ type simple struct {
+ Bool bool `toml:"bool,omitempty"`
+ String string `toml:"string,omitempty"`
+ Array [0]byte `toml:"array,omitempty"`
+ Slice []int `toml:"slice,omitempty"`
+ Map map[string]string `toml:"map,omitempty"`
+ }
+
+ var v simple
+ encodeExpected(t, "fields with omitempty are omitted when empty", v, "", nil)
+ v = simple{
+ Bool: true,
+ String: " ",
+ Slice: []int{2, 3, 4},
+ Map: map[string]string{"foo": "bar"},
+ }
+ expected := `bool = true
+string = " "
+slice = [2, 3, 4]
+
+[map]
+ foo = "bar"
+`
+ encodeExpected(t, "fields with omitempty are not omitted when non-empty",
+ v, expected, nil)
+}
+
+func TestEncodeWithOmitZero(t *testing.T) {
+ type simple struct {
+ Number int `toml:"number,omitzero"`
+ Real float64 `toml:"real,omitzero"`
+ Unsigned uint `toml:"unsigned,omitzero"`
+ }
+
+ value := simple{0, 0.0, uint(0)}
+ expected := ""
+
+ encodeExpected(t, "simple with omitzero, all zero", value, expected, nil)
+
+ value.Number = 10
+ value.Real = 20
+ value.Unsigned = 5
+ expected = `number = 10
+real = 20.0
+unsigned = 5
+`
+ encodeExpected(t, "simple with omitzero, non-zero", value, expected, nil)
+}
+
+func TestEncodeOmitemptyWithEmptyName(t *testing.T) {
+ type simple struct {
+ S []int `toml:",omitempty"`
+ }
+ v := simple{[]int{1, 2, 3}}
+ expected := "S = [1, 2, 3]\n"
+ encodeExpected(t, "simple with omitempty, no name, non-empty field",
+ v, expected, nil)
+}
+
+func TestEncodeAnonymousStruct(t *testing.T) {
+ type Inner struct{ N int }
+ type Outer0 struct{ Inner }
+ type Outer1 struct {
+ Inner `toml:"inner"`
+ }
+
+ v0 := Outer0{Inner{3}}
+ expected := "N = 3\n"
+ encodeExpected(t, "embedded anonymous untagged struct", v0, expected, nil)
+
+ v1 := Outer1{Inner{3}}
+ expected = "[inner]\n N = 3\n"
+ encodeExpected(t, "embedded anonymous tagged struct", v1, expected, nil)
+}
+
+func TestEncodeAnonymousStructPointerField(t *testing.T) {
+ type Inner struct{ N int }
+ type Outer0 struct{ *Inner }
+ type Outer1 struct {
+ *Inner `toml:"inner"`
+ }
+
+ v0 := Outer0{}
+ expected := ""
+ encodeExpected(t, "nil anonymous untagged struct pointer field", v0, expected, nil)
+
+ v0 = Outer0{&Inner{3}}
+ expected = "N = 3\n"
+ encodeExpected(t, "non-nil anonymous untagged struct pointer field", v0, expected, nil)
+
+ v1 := Outer1{}
+ expected = ""
+ encodeExpected(t, "nil anonymous tagged struct pointer field", v1, expected, nil)
+
+ v1 = Outer1{&Inner{3}}
+ expected = "[inner]\n N = 3\n"
+ encodeExpected(t, "non-nil anonymous tagged struct pointer field", v1, expected, nil)
+}
+
+func TestEncodeIgnoredFields(t *testing.T) {
+ type simple struct {
+ Number int `toml:"-"`
+ }
+ value := simple{}
+ expected := ""
+ encodeExpected(t, "ignored field", value, expected, nil)
+}
+
+func encodeExpected(
+ t *testing.T, label string, val interface{}, wantStr string, wantErr error,
+) {
+ var buf bytes.Buffer
+ enc := NewEncoder(&buf)
+ err := enc.Encode(val)
+ if err != wantErr {
+ if wantErr != nil {
+ if wantErr == errAnything && err != nil {
+ return
+ }
+ t.Errorf("%s: want Encode error %v, got %v", label, wantErr, err)
+ } else {
+ t.Errorf("%s: Encode failed: %s", label, err)
+ }
+ }
+ if err != nil {
+ return
+ }
+ if got := buf.String(); wantStr != got {
+ t.Errorf("%s: want\n-----\n%q\n-----\nbut got\n-----\n%q\n-----\n",
+ label, wantStr, got)
+ }
+}
+
+func ExampleEncoder_Encode() {
+ date, _ := time.Parse(time.RFC822, "14 Mar 10 18:00 UTC")
+ var config = map[string]interface{}{
+ "date": date,
+ "counts": []int{1, 1, 2, 3, 5, 8},
+ "hash": map[string]string{
+ "key1": "val1",
+ "key2": "val2",
+ },
+ }
+ buf := new(bytes.Buffer)
+ if err := NewEncoder(buf).Encode(config); err != nil {
+ log.Fatal(err)
+ }
+ fmt.Println(buf.String())
+
+ // Output:
+ // counts = [1, 1, 2, 3, 5, 8]
+ // date = 2010-03-14T18:00:00Z
+ //
+ // [hash]
+ // key1 = "val1"
+ // key2 = "val2"
+}
diff --git a/vendor/github.com/BurntSushi/toml/encoding_types.go b/vendor/github.com/BurntSushi/toml/encoding_types.go
new file mode 100644
index 0000000..d36e1dd
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/encoding_types.go
@@ -0,0 +1,19 @@
+// +build go1.2
+
+package toml
+
+// In order to support Go 1.1, we define our own TextMarshaler and
+// TextUnmarshaler types. For Go 1.2+, we just alias them with the
+// standard library interfaces.
+
+import (
+ "encoding"
+)
+
+// TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here
+// so that Go 1.1 can be supported.
+type TextMarshaler encoding.TextMarshaler
+
+// TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined
+// here so that Go 1.1 can be supported.
+type TextUnmarshaler encoding.TextUnmarshaler
diff --git a/vendor/github.com/BurntSushi/toml/encoding_types_1.1.go b/vendor/github.com/BurntSushi/toml/encoding_types_1.1.go
new file mode 100644
index 0000000..e8d503d
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/encoding_types_1.1.go
@@ -0,0 +1,18 @@
+// +build !go1.2
+
+package toml
+
+// These interfaces were introduced in Go 1.2, so we add them manually when
+// compiling for Go 1.1.
+
+// TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here
+// so that Go 1.1 can be supported.
+type TextMarshaler interface {
+ MarshalText() (text []byte, err error)
+}
+
+// TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined
+// here so that Go 1.1 can be supported.
+type TextUnmarshaler interface {
+ UnmarshalText(text []byte) error
+}
diff --git a/vendor/github.com/BurntSushi/toml/lex.go b/vendor/github.com/BurntSushi/toml/lex.go
new file mode 100644
index 0000000..6dee7fc
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/lex.go
@@ -0,0 +1,953 @@
+package toml
+
+import (
+ "fmt"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+type itemType int
+
+const (
+ itemError itemType = iota
+ itemNIL // used in the parser to indicate no type
+ itemEOF
+ itemText
+ itemString
+ itemRawString
+ itemMultilineString
+ itemRawMultilineString
+ itemBool
+ itemInteger
+ itemFloat
+ itemDatetime
+ itemArray // the start of an array
+ itemArrayEnd
+ itemTableStart
+ itemTableEnd
+ itemArrayTableStart
+ itemArrayTableEnd
+ itemKeyStart
+ itemCommentStart
+ itemInlineTableStart
+ itemInlineTableEnd
+)
+
+const (
+ eof = 0
+ comma = ','
+ tableStart = '['
+ tableEnd = ']'
+ arrayTableStart = '['
+ arrayTableEnd = ']'
+ tableSep = '.'
+ keySep = '='
+ arrayStart = '['
+ arrayEnd = ']'
+ commentStart = '#'
+ stringStart = '"'
+ stringEnd = '"'
+ rawStringStart = '\''
+ rawStringEnd = '\''
+ inlineTableStart = '{'
+ inlineTableEnd = '}'
+)
+
+type stateFn func(lx *lexer) stateFn
+
+type lexer struct {
+ input string
+ start int
+ pos int
+ line int
+ state stateFn
+ items chan item
+
+ // Allow for backing up up to three runes.
+ // This is necessary because TOML contains 3-rune tokens (""" and ''').
+ prevWidths [3]int
+ nprev int // how many of prevWidths are in use
+ // If we emit an eof, we can still back up, but it is not OK to call
+ // next again.
+ atEOF bool
+
+ // A stack of state functions used to maintain context.
+ // The idea is to reuse parts of the state machine in various places.
+ // For example, values can appear at the top level or within arbitrarily
+ // nested arrays. The last state on the stack is used after a value has
+ // been lexed. Similarly for comments.
+ stack []stateFn
+}
+
+type item struct {
+ typ itemType
+ val string
+ line int
+}
+
+func (lx *lexer) nextItem() item {
+ for {
+ select {
+ case item := <-lx.items:
+ return item
+ default:
+ lx.state = lx.state(lx)
+ }
+ }
+}
+
+func lex(input string) *lexer {
+ lx := &lexer{
+ input: input,
+ state: lexTop,
+ line: 1,
+ items: make(chan item, 10),
+ stack: make([]stateFn, 0, 10),
+ }
+ return lx
+}
+
+func (lx *lexer) push(state stateFn) {
+ lx.stack = append(lx.stack, state)
+}
+
+func (lx *lexer) pop() stateFn {
+ if len(lx.stack) == 0 {
+ return lx.errorf("BUG in lexer: no states to pop")
+ }
+ last := lx.stack[len(lx.stack)-1]
+ lx.stack = lx.stack[0 : len(lx.stack)-1]
+ return last
+}
+
+func (lx *lexer) current() string {
+ return lx.input[lx.start:lx.pos]
+}
+
+func (lx *lexer) emit(typ itemType) {
+ lx.items <- item{typ, lx.current(), lx.line}
+ lx.start = lx.pos
+}
+
+func (lx *lexer) emitTrim(typ itemType) {
+ lx.items <- item{typ, strings.TrimSpace(lx.current()), lx.line}
+ lx.start = lx.pos
+}
+
+func (lx *lexer) next() (r rune) {
+ if lx.atEOF {
+ panic("next called after EOF")
+ }
+ if lx.pos >= len(lx.input) {
+ lx.atEOF = true
+ return eof
+ }
+
+ if lx.input[lx.pos] == '\n' {
+ lx.line++
+ }
+ lx.prevWidths[2] = lx.prevWidths[1]
+ lx.prevWidths[1] = lx.prevWidths[0]
+ if lx.nprev < 3 {
+ lx.nprev++
+ }
+ r, w := utf8.DecodeRuneInString(lx.input[lx.pos:])
+ lx.prevWidths[0] = w
+ lx.pos += w
+ return r
+}
+
+// ignore skips over the pending input before this point.
+func (lx *lexer) ignore() {
+ lx.start = lx.pos
+}
+
+// backup steps back one rune. Can be called only twice between calls to next.
+func (lx *lexer) backup() {
+ if lx.atEOF {
+ lx.atEOF = false
+ return
+ }
+ if lx.nprev < 1 {
+ panic("backed up too far")
+ }
+ w := lx.prevWidths[0]
+ lx.prevWidths[0] = lx.prevWidths[1]
+ lx.prevWidths[1] = lx.prevWidths[2]
+ lx.nprev--
+ lx.pos -= w
+ if lx.pos < len(lx.input) && lx.input[lx.pos] == '\n' {
+ lx.line--
+ }
+}
+
+// accept consumes the next rune if it's equal to `valid`.
+func (lx *lexer) accept(valid rune) bool {
+ if lx.next() == valid {
+ return true
+ }
+ lx.backup()
+ return false
+}
+
+// peek returns but does not consume the next rune in the input.
+func (lx *lexer) peek() rune {
+ r := lx.next()
+ lx.backup()
+ return r
+}
+
+// skip ignores all input that matches the given predicate.
+func (lx *lexer) skip(pred func(rune) bool) {
+ for {
+ r := lx.next()
+ if pred(r) {
+ continue
+ }
+ lx.backup()
+ lx.ignore()
+ return
+ }
+}
+
+// errorf stops all lexing by emitting an error and returning `nil`.
+// Note that any value that is a character is escaped if it's a special
+// character (newlines, tabs, etc.).
+func (lx *lexer) errorf(format string, values ...interface{}) stateFn {
+ lx.items <- item{
+ itemError,
+ fmt.Sprintf(format, values...),
+ lx.line,
+ }
+ return nil
+}
+
+// lexTop consumes elements at the top level of TOML data.
+func lexTop(lx *lexer) stateFn {
+ r := lx.next()
+ if isWhitespace(r) || isNL(r) {
+ return lexSkip(lx, lexTop)
+ }
+ switch r {
+ case commentStart:
+ lx.push(lexTop)
+ return lexCommentStart
+ case tableStart:
+ return lexTableStart
+ case eof:
+ if lx.pos > lx.start {
+ return lx.errorf("unexpected EOF")
+ }
+ lx.emit(itemEOF)
+ return nil
+ }
+
+ // At this point, the only valid item can be a key, so we back up
+ // and let the key lexer do the rest.
+ lx.backup()
+ lx.push(lexTopEnd)
+ return lexKeyStart
+}
+
+// lexTopEnd is entered whenever a top-level item has been consumed. (A value
+// or a table.) It must see only whitespace, and will turn back to lexTop
+// upon a newline. If it sees EOF, it will quit the lexer successfully.
+func lexTopEnd(lx *lexer) stateFn {
+ r := lx.next()
+ switch {
+ case r == commentStart:
+ // a comment will read to a newline for us.
+ lx.push(lexTop)
+ return lexCommentStart
+ case isWhitespace(r):
+ return lexTopEnd
+ case isNL(r):
+ lx.ignore()
+ return lexTop
+ case r == eof:
+ lx.emit(itemEOF)
+ return nil
+ }
+ return lx.errorf("expected a top-level item to end with a newline, "+
+ "comment, or EOF, but got %q instead", r)
+}
+
+// lexTable lexes the beginning of a table. Namely, it makes sure that
+// it starts with a character other than '.' and ']'.
+// It assumes that '[' has already been consumed.
+// It also handles the case that this is an item in an array of tables.
+// e.g., '[[name]]'.
+func lexTableStart(lx *lexer) stateFn {
+ if lx.peek() == arrayTableStart {
+ lx.next()
+ lx.emit(itemArrayTableStart)
+ lx.push(lexArrayTableEnd)
+ } else {
+ lx.emit(itemTableStart)
+ lx.push(lexTableEnd)
+ }
+ return lexTableNameStart
+}
+
+func lexTableEnd(lx *lexer) stateFn {
+ lx.emit(itemTableEnd)
+ return lexTopEnd
+}
+
+func lexArrayTableEnd(lx *lexer) stateFn {
+ if r := lx.next(); r != arrayTableEnd {
+ return lx.errorf("expected end of table array name delimiter %q, "+
+ "but got %q instead", arrayTableEnd, r)
+ }
+ lx.emit(itemArrayTableEnd)
+ return lexTopEnd
+}
+
+func lexTableNameStart(lx *lexer) stateFn {
+ lx.skip(isWhitespace)
+ switch r := lx.peek(); {
+ case r == tableEnd || r == eof:
+ return lx.errorf("unexpected end of table name " +
+ "(table names cannot be empty)")
+ case r == tableSep:
+ return lx.errorf("unexpected table separator " +
+ "(table names cannot be empty)")
+ case r == stringStart || r == rawStringStart:
+ lx.ignore()
+ lx.push(lexTableNameEnd)
+ return lexValue // reuse string lexing
+ default:
+ return lexBareTableName
+ }
+}
+
+// lexBareTableName lexes the name of a table. It assumes that at least one
+// valid character for the table has already been read.
+func lexBareTableName(lx *lexer) stateFn {
+ r := lx.next()
+ if isBareKeyChar(r) {
+ return lexBareTableName
+ }
+ lx.backup()
+ lx.emit(itemText)
+ return lexTableNameEnd
+}
+
+// lexTableNameEnd reads the end of a piece of a table name, optionally
+// consuming whitespace.
+func lexTableNameEnd(lx *lexer) stateFn {
+ lx.skip(isWhitespace)
+ switch r := lx.next(); {
+ case isWhitespace(r):
+ return lexTableNameEnd
+ case r == tableSep:
+ lx.ignore()
+ return lexTableNameStart
+ case r == tableEnd:
+ return lx.pop()
+ default:
+ return lx.errorf("expected '.' or ']' to end table name, "+
+ "but got %q instead", r)
+ }
+}
+
+// lexKeyStart consumes a key name up until the first non-whitespace character.
+// lexKeyStart will ignore whitespace.
+func lexKeyStart(lx *lexer) stateFn {
+ r := lx.peek()
+ switch {
+ case r == keySep:
+ return lx.errorf("unexpected key separator %q", keySep)
+ case isWhitespace(r) || isNL(r):
+ lx.next()
+ return lexSkip(lx, lexKeyStart)
+ case r == stringStart || r == rawStringStart:
+ lx.ignore()
+ lx.emit(itemKeyStart)
+ lx.push(lexKeyEnd)
+ return lexValue // reuse string lexing
+ default:
+ lx.ignore()
+ lx.emit(itemKeyStart)
+ return lexBareKey
+ }
+}
+
+// lexBareKey consumes the text of a bare key. Assumes that the first character
+// (which is not whitespace) has not yet been consumed.
+func lexBareKey(lx *lexer) stateFn {
+ switch r := lx.next(); {
+ case isBareKeyChar(r):
+ return lexBareKey
+ case isWhitespace(r):
+ lx.backup()
+ lx.emit(itemText)
+ return lexKeyEnd
+ case r == keySep:
+ lx.backup()
+ lx.emit(itemText)
+ return lexKeyEnd
+ default:
+ return lx.errorf("bare keys cannot contain %q", r)
+ }
+}
+
+// lexKeyEnd consumes the end of a key and trims whitespace (up to the key
+// separator).
+func lexKeyEnd(lx *lexer) stateFn {
+ switch r := lx.next(); {
+ case r == keySep:
+ return lexSkip(lx, lexValue)
+ case isWhitespace(r):
+ return lexSkip(lx, lexKeyEnd)
+ default:
+ return lx.errorf("expected key separator %q, but got %q instead",
+ keySep, r)
+ }
+}
+
+// lexValue starts the consumption of a value anywhere a value is expected.
+// lexValue will ignore whitespace.
+// After a value is lexed, the last state on the next is popped and returned.
+func lexValue(lx *lexer) stateFn {
+ // We allow whitespace to precede a value, but NOT newlines.
+ // In array syntax, the array states are responsible for ignoring newlines.
+ r := lx.next()
+ switch {
+ case isWhitespace(r):
+ return lexSkip(lx, lexValue)
+ case isDigit(r):
+ lx.backup() // avoid an extra state and use the same as above
+ return lexNumberOrDateStart
+ }
+ switch r {
+ case arrayStart:
+ lx.ignore()
+ lx.emit(itemArray)
+ return lexArrayValue
+ case inlineTableStart:
+ lx.ignore()
+ lx.emit(itemInlineTableStart)
+ return lexInlineTableValue
+ case stringStart:
+ if lx.accept(stringStart) {
+ if lx.accept(stringStart) {
+ lx.ignore() // Ignore """
+ return lexMultilineString
+ }
+ lx.backup()
+ }
+ lx.ignore() // ignore the '"'
+ return lexString
+ case rawStringStart:
+ if lx.accept(rawStringStart) {
+ if lx.accept(rawStringStart) {
+ lx.ignore() // Ignore """
+ return lexMultilineRawString
+ }
+ lx.backup()
+ }
+ lx.ignore() // ignore the "'"
+ return lexRawString
+ case '+', '-':
+ return lexNumberStart
+ case '.': // special error case, be kind to users
+ return lx.errorf("floats must start with a digit, not '.'")
+ }
+ if unicode.IsLetter(r) {
+ // Be permissive here; lexBool will give a nice error if the
+ // user wrote something like
+ // x = foo
+ // (i.e. not 'true' or 'false' but is something else word-like.)
+ lx.backup()
+ return lexBool
+ }
+ return lx.errorf("expected value but found %q instead", r)
+}
+
+// lexArrayValue consumes one value in an array. It assumes that '[' or ','
+// have already been consumed. All whitespace and newlines are ignored.
+func lexArrayValue(lx *lexer) stateFn {
+ r := lx.next()
+ switch {
+ case isWhitespace(r) || isNL(r):
+ return lexSkip(lx, lexArrayValue)
+ case r == commentStart:
+ lx.push(lexArrayValue)
+ return lexCommentStart
+ case r == comma:
+ return lx.errorf("unexpected comma")
+ case r == arrayEnd:
+ // NOTE(caleb): The spec isn't clear about whether you can have
+ // a trailing comma or not, so we'll allow it.
+ return lexArrayEnd
+ }
+
+ lx.backup()
+ lx.push(lexArrayValueEnd)
+ return lexValue
+}
+
+// lexArrayValueEnd consumes everything between the end of an array value and
+// the next value (or the end of the array): it ignores whitespace and newlines
+// and expects either a ',' or a ']'.
+func lexArrayValueEnd(lx *lexer) stateFn {
+ r := lx.next()
+ switch {
+ case isWhitespace(r) || isNL(r):
+ return lexSkip(lx, lexArrayValueEnd)
+ case r == commentStart:
+ lx.push(lexArrayValueEnd)
+ return lexCommentStart
+ case r == comma:
+ lx.ignore()
+ return lexArrayValue // move on to the next value
+ case r == arrayEnd:
+ return lexArrayEnd
+ }
+ return lx.errorf(
+ "expected a comma or array terminator %q, but got %q instead",
+ arrayEnd, r,
+ )
+}
+
+// lexArrayEnd finishes the lexing of an array.
+// It assumes that a ']' has just been consumed.
+func lexArrayEnd(lx *lexer) stateFn {
+ lx.ignore()
+ lx.emit(itemArrayEnd)
+ return lx.pop()
+}
+
+// lexInlineTableValue consumes one key/value pair in an inline table.
+// It assumes that '{' or ',' have already been consumed. Whitespace is ignored.
+func lexInlineTableValue(lx *lexer) stateFn {
+ r := lx.next()
+ switch {
+ case isWhitespace(r):
+ return lexSkip(lx, lexInlineTableValue)
+ case isNL(r):
+ return lx.errorf("newlines not allowed within inline tables")
+ case r == commentStart:
+ lx.push(lexInlineTableValue)
+ return lexCommentStart
+ case r == comma:
+ return lx.errorf("unexpected comma")
+ case r == inlineTableEnd:
+ return lexInlineTableEnd
+ }
+ lx.backup()
+ lx.push(lexInlineTableValueEnd)
+ return lexKeyStart
+}
+
+// lexInlineTableValueEnd consumes everything between the end of an inline table
+// key/value pair and the next pair (or the end of the table):
+// it ignores whitespace and expects either a ',' or a '}'.
+func lexInlineTableValueEnd(lx *lexer) stateFn {
+ r := lx.next()
+ switch {
+ case isWhitespace(r):
+ return lexSkip(lx, lexInlineTableValueEnd)
+ case isNL(r):
+ return lx.errorf("newlines not allowed within inline tables")
+ case r == commentStart:
+ lx.push(lexInlineTableValueEnd)
+ return lexCommentStart
+ case r == comma:
+ lx.ignore()
+ return lexInlineTableValue
+ case r == inlineTableEnd:
+ return lexInlineTableEnd
+ }
+ return lx.errorf("expected a comma or an inline table terminator %q, "+
+ "but got %q instead", inlineTableEnd, r)
+}
+
+// lexInlineTableEnd finishes the lexing of an inline table.
+// It assumes that a '}' has just been consumed.
+func lexInlineTableEnd(lx *lexer) stateFn {
+ lx.ignore()
+ lx.emit(itemInlineTableEnd)
+ return lx.pop()
+}
+
+// lexString consumes the inner contents of a string. It assumes that the
+// beginning '"' has already been consumed and ignored.
+func lexString(lx *lexer) stateFn {
+ r := lx.next()
+ switch {
+ case r == eof:
+ return lx.errorf("unexpected EOF")
+ case isNL(r):
+ return lx.errorf("strings cannot contain newlines")
+ case r == '\\':
+ lx.push(lexString)
+ return lexStringEscape
+ case r == stringEnd:
+ lx.backup()
+ lx.emit(itemString)
+ lx.next()
+ lx.ignore()
+ return lx.pop()
+ }
+ return lexString
+}
+
+// lexMultilineString consumes the inner contents of a string. It assumes that
+// the beginning '"""' has already been consumed and ignored.
+func lexMultilineString(lx *lexer) stateFn {
+ switch lx.next() {
+ case eof:
+ return lx.errorf("unexpected EOF")
+ case '\\':
+ return lexMultilineStringEscape
+ case stringEnd:
+ if lx.accept(stringEnd) {
+ if lx.accept(stringEnd) {
+ lx.backup()
+ lx.backup()
+ lx.backup()
+ lx.emit(itemMultilineString)
+ lx.next()
+ lx.next()
+ lx.next()
+ lx.ignore()
+ return lx.pop()
+ }
+ lx.backup()
+ }
+ }
+ return lexMultilineString
+}
+
+// lexRawString consumes a raw string. Nothing can be escaped in such a string.
+// It assumes that the beginning "'" has already been consumed and ignored.
+func lexRawString(lx *lexer) stateFn {
+ r := lx.next()
+ switch {
+ case r == eof:
+ return lx.errorf("unexpected EOF")
+ case isNL(r):
+ return lx.errorf("strings cannot contain newlines")
+ case r == rawStringEnd:
+ lx.backup()
+ lx.emit(itemRawString)
+ lx.next()
+ lx.ignore()
+ return lx.pop()
+ }
+ return lexRawString
+}
+
+// lexMultilineRawString consumes a raw string. Nothing can be escaped in such
+// a string. It assumes that the beginning "'''" has already been consumed and
+// ignored.
+func lexMultilineRawString(lx *lexer) stateFn {
+ switch lx.next() {
+ case eof:
+ return lx.errorf("unexpected EOF")
+ case rawStringEnd:
+ if lx.accept(rawStringEnd) {
+ if lx.accept(rawStringEnd) {
+ lx.backup()
+ lx.backup()
+ lx.backup()
+ lx.emit(itemRawMultilineString)
+ lx.next()
+ lx.next()
+ lx.next()
+ lx.ignore()
+ return lx.pop()
+ }
+ lx.backup()
+ }
+ }
+ return lexMultilineRawString
+}
+
+// lexMultilineStringEscape consumes an escaped character. It assumes that the
+// preceding '\\' has already been consumed.
+func lexMultilineStringEscape(lx *lexer) stateFn {
+ // Handle the special case first:
+ if isNL(lx.next()) {
+ return lexMultilineString
+ }
+ lx.backup()
+ lx.push(lexMultilineString)
+ return lexStringEscape(lx)
+}
+
+func lexStringEscape(lx *lexer) stateFn {
+ r := lx.next()
+ switch r {
+ case 'b':
+ fallthrough
+ case 't':
+ fallthrough
+ case 'n':
+ fallthrough
+ case 'f':
+ fallthrough
+ case 'r':
+ fallthrough
+ case '"':
+ fallthrough
+ case '\\':
+ return lx.pop()
+ case 'u':
+ return lexShortUnicodeEscape
+ case 'U':
+ return lexLongUnicodeEscape
+ }
+ return lx.errorf("invalid escape character %q; only the following "+
+ "escape characters are allowed: "+
+ `\b, \t, \n, \f, \r, \", \\, \uXXXX, and \UXXXXXXXX`, r)
+}
+
+func lexShortUnicodeEscape(lx *lexer) stateFn {
+ var r rune
+ for i := 0; i < 4; i++ {
+ r = lx.next()
+ if !isHexadecimal(r) {
+ return lx.errorf(`expected four hexadecimal digits after '\u', `+
+ "but got %q instead", lx.current())
+ }
+ }
+ return lx.pop()
+}
+
+func lexLongUnicodeEscape(lx *lexer) stateFn {
+ var r rune
+ for i := 0; i < 8; i++ {
+ r = lx.next()
+ if !isHexadecimal(r) {
+ return lx.errorf(`expected eight hexadecimal digits after '\U', `+
+ "but got %q instead", lx.current())
+ }
+ }
+ return lx.pop()
+}
+
+// lexNumberOrDateStart consumes either an integer, a float, or datetime.
+func lexNumberOrDateStart(lx *lexer) stateFn {
+ r := lx.next()
+ if isDigit(r) {
+ return lexNumberOrDate
+ }
+ switch r {
+ case '_':
+ return lexNumber
+ case 'e', 'E':
+ return lexFloat
+ case '.':
+ return lx.errorf("floats must start with a digit, not '.'")
+ }
+ return lx.errorf("expected a digit but got %q", r)
+}
+
+// lexNumberOrDate consumes either an integer, float or datetime.
+func lexNumberOrDate(lx *lexer) stateFn {
+ r := lx.next()
+ if isDigit(r) {
+ return lexNumberOrDate
+ }
+ switch r {
+ case '-':
+ return lexDatetime
+ case '_':
+ return lexNumber
+ case '.', 'e', 'E':
+ return lexFloat
+ }
+
+ lx.backup()
+ lx.emit(itemInteger)
+ return lx.pop()
+}
+
+// lexDatetime consumes a Datetime, to a first approximation.
+// The parser validates that it matches one of the accepted formats.
+func lexDatetime(lx *lexer) stateFn {
+ r := lx.next()
+ if isDigit(r) {
+ return lexDatetime
+ }
+ switch r {
+ case '-', 'T', ':', '.', 'Z':
+ return lexDatetime
+ }
+
+ lx.backup()
+ lx.emit(itemDatetime)
+ return lx.pop()
+}
+
+// lexNumberStart consumes either an integer or a float. It assumes that a sign
+// has already been read, but that *no* digits have been consumed.
+// lexNumberStart will move to the appropriate integer or float states.
+func lexNumberStart(lx *lexer) stateFn {
+ // We MUST see a digit. Even floats have to start with a digit.
+ r := lx.next()
+ if !isDigit(r) {
+ if r == '.' {
+ return lx.errorf("floats must start with a digit, not '.'")
+ }
+ return lx.errorf("expected a digit but got %q", r)
+ }
+ return lexNumber
+}
+
+// lexNumber consumes an integer or a float after seeing the first digit.
+func lexNumber(lx *lexer) stateFn {
+ r := lx.next()
+ if isDigit(r) {
+ return lexNumber
+ }
+ switch r {
+ case '_':
+ return lexNumber
+ case '.', 'e', 'E':
+ return lexFloat
+ }
+
+ lx.backup()
+ lx.emit(itemInteger)
+ return lx.pop()
+}
+
+// lexFloat consumes the elements of a float. It allows any sequence of
+// float-like characters, so floats emitted by the lexer are only a first
+// approximation and must be validated by the parser.
+func lexFloat(lx *lexer) stateFn {
+ r := lx.next()
+ if isDigit(r) {
+ return lexFloat
+ }
+ switch r {
+ case '_', '.', '-', '+', 'e', 'E':
+ return lexFloat
+ }
+
+ lx.backup()
+ lx.emit(itemFloat)
+ return lx.pop()
+}
+
+// lexBool consumes a bool string: 'true' or 'false.
+func lexBool(lx *lexer) stateFn {
+ var rs []rune
+ for {
+ r := lx.next()
+ if !unicode.IsLetter(r) {
+ lx.backup()
+ break
+ }
+ rs = append(rs, r)
+ }
+ s := string(rs)
+ switch s {
+ case "true", "false":
+ lx.emit(itemBool)
+ return lx.pop()
+ }
+ return lx.errorf("expected value but found %q instead", s)
+}
+
+// lexCommentStart begins the lexing of a comment. It will emit
+// itemCommentStart and consume no characters, passing control to lexComment.
+func lexCommentStart(lx *lexer) stateFn {
+ lx.ignore()
+ lx.emit(itemCommentStart)
+ return lexComment
+}
+
+// lexComment lexes an entire comment. It assumes that '#' has been consumed.
+// It will consume *up to* the first newline character, and pass control
+// back to the last state on the stack.
+func lexComment(lx *lexer) stateFn {
+ r := lx.peek()
+ if isNL(r) || r == eof {
+ lx.emit(itemText)
+ return lx.pop()
+ }
+ lx.next()
+ return lexComment
+}
+
+// lexSkip ignores all slurped input and moves on to the next state.
+func lexSkip(lx *lexer, nextState stateFn) stateFn {
+ return func(lx *lexer) stateFn {
+ lx.ignore()
+ return nextState
+ }
+}
+
+// isWhitespace returns true if `r` is a whitespace character according
+// to the spec.
+func isWhitespace(r rune) bool {
+ return r == '\t' || r == ' '
+}
+
+func isNL(r rune) bool {
+ return r == '\n' || r == '\r'
+}
+
+func isDigit(r rune) bool {
+ return r >= '0' && r <= '9'
+}
+
+func isHexadecimal(r rune) bool {
+ return (r >= '0' && r <= '9') ||
+ (r >= 'a' && r <= 'f') ||
+ (r >= 'A' && r <= 'F')
+}
+
+func isBareKeyChar(r rune) bool {
+ return (r >= 'A' && r <= 'Z') ||
+ (r >= 'a' && r <= 'z') ||
+ (r >= '0' && r <= '9') ||
+ r == '_' ||
+ r == '-'
+}
+
+func (itype itemType) String() string {
+ switch itype {
+ case itemError:
+ return "Error"
+ case itemNIL:
+ return "NIL"
+ case itemEOF:
+ return "EOF"
+ case itemText:
+ return "Text"
+ case itemString, itemRawString, itemMultilineString, itemRawMultilineString:
+ return "String"
+ case itemBool:
+ return "Bool"
+ case itemInteger:
+ return "Integer"
+ case itemFloat:
+ return "Float"
+ case itemDatetime:
+ return "DateTime"
+ case itemTableStart:
+ return "TableStart"
+ case itemTableEnd:
+ return "TableEnd"
+ case itemKeyStart:
+ return "KeyStart"
+ case itemArray:
+ return "Array"
+ case itemArrayEnd:
+ return "ArrayEnd"
+ case itemCommentStart:
+ return "CommentStart"
+ }
+ panic(fmt.Sprintf("BUG: Unknown type '%d'.", int(itype)))
+}
+
+func (item item) String() string {
+ return fmt.Sprintf("(%s, %s)", item.typ.String(), item.val)
+}
diff --git a/vendor/github.com/BurntSushi/toml/parse.go b/vendor/github.com/BurntSushi/toml/parse.go
new file mode 100644
index 0000000..50869ef
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/parse.go
@@ -0,0 +1,592 @@
+package toml
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "time"
+ "unicode"
+ "unicode/utf8"
+)
+
+type parser struct {
+ mapping map[string]interface{}
+ types map[string]tomlType
+ lx *lexer
+
+ // A list of keys in the order that they appear in the TOML data.
+ ordered []Key
+
+ // the full key for the current hash in scope
+ context Key
+
+ // the base key name for everything except hashes
+ currentKey string
+
+ // rough approximation of line number
+ approxLine int
+
+ // A map of 'key.group.names' to whether they were created implicitly.
+ implicits map[string]bool
+}
+
+type parseError string
+
+func (pe parseError) Error() string {
+ return string(pe)
+}
+
+func parse(data string) (p *parser, err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ var ok bool
+ if err, ok = r.(parseError); ok {
+ return
+ }
+ panic(r)
+ }
+ }()
+
+ p = &parser{
+ mapping: make(map[string]interface{}),
+ types: make(map[string]tomlType),
+ lx: lex(data),
+ ordered: make([]Key, 0),
+ implicits: make(map[string]bool),
+ }
+ for {
+ item := p.next()
+ if item.typ == itemEOF {
+ break
+ }
+ p.topLevel(item)
+ }
+
+ return p, nil
+}
+
+func (p *parser) panicf(format string, v ...interface{}) {
+ msg := fmt.Sprintf("Near line %d (last key parsed '%s'): %s",
+ p.approxLine, p.current(), fmt.Sprintf(format, v...))
+ panic(parseError(msg))
+}
+
+func (p *parser) next() item {
+ it := p.lx.nextItem()
+ if it.typ == itemError {
+ p.panicf("%s", it.val)
+ }
+ return it
+}
+
+func (p *parser) bug(format string, v ...interface{}) {
+ panic(fmt.Sprintf("BUG: "+format+"\n\n", v...))
+}
+
+func (p *parser) expect(typ itemType) item {
+ it := p.next()
+ p.assertEqual(typ, it.typ)
+ return it
+}
+
+func (p *parser) assertEqual(expected, got itemType) {
+ if expected != got {
+ p.bug("Expected '%s' but got '%s'.", expected, got)
+ }
+}
+
+func (p *parser) topLevel(item item) {
+ switch item.typ {
+ case itemCommentStart:
+ p.approxLine = item.line
+ p.expect(itemText)
+ case itemTableStart:
+ kg := p.next()
+ p.approxLine = kg.line
+
+ var key Key
+ for ; kg.typ != itemTableEnd && kg.typ != itemEOF; kg = p.next() {
+ key = append(key, p.keyString(kg))
+ }
+ p.assertEqual(itemTableEnd, kg.typ)
+
+ p.establishContext(key, false)
+ p.setType("", tomlHash)
+ p.ordered = append(p.ordered, key)
+ case itemArrayTableStart:
+ kg := p.next()
+ p.approxLine = kg.line
+
+ var key Key
+ for ; kg.typ != itemArrayTableEnd && kg.typ != itemEOF; kg = p.next() {
+ key = append(key, p.keyString(kg))
+ }
+ p.assertEqual(itemArrayTableEnd, kg.typ)
+
+ p.establishContext(key, true)
+ p.setType("", tomlArrayHash)
+ p.ordered = append(p.ordered, key)
+ case itemKeyStart:
+ kname := p.next()
+ p.approxLine = kname.line
+ p.currentKey = p.keyString(kname)
+
+ val, typ := p.value(p.next())
+ p.setValue(p.currentKey, val)
+ p.setType(p.currentKey, typ)
+ p.ordered = append(p.ordered, p.context.add(p.currentKey))
+ p.currentKey = ""
+ default:
+ p.bug("Unexpected type at top level: %s", item.typ)
+ }
+}
+
+// Gets a string for a key (or part of a key in a table name).
+func (p *parser) keyString(it item) string {
+ switch it.typ {
+ case itemText:
+ return it.val
+ case itemString, itemMultilineString,
+ itemRawString, itemRawMultilineString:
+ s, _ := p.value(it)
+ return s.(string)
+ default:
+ p.bug("Unexpected key type: %s", it.typ)
+ panic("unreachable")
+ }
+}
+
+// value translates an expected value from the lexer into a Go value wrapped
+// as an empty interface.
+func (p *parser) value(it item) (interface{}, tomlType) {
+ switch it.typ {
+ case itemString:
+ return p.replaceEscapes(it.val), p.typeOfPrimitive(it)
+ case itemMultilineString:
+ trimmed := stripFirstNewline(stripEscapedWhitespace(it.val))
+ return p.replaceEscapes(trimmed), p.typeOfPrimitive(it)
+ case itemRawString:
+ return it.val, p.typeOfPrimitive(it)
+ case itemRawMultilineString:
+ return stripFirstNewline(it.val), p.typeOfPrimitive(it)
+ case itemBool:
+ switch it.val {
+ case "true":
+ return true, p.typeOfPrimitive(it)
+ case "false":
+ return false, p.typeOfPrimitive(it)
+ }
+ p.bug("Expected boolean value, but got '%s'.", it.val)
+ case itemInteger:
+ if !numUnderscoresOK(it.val) {
+ p.panicf("Invalid integer %q: underscores must be surrounded by digits",
+ it.val)
+ }
+ val := strings.Replace(it.val, "_", "", -1)
+ num, err := strconv.ParseInt(val, 10, 64)
+ if err != nil {
+ // Distinguish integer values. Normally, it'd be a bug if the lexer
+ // provides an invalid integer, but it's possible that the number is
+ // out of range of valid values (which the lexer cannot determine).
+ // So mark the former as a bug but the latter as a legitimate user
+ // error.
+ if e, ok := err.(*strconv.NumError); ok &&
+ e.Err == strconv.ErrRange {
+
+ p.panicf("Integer '%s' is out of the range of 64-bit "+
+ "signed integers.", it.val)
+ } else {
+ p.bug("Expected integer value, but got '%s'.", it.val)
+ }
+ }
+ return num, p.typeOfPrimitive(it)
+ case itemFloat:
+ parts := strings.FieldsFunc(it.val, func(r rune) bool {
+ switch r {
+ case '.', 'e', 'E':
+ return true
+ }
+ return false
+ })
+ for _, part := range parts {
+ if !numUnderscoresOK(part) {
+ p.panicf("Invalid float %q: underscores must be "+
+ "surrounded by digits", it.val)
+ }
+ }
+ if !numPeriodsOK(it.val) {
+ // As a special case, numbers like '123.' or '1.e2',
+ // which are valid as far as Go/strconv are concerned,
+ // must be rejected because TOML says that a fractional
+ // part consists of '.' followed by 1+ digits.
+ p.panicf("Invalid float %q: '.' must be followed "+
+ "by one or more digits", it.val)
+ }
+ val := strings.Replace(it.val, "_", "", -1)
+ num, err := strconv.ParseFloat(val, 64)
+ if err != nil {
+ if e, ok := err.(*strconv.NumError); ok &&
+ e.Err == strconv.ErrRange {
+
+ p.panicf("Float '%s' is out of the range of 64-bit "+
+ "IEEE-754 floating-point numbers.", it.val)
+ } else {
+ p.panicf("Invalid float value: %q", it.val)
+ }
+ }
+ return num, p.typeOfPrimitive(it)
+ case itemDatetime:
+ var t time.Time
+ var ok bool
+ var err error
+ for _, format := range []string{
+ "2006-01-02T15:04:05Z07:00",
+ "2006-01-02T15:04:05",
+ "2006-01-02",
+ } {
+ t, err = time.ParseInLocation(format, it.val, time.Local)
+ if err == nil {
+ ok = true
+ break
+ }
+ }
+ if !ok {
+ p.panicf("Invalid TOML Datetime: %q.", it.val)
+ }
+ return t, p.typeOfPrimitive(it)
+ case itemArray:
+ array := make([]interface{}, 0)
+ types := make([]tomlType, 0)
+
+ for it = p.next(); it.typ != itemArrayEnd; it = p.next() {
+ if it.typ == itemCommentStart {
+ p.expect(itemText)
+ continue
+ }
+
+ val, typ := p.value(it)
+ array = append(array, val)
+ types = append(types, typ)
+ }
+ return array, p.typeOfArray(types)
+ case itemInlineTableStart:
+ var (
+ hash = make(map[string]interface{})
+ outerContext = p.context
+ outerKey = p.currentKey
+ )
+
+ p.context = append(p.context, p.currentKey)
+ p.currentKey = ""
+ for it := p.next(); it.typ != itemInlineTableEnd; it = p.next() {
+ if it.typ != itemKeyStart {
+ p.bug("Expected key start but instead found %q, around line %d",
+ it.val, p.approxLine)
+ }
+ if it.typ == itemCommentStart {
+ p.expect(itemText)
+ continue
+ }
+
+ // retrieve key
+ k := p.next()
+ p.approxLine = k.line
+ kname := p.keyString(k)
+
+ // retrieve value
+ p.currentKey = kname
+ val, typ := p.value(p.next())
+ // make sure we keep metadata up to date
+ p.setType(kname, typ)
+ p.ordered = append(p.ordered, p.context.add(p.currentKey))
+ hash[kname] = val
+ }
+ p.context = outerContext
+ p.currentKey = outerKey
+ return hash, tomlHash
+ }
+ p.bug("Unexpected value type: %s", it.typ)
+ panic("unreachable")
+}
+
+// numUnderscoresOK checks whether each underscore in s is surrounded by
+// characters that are not underscores.
+func numUnderscoresOK(s string) bool {
+ accept := false
+ for _, r := range s {
+ if r == '_' {
+ if !accept {
+ return false
+ }
+ accept = false
+ continue
+ }
+ accept = true
+ }
+ return accept
+}
+
+// numPeriodsOK checks whether every period in s is followed by a digit.
+func numPeriodsOK(s string) bool {
+ period := false
+ for _, r := range s {
+ if period && !isDigit(r) {
+ return false
+ }
+ period = r == '.'
+ }
+ return !period
+}
+
+// establishContext sets the current context of the parser,
+// where the context is either a hash or an array of hashes. Which one is
+// set depends on the value of the `array` parameter.
+//
+// Establishing the context also makes sure that the key isn't a duplicate, and
+// will create implicit hashes automatically.
+func (p *parser) establishContext(key Key, array bool) {
+ var ok bool
+
+ // Always start at the top level and drill down for our context.
+ hashContext := p.mapping
+ keyContext := make(Key, 0)
+
+ // We only need implicit hashes for key[0:-1]
+ for _, k := range key[0 : len(key)-1] {
+ _, ok = hashContext[k]
+ keyContext = append(keyContext, k)
+
+ // No key? Make an implicit hash and move on.
+ if !ok {
+ p.addImplicit(keyContext)
+ hashContext[k] = make(map[string]interface{})
+ }
+
+ // If the hash context is actually an array of tables, then set
+ // the hash context to the last element in that array.
+ //
+ // Otherwise, it better be a table, since this MUST be a key group (by
+ // virtue of it not being the last element in a key).
+ switch t := hashContext[k].(type) {
+ case []map[string]interface{}:
+ hashContext = t[len(t)-1]
+ case map[string]interface{}:
+ hashContext = t
+ default:
+ p.panicf("Key '%s' was already created as a hash.", keyContext)
+ }
+ }
+
+ p.context = keyContext
+ if array {
+ // If this is the first element for this array, then allocate a new
+ // list of tables for it.
+ k := key[len(key)-1]
+ if _, ok := hashContext[k]; !ok {
+ hashContext[k] = make([]map[string]interface{}, 0, 5)
+ }
+
+ // Add a new table. But make sure the key hasn't already been used
+ // for something else.
+ if hash, ok := hashContext[k].([]map[string]interface{}); ok {
+ hashContext[k] = append(hash, make(map[string]interface{}))
+ } else {
+ p.panicf("Key '%s' was already created and cannot be used as "+
+ "an array.", keyContext)
+ }
+ } else {
+ p.setValue(key[len(key)-1], make(map[string]interface{}))
+ }
+ p.context = append(p.context, key[len(key)-1])
+}
+
+// setValue sets the given key to the given value in the current context.
+// It will make sure that the key hasn't already been defined, account for
+// implicit key groups.
+func (p *parser) setValue(key string, value interface{}) {
+ var tmpHash interface{}
+ var ok bool
+
+ hash := p.mapping
+ keyContext := make(Key, 0)
+ for _, k := range p.context {
+ keyContext = append(keyContext, k)
+ if tmpHash, ok = hash[k]; !ok {
+ p.bug("Context for key '%s' has not been established.", keyContext)
+ }
+ switch t := tmpHash.(type) {
+ case []map[string]interface{}:
+ // The context is a table of hashes. Pick the most recent table
+ // defined as the current hash.
+ hash = t[len(t)-1]
+ case map[string]interface{}:
+ hash = t
+ default:
+ p.bug("Expected hash to have type 'map[string]interface{}', but "+
+ "it has '%T' instead.", tmpHash)
+ }
+ }
+ keyContext = append(keyContext, key)
+
+ if _, ok := hash[key]; ok {
+ // Typically, if the given key has already been set, then we have
+ // to raise an error since duplicate keys are disallowed. However,
+ // it's possible that a key was previously defined implicitly. In this
+ // case, it is allowed to be redefined concretely. (See the
+ // `tests/valid/implicit-and-explicit-after.toml` test in `toml-test`.)
+ //
+ // But we have to make sure to stop marking it as an implicit. (So that
+ // another redefinition provokes an error.)
+ //
+ // Note that since it has already been defined (as a hash), we don't
+ // want to overwrite it. So our business is done.
+ if p.isImplicit(keyContext) {
+ p.removeImplicit(keyContext)
+ return
+ }
+
+ // Otherwise, we have a concrete key trying to override a previous
+ // key, which is *always* wrong.
+ p.panicf("Key '%s' has already been defined.", keyContext)
+ }
+ hash[key] = value
+}
+
+// setType sets the type of a particular value at a given key.
+// It should be called immediately AFTER setValue.
+//
+// Note that if `key` is empty, then the type given will be applied to the
+// current context (which is either a table or an array of tables).
+func (p *parser) setType(key string, typ tomlType) {
+ keyContext := make(Key, 0, len(p.context)+1)
+ for _, k := range p.context {
+ keyContext = append(keyContext, k)
+ }
+ if len(key) > 0 { // allow type setting for hashes
+ keyContext = append(keyContext, key)
+ }
+ p.types[keyContext.String()] = typ
+}
+
+// addImplicit sets the given Key as having been created implicitly.
+func (p *parser) addImplicit(key Key) {
+ p.implicits[key.String()] = true
+}
+
+// removeImplicit stops tagging the given key as having been implicitly
+// created.
+func (p *parser) removeImplicit(key Key) {
+ p.implicits[key.String()] = false
+}
+
+// isImplicit returns true if the key group pointed to by the key was created
+// implicitly.
+func (p *parser) isImplicit(key Key) bool {
+ return p.implicits[key.String()]
+}
+
+// current returns the full key name of the current context.
+func (p *parser) current() string {
+ if len(p.currentKey) == 0 {
+ return p.context.String()
+ }
+ if len(p.context) == 0 {
+ return p.currentKey
+ }
+ return fmt.Sprintf("%s.%s", p.context, p.currentKey)
+}
+
+func stripFirstNewline(s string) string {
+ if len(s) == 0 || s[0] != '\n' {
+ return s
+ }
+ return s[1:]
+}
+
+func stripEscapedWhitespace(s string) string {
+ esc := strings.Split(s, "\\\n")
+ if len(esc) > 1 {
+ for i := 1; i < len(esc); i++ {
+ esc[i] = strings.TrimLeftFunc(esc[i], unicode.IsSpace)
+ }
+ }
+ return strings.Join(esc, "")
+}
+
+func (p *parser) replaceEscapes(str string) string {
+ var replaced []rune
+ s := []byte(str)
+ r := 0
+ for r < len(s) {
+ if s[r] != '\\' {
+ c, size := utf8.DecodeRune(s[r:])
+ r += size
+ replaced = append(replaced, c)
+ continue
+ }
+ r += 1
+ if r >= len(s) {
+ p.bug("Escape sequence at end of string.")
+ return ""
+ }
+ switch s[r] {
+ default:
+ p.bug("Expected valid escape code after \\, but got %q.", s[r])
+ return ""
+ case 'b':
+ replaced = append(replaced, rune(0x0008))
+ r += 1
+ case 't':
+ replaced = append(replaced, rune(0x0009))
+ r += 1
+ case 'n':
+ replaced = append(replaced, rune(0x000A))
+ r += 1
+ case 'f':
+ replaced = append(replaced, rune(0x000C))
+ r += 1
+ case 'r':
+ replaced = append(replaced, rune(0x000D))
+ r += 1
+ case '"':
+ replaced = append(replaced, rune(0x0022))
+ r += 1
+ case '\\':
+ replaced = append(replaced, rune(0x005C))
+ r += 1
+ case 'u':
+ // At this point, we know we have a Unicode escape of the form
+ // `uXXXX` at [r, r+5). (Because the lexer guarantees this
+ // for us.)
+ escaped := p.asciiEscapeToUnicode(s[r+1 : r+5])
+ replaced = append(replaced, escaped)
+ r += 5
+ case 'U':
+ // At this point, we know we have a Unicode escape of the form
+ // `uXXXX` at [r, r+9). (Because the lexer guarantees this
+ // for us.)
+ escaped := p.asciiEscapeToUnicode(s[r+1 : r+9])
+ replaced = append(replaced, escaped)
+ r += 9
+ }
+ }
+ return string(replaced)
+}
+
+func (p *parser) asciiEscapeToUnicode(bs []byte) rune {
+ s := string(bs)
+ hex, err := strconv.ParseUint(strings.ToLower(s), 16, 32)
+ if err != nil {
+ p.bug("Could not parse '%s' as a hexadecimal number, but the "+
+ "lexer claims it's OK: %s", s, err)
+ }
+ if !utf8.ValidRune(rune(hex)) {
+ p.panicf("Escaped character '\\u%s' is not valid UTF-8.", s)
+ }
+ return rune(hex)
+}
+
+func isStringType(ty itemType) bool {
+ return ty == itemString || ty == itemMultilineString ||
+ ty == itemRawString || ty == itemRawMultilineString
+}
diff --git a/vendor/github.com/BurntSushi/toml/session.vim b/vendor/github.com/BurntSushi/toml/session.vim
new file mode 100644
index 0000000..562164b
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/session.vim
@@ -0,0 +1 @@
+au BufWritePost *.go silent!make tags > /dev/null 2>&1
diff --git a/vendor/github.com/BurntSushi/toml/type_check.go b/vendor/github.com/BurntSushi/toml/type_check.go
new file mode 100644
index 0000000..c73f8af
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/type_check.go
@@ -0,0 +1,91 @@
+package toml
+
+// tomlType represents any Go type that corresponds to a TOML type.
+// While the first draft of the TOML spec has a simplistic type system that
+// probably doesn't need this level of sophistication, we seem to be militating
+// toward adding real composite types.
+type tomlType interface {
+ typeString() string
+}
+
+// typeEqual accepts any two types and returns true if they are equal.
+func typeEqual(t1, t2 tomlType) bool {
+ if t1 == nil || t2 == nil {
+ return false
+ }
+ return t1.typeString() == t2.typeString()
+}
+
+func typeIsHash(t tomlType) bool {
+ return typeEqual(t, tomlHash) || typeEqual(t, tomlArrayHash)
+}
+
+type tomlBaseType string
+
+func (btype tomlBaseType) typeString() string {
+ return string(btype)
+}
+
+func (btype tomlBaseType) String() string {
+ return btype.typeString()
+}
+
+var (
+ tomlInteger tomlBaseType = "Integer"
+ tomlFloat tomlBaseType = "Float"
+ tomlDatetime tomlBaseType = "Datetime"
+ tomlString tomlBaseType = "String"
+ tomlBool tomlBaseType = "Bool"
+ tomlArray tomlBaseType = "Array"
+ tomlHash tomlBaseType = "Hash"
+ tomlArrayHash tomlBaseType = "ArrayHash"
+)
+
+// typeOfPrimitive returns a tomlType of any primitive value in TOML.
+// Primitive values are: Integer, Float, Datetime, String and Bool.
+//
+// Passing a lexer item other than the following will cause a BUG message
+// to occur: itemString, itemBool, itemInteger, itemFloat, itemDatetime.
+func (p *parser) typeOfPrimitive(lexItem item) tomlType {
+ switch lexItem.typ {
+ case itemInteger:
+ return tomlInteger
+ case itemFloat:
+ return tomlFloat
+ case itemDatetime:
+ return tomlDatetime
+ case itemString:
+ return tomlString
+ case itemMultilineString:
+ return tomlString
+ case itemRawString:
+ return tomlString
+ case itemRawMultilineString:
+ return tomlString
+ case itemBool:
+ return tomlBool
+ }
+ p.bug("Cannot infer primitive type of lex item '%s'.", lexItem)
+ panic("unreachable")
+}
+
+// typeOfArray returns a tomlType for an array given a list of types of its
+// values.
+//
+// In the current spec, if an array is homogeneous, then its type is always
+// "Array". If the array is not homogeneous, an error is generated.
+func (p *parser) typeOfArray(types []tomlType) tomlType {
+ // Empty arrays are cool.
+ if len(types) == 0 {
+ return tomlArray
+ }
+
+ theType := types[0]
+ for _, t := range types[1:] {
+ if !typeEqual(theType, t) {
+ p.panicf("Array contains values of type '%s' and '%s', but "+
+ "arrays must be homogeneous.", theType, t)
+ }
+ }
+ return tomlArray
+}
diff --git a/vendor/github.com/BurntSushi/toml/type_fields.go b/vendor/github.com/BurntSushi/toml/type_fields.go
new file mode 100644
index 0000000..608997c
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/type_fields.go
@@ -0,0 +1,242 @@
+package toml
+
+// Struct field handling is adapted from code in encoding/json:
+//
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the Go distribution.
+
+import (
+ "reflect"
+ "sort"
+ "sync"
+)
+
+// A field represents a single field found in a struct.
+type field struct {
+ name string // the name of the field (`toml` tag included)
+ tag bool // whether field has a `toml` tag
+ index []int // represents the depth of an anonymous field
+ typ reflect.Type // the type of the field
+}
+
+// byName sorts field by name, breaking ties with depth,
+// then breaking ties with "name came from toml tag", then
+// breaking ties with index sequence.
+type byName []field
+
+func (x byName) Len() int { return len(x) }
+
+func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+
+func (x byName) Less(i, j int) bool {
+ if x[i].name != x[j].name {
+ return x[i].name < x[j].name
+ }
+ if len(x[i].index) != len(x[j].index) {
+ return len(x[i].index) < len(x[j].index)
+ }
+ if x[i].tag != x[j].tag {
+ return x[i].tag
+ }
+ return byIndex(x).Less(i, j)
+}
+
+// byIndex sorts field by index sequence.
+type byIndex []field
+
+func (x byIndex) Len() int { return len(x) }
+
+func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+
+func (x byIndex) Less(i, j int) bool {
+ for k, xik := range x[i].index {
+ if k >= len(x[j].index) {
+ return false
+ }
+ if xik != x[j].index[k] {
+ return xik < x[j].index[k]
+ }
+ }
+ return len(x[i].index) < len(x[j].index)
+}
+
+// typeFields returns a list of fields that TOML should recognize for the given
+// type. The algorithm is breadth-first search over the set of structs to
+// include - the top struct and then any reachable anonymous structs.
+func typeFields(t reflect.Type) []field {
+ // Anonymous fields to explore at the current level and the next.
+ current := []field{}
+ next := []field{{typ: t}}
+
+ // Count of queued names for current level and the next.
+ count := map[reflect.Type]int{}
+ nextCount := map[reflect.Type]int{}
+
+ // Types already visited at an earlier level.
+ visited := map[reflect.Type]bool{}
+
+ // Fields found.
+ var fields []field
+
+ for len(next) > 0 {
+ current, next = next, current[:0]
+ count, nextCount = nextCount, map[reflect.Type]int{}
+
+ for _, f := range current {
+ if visited[f.typ] {
+ continue
+ }
+ visited[f.typ] = true
+
+ // Scan f.typ for fields to include.
+ for i := 0; i < f.typ.NumField(); i++ {
+ sf := f.typ.Field(i)
+ if sf.PkgPath != "" && !sf.Anonymous { // unexported
+ continue
+ }
+ opts := getOptions(sf.Tag)
+ if opts.skip {
+ continue
+ }
+ index := make([]int, len(f.index)+1)
+ copy(index, f.index)
+ index[len(f.index)] = i
+
+ ft := sf.Type
+ if ft.Name() == "" && ft.Kind() == reflect.Ptr {
+ // Follow pointer.
+ ft = ft.Elem()
+ }
+
+ // Record found field and index sequence.
+ if opts.name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
+ tagged := opts.name != ""
+ name := opts.name
+ if name == "" {
+ name = sf.Name
+ }
+ fields = append(fields, field{name, tagged, index, ft})
+ if count[f.typ] > 1 {
+ // If there were multiple instances, add a second,
+ // so that the annihilation code will see a duplicate.
+ // It only cares about the distinction between 1 or 2,
+ // so don't bother generating any more copies.
+ fields = append(fields, fields[len(fields)-1])
+ }
+ continue
+ }
+
+ // Record new anonymous struct to explore in next round.
+ nextCount[ft]++
+ if nextCount[ft] == 1 {
+ f := field{name: ft.Name(), index: index, typ: ft}
+ next = append(next, f)
+ }
+ }
+ }
+ }
+
+ sort.Sort(byName(fields))
+
+ // Delete all fields that are hidden by the Go rules for embedded fields,
+ // except that fields with TOML tags are promoted.
+
+ // The fields are sorted in primary order of name, secondary order
+ // of field index length. Loop over names; for each name, delete
+ // hidden fields by choosing the one dominant field that survives.
+ out := fields[:0]
+ for advance, i := 0, 0; i < len(fields); i += advance {
+ // One iteration per name.
+ // Find the sequence of fields with the name of this first field.
+ fi := fields[i]
+ name := fi.name
+ for advance = 1; i+advance < len(fields); advance++ {
+ fj := fields[i+advance]
+ if fj.name != name {
+ break
+ }
+ }
+ if advance == 1 { // Only one field with this name
+ out = append(out, fi)
+ continue
+ }
+ dominant, ok := dominantField(fields[i : i+advance])
+ if ok {
+ out = append(out, dominant)
+ }
+ }
+
+ fields = out
+ sort.Sort(byIndex(fields))
+
+ return fields
+}
+
+// dominantField looks through the fields, all of which are known to
+// have the same name, to find the single field that dominates the
+// others using Go's embedding rules, modified by the presence of
+// TOML tags. If there are multiple top-level fields, the boolean
+// will be false: This condition is an error in Go and we skip all
+// the fields.
+func dominantField(fields []field) (field, bool) {
+ // The fields are sorted in increasing index-length order. The winner
+ // must therefore be one with the shortest index length. Drop all
+ // longer entries, which is easy: just truncate the slice.
+ length := len(fields[0].index)
+ tagged := -1 // Index of first tagged field.
+ for i, f := range fields {
+ if len(f.index) > length {
+ fields = fields[:i]
+ break
+ }
+ if f.tag {
+ if tagged >= 0 {
+ // Multiple tagged fields at the same level: conflict.
+ // Return no field.
+ return field{}, false
+ }
+ tagged = i
+ }
+ }
+ if tagged >= 0 {
+ return fields[tagged], true
+ }
+ // All remaining fields have the same length. If there's more than one,
+ // we have a conflict (two fields named "X" at the same level) and we
+ // return no field.
+ if len(fields) > 1 {
+ return field{}, false
+ }
+ return fields[0], true
+}
+
+var fieldCache struct {
+ sync.RWMutex
+ m map[reflect.Type][]field
+}
+
+// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
+func cachedTypeFields(t reflect.Type) []field {
+ fieldCache.RLock()
+ f := fieldCache.m[t]
+ fieldCache.RUnlock()
+ if f != nil {
+ return f
+ }
+
+ // Compute fields without lock.
+ // Might duplicate effort but won't hold other computations back.
+ f = typeFields(t)
+ if f == nil {
+ f = []field{}
+ }
+
+ fieldCache.Lock()
+ if fieldCache.m == nil {
+ fieldCache.m = map[reflect.Type][]field{}
+ }
+ fieldCache.m[t] = f
+ fieldCache.Unlock()
+ return f
+}
diff --git a/vendor/github.com/anaskhan96/soup/.gitignore b/vendor/github.com/anaskhan96/soup/.gitignore
new file mode 100644
index 0000000..9f11b75
--- /dev/null
+++ b/vendor/github.com/anaskhan96/soup/.gitignore
@@ -0,0 +1 @@
+.idea/
diff --git a/vendor/github.com/anaskhan96/soup/.travis.yml b/vendor/github.com/anaskhan96/soup/.travis.yml
new file mode 100644
index 0000000..0206c78
--- /dev/null
+++ b/vendor/github.com/anaskhan96/soup/.travis.yml
@@ -0,0 +1,9 @@
+language: go
+
+go:
+ - 1.6.x
+ - 1.7.x
+ - 1.8.x
+
+script:
+ - go test
diff --git a/vendor/github.com/anaskhan96/soup/CHANGELOG.md b/vendor/github.com/anaskhan96/soup/CHANGELOG.md
new file mode 100644
index 0000000..d9385ae
--- /dev/null
+++ b/vendor/github.com/anaskhan96/soup/CHANGELOG.md
@@ -0,0 +1,15 @@
+## v1.1
+
+### Added
+
+- Cookies can be added to the HTTP request, either via the `Cookies` map or the `Cookie()` function
+- Function `GetWithClient()` provides the ability to send the request with a custom HTTP client
+- Function `FindStrict()` finds the first instance of the mentioned tag with the exact matching values of the provided attribute (previously `Find()`)
+- Function `FindAllStrict()` finds all the instances of the mentioned tag with the exact matching values of the attributes (previously `FindAll()`)
+
+## Changed
+
+- Function `Find()` now finds the first instance of the mentioned tag with any matching values of the provided attribute.
+- Function `FindAll()` now finds all the instances of the mentioned tag with any matching values of the provided attribute.
+
+---
\ No newline at end of file
diff --git a/vendor/github.com/anaskhan96/soup/README.md b/vendor/github.com/anaskhan96/soup/README.md
new file mode 100644
index 0000000..b3027b7
--- /dev/null
+++ b/vendor/github.com/anaskhan96/soup/README.md
@@ -0,0 +1,70 @@
+# soup
+[![Build Status](https://travis-ci.org/anaskhan96/soup.svg?branch=master)](https://travis-ci.org/anaskhan96/soup)
+[![GoDoc](https://godoc.org/github.com/anaskhan96/soup?status.svg)](https://godoc.org/github.com/anaskhan96/soup)
+[![Go Report Card](https://goreportcard.com/badge/github.com/anaskhan96/soup)](https://goreportcard.com/report/github.com/anaskhan96/soup)
+
+**Web Scraper in Go, similar to BeautifulSoup**
+
+*soup* is a small web scraper package for Go, with its interface highly similar to that of BeautifulSoup.
+
+Exported variables and functions implemented till now :
+```go
+var Headers map[string]string // Set headers as a map of key-value pairs, an alternative to calling Header() individually
+var Cookies map[string]string // Set cookies as a map of key-value pairs, an alternative to calling Cookie() individually
+func Get(string) (string,error) // Takes the url as an argument, returns HTML string
+func GetWithClient(string, *http.Client) // Takes the url and a custom HTTP client as arguments, returns HTML string
+func Header(string, string) // Takes key,value pair to set as headers for the HTTP request made in Get()
+func Cookie(string, string) // Takes key, value pair to set as cookies to be sent with the HTTP request in Get()
+func HTMLParse(string) Root // Takes the HTML string as an argument, returns a pointer to the DOM constructed
+func Find([]string) Root // Element tag,(attribute key-value pair) as argument, pointer to first occurence returned
+func FindAll([]string) []Root // Same as Find(), but pointers to all occurrences returned
+func FindStrict([]string) Root // Element tag,(attribute key-value pair) as argument, pointer to first occurence returned with exact matching values
+func FindAllStrict([]string) []Root // Same as FindStrict(), but pointers to all occurrences returned
+func FindNextSibling() Root // Pointer to the next sibling of the Element in the DOM returned
+func FindNextElementSibling() Root // Pointer to the next element sibling of the Element in the DOM returned
+func FindPrevSibling() Root // Pointer to the previous sibling of the Element in the DOM returned
+func FindPrevElementSibling() Root // Pointer to the previous element sibling of the Element in the DOM returned
+func Attrs() map[string]string // Map returned with all the attributes of the Element as lookup to their respective values
+func Text() string // Full text inside a non-nested tag returned
+func SetDebug(bool) // Sets the debug mode to true or false; false by default
+```
+
+`Root` is a struct, containing three fields :
+* `Pointer` containing the pointer to the current html node
+* `NodeValue` containing the current html node's value, i.e. the tag name for an ElementNode, or the text in case of a TextNode
+* `Error` containing an error if one occurrs, else `nil` is returned.
+
+## Installation
+Install the package using the command
+```bash
+go get github.com/anaskhan96/soup
+```
+
+## Example
+An example code is given below to scrape the "Comics I Enjoy" part (text and its links) from [xkcd](https://xkcd.com).
+
+[More Examples](https://github.com/anaskhan96/soup/tree/master/examples)
+```go
+package main
+
+import (
+ "fmt"
+ "github.com/anaskhan96/soup"
+ "os"
+)
+
+func main() {
+ resp, err := soup.Get("https://xkcd.com")
+ if err != nil {
+ os.Exit(1)
+ }
+ doc := soup.HTMLParse(resp)
+ links := doc.Find("div", "id", "comicLinks").FindAll("a")
+ for _, link := range links {
+ fmt.Println(link.Text(), "| Link :", link.Attrs()["href"])
+ }
+}
+```
+
+## Contributions
+This package was developed in my free time. However, contributions from everybody in the community are welcome, to make it a better web scraper. If you think there should be a particular feature or function included in the package, feel free to open up a new issue or pull request.
\ No newline at end of file
diff --git a/vendor/github.com/anaskhan96/soup/examples/weather/weather.go b/vendor/github.com/anaskhan96/soup/examples/weather/weather.go
new file mode 100644
index 0000000..9f9423a
--- /dev/null
+++ b/vendor/github.com/anaskhan96/soup/examples/weather/weather.go
@@ -0,0 +1,38 @@
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "log"
+ "os"
+ "strings"
+
+ "github.com/anaskhan96/soup"
+)
+
+func main() {
+ fmt.Printf("Enter the name of the city : ")
+ city, _ := bufio.NewReader(os.Stdin).ReadString('\n')
+ city = city[:len(city)-1]
+ cityInURL := strings.Join(strings.Split(city, " "), "+")
+ url := "https://www.bing.com/search?q=weather+" + cityInURL
+ resp, err := soup.Get(url)
+ if err != nil {
+ log.Fatal(err)
+ }
+ doc := soup.HTMLParse(resp)
+ grid := doc.Find("div", "class", "b_antiTopBleed b_antiSideBleed b_antiBottomBleed")
+ heading := grid.Find("div", "class", "wtr_titleCtrn").Find("div").Text()
+ conditions := grid.Find("div", "class", "wtr_condition")
+ primaryCondition := conditions.Find("div")
+ secondaryCondition := primaryCondition.FindNextElementSibling()
+ temp := primaryCondition.Find("div", "class", "wtr_condiTemp").Find("div").Text()
+ others := primaryCondition.Find("div", "class", "wtr_condiAttribs").FindAll("div")
+ caption := secondaryCondition.Find("div").Text()
+ fmt.Println("City Name : " + heading)
+ fmt.Println("Temperature : " + temp + "˚C")
+ for _, i := range others {
+ fmt.Println(i.Text())
+ }
+ fmt.Println(caption)
+}
diff --git a/vendor/github.com/anaskhan96/soup/examples/xkcdextract/xkcdextract.go b/vendor/github.com/anaskhan96/soup/examples/xkcdextract/xkcdextract.go
new file mode 100644
index 0000000..a81ff93
--- /dev/null
+++ b/vendor/github.com/anaskhan96/soup/examples/xkcdextract/xkcdextract.go
@@ -0,0 +1,29 @@
+package main
+
+import (
+ "fmt"
+
+ "github.com/anaskhan96/soup"
+)
+
+func main() {
+ fmt.Println("Enter the xkcd comic number :")
+ var num int
+ fmt.Scanf("%d", &num)
+ url := fmt.Sprintf("https://xkcd.com/%d", num)
+ resp, _ := soup.Get(url)
+ doc := soup.HTMLParse(resp)
+ title := doc.Find("div", "id", "ctitle").Text()
+ fmt.Println("Title of the comic :", title)
+ comicImg := doc.Find("div", "id", "comic").Find("img")
+ fmt.Println("Source of the image :", comicImg.Attrs()["src"])
+ fmt.Println("Underlying text of the image :", comicImg.Attrs()["title"])
+}
+
+/* --- Console I/O ---
+Enter the xkcd comic number :
+353
+Title of the comic : Python
+Source of the image : //imgs.xkcd.com/comics/python.png
+Underlying text of the image : I wrote 20 short programs in Python yesterday. It was wonderful. Perl, I'm leaving you.
+*/
diff --git a/vendor/github.com/anaskhan96/soup/license b/vendor/github.com/anaskhan96/soup/license
new file mode 100644
index 0000000..c3ef1de
--- /dev/null
+++ b/vendor/github.com/anaskhan96/soup/license
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 Anas Khan
+
+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/anaskhan96/soup/soup.go b/vendor/github.com/anaskhan96/soup/soup.go
new file mode 100644
index 0000000..9e62ddf
--- /dev/null
+++ b/vendor/github.com/anaskhan96/soup/soup.go
@@ -0,0 +1,373 @@
+/* soup package implements a simple web scraper for Go,
+keeping it as similar as possible to BeautifulSoup
+*/
+
+package soup
+
+import (
+ "errors"
+ "io/ioutil"
+ "net/http"
+ "regexp"
+ "strings"
+
+ "golang.org/x/net/html"
+)
+
+// Root is a structure containing a pointer to an html node, the node value, and an error variable to return an error if occurred
+type Root struct {
+ Pointer *html.Node
+ NodeValue string
+ Error error
+}
+
+var debug = false
+
+// Headers contains all HTTP headers to send
+var Headers = make(map[string]string)
+
+// Cookies contains all HTTP cookies to send
+var Cookies = make(map[string]string)
+
+// SetDebug sets the debug status
+// Setting this to true causes the panics to be thrown and logged onto the console.
+// Setting this to false causes the errors to be saved in the Error field in the returned struct.
+func SetDebug(d bool) {
+ debug = d
+}
+
+// Header sets a new HTTP header
+func Header(n string, v string) {
+ Headers[n] = v
+}
+
+func Cookie(n string, v string) {
+ Cookies[n] = v
+}
+
+// GetWithClient returns the HTML returned by the url using a provided HTTP client
+func GetWithClient(url string, client *http.Client) (string, error) {
+ req, err := http.NewRequest("GET", url, nil)
+ if err != nil {
+ if debug {
+ panic("Couldn't perform GET request to " + url)
+ }
+ return "", errors.New("couldn't perform GET request to " + url)
+ }
+ // Set headers
+ for hName, hValue := range Headers {
+ req.Header.Set(hName, hValue)
+ }
+ // Set cookies
+ for cName, cValue := range Cookies {
+ req.AddCookie(&http.Cookie{
+ Name: cName,
+ Value: cValue,
+ })
+ }
+ // Perform request
+ resp, err := client.Do(req)
+ if err != nil {
+ if debug {
+ panic("Couldn't perform GET request to " + url)
+ }
+ return "", errors.New("couldn't perform GET request to " + url)
+ }
+ defer resp.Body.Close()
+ bytes, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ if debug {
+ panic("Unable to read the response body")
+ }
+ return "", errors.New("unable to read the response body")
+ }
+ return string(bytes), nil
+}
+
+// Get returns the HTML returned by the url in string using the default HTTP client
+func Get(url string) (string, error) {
+ // Init a new HTTP client
+ client := &http.Client{}
+ return GetWithClient(url, client)
+}
+
+// HTMLParse parses the HTML returning a start pointer to the DOM
+func HTMLParse(s string) Root {
+ r, err := html.Parse(strings.NewReader(s))
+ if err != nil {
+ if debug {
+ panic("Unable to parse the HTML")
+ }
+ return Root{nil, "", errors.New("unable to parse the HTML")}
+ }
+ for r.Type != html.ElementNode {
+ switch r.Type {
+ case html.DocumentNode:
+ r = r.FirstChild
+ case html.DoctypeNode:
+ r = r.NextSibling
+ case html.CommentNode:
+ r = r.NextSibling
+ }
+ }
+ return Root{r, r.Data, nil}
+}
+
+// Find finds the first occurrence of the given tag name,
+// with or without attribute key and value specified,
+// and returns a struct with a pointer to it
+func (r Root) Find(args ...string) Root {
+ temp, ok := findOnce(r.Pointer, args, false, false)
+ if ok == false {
+ if debug {
+ panic("Element `" + args[0] + "` with attributes `" + strings.Join(args[1:], " ") + "` not found")
+ }
+ return Root{nil, "", errors.New("element `" + args[0] + "` with attributes `" + strings.Join(args[1:], " ") + "` not found")}
+ }
+ return Root{temp, temp.Data, nil}
+}
+
+// FindAll finds all occurrences of the given tag name,
+// with or without key and value specified,
+// and returns an array of structs, each having
+// the respective pointers
+func (r Root) FindAll(args ...string) []Root {
+ temp := findAllofem(r.Pointer, args, false)
+ if len(temp) == 0 {
+ if debug {
+ panic("Element `" + args[0] + "` with attributes `" + strings.Join(args[1:], " ") + "` not found")
+ }
+ return []Root{}
+ }
+ pointers := make([]Root, 0, len(temp))
+ for i := 0; i < len(temp); i++ {
+ pointers = append(pointers, Root{temp[i], temp[i].Data, nil})
+ }
+ return pointers
+}
+
+// FindStrict finds the first occurrence of the given tag name
+// only if all the values of the provided attribute are an exact match
+func (r Root) FindStrict(args ...string) Root {
+ temp, ok := findOnce(r.Pointer, args, false, true)
+ if ok == false {
+ if debug {
+ panic("Element `" + args[0] + "` with attributes `" + strings.Join(args[1:], " ") + "` not found")
+ }
+ return Root{nil, "", errors.New("element `" + args[0] + "` with attributes `" + strings.Join(args[1:], " ") + "` not found")}
+ }
+ return Root{temp, temp.Data, nil}
+}
+
+// FindAllStrict finds all occurrences of the given tag name
+// only if all the values of the provided attribute are an exact match
+func (r Root) FindAllStrict(args ...string) []Root {
+ temp := findAllofem(r.Pointer, args, true)
+ if len(temp) == 0 {
+ if debug {
+ panic("Element `" + args[0] + "` with attributes `" + strings.Join(args[1:], " ") + "` not found")
+ }
+ return []Root{}
+ }
+ pointers := make([]Root, 0, len(temp))
+ for i := 0; i < len(temp); i++ {
+ pointers = append(pointers, Root{temp[i], temp[i].Data, nil})
+ }
+ return pointers
+}
+
+// FindNextSibling finds the next sibling of the pointer in the DOM
+// returning a struct with a pointer to it
+func (r Root) FindNextSibling() Root {
+ nextSibling := r.Pointer.NextSibling
+ if nextSibling == nil {
+ if debug {
+ panic("No next sibling found")
+ }
+ return Root{nil, "", errors.New("no next sibling found")}
+ }
+ return Root{nextSibling, nextSibling.Data, nil}
+}
+
+// FindPrevSibling finds the previous sibling of the pointer in the DOM
+// returning a struct with a pointer to it
+func (r Root) FindPrevSibling() Root {
+ prevSibling := r.Pointer.PrevSibling
+ if prevSibling == nil {
+ if debug {
+ panic("No previous sibling found")
+ }
+ return Root{nil, "", errors.New("no previous sibling found")}
+ }
+ return Root{prevSibling, prevSibling.Data, nil}
+}
+
+// FindNextElementSibling finds the next element sibling of the pointer in the DOM
+// returning a struct with a pointer to it
+func (r Root) FindNextElementSibling() Root {
+ nextSibling := r.Pointer.NextSibling
+ if nextSibling == nil {
+ if debug {
+ panic("No next element sibling found")
+ }
+ return Root{nil, "", errors.New("no next element sibling found")}
+ }
+ if nextSibling.Type == html.ElementNode {
+ return Root{nextSibling, nextSibling.Data, nil}
+ }
+ p := Root{nextSibling, nextSibling.Data, nil}
+ return p.FindNextElementSibling()
+}
+
+// FindPrevElementSibling finds the previous element sibling of the pointer in the DOM
+// returning a struct with a pointer to it
+func (r Root) FindPrevElementSibling() Root {
+ prevSibling := r.Pointer.PrevSibling
+ if prevSibling == nil {
+ if debug {
+ panic("No previous element sibling found")
+ }
+ return Root{nil, "", errors.New("no previous element sibling found")}
+ }
+ if prevSibling.Type == html.ElementNode {
+ return Root{prevSibling, prevSibling.Data, nil}
+ }
+ p := Root{prevSibling, prevSibling.Data, nil}
+ return p.FindPrevElementSibling()
+}
+
+// Attrs returns a map containing all attributes
+func (r Root) Attrs() map[string]string {
+ if r.Pointer.Type != html.ElementNode {
+ if debug {
+ panic("Not an ElementNode")
+ }
+ return nil
+ }
+ if len(r.Pointer.Attr) == 0 {
+ return nil
+ }
+ return getKeyValue(r.Pointer.Attr)
+}
+
+// Text returns the string inside a non-nested element
+func (r Root) Text() string {
+ k := r.Pointer.FirstChild
+checkNode:
+ if k.Type != html.TextNode {
+ k = k.NextSibling
+ if k == nil {
+ if debug {
+ panic("No text node found")
+ }
+ return ""
+ }
+ goto checkNode
+ }
+ if k != nil {
+ r, _ := regexp.Compile(`^\s+$`)
+ if ok := r.MatchString(k.Data); ok {
+ k = k.NextSibling
+ if k == nil {
+ if debug {
+ panic("No text node found")
+ }
+ return ""
+ }
+ goto checkNode
+ }
+ return k.Data
+ }
+ return ""
+}
+
+// Using depth first search to find the first occurrence and return
+func findOnce(n *html.Node, args []string, uni bool, strict bool) (*html.Node, bool) {
+ if uni == true {
+ if n.Type == html.ElementNode && n.Data == args[0] {
+ if len(args) > 1 && len(args) < 4 {
+ for i := 0; i < len(n.Attr); i++ {
+ attr := n.Attr[i]
+ searchAttrName := args[1]
+ searchAttrVal := args[2]
+ if (strict && attributeAndValueEquals(attr, searchAttrName, searchAttrVal)) ||
+ (!strict && attributeContainsValue(attr, searchAttrName, searchAttrVal)) {
+ return n, true
+ }
+ }
+ } else if len(args) == 1 {
+ return n, true
+ }
+ }
+ }
+ uni = true
+ for c := n.FirstChild; c != nil; c = c.NextSibling {
+ p, q := findOnce(c, args, true, strict)
+ if q != false {
+ return p, q
+ }
+ }
+ return nil, false
+}
+
+// Using depth first search to find all occurrences and return
+func findAllofem(n *html.Node, args []string, strict bool) []*html.Node {
+ var nodeLinks = make([]*html.Node, 0, 10)
+ var f func(*html.Node, []string, bool)
+ f = func(n *html.Node, args []string, uni bool) {
+ if uni == true {
+ if n.Data == args[0] {
+ if len(args) > 1 && len(args) < 4 {
+ for i := 0; i < len(n.Attr); i++ {
+ attr := n.Attr[i]
+ searchAttrName := args[1]
+ searchAttrVal := args[2]
+ if (strict && attributeAndValueEquals(attr, searchAttrName, searchAttrVal)) ||
+ (!strict && attributeContainsValue(attr, searchAttrName, searchAttrVal)) {
+ nodeLinks = append(nodeLinks, n)
+ }
+ }
+ } else if len(args) == 1 {
+ nodeLinks = append(nodeLinks, n)
+ }
+ }
+ }
+ uni = true
+ for c := n.FirstChild; c != nil; c = c.NextSibling {
+ f(c, args, true)
+ }
+ }
+ f(n, args, false)
+ return nodeLinks
+}
+
+// attributeAndValueEquals reports when the html.Attribute attr has the same attribute name and value as from
+// provided arguments
+func attributeAndValueEquals(attr html.Attribute, attribute, value string) bool {
+ return attr.Key == attribute && attr.Val == value
+}
+
+// attributeContainsValue reports when the html.Attribute attr has the same attribute name as from provided
+// attribute argument and compares if it has the same value in its values parameter
+func attributeContainsValue(attr html.Attribute, attribute, value string) bool {
+ if attr.Key == attribute {
+ for _, attrVal := range strings.Fields(attr.Val) {
+ if attrVal == value {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// Returns a key pair value (like a dictionary) for each attribute
+func getKeyValue(attributes []html.Attribute) map[string]string {
+ var keyvalues = make(map[string]string)
+ for i := 0; i < len(attributes); i++ {
+ _, exists := keyvalues[attributes[i].Key]
+ if exists == false {
+ keyvalues[attributes[i].Key] = attributes[i].Val
+ }
+ }
+ return keyvalues
+}
diff --git a/vendor/github.com/anaskhan96/soup/soup_test.go b/vendor/github.com/anaskhan96/soup/soup_test.go
new file mode 100644
index 0000000..41ef933
--- /dev/null
+++ b/vendor/github.com/anaskhan96/soup/soup_test.go
@@ -0,0 +1,169 @@
+package soup
+
+import (
+ "reflect"
+ "strconv"
+ "strings"
+ "testing"
+)
+
+const testHTML = `
+
+
+ Sample "Hello, World" Application
+
+
+
+
+
+
+
+ |
+
+ Sample "Hello, World" Application
+ |
+
+
+
+
Just two divs peacing out
+
+ check
+ One more
+ This is the home page for the HelloWorld Web application.
+ To prove that they work, you can execute either of the following links:
+
+
+
+
+
+
+`
+
+const multipleClassesHTML = `
+
+
+ Sample Application
+
+
+ Multiple classes
+ Single class
+ Multiple classes inorder
+
+
Inner single class
+
Inner multiple classes
+
Inner multiple classes inorder
+
+
+
+`
+
+var doc = HTMLParse(testHTML)
+var multipleClasses = HTMLParse(multipleClassesHTML)
+
+func TestFind(t *testing.T) {
+ // Find() and Attrs()
+ actual := doc.Find("img").Attrs()["src"]
+ if !reflect.DeepEqual(actual, "images/springsource.png") {
+ t.Error("Instead of `images/springsource.png`, got", actual)
+ }
+ // Find(...) and Text()
+ actual = doc.Find("a", "href", "hello").Text()
+ if !reflect.DeepEqual(actual, "servlet") {
+ t.Error("Instead of `servlet`, got", actual)
+ }
+ // Nested Find()
+ actual = doc.Find("div").Find("div").Text()
+ if !reflect.DeepEqual(actual, "Just two divs peacing out") {
+ t.Error("Instead of `Just two divs peacing out`, got", actual)
+ }
+}
+
+func TestFindNextPrevElement(t *testing.T) {
+ // FindNextSibling() and NodeValue field
+ actual := doc.Find("div", "id", "0").FindNextSibling().NodeValue
+ if !reflect.DeepEqual(strings.TrimSpace(actual), "check") {
+ t.Error("Instead of `check`, got", actual)
+ }
+ // FindPrevSibling() and NodeValue field
+ actual = doc.Find("div", "id", "2").FindPrevSibling().NodeValue
+ if !reflect.DeepEqual(strings.TrimSpace(actual), "check") {
+ t.Error("Instead of `check`, got", actual)
+ }
+ // FindNextElementSibling() and NodeValue field
+ actual = doc.Find("table").FindNextElementSibling().NodeValue
+ if !reflect.DeepEqual(actual, "div") {
+ t.Error("Instead of `div`, got", actual)
+ }
+ // FindPrevElementSibling() and NodeValue field
+ actual = doc.Find("p").FindPrevElementSibling().NodeValue
+ if !reflect.DeepEqual(actual, "div") {
+ t.Error("Instead of `div`, got", actual)
+ }
+}
+
+func TestFindAll(t *testing.T) {
+ // FindAll() and Attrs()
+ allDivs := doc.FindAll("div")
+ for i := 0; i < len(allDivs); i++ {
+ id := allDivs[i].Attrs()["id"]
+ actual, _ := strconv.Atoi(id)
+ if !reflect.DeepEqual(actual, i) {
+ t.Error("Instead of", i, "got", actual)
+ }
+ }
+}
+
+func TestFindAllBySingleClass(t *testing.T) {
+ actual := multipleClasses.FindAll("div", "class", "first")
+ if len(actual) != 6 {
+ t.Errorf("Expected 6 elements to be returned. Actual: %d", len(actual))
+ }
+ actual = multipleClasses.FindAll("div", "class", "third")
+ if len(actual) != 1 {
+ t.Errorf("Expected 1 element to be returned. Actual: %d", len(actual))
+ }
+}
+
+func TestFindBySingleClass(t *testing.T) {
+ actual := multipleClasses.Find("div", "class", "first")
+ if actual.Text() != "Multiple classes" {
+ t.Errorf("Wrong element returned: %s", actual.Text())
+ }
+ actual = multipleClasses.Find("div", "class", "third")
+ if actual.Text() != "Multiple classes inorder" {
+ t.Errorf("Wrong element returned: %s", actual.Text())
+ }
+}
+
+func TestFindAllStrict(t *testing.T) {
+ actual := multipleClasses.FindAllStrict("div", "class", "first second")
+ if len(actual) != 2 {
+ t.Errorf("Expected 2 elements to be returned. Actual: %d", len(actual))
+ }
+ actual = multipleClasses.FindAllStrict("div", "class", "first third second")
+ if len(actual) != 0 {
+ t.Errorf("0 elements should be returned")
+ }
+
+ actual = multipleClasses.FindAllStrict("div", "class", "second first third")
+ if len(actual) != 1 {
+ t.Errorf("Single item should be returned")
+ }
+}
+
+func TestFindStrict(t *testing.T) {
+ actual := multipleClasses.FindStrict("div", "class", "first")
+ if actual.Text() != "Single class" {
+ t.Errorf("Wrong element returned: %s", actual.Text())
+ }
+
+ actual = multipleClasses.FindStrict("div", "class", "third")
+ if actual.Error == nil {
+ t.Errorf("Element with class \"third\" should not be returned in strict mode")
+ }
+}
diff --git a/vendor/github.com/fatih/color/.travis.yml b/vendor/github.com/fatih/color/.travis.yml
new file mode 100644
index 0000000..95f8a1f
--- /dev/null
+++ b/vendor/github.com/fatih/color/.travis.yml
@@ -0,0 +1,5 @@
+language: go
+go:
+ - 1.8.x
+ - tip
+
diff --git a/vendor/github.com/fatih/color/Gopkg.lock b/vendor/github.com/fatih/color/Gopkg.lock
new file mode 100644
index 0000000..7d879e9
--- /dev/null
+++ b/vendor/github.com/fatih/color/Gopkg.lock
@@ -0,0 +1,27 @@
+# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
+
+
+[[projects]]
+ name = "github.com/mattn/go-colorable"
+ packages = ["."]
+ revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
+ version = "v0.0.9"
+
+[[projects]]
+ name = "github.com/mattn/go-isatty"
+ packages = ["."]
+ revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
+ version = "v0.0.3"
+
+[[projects]]
+ branch = "master"
+ name = "golang.org/x/sys"
+ packages = ["unix"]
+ revision = "37707fdb30a5b38865cfb95e5aab41707daec7fd"
+
+[solve-meta]
+ analyzer-name = "dep"
+ analyzer-version = 1
+ inputs-digest = "e8a50671c3cb93ea935bf210b1cd20702876b9d9226129be581ef646d1565cdc"
+ solver-name = "gps-cdcl"
+ solver-version = 1
diff --git a/vendor/github.com/fatih/color/Gopkg.toml b/vendor/github.com/fatih/color/Gopkg.toml
new file mode 100644
index 0000000..ff1617f
--- /dev/null
+++ b/vendor/github.com/fatih/color/Gopkg.toml
@@ -0,0 +1,30 @@
+
+# Gopkg.toml example
+#
+# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
+# for detailed Gopkg.toml documentation.
+#
+# required = ["github.com/user/thing/cmd/thing"]
+# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
+#
+# [[constraint]]
+# name = "github.com/user/project"
+# version = "1.0.0"
+#
+# [[constraint]]
+# name = "github.com/user/project2"
+# branch = "dev"
+# source = "github.com/myfork/project2"
+#
+# [[override]]
+# name = "github.com/x/y"
+# version = "2.4.0"
+
+
+[[constraint]]
+ name = "github.com/mattn/go-colorable"
+ version = "0.0.9"
+
+[[constraint]]
+ name = "github.com/mattn/go-isatty"
+ version = "0.0.3"
diff --git a/vendor/github.com/fatih/color/LICENSE.md b/vendor/github.com/fatih/color/LICENSE.md
new file mode 100644
index 0000000..25fdaf6
--- /dev/null
+++ b/vendor/github.com/fatih/color/LICENSE.md
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Fatih Arslan
+
+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/fatih/color/README.md b/vendor/github.com/fatih/color/README.md
new file mode 100644
index 0000000..3fc9544
--- /dev/null
+++ b/vendor/github.com/fatih/color/README.md
@@ -0,0 +1,179 @@
+# Color [![GoDoc](https://godoc.org/github.com/fatih/color?status.svg)](https://godoc.org/github.com/fatih/color) [![Build Status](https://img.shields.io/travis/fatih/color.svg?style=flat-square)](https://travis-ci.org/fatih/color)
+
+
+
+Color lets you use colorized outputs in terms of [ANSI Escape
+Codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors) in Go (Golang). It
+has support for Windows too! The API can be used in several ways, pick one that
+suits you.
+
+
+![Color](https://i.imgur.com/c1JI0lA.png)
+
+
+## Install
+
+```bash
+go get github.com/fatih/color
+```
+
+Note that the `vendor` folder is here for stability. Remove the folder if you
+already have the dependencies in your GOPATH.
+
+## Examples
+
+### Standard colors
+
+```go
+// Print with default helper functions
+color.Cyan("Prints text in cyan.")
+
+// A newline will be appended automatically
+color.Blue("Prints %s in blue.", "text")
+
+// These are using the default foreground colors
+color.Red("We have red")
+color.Magenta("And many others ..")
+
+```
+
+### Mix and reuse colors
+
+```go
+// Create a new color object
+c := color.New(color.FgCyan).Add(color.Underline)
+c.Println("Prints cyan text with an underline.")
+
+// Or just add them to New()
+d := color.New(color.FgCyan, color.Bold)
+d.Printf("This prints bold cyan %s\n", "too!.")
+
+// Mix up foreground and background colors, create new mixes!
+red := color.New(color.FgRed)
+
+boldRed := red.Add(color.Bold)
+boldRed.Println("This will print text in bold red.")
+
+whiteBackground := red.Add(color.BgWhite)
+whiteBackground.Println("Red text with white background.")
+```
+
+### Use your own output (io.Writer)
+
+```go
+// Use your own io.Writer output
+color.New(color.FgBlue).Fprintln(myWriter, "blue color!")
+
+blue := color.New(color.FgBlue)
+blue.Fprint(writer, "This will print text in blue.")
+```
+
+### Custom print functions (PrintFunc)
+
+```go
+// Create a custom print function for convenience
+red := color.New(color.FgRed).PrintfFunc()
+red("Warning")
+red("Error: %s", err)
+
+// Mix up multiple attributes
+notice := color.New(color.Bold, color.FgGreen).PrintlnFunc()
+notice("Don't forget this...")
+```
+
+### Custom fprint functions (FprintFunc)
+
+```go
+blue := color.New(FgBlue).FprintfFunc()
+blue(myWriter, "important notice: %s", stars)
+
+// Mix up with multiple attributes
+success := color.New(color.Bold, color.FgGreen).FprintlnFunc()
+success(myWriter, "Don't forget this...")
+```
+
+### Insert into noncolor strings (SprintFunc)
+
+```go
+// Create SprintXxx functions to mix strings with other non-colorized strings:
+yellow := color.New(color.FgYellow).SprintFunc()
+red := color.New(color.FgRed).SprintFunc()
+fmt.Printf("This is a %s and this is %s.\n", yellow("warning"), red("error"))
+
+info := color.New(color.FgWhite, color.BgGreen).SprintFunc()
+fmt.Printf("This %s rocks!\n", info("package"))
+
+// Use helper functions
+fmt.Println("This", color.RedString("warning"), "should be not neglected.")
+fmt.Printf("%v %v\n", color.GreenString("Info:"), "an important message.")
+
+// Windows supported too! Just don't forget to change the output to color.Output
+fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS"))
+```
+
+### Plug into existing code
+
+```go
+// Use handy standard colors
+color.Set(color.FgYellow)
+
+fmt.Println("Existing text will now be in yellow")
+fmt.Printf("This one %s\n", "too")
+
+color.Unset() // Don't forget to unset
+
+// You can mix up parameters
+color.Set(color.FgMagenta, color.Bold)
+defer color.Unset() // Use it in your function
+
+fmt.Println("All text will now be bold magenta.")
+```
+
+### Disable/Enable color
+
+There might be a case where you want to explicitly disable/enable color output. the
+`go-isatty` package will automatically disable color output for non-tty output streams
+(for example if the output were piped directly to `less`)
+
+`Color` has support to disable/enable colors both globally and for single color
+definitions. For example suppose you have a CLI app and a `--no-color` bool flag. You
+can easily disable the color output with:
+
+```go
+
+var flagNoColor = flag.Bool("no-color", false, "Disable color output")
+
+if *flagNoColor {
+ color.NoColor = true // disables colorized output
+}
+```
+
+It also has support for single color definitions (local). You can
+disable/enable color output on the fly:
+
+```go
+c := color.New(color.FgCyan)
+c.Println("Prints cyan text")
+
+c.DisableColor()
+c.Println("This is printed without any color")
+
+c.EnableColor()
+c.Println("This prints again cyan...")
+```
+
+## Todo
+
+* Save/Return previous values
+* Evaluate fmt.Formatter interface
+
+
+## Credits
+
+ * [Fatih Arslan](https://github.com/fatih)
+ * Windows support via @mattn: [colorable](https://github.com/mattn/go-colorable)
+
+## License
+
+The MIT License (MIT) - see [`LICENSE.md`](https://github.com/fatih/color/blob/master/LICENSE.md) for more details
+
diff --git a/vendor/github.com/fatih/color/color.go b/vendor/github.com/fatih/color/color.go
new file mode 100644
index 0000000..b1f591d
--- /dev/null
+++ b/vendor/github.com/fatih/color/color.go
@@ -0,0 +1,600 @@
+package color
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "strconv"
+ "strings"
+ "sync"
+
+ "github.com/mattn/go-colorable"
+ "github.com/mattn/go-isatty"
+)
+
+var (
+ // NoColor defines if the output is colorized or not. It's dynamically set to
+ // false or true based on the stdout's file descriptor referring to a terminal
+ // or not. This is a global option and affects all colors. For more control
+ // over each color block use the methods DisableColor() individually.
+ NoColor = os.Getenv("TERM") == "dumb" ||
+ (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd()))
+
+ // Output defines the standard output of the print functions. By default
+ // os.Stdout is used.
+ Output = colorable.NewColorableStdout()
+
+ // colorsCache is used to reduce the count of created Color objects and
+ // allows to reuse already created objects with required Attribute.
+ colorsCache = make(map[Attribute]*Color)
+ colorsCacheMu sync.Mutex // protects colorsCache
+)
+
+// Color defines a custom color object which is defined by SGR parameters.
+type Color struct {
+ params []Attribute
+ noColor *bool
+}
+
+// Attribute defines a single SGR Code
+type Attribute int
+
+const escape = "\x1b"
+
+// Base attributes
+const (
+ Reset Attribute = iota
+ Bold
+ Faint
+ Italic
+ Underline
+ BlinkSlow
+ BlinkRapid
+ ReverseVideo
+ Concealed
+ CrossedOut
+)
+
+// Foreground text colors
+const (
+ FgBlack Attribute = iota + 30
+ FgRed
+ FgGreen
+ FgYellow
+ FgBlue
+ FgMagenta
+ FgCyan
+ FgWhite
+)
+
+// Foreground Hi-Intensity text colors
+const (
+ FgHiBlack Attribute = iota + 90
+ FgHiRed
+ FgHiGreen
+ FgHiYellow
+ FgHiBlue
+ FgHiMagenta
+ FgHiCyan
+ FgHiWhite
+)
+
+// Background text colors
+const (
+ BgBlack Attribute = iota + 40
+ BgRed
+ BgGreen
+ BgYellow
+ BgBlue
+ BgMagenta
+ BgCyan
+ BgWhite
+)
+
+// Background Hi-Intensity text colors
+const (
+ BgHiBlack Attribute = iota + 100
+ BgHiRed
+ BgHiGreen
+ BgHiYellow
+ BgHiBlue
+ BgHiMagenta
+ BgHiCyan
+ BgHiWhite
+)
+
+// New returns a newly created color object.
+func New(value ...Attribute) *Color {
+ c := &Color{params: make([]Attribute, 0)}
+ c.Add(value...)
+ return c
+}
+
+// Set sets the given parameters immediately. It will change the color of
+// output with the given SGR parameters until color.Unset() is called.
+func Set(p ...Attribute) *Color {
+ c := New(p...)
+ c.Set()
+ return c
+}
+
+// Unset resets all escape attributes and clears the output. Usually should
+// be called after Set().
+func Unset() {
+ if NoColor {
+ return
+ }
+
+ fmt.Fprintf(Output, "%s[%dm", escape, Reset)
+}
+
+// Set sets the SGR sequence.
+func (c *Color) Set() *Color {
+ if c.isNoColorSet() {
+ return c
+ }
+
+ fmt.Fprintf(Output, c.format())
+ return c
+}
+
+func (c *Color) unset() {
+ if c.isNoColorSet() {
+ return
+ }
+
+ Unset()
+}
+
+func (c *Color) setWriter(w io.Writer) *Color {
+ if c.isNoColorSet() {
+ return c
+ }
+
+ fmt.Fprintf(w, c.format())
+ return c
+}
+
+func (c *Color) unsetWriter(w io.Writer) {
+ if c.isNoColorSet() {
+ return
+ }
+
+ if NoColor {
+ return
+ }
+
+ fmt.Fprintf(w, "%s[%dm", escape, Reset)
+}
+
+// Add is used to chain SGR parameters. Use as many as parameters to combine
+// and create custom color objects. Example: Add(color.FgRed, color.Underline).
+func (c *Color) Add(value ...Attribute) *Color {
+ c.params = append(c.params, value...)
+ return c
+}
+
+func (c *Color) prepend(value Attribute) {
+ c.params = append(c.params, 0)
+ copy(c.params[1:], c.params[0:])
+ c.params[0] = value
+}
+
+// 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.
+// On Windows, users should wrap w with colorable.NewColorable() if w is of
+// type *os.File.
+func (c *Color) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
+ c.setWriter(w)
+ defer c.unsetWriter(w)
+
+ return fmt.Fprint(w, 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. This is the standard fmt.Print() method wrapped with the given
+// color.
+func (c *Color) Print(a ...interface{}) (n int, err error) {
+ c.Set()
+ defer c.unset()
+
+ return fmt.Fprint(Output, a...)
+}
+
+// Fprintf formats according to a format specifier and writes to w.
+// It returns the number of bytes written and any write error encountered.
+// On Windows, users should wrap w with colorable.NewColorable() if w is of
+// type *os.File.
+func (c *Color) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
+ c.setWriter(w)
+ defer c.unsetWriter(w)
+
+ return fmt.Fprintf(w, format, 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.
+// This is the standard fmt.Printf() method wrapped with the given color.
+func (c *Color) Printf(format string, a ...interface{}) (n int, err error) {
+ c.Set()
+ defer c.unset()
+
+ return fmt.Fprintf(Output, format, a...)
+}
+
+// Fprintln formats using the default formats for its operands and writes to w.
+// Spaces are always added between operands and a newline is appended.
+// On Windows, users should wrap w with colorable.NewColorable() if w is of
+// type *os.File.
+func (c *Color) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
+ c.setWriter(w)
+ defer c.unsetWriter(w)
+
+ return fmt.Fprintln(w, 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. This is the standard fmt.Print() method wrapped with the given
+// color.
+func (c *Color) Println(a ...interface{}) (n int, err error) {
+ c.Set()
+ defer c.unset()
+
+ return fmt.Fprintln(Output, a...)
+}
+
+// Sprint is just like Print, but returns a string instead of printing it.
+func (c *Color) Sprint(a ...interface{}) string {
+ return c.wrap(fmt.Sprint(a...))
+}
+
+// Sprintln is just like Println, but returns a string instead of printing it.
+func (c *Color) Sprintln(a ...interface{}) string {
+ return c.wrap(fmt.Sprintln(a...))
+}
+
+// Sprintf is just like Printf, but returns a string instead of printing it.
+func (c *Color) Sprintf(format string, a ...interface{}) string {
+ return c.wrap(fmt.Sprintf(format, a...))
+}
+
+// FprintFunc returns a new function that prints the passed arguments as
+// colorized with color.Fprint().
+func (c *Color) FprintFunc() func(w io.Writer, a ...interface{}) {
+ return func(w io.Writer, a ...interface{}) {
+ c.Fprint(w, a...)
+ }
+}
+
+// PrintFunc returns a new function that prints the passed arguments as
+// colorized with color.Print().
+func (c *Color) PrintFunc() func(a ...interface{}) {
+ return func(a ...interface{}) {
+ c.Print(a...)
+ }
+}
+
+// FprintfFunc returns a new function that prints the passed arguments as
+// colorized with color.Fprintf().
+func (c *Color) FprintfFunc() func(w io.Writer, format string, a ...interface{}) {
+ return func(w io.Writer, format string, a ...interface{}) {
+ c.Fprintf(w, format, a...)
+ }
+}
+
+// PrintfFunc returns a new function that prints the passed arguments as
+// colorized with color.Printf().
+func (c *Color) PrintfFunc() func(format string, a ...interface{}) {
+ return func(format string, a ...interface{}) {
+ c.Printf(format, a...)
+ }
+}
+
+// FprintlnFunc returns a new function that prints the passed arguments as
+// colorized with color.Fprintln().
+func (c *Color) FprintlnFunc() func(w io.Writer, a ...interface{}) {
+ return func(w io.Writer, a ...interface{}) {
+ c.Fprintln(w, a...)
+ }
+}
+
+// PrintlnFunc returns a new function that prints the passed arguments as
+// colorized with color.Println().
+func (c *Color) PrintlnFunc() func(a ...interface{}) {
+ return func(a ...interface{}) {
+ c.Println(a...)
+ }
+}
+
+// SprintFunc returns a new function that returns colorized strings for the
+// given arguments with fmt.Sprint(). Useful to put into or mix into other
+// string. Windows users should use this in conjunction with color.Output, example:
+//
+// put := New(FgYellow).SprintFunc()
+// fmt.Fprintf(color.Output, "This is a %s", put("warning"))
+func (c *Color) SprintFunc() func(a ...interface{}) string {
+ return func(a ...interface{}) string {
+ return c.wrap(fmt.Sprint(a...))
+ }
+}
+
+// SprintfFunc returns a new function that returns colorized strings for the
+// given arguments with fmt.Sprintf(). Useful to put into or mix into other
+// string. Windows users should use this in conjunction with color.Output.
+func (c *Color) SprintfFunc() func(format string, a ...interface{}) string {
+ return func(format string, a ...interface{}) string {
+ return c.wrap(fmt.Sprintf(format, a...))
+ }
+}
+
+// SprintlnFunc returns a new function that returns colorized strings for the
+// given arguments with fmt.Sprintln(). Useful to put into or mix into other
+// string. Windows users should use this in conjunction with color.Output.
+func (c *Color) SprintlnFunc() func(a ...interface{}) string {
+ return func(a ...interface{}) string {
+ return c.wrap(fmt.Sprintln(a...))
+ }
+}
+
+// sequence returns a formatted SGR sequence to be plugged into a "\x1b[...m"
+// an example output might be: "1;36" -> bold cyan
+func (c *Color) sequence() string {
+ format := make([]string, len(c.params))
+ for i, v := range c.params {
+ format[i] = strconv.Itoa(int(v))
+ }
+
+ return strings.Join(format, ";")
+}
+
+// wrap wraps the s string with the colors attributes. The string is ready to
+// be printed.
+func (c *Color) wrap(s string) string {
+ if c.isNoColorSet() {
+ return s
+ }
+
+ return c.format() + s + c.unformat()
+}
+
+func (c *Color) format() string {
+ return fmt.Sprintf("%s[%sm", escape, c.sequence())
+}
+
+func (c *Color) unformat() string {
+ return fmt.Sprintf("%s[%dm", escape, Reset)
+}
+
+// DisableColor disables the color output. Useful to not change any existing
+// code and still being able to output. Can be used for flags like
+// "--no-color". To enable back use EnableColor() method.
+func (c *Color) DisableColor() {
+ c.noColor = boolPtr(true)
+}
+
+// EnableColor enables the color output. Use it in conjunction with
+// DisableColor(). Otherwise this method has no side effects.
+func (c *Color) EnableColor() {
+ c.noColor = boolPtr(false)
+}
+
+func (c *Color) isNoColorSet() bool {
+ // check first if we have user setted action
+ if c.noColor != nil {
+ return *c.noColor
+ }
+
+ // if not return the global option, which is disabled by default
+ return NoColor
+}
+
+// Equals returns a boolean value indicating whether two colors are equal.
+func (c *Color) Equals(c2 *Color) bool {
+ if len(c.params) != len(c2.params) {
+ return false
+ }
+
+ for _, attr := range c.params {
+ if !c2.attrExists(attr) {
+ return false
+ }
+ }
+
+ return true
+}
+
+func (c *Color) attrExists(a Attribute) bool {
+ for _, attr := range c.params {
+ if attr == a {
+ return true
+ }
+ }
+
+ return false
+}
+
+func boolPtr(v bool) *bool {
+ return &v
+}
+
+func getCachedColor(p Attribute) *Color {
+ colorsCacheMu.Lock()
+ defer colorsCacheMu.Unlock()
+
+ c, ok := colorsCache[p]
+ if !ok {
+ c = New(p)
+ colorsCache[p] = c
+ }
+
+ return c
+}
+
+func colorPrint(format string, p Attribute, a ...interface{}) {
+ c := getCachedColor(p)
+
+ if !strings.HasSuffix(format, "\n") {
+ format += "\n"
+ }
+
+ if len(a) == 0 {
+ c.Print(format)
+ } else {
+ c.Printf(format, a...)
+ }
+}
+
+func colorString(format string, p Attribute, a ...interface{}) string {
+ c := getCachedColor(p)
+
+ if len(a) == 0 {
+ return c.SprintFunc()(format)
+ }
+
+ return c.SprintfFunc()(format, a...)
+}
+
+// Black is a convenient helper function to print with black foreground. A
+// newline is appended to format by default.
+func Black(format string, a ...interface{}) { colorPrint(format, FgBlack, a...) }
+
+// Red is a convenient helper function to print with red foreground. A
+// newline is appended to format by default.
+func Red(format string, a ...interface{}) { colorPrint(format, FgRed, a...) }
+
+// Green is a convenient helper function to print with green foreground. A
+// newline is appended to format by default.
+func Green(format string, a ...interface{}) { colorPrint(format, FgGreen, a...) }
+
+// Yellow is a convenient helper function to print with yellow foreground.
+// A newline is appended to format by default.
+func Yellow(format string, a ...interface{}) { colorPrint(format, FgYellow, a...) }
+
+// Blue is a convenient helper function to print with blue foreground. A
+// newline is appended to format by default.
+func Blue(format string, a ...interface{}) { colorPrint(format, FgBlue, a...) }
+
+// Magenta is a convenient helper function to print with magenta foreground.
+// A newline is appended to format by default.
+func Magenta(format string, a ...interface{}) { colorPrint(format, FgMagenta, a...) }
+
+// Cyan is a convenient helper function to print with cyan foreground. A
+// newline is appended to format by default.
+func Cyan(format string, a ...interface{}) { colorPrint(format, FgCyan, a...) }
+
+// White is a convenient helper function to print with white foreground. A
+// newline is appended to format by default.
+func White(format string, a ...interface{}) { colorPrint(format, FgWhite, a...) }
+
+// BlackString is a convenient helper function to return a string with black
+// foreground.
+func BlackString(format string, a ...interface{}) string { return colorString(format, FgBlack, a...) }
+
+// RedString is a convenient helper function to return a string with red
+// foreground.
+func RedString(format string, a ...interface{}) string { return colorString(format, FgRed, a...) }
+
+// GreenString is a convenient helper function to return a string with green
+// foreground.
+func GreenString(format string, a ...interface{}) string { return colorString(format, FgGreen, a...) }
+
+// YellowString is a convenient helper function to return a string with yellow
+// foreground.
+func YellowString(format string, a ...interface{}) string { return colorString(format, FgYellow, a...) }
+
+// BlueString is a convenient helper function to return a string with blue
+// foreground.
+func BlueString(format string, a ...interface{}) string { return colorString(format, FgBlue, a...) }
+
+// MagentaString is a convenient helper function to return a string with magenta
+// foreground.
+func MagentaString(format string, a ...interface{}) string {
+ return colorString(format, FgMagenta, a...)
+}
+
+// CyanString is a convenient helper function to return a string with cyan
+// foreground.
+func CyanString(format string, a ...interface{}) string { return colorString(format, FgCyan, a...) }
+
+// WhiteString is a convenient helper function to return a string with white
+// foreground.
+func WhiteString(format string, a ...interface{}) string { return colorString(format, FgWhite, a...) }
+
+// HiBlack is a convenient helper function to print with hi-intensity black foreground. A
+// newline is appended to format by default.
+func HiBlack(format string, a ...interface{}) { colorPrint(format, FgHiBlack, a...) }
+
+// HiRed is a convenient helper function to print with hi-intensity red foreground. A
+// newline is appended to format by default.
+func HiRed(format string, a ...interface{}) { colorPrint(format, FgHiRed, a...) }
+
+// HiGreen is a convenient helper function to print with hi-intensity green foreground. A
+// newline is appended to format by default.
+func HiGreen(format string, a ...interface{}) { colorPrint(format, FgHiGreen, a...) }
+
+// HiYellow is a convenient helper function to print with hi-intensity yellow foreground.
+// A newline is appended to format by default.
+func HiYellow(format string, a ...interface{}) { colorPrint(format, FgHiYellow, a...) }
+
+// HiBlue is a convenient helper function to print with hi-intensity blue foreground. A
+// newline is appended to format by default.
+func HiBlue(format string, a ...interface{}) { colorPrint(format, FgHiBlue, a...) }
+
+// HiMagenta is a convenient helper function to print with hi-intensity magenta foreground.
+// A newline is appended to format by default.
+func HiMagenta(format string, a ...interface{}) { colorPrint(format, FgHiMagenta, a...) }
+
+// HiCyan is a convenient helper function to print with hi-intensity cyan foreground. A
+// newline is appended to format by default.
+func HiCyan(format string, a ...interface{}) { colorPrint(format, FgHiCyan, a...) }
+
+// HiWhite is a convenient helper function to print with hi-intensity white foreground. A
+// newline is appended to format by default.
+func HiWhite(format string, a ...interface{}) { colorPrint(format, FgHiWhite, a...) }
+
+// HiBlackString is a convenient helper function to return a string with hi-intensity black
+// foreground.
+func HiBlackString(format string, a ...interface{}) string {
+ return colorString(format, FgHiBlack, a...)
+}
+
+// HiRedString is a convenient helper function to return a string with hi-intensity red
+// foreground.
+func HiRedString(format string, a ...interface{}) string { return colorString(format, FgHiRed, a...) }
+
+// HiGreenString is a convenient helper function to return a string with hi-intensity green
+// foreground.
+func HiGreenString(format string, a ...interface{}) string {
+ return colorString(format, FgHiGreen, a...)
+}
+
+// HiYellowString is a convenient helper function to return a string with hi-intensity yellow
+// foreground.
+func HiYellowString(format string, a ...interface{}) string {
+ return colorString(format, FgHiYellow, a...)
+}
+
+// HiBlueString is a convenient helper function to return a string with hi-intensity blue
+// foreground.
+func HiBlueString(format string, a ...interface{}) string { return colorString(format, FgHiBlue, a...) }
+
+// HiMagentaString is a convenient helper function to return a string with hi-intensity magenta
+// foreground.
+func HiMagentaString(format string, a ...interface{}) string {
+ return colorString(format, FgHiMagenta, a...)
+}
+
+// HiCyanString is a convenient helper function to return a string with hi-intensity cyan
+// foreground.
+func HiCyanString(format string, a ...interface{}) string { return colorString(format, FgHiCyan, a...) }
+
+// HiWhiteString is a convenient helper function to return a string with hi-intensity white
+// foreground.
+func HiWhiteString(format string, a ...interface{}) string {
+ return colorString(format, FgHiWhite, a...)
+}
diff --git a/vendor/github.com/fatih/color/color_test.go b/vendor/github.com/fatih/color/color_test.go
new file mode 100644
index 0000000..a8ed14f
--- /dev/null
+++ b/vendor/github.com/fatih/color/color_test.go
@@ -0,0 +1,342 @@
+package color
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "testing"
+
+ "github.com/mattn/go-colorable"
+)
+
+// Testing colors is kinda different. First we test for given colors and their
+// escaped formatted results. Next we create some visual tests to be tested.
+// Each visual test includes the color name to be compared.
+func TestColor(t *testing.T) {
+ rb := new(bytes.Buffer)
+ Output = rb
+
+ NoColor = false
+
+ testColors := []struct {
+ text string
+ code Attribute
+ }{
+ {text: "black", code: FgBlack},
+ {text: "red", code: FgRed},
+ {text: "green", code: FgGreen},
+ {text: "yellow", code: FgYellow},
+ {text: "blue", code: FgBlue},
+ {text: "magent", code: FgMagenta},
+ {text: "cyan", code: FgCyan},
+ {text: "white", code: FgWhite},
+ {text: "hblack", code: FgHiBlack},
+ {text: "hred", code: FgHiRed},
+ {text: "hgreen", code: FgHiGreen},
+ {text: "hyellow", code: FgHiYellow},
+ {text: "hblue", code: FgHiBlue},
+ {text: "hmagent", code: FgHiMagenta},
+ {text: "hcyan", code: FgHiCyan},
+ {text: "hwhite", code: FgHiWhite},
+ }
+
+ for _, c := range testColors {
+ New(c.code).Print(c.text)
+
+ line, _ := rb.ReadString('\n')
+ scannedLine := fmt.Sprintf("%q", line)
+ colored := fmt.Sprintf("\x1b[%dm%s\x1b[0m", c.code, c.text)
+ escapedForm := fmt.Sprintf("%q", colored)
+
+ fmt.Printf("%s\t: %s\n", c.text, line)
+
+ if scannedLine != escapedForm {
+ t.Errorf("Expecting %s, got '%s'\n", escapedForm, scannedLine)
+ }
+ }
+
+ for _, c := range testColors {
+ line := New(c.code).Sprintf("%s", c.text)
+ scannedLine := fmt.Sprintf("%q", line)
+ colored := fmt.Sprintf("\x1b[%dm%s\x1b[0m", c.code, c.text)
+ escapedForm := fmt.Sprintf("%q", colored)
+
+ fmt.Printf("%s\t: %s\n", c.text, line)
+
+ if scannedLine != escapedForm {
+ t.Errorf("Expecting %s, got '%s'\n", escapedForm, scannedLine)
+ }
+ }
+}
+
+func TestColorEquals(t *testing.T) {
+ fgblack1 := New(FgBlack)
+ fgblack2 := New(FgBlack)
+ bgblack := New(BgBlack)
+ fgbgblack := New(FgBlack, BgBlack)
+ fgblackbgred := New(FgBlack, BgRed)
+ fgred := New(FgRed)
+ bgred := New(BgRed)
+
+ if !fgblack1.Equals(fgblack2) {
+ t.Error("Two black colors are not equal")
+ }
+
+ if fgblack1.Equals(bgblack) {
+ t.Error("Fg and bg black colors are equal")
+ }
+
+ if fgblack1.Equals(fgbgblack) {
+ t.Error("Fg black equals fg/bg black color")
+ }
+
+ if fgblack1.Equals(fgred) {
+ t.Error("Fg black equals Fg red")
+ }
+
+ if fgblack1.Equals(bgred) {
+ t.Error("Fg black equals Bg red")
+ }
+
+ if fgblack1.Equals(fgblackbgred) {
+ t.Error("Fg black equals fg black bg red")
+ }
+}
+
+func TestNoColor(t *testing.T) {
+ rb := new(bytes.Buffer)
+ Output = rb
+
+ testColors := []struct {
+ text string
+ code Attribute
+ }{
+ {text: "black", code: FgBlack},
+ {text: "red", code: FgRed},
+ {text: "green", code: FgGreen},
+ {text: "yellow", code: FgYellow},
+ {text: "blue", code: FgBlue},
+ {text: "magent", code: FgMagenta},
+ {text: "cyan", code: FgCyan},
+ {text: "white", code: FgWhite},
+ {text: "hblack", code: FgHiBlack},
+ {text: "hred", code: FgHiRed},
+ {text: "hgreen", code: FgHiGreen},
+ {text: "hyellow", code: FgHiYellow},
+ {text: "hblue", code: FgHiBlue},
+ {text: "hmagent", code: FgHiMagenta},
+ {text: "hcyan", code: FgHiCyan},
+ {text: "hwhite", code: FgHiWhite},
+ }
+
+ for _, c := range testColors {
+ p := New(c.code)
+ p.DisableColor()
+ p.Print(c.text)
+
+ line, _ := rb.ReadString('\n')
+ if line != c.text {
+ t.Errorf("Expecting %s, got '%s'\n", c.text, line)
+ }
+ }
+
+ // global check
+ NoColor = true
+ defer func() {
+ NoColor = false
+ }()
+ for _, c := range testColors {
+ p := New(c.code)
+ p.Print(c.text)
+
+ line, _ := rb.ReadString('\n')
+ if line != c.text {
+ t.Errorf("Expecting %s, got '%s'\n", c.text, line)
+ }
+ }
+
+}
+
+func TestColorVisual(t *testing.T) {
+ // First Visual Test
+ Output = colorable.NewColorableStdout()
+
+ New(FgRed).Printf("red\t")
+ New(BgRed).Print(" ")
+ New(FgRed, Bold).Println(" red")
+
+ New(FgGreen).Printf("green\t")
+ New(BgGreen).Print(" ")
+ New(FgGreen, Bold).Println(" green")
+
+ New(FgYellow).Printf("yellow\t")
+ New(BgYellow).Print(" ")
+ New(FgYellow, Bold).Println(" yellow")
+
+ New(FgBlue).Printf("blue\t")
+ New(BgBlue).Print(" ")
+ New(FgBlue, Bold).Println(" blue")
+
+ New(FgMagenta).Printf("magenta\t")
+ New(BgMagenta).Print(" ")
+ New(FgMagenta, Bold).Println(" magenta")
+
+ New(FgCyan).Printf("cyan\t")
+ New(BgCyan).Print(" ")
+ New(FgCyan, Bold).Println(" cyan")
+
+ New(FgWhite).Printf("white\t")
+ New(BgWhite).Print(" ")
+ New(FgWhite, Bold).Println(" white")
+ fmt.Println("")
+
+ // Second Visual test
+ Black("black")
+ Red("red")
+ Green("green")
+ Yellow("yellow")
+ Blue("blue")
+ Magenta("magenta")
+ Cyan("cyan")
+ White("white")
+ HiBlack("hblack")
+ HiRed("hred")
+ HiGreen("hgreen")
+ HiYellow("hyellow")
+ HiBlue("hblue")
+ HiMagenta("hmagenta")
+ HiCyan("hcyan")
+ HiWhite("hwhite")
+
+ // Third visual test
+ fmt.Println()
+ Set(FgBlue)
+ fmt.Println("is this blue?")
+ Unset()
+
+ Set(FgMagenta)
+ fmt.Println("and this magenta?")
+ Unset()
+
+ // Fourth Visual test
+ fmt.Println()
+ blue := New(FgBlue).PrintlnFunc()
+ blue("blue text with custom print func")
+
+ red := New(FgRed).PrintfFunc()
+ red("red text with a printf func: %d\n", 123)
+
+ put := New(FgYellow).SprintFunc()
+ warn := New(FgRed).SprintFunc()
+
+ fmt.Fprintf(Output, "this is a %s and this is %s.\n", put("warning"), warn("error"))
+
+ info := New(FgWhite, BgGreen).SprintFunc()
+ fmt.Fprintf(Output, "this %s rocks!\n", info("package"))
+
+ notice := New(FgBlue).FprintFunc()
+ notice(os.Stderr, "just a blue notice to stderr")
+
+ // Fifth Visual Test
+ fmt.Println()
+
+ fmt.Fprintln(Output, BlackString("black"))
+ fmt.Fprintln(Output, RedString("red"))
+ fmt.Fprintln(Output, GreenString("green"))
+ fmt.Fprintln(Output, YellowString("yellow"))
+ fmt.Fprintln(Output, BlueString("blue"))
+ fmt.Fprintln(Output, MagentaString("magenta"))
+ fmt.Fprintln(Output, CyanString("cyan"))
+ fmt.Fprintln(Output, WhiteString("white"))
+ fmt.Fprintln(Output, HiBlackString("hblack"))
+ fmt.Fprintln(Output, HiRedString("hred"))
+ fmt.Fprintln(Output, HiGreenString("hgreen"))
+ fmt.Fprintln(Output, HiYellowString("hyellow"))
+ fmt.Fprintln(Output, HiBlueString("hblue"))
+ fmt.Fprintln(Output, HiMagentaString("hmagenta"))
+ fmt.Fprintln(Output, HiCyanString("hcyan"))
+ fmt.Fprintln(Output, HiWhiteString("hwhite"))
+}
+
+func TestNoFormat(t *testing.T) {
+ fmt.Printf("%s %%s = ", BlackString("Black"))
+ Black("%s")
+
+ fmt.Printf("%s %%s = ", RedString("Red"))
+ Red("%s")
+
+ fmt.Printf("%s %%s = ", GreenString("Green"))
+ Green("%s")
+
+ fmt.Printf("%s %%s = ", YellowString("Yellow"))
+ Yellow("%s")
+
+ fmt.Printf("%s %%s = ", BlueString("Blue"))
+ Blue("%s")
+
+ fmt.Printf("%s %%s = ", MagentaString("Magenta"))
+ Magenta("%s")
+
+ fmt.Printf("%s %%s = ", CyanString("Cyan"))
+ Cyan("%s")
+
+ fmt.Printf("%s %%s = ", WhiteString("White"))
+ White("%s")
+
+ fmt.Printf("%s %%s = ", HiBlackString("HiBlack"))
+ HiBlack("%s")
+
+ fmt.Printf("%s %%s = ", HiRedString("HiRed"))
+ HiRed("%s")
+
+ fmt.Printf("%s %%s = ", HiGreenString("HiGreen"))
+ HiGreen("%s")
+
+ fmt.Printf("%s %%s = ", HiYellowString("HiYellow"))
+ HiYellow("%s")
+
+ fmt.Printf("%s %%s = ", HiBlueString("HiBlue"))
+ HiBlue("%s")
+
+ fmt.Printf("%s %%s = ", HiMagentaString("HiMagenta"))
+ HiMagenta("%s")
+
+ fmt.Printf("%s %%s = ", HiCyanString("HiCyan"))
+ HiCyan("%s")
+
+ fmt.Printf("%s %%s = ", HiWhiteString("HiWhite"))
+ HiWhite("%s")
+}
+
+func TestNoFormatString(t *testing.T) {
+ tests := []struct {
+ f func(string, ...interface{}) string
+ format string
+ args []interface{}
+ want string
+ }{
+ {BlackString, "%s", nil, "\x1b[30m%s\x1b[0m"},
+ {RedString, "%s", nil, "\x1b[31m%s\x1b[0m"},
+ {GreenString, "%s", nil, "\x1b[32m%s\x1b[0m"},
+ {YellowString, "%s", nil, "\x1b[33m%s\x1b[0m"},
+ {BlueString, "%s", nil, "\x1b[34m%s\x1b[0m"},
+ {MagentaString, "%s", nil, "\x1b[35m%s\x1b[0m"},
+ {CyanString, "%s", nil, "\x1b[36m%s\x1b[0m"},
+ {WhiteString, "%s", nil, "\x1b[37m%s\x1b[0m"},
+ {HiBlackString, "%s", nil, "\x1b[90m%s\x1b[0m"},
+ {HiRedString, "%s", nil, "\x1b[91m%s\x1b[0m"},
+ {HiGreenString, "%s", nil, "\x1b[92m%s\x1b[0m"},
+ {HiYellowString, "%s", nil, "\x1b[93m%s\x1b[0m"},
+ {HiBlueString, "%s", nil, "\x1b[94m%s\x1b[0m"},
+ {HiMagentaString, "%s", nil, "\x1b[95m%s\x1b[0m"},
+ {HiCyanString, "%s", nil, "\x1b[96m%s\x1b[0m"},
+ {HiWhiteString, "%s", nil, "\x1b[97m%s\x1b[0m"},
+ }
+
+ for i, test := range tests {
+ s := fmt.Sprintf("%s", test.f(test.format, test.args...))
+ if s != test.want {
+ t.Errorf("[%d] want: %q, got: %q", i, test.want, s)
+ }
+ }
+}
diff --git a/vendor/github.com/fatih/color/doc.go b/vendor/github.com/fatih/color/doc.go
new file mode 100644
index 0000000..cf1e965
--- /dev/null
+++ b/vendor/github.com/fatih/color/doc.go
@@ -0,0 +1,133 @@
+/*
+Package color is an ANSI color package to output colorized or SGR defined
+output to the standard output. The API can be used in several way, pick one
+that suits you.
+
+Use simple and default helper functions with predefined foreground colors:
+
+ color.Cyan("Prints text in cyan.")
+
+ // a newline will be appended automatically
+ color.Blue("Prints %s in blue.", "text")
+
+ // More default foreground colors..
+ color.Red("We have red")
+ color.Yellow("Yellow color too!")
+ color.Magenta("And many others ..")
+
+ // Hi-intensity colors
+ color.HiGreen("Bright green color.")
+ color.HiBlack("Bright black means gray..")
+ color.HiWhite("Shiny white color!")
+
+However there are times where custom color mixes are required. Below are some
+examples to create custom color objects and use the print functions of each
+separate color object.
+
+ // Create a new color object
+ c := color.New(color.FgCyan).Add(color.Underline)
+ c.Println("Prints cyan text with an underline.")
+
+ // Or just add them to New()
+ d := color.New(color.FgCyan, color.Bold)
+ d.Printf("This prints bold cyan %s\n", "too!.")
+
+
+ // Mix up foreground and background colors, create new mixes!
+ red := color.New(color.FgRed)
+
+ boldRed := red.Add(color.Bold)
+ boldRed.Println("This will print text in bold red.")
+
+ whiteBackground := red.Add(color.BgWhite)
+ whiteBackground.Println("Red text with White background.")
+
+ // Use your own io.Writer output
+ color.New(color.FgBlue).Fprintln(myWriter, "blue color!")
+
+ blue := color.New(color.FgBlue)
+ blue.Fprint(myWriter, "This will print text in blue.")
+
+You can create PrintXxx functions to simplify even more:
+
+ // Create a custom print function for convenient
+ red := color.New(color.FgRed).PrintfFunc()
+ red("warning")
+ red("error: %s", err)
+
+ // Mix up multiple attributes
+ notice := color.New(color.Bold, color.FgGreen).PrintlnFunc()
+ notice("don't forget this...")
+
+You can also FprintXxx functions to pass your own io.Writer:
+
+ blue := color.New(FgBlue).FprintfFunc()
+ blue(myWriter, "important notice: %s", stars)
+
+ // Mix up with multiple attributes
+ success := color.New(color.Bold, color.FgGreen).FprintlnFunc()
+ success(myWriter, don't forget this...")
+
+
+Or create SprintXxx functions to mix strings with other non-colorized strings:
+
+ yellow := New(FgYellow).SprintFunc()
+ red := New(FgRed).SprintFunc()
+
+ fmt.Printf("this is a %s and this is %s.\n", yellow("warning"), red("error"))
+
+ info := New(FgWhite, BgGreen).SprintFunc()
+ fmt.Printf("this %s rocks!\n", info("package"))
+
+Windows support is enabled by default. All Print functions work as intended.
+However only for color.SprintXXX functions, user should use fmt.FprintXXX and
+set the output to color.Output:
+
+ fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS"))
+
+ info := New(FgWhite, BgGreen).SprintFunc()
+ fmt.Fprintf(color.Output, "this %s rocks!\n", info("package"))
+
+Using with existing code is possible. Just use the Set() method to set the
+standard output to the given parameters. That way a rewrite of an existing
+code is not required.
+
+ // Use handy standard colors.
+ color.Set(color.FgYellow)
+
+ fmt.Println("Existing text will be now in Yellow")
+ fmt.Printf("This one %s\n", "too")
+
+ color.Unset() // don't forget to unset
+
+ // You can mix up parameters
+ color.Set(color.FgMagenta, color.Bold)
+ defer color.Unset() // use it in your function
+
+ fmt.Println("All text will be now bold magenta.")
+
+There might be a case where you want to disable color output (for example to
+pipe the standard output of your app to somewhere else). `Color` has support to
+disable colors both globally and for single color definition. For example
+suppose you have a CLI app and a `--no-color` bool flag. You can easily disable
+the color output with:
+
+ var flagNoColor = flag.Bool("no-color", false, "Disable color output")
+
+ if *flagNoColor {
+ color.NoColor = true // disables colorized output
+ }
+
+It also has support for single color definitions (local). You can
+disable/enable color output on the fly:
+
+ c := color.New(color.FgCyan)
+ c.Println("Prints cyan text")
+
+ c.DisableColor()
+ c.Println("This is printed without any color")
+
+ c.EnableColor()
+ c.Println("This prints again cyan...")
+*/
+package color
diff --git a/vendor/github.com/mattn/go-colorable/.travis.yml b/vendor/github.com/mattn/go-colorable/.travis.yml
new file mode 100644
index 0000000..98db8f0
--- /dev/null
+++ b/vendor/github.com/mattn/go-colorable/.travis.yml
@@ -0,0 +1,9 @@
+language: go
+go:
+ - tip
+
+before_install:
+ - go get github.com/mattn/goveralls
+ - go get golang.org/x/tools/cmd/cover
+script:
+ - $HOME/gopath/bin/goveralls -repotoken xnXqRGwgW3SXIguzxf90ZSK1GPYZPaGrw
diff --git a/vendor/github.com/mattn/go-colorable/LICENSE b/vendor/github.com/mattn/go-colorable/LICENSE
new file mode 100644
index 0000000..91b5cef
--- /dev/null
+++ b/vendor/github.com/mattn/go-colorable/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-colorable/README.md b/vendor/github.com/mattn/go-colorable/README.md
new file mode 100644
index 0000000..56729a9
--- /dev/null
+++ b/vendor/github.com/mattn/go-colorable/README.md
@@ -0,0 +1,48 @@
+# go-colorable
+
+[![Godoc Reference](https://godoc.org/github.com/mattn/go-colorable?status.svg)](http://godoc.org/github.com/mattn/go-colorable)
+[![Build Status](https://travis-ci.org/mattn/go-colorable.svg?branch=master)](https://travis-ci.org/mattn/go-colorable)
+[![Coverage Status](https://coveralls.io/repos/github/mattn/go-colorable/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-colorable?branch=master)
+[![Go Report Card](https://goreportcard.com/badge/mattn/go-colorable)](https://goreportcard.com/report/mattn/go-colorable)
+
+Colorable writer for windows.
+
+For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.)
+This package is possible to handle escape sequence for ansi color on windows.
+
+## Too Bad!
+
+![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/bad.png)
+
+
+## So Good!
+
+![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/good.png)
+
+## Usage
+
+```go
+logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true})
+logrus.SetOutput(colorable.NewColorableStdout())
+
+logrus.Info("succeeded")
+logrus.Warn("not correct")
+logrus.Error("something error")
+logrus.Fatal("panic")
+```
+
+You can compile above code on non-windows OSs.
+
+## Installation
+
+```
+$ go get github.com/mattn/go-colorable
+```
+
+# License
+
+MIT
+
+# Author
+
+Yasuhiro Matsumoto (a.k.a mattn)
diff --git a/vendor/github.com/mattn/go-colorable/_example/escape-seq/main.go b/vendor/github.com/mattn/go-colorable/_example/escape-seq/main.go
new file mode 100644
index 0000000..8cbcb90
--- /dev/null
+++ b/vendor/github.com/mattn/go-colorable/_example/escape-seq/main.go
@@ -0,0 +1,16 @@
+package main
+
+import (
+ "bufio"
+ "fmt"
+
+ "github.com/mattn/go-colorable"
+)
+
+func main() {
+ stdOut := bufio.NewWriter(colorable.NewColorableStdout())
+
+ fmt.Fprint(stdOut, "\x1B[3GMove to 3rd Column\n")
+ fmt.Fprint(stdOut, "\x1B[1;2HMove to 2nd Column on 1st Line\n")
+ stdOut.Flush()
+}
diff --git a/vendor/github.com/mattn/go-colorable/_example/logrus/main.go b/vendor/github.com/mattn/go-colorable/_example/logrus/main.go
new file mode 100644
index 0000000..c569164
--- /dev/null
+++ b/vendor/github.com/mattn/go-colorable/_example/logrus/main.go
@@ -0,0 +1,16 @@
+package main
+
+import (
+ "github.com/mattn/go-colorable"
+ "github.com/sirupsen/logrus"
+)
+
+func main() {
+ logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true})
+ logrus.SetOutput(colorable.NewColorableStdout())
+
+ logrus.Info("succeeded")
+ logrus.Warn("not correct")
+ logrus.Error("something error")
+ logrus.Fatal("panic")
+}
diff --git a/vendor/github.com/mattn/go-colorable/_example/title/main.go b/vendor/github.com/mattn/go-colorable/_example/title/main.go
new file mode 100644
index 0000000..e208870
--- /dev/null
+++ b/vendor/github.com/mattn/go-colorable/_example/title/main.go
@@ -0,0 +1,14 @@
+package main
+
+import (
+ "fmt"
+ "os"
+ . "github.com/mattn/go-colorable"
+)
+
+func main() {
+ out := NewColorableStdout()
+ fmt.Fprint(out, "\x1B]0;TITLE Changed\007(See title and hit any key)")
+ var c [1]byte
+ os.Stdin.Read(c[:])
+}
diff --git a/vendor/github.com/mattn/go-colorable/colorable_appengine.go b/vendor/github.com/mattn/go-colorable/colorable_appengine.go
new file mode 100644
index 0000000..1f28d77
--- /dev/null
+++ b/vendor/github.com/mattn/go-colorable/colorable_appengine.go
@@ -0,0 +1,29 @@
+// +build appengine
+
+package colorable
+
+import (
+ "io"
+ "os"
+
+ _ "github.com/mattn/go-isatty"
+)
+
+// NewColorable return new instance of Writer which handle escape sequence.
+func NewColorable(file *os.File) io.Writer {
+ if file == nil {
+ panic("nil passed instead of *os.File to NewColorable()")
+ }
+
+ return file
+}
+
+// NewColorableStdout return new instance of Writer which handle escape sequence for stdout.
+func NewColorableStdout() io.Writer {
+ return os.Stdout
+}
+
+// NewColorableStderr return new instance of Writer which handle escape sequence for stderr.
+func NewColorableStderr() io.Writer {
+ return os.Stderr
+}
diff --git a/vendor/github.com/mattn/go-colorable/colorable_others.go b/vendor/github.com/mattn/go-colorable/colorable_others.go
new file mode 100644
index 0000000..887f203
--- /dev/null
+++ b/vendor/github.com/mattn/go-colorable/colorable_others.go
@@ -0,0 +1,30 @@
+// +build !windows
+// +build !appengine
+
+package colorable
+
+import (
+ "io"
+ "os"
+
+ _ "github.com/mattn/go-isatty"
+)
+
+// NewColorable return new instance of Writer which handle escape sequence.
+func NewColorable(file *os.File) io.Writer {
+ if file == nil {
+ panic("nil passed instead of *os.File to NewColorable()")
+ }
+
+ return file
+}
+
+// NewColorableStdout return new instance of Writer which handle escape sequence for stdout.
+func NewColorableStdout() io.Writer {
+ return os.Stdout
+}
+
+// NewColorableStderr return new instance of Writer which handle escape sequence for stderr.
+func NewColorableStderr() io.Writer {
+ return os.Stderr
+}
diff --git a/vendor/github.com/mattn/go-colorable/colorable_test.go b/vendor/github.com/mattn/go-colorable/colorable_test.go
new file mode 100644
index 0000000..3069869
--- /dev/null
+++ b/vendor/github.com/mattn/go-colorable/colorable_test.go
@@ -0,0 +1,83 @@
+package colorable
+
+import (
+ "bytes"
+ "os"
+ "runtime"
+ "testing"
+)
+
+// checkEncoding checks that colorable is output encoding agnostic as long as
+// the encoding is a superset of ASCII. This implies that one byte not part of
+// an ANSI sequence must give exactly one byte in output
+func checkEncoding(t *testing.T, data []byte) {
+ // Send non-UTF8 data to colorable
+ b := bytes.NewBuffer(make([]byte, 0, 10))
+ if b.Len() != 0 {
+ t.FailNow()
+ }
+ // TODO move colorable wrapping outside the test
+ c := NewNonColorable(b)
+ c.Write(data)
+ if b.Len() != len(data) {
+ t.Fatalf("%d bytes expected, got %d", len(data), b.Len())
+ }
+}
+
+func TestEncoding(t *testing.T) {
+ checkEncoding(t, []byte{}) // Empty
+ checkEncoding(t, []byte(`abc`)) // "abc"
+ checkEncoding(t, []byte(`é`)) // "é" in UTF-8
+ checkEncoding(t, []byte{233}) // 'é' in Latin-1
+}
+
+func TestNonColorable(t *testing.T) {
+ var buf bytes.Buffer
+ want := "hello"
+ NewNonColorable(&buf).Write([]byte("\x1b[0m" + want + "\x1b[2J"))
+ got := buf.String()
+ if got != "hello" {
+ t.Fatalf("want %q but %q", want, got)
+ }
+
+ buf.Reset()
+ NewNonColorable(&buf).Write([]byte("\x1b["))
+ got = buf.String()
+ if got != "" {
+ t.Fatalf("want %q but %q", "", got)
+ }
+}
+
+func TestNonColorableNil(t *testing.T) {
+ paniced := false
+ func() {
+ defer func() {
+ recover()
+ paniced = true
+ }()
+ NewNonColorable(nil)
+ NewColorable(nil)
+ }()
+
+ if !paniced {
+ t.Fatalf("should panic")
+ }
+}
+
+func TestColorable(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Skipf("skip this test on windows")
+ }
+ _, ok := NewColorableStdout().(*os.File)
+ if !ok {
+ t.Fatalf("should os.Stdout on UNIX")
+ }
+ _, ok = NewColorableStderr().(*os.File)
+ if !ok {
+ t.Fatalf("should os.Stdout on UNIX")
+ }
+ _, ok = NewColorable(os.Stdout).(*os.File)
+ if !ok {
+ t.Fatalf("should os.Stdout on UNIX")
+ }
+}
diff --git a/vendor/github.com/mattn/go-colorable/colorable_windows.go b/vendor/github.com/mattn/go-colorable/colorable_windows.go
new file mode 100644
index 0000000..e17a547
--- /dev/null
+++ b/vendor/github.com/mattn/go-colorable/colorable_windows.go
@@ -0,0 +1,884 @@
+// +build windows
+// +build !appengine
+
+package colorable
+
+import (
+ "bytes"
+ "io"
+ "math"
+ "os"
+ "strconv"
+ "strings"
+ "syscall"
+ "unsafe"
+
+ "github.com/mattn/go-isatty"
+)
+
+const (
+ foregroundBlue = 0x1
+ foregroundGreen = 0x2
+ foregroundRed = 0x4
+ foregroundIntensity = 0x8
+ foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity)
+ backgroundBlue = 0x10
+ backgroundGreen = 0x20
+ backgroundRed = 0x40
+ backgroundIntensity = 0x80
+ backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity)
+)
+
+type wchar uint16
+type short int16
+type dword uint32
+type word uint16
+
+type coord struct {
+ x short
+ y short
+}
+
+type smallRect struct {
+ left short
+ top short
+ right short
+ bottom short
+}
+
+type consoleScreenBufferInfo struct {
+ size coord
+ cursorPosition coord
+ attributes word
+ window smallRect
+ maximumWindowSize coord
+}
+
+type consoleCursorInfo struct {
+ size dword
+ visible int32
+}
+
+var (
+ kernel32 = syscall.NewLazyDLL("kernel32.dll")
+ procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
+ procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
+ procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
+ procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
+ procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute")
+ procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo")
+ procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo")
+ procSetConsoleTitle = kernel32.NewProc("SetConsoleTitleW")
+)
+
+// Writer provide colorable Writer to the console
+type Writer struct {
+ out io.Writer
+ handle syscall.Handle
+ oldattr word
+ oldpos coord
+}
+
+// NewColorable return new instance of Writer which handle escape sequence from File.
+func NewColorable(file *os.File) io.Writer {
+ if file == nil {
+ panic("nil passed instead of *os.File to NewColorable()")
+ }
+
+ if isatty.IsTerminal(file.Fd()) {
+ var csbi consoleScreenBufferInfo
+ handle := syscall.Handle(file.Fd())
+ procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+ return &Writer{out: file, handle: handle, oldattr: csbi.attributes, oldpos: coord{0, 0}}
+ }
+ return file
+}
+
+// NewColorableStdout return new instance of Writer which handle escape sequence for stdout.
+func NewColorableStdout() io.Writer {
+ return NewColorable(os.Stdout)
+}
+
+// NewColorableStderr return new instance of Writer which handle escape sequence for stderr.
+func NewColorableStderr() io.Writer {
+ return NewColorable(os.Stderr)
+}
+
+var color256 = map[int]int{
+ 0: 0x000000,
+ 1: 0x800000,
+ 2: 0x008000,
+ 3: 0x808000,
+ 4: 0x000080,
+ 5: 0x800080,
+ 6: 0x008080,
+ 7: 0xc0c0c0,
+ 8: 0x808080,
+ 9: 0xff0000,
+ 10: 0x00ff00,
+ 11: 0xffff00,
+ 12: 0x0000ff,
+ 13: 0xff00ff,
+ 14: 0x00ffff,
+ 15: 0xffffff,
+ 16: 0x000000,
+ 17: 0x00005f,
+ 18: 0x000087,
+ 19: 0x0000af,
+ 20: 0x0000d7,
+ 21: 0x0000ff,
+ 22: 0x005f00,
+ 23: 0x005f5f,
+ 24: 0x005f87,
+ 25: 0x005faf,
+ 26: 0x005fd7,
+ 27: 0x005fff,
+ 28: 0x008700,
+ 29: 0x00875f,
+ 30: 0x008787,
+ 31: 0x0087af,
+ 32: 0x0087d7,
+ 33: 0x0087ff,
+ 34: 0x00af00,
+ 35: 0x00af5f,
+ 36: 0x00af87,
+ 37: 0x00afaf,
+ 38: 0x00afd7,
+ 39: 0x00afff,
+ 40: 0x00d700,
+ 41: 0x00d75f,
+ 42: 0x00d787,
+ 43: 0x00d7af,
+ 44: 0x00d7d7,
+ 45: 0x00d7ff,
+ 46: 0x00ff00,
+ 47: 0x00ff5f,
+ 48: 0x00ff87,
+ 49: 0x00ffaf,
+ 50: 0x00ffd7,
+ 51: 0x00ffff,
+ 52: 0x5f0000,
+ 53: 0x5f005f,
+ 54: 0x5f0087,
+ 55: 0x5f00af,
+ 56: 0x5f00d7,
+ 57: 0x5f00ff,
+ 58: 0x5f5f00,
+ 59: 0x5f5f5f,
+ 60: 0x5f5f87,
+ 61: 0x5f5faf,
+ 62: 0x5f5fd7,
+ 63: 0x5f5fff,
+ 64: 0x5f8700,
+ 65: 0x5f875f,
+ 66: 0x5f8787,
+ 67: 0x5f87af,
+ 68: 0x5f87d7,
+ 69: 0x5f87ff,
+ 70: 0x5faf00,
+ 71: 0x5faf5f,
+ 72: 0x5faf87,
+ 73: 0x5fafaf,
+ 74: 0x5fafd7,
+ 75: 0x5fafff,
+ 76: 0x5fd700,
+ 77: 0x5fd75f,
+ 78: 0x5fd787,
+ 79: 0x5fd7af,
+ 80: 0x5fd7d7,
+ 81: 0x5fd7ff,
+ 82: 0x5fff00,
+ 83: 0x5fff5f,
+ 84: 0x5fff87,
+ 85: 0x5fffaf,
+ 86: 0x5fffd7,
+ 87: 0x5fffff,
+ 88: 0x870000,
+ 89: 0x87005f,
+ 90: 0x870087,
+ 91: 0x8700af,
+ 92: 0x8700d7,
+ 93: 0x8700ff,
+ 94: 0x875f00,
+ 95: 0x875f5f,
+ 96: 0x875f87,
+ 97: 0x875faf,
+ 98: 0x875fd7,
+ 99: 0x875fff,
+ 100: 0x878700,
+ 101: 0x87875f,
+ 102: 0x878787,
+ 103: 0x8787af,
+ 104: 0x8787d7,
+ 105: 0x8787ff,
+ 106: 0x87af00,
+ 107: 0x87af5f,
+ 108: 0x87af87,
+ 109: 0x87afaf,
+ 110: 0x87afd7,
+ 111: 0x87afff,
+ 112: 0x87d700,
+ 113: 0x87d75f,
+ 114: 0x87d787,
+ 115: 0x87d7af,
+ 116: 0x87d7d7,
+ 117: 0x87d7ff,
+ 118: 0x87ff00,
+ 119: 0x87ff5f,
+ 120: 0x87ff87,
+ 121: 0x87ffaf,
+ 122: 0x87ffd7,
+ 123: 0x87ffff,
+ 124: 0xaf0000,
+ 125: 0xaf005f,
+ 126: 0xaf0087,
+ 127: 0xaf00af,
+ 128: 0xaf00d7,
+ 129: 0xaf00ff,
+ 130: 0xaf5f00,
+ 131: 0xaf5f5f,
+ 132: 0xaf5f87,
+ 133: 0xaf5faf,
+ 134: 0xaf5fd7,
+ 135: 0xaf5fff,
+ 136: 0xaf8700,
+ 137: 0xaf875f,
+ 138: 0xaf8787,
+ 139: 0xaf87af,
+ 140: 0xaf87d7,
+ 141: 0xaf87ff,
+ 142: 0xafaf00,
+ 143: 0xafaf5f,
+ 144: 0xafaf87,
+ 145: 0xafafaf,
+ 146: 0xafafd7,
+ 147: 0xafafff,
+ 148: 0xafd700,
+ 149: 0xafd75f,
+ 150: 0xafd787,
+ 151: 0xafd7af,
+ 152: 0xafd7d7,
+ 153: 0xafd7ff,
+ 154: 0xafff00,
+ 155: 0xafff5f,
+ 156: 0xafff87,
+ 157: 0xafffaf,
+ 158: 0xafffd7,
+ 159: 0xafffff,
+ 160: 0xd70000,
+ 161: 0xd7005f,
+ 162: 0xd70087,
+ 163: 0xd700af,
+ 164: 0xd700d7,
+ 165: 0xd700ff,
+ 166: 0xd75f00,
+ 167: 0xd75f5f,
+ 168: 0xd75f87,
+ 169: 0xd75faf,
+ 170: 0xd75fd7,
+ 171: 0xd75fff,
+ 172: 0xd78700,
+ 173: 0xd7875f,
+ 174: 0xd78787,
+ 175: 0xd787af,
+ 176: 0xd787d7,
+ 177: 0xd787ff,
+ 178: 0xd7af00,
+ 179: 0xd7af5f,
+ 180: 0xd7af87,
+ 181: 0xd7afaf,
+ 182: 0xd7afd7,
+ 183: 0xd7afff,
+ 184: 0xd7d700,
+ 185: 0xd7d75f,
+ 186: 0xd7d787,
+ 187: 0xd7d7af,
+ 188: 0xd7d7d7,
+ 189: 0xd7d7ff,
+ 190: 0xd7ff00,
+ 191: 0xd7ff5f,
+ 192: 0xd7ff87,
+ 193: 0xd7ffaf,
+ 194: 0xd7ffd7,
+ 195: 0xd7ffff,
+ 196: 0xff0000,
+ 197: 0xff005f,
+ 198: 0xff0087,
+ 199: 0xff00af,
+ 200: 0xff00d7,
+ 201: 0xff00ff,
+ 202: 0xff5f00,
+ 203: 0xff5f5f,
+ 204: 0xff5f87,
+ 205: 0xff5faf,
+ 206: 0xff5fd7,
+ 207: 0xff5fff,
+ 208: 0xff8700,
+ 209: 0xff875f,
+ 210: 0xff8787,
+ 211: 0xff87af,
+ 212: 0xff87d7,
+ 213: 0xff87ff,
+ 214: 0xffaf00,
+ 215: 0xffaf5f,
+ 216: 0xffaf87,
+ 217: 0xffafaf,
+ 218: 0xffafd7,
+ 219: 0xffafff,
+ 220: 0xffd700,
+ 221: 0xffd75f,
+ 222: 0xffd787,
+ 223: 0xffd7af,
+ 224: 0xffd7d7,
+ 225: 0xffd7ff,
+ 226: 0xffff00,
+ 227: 0xffff5f,
+ 228: 0xffff87,
+ 229: 0xffffaf,
+ 230: 0xffffd7,
+ 231: 0xffffff,
+ 232: 0x080808,
+ 233: 0x121212,
+ 234: 0x1c1c1c,
+ 235: 0x262626,
+ 236: 0x303030,
+ 237: 0x3a3a3a,
+ 238: 0x444444,
+ 239: 0x4e4e4e,
+ 240: 0x585858,
+ 241: 0x626262,
+ 242: 0x6c6c6c,
+ 243: 0x767676,
+ 244: 0x808080,
+ 245: 0x8a8a8a,
+ 246: 0x949494,
+ 247: 0x9e9e9e,
+ 248: 0xa8a8a8,
+ 249: 0xb2b2b2,
+ 250: 0xbcbcbc,
+ 251: 0xc6c6c6,
+ 252: 0xd0d0d0,
+ 253: 0xdadada,
+ 254: 0xe4e4e4,
+ 255: 0xeeeeee,
+}
+
+// `\033]0;TITLESTR\007`
+func doTitleSequence(er *bytes.Reader) error {
+ var c byte
+ var err error
+
+ c, err = er.ReadByte()
+ if err != nil {
+ return err
+ }
+ if c != '0' && c != '2' {
+ return nil
+ }
+ c, err = er.ReadByte()
+ if err != nil {
+ return err
+ }
+ if c != ';' {
+ return nil
+ }
+ title := make([]byte, 0, 80)
+ for {
+ c, err = er.ReadByte()
+ if err != nil {
+ return err
+ }
+ if c == 0x07 || c == '\n' {
+ break
+ }
+ title = append(title, c)
+ }
+ if len(title) > 0 {
+ title8, err := syscall.UTF16PtrFromString(string(title))
+ if err == nil {
+ procSetConsoleTitle.Call(uintptr(unsafe.Pointer(title8)))
+ }
+ }
+ return nil
+}
+
+// Write write data on console
+func (w *Writer) Write(data []byte) (n int, err error) {
+ var csbi consoleScreenBufferInfo
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+
+ er := bytes.NewReader(data)
+ var bw [1]byte
+loop:
+ for {
+ c1, err := er.ReadByte()
+ if err != nil {
+ break loop
+ }
+ if c1 != 0x1b {
+ bw[0] = c1
+ w.out.Write(bw[:])
+ continue
+ }
+ c2, err := er.ReadByte()
+ if err != nil {
+ break loop
+ }
+
+ if c2 == ']' {
+ if err := doTitleSequence(er); err != nil {
+ break loop
+ }
+ continue
+ }
+ if c2 != 0x5b {
+ continue
+ }
+
+ var buf bytes.Buffer
+ var m byte
+ for {
+ c, err := er.ReadByte()
+ if err != nil {
+ break loop
+ }
+ if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
+ m = c
+ break
+ }
+ buf.Write([]byte(string(c)))
+ }
+
+ switch m {
+ case 'A':
+ n, err = strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+ csbi.cursorPosition.y -= short(n)
+ procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'B':
+ n, err = strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+ csbi.cursorPosition.y += short(n)
+ procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'C':
+ n, err = strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+ csbi.cursorPosition.x += short(n)
+ procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'D':
+ n, err = strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+ csbi.cursorPosition.x -= short(n)
+ procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'E':
+ n, err = strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+ csbi.cursorPosition.x = 0
+ csbi.cursorPosition.y += short(n)
+ procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'F':
+ n, err = strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+ csbi.cursorPosition.x = 0
+ csbi.cursorPosition.y -= short(n)
+ procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'G':
+ n, err = strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+ csbi.cursorPosition.x = short(n - 1)
+ procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'H', 'f':
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+ if buf.Len() > 0 {
+ token := strings.Split(buf.String(), ";")
+ switch len(token) {
+ case 1:
+ n1, err := strconv.Atoi(token[0])
+ if err != nil {
+ continue
+ }
+ csbi.cursorPosition.y = short(n1 - 1)
+ case 2:
+ n1, err := strconv.Atoi(token[0])
+ if err != nil {
+ continue
+ }
+ n2, err := strconv.Atoi(token[1])
+ if err != nil {
+ continue
+ }
+ csbi.cursorPosition.x = short(n2 - 1)
+ csbi.cursorPosition.y = short(n1 - 1)
+ }
+ } else {
+ csbi.cursorPosition.y = 0
+ }
+ procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'J':
+ n := 0
+ if buf.Len() > 0 {
+ n, err = strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ }
+ var count, written dword
+ var cursor coord
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+ switch n {
+ case 0:
+ cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
+ count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x)
+ case 1:
+ cursor = coord{x: csbi.window.left, y: csbi.window.top}
+ count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.window.top-csbi.cursorPosition.y)*csbi.size.x)
+ case 2:
+ cursor = coord{x: csbi.window.left, y: csbi.window.top}
+ count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x)
+ }
+ procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
+ procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
+ case 'K':
+ n := 0
+ if buf.Len() > 0 {
+ n, err = strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+ var cursor coord
+ var count, written dword
+ switch n {
+ case 0:
+ cursor = coord{x: csbi.cursorPosition.x + 1, y: csbi.cursorPosition.y}
+ count = dword(csbi.size.x - csbi.cursorPosition.x - 1)
+ case 1:
+ cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y}
+ count = dword(csbi.size.x - csbi.cursorPosition.x)
+ case 2:
+ cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y}
+ count = dword(csbi.size.x)
+ }
+ procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
+ procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
+ case 'm':
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+ attr := csbi.attributes
+ cs := buf.String()
+ if cs == "" {
+ procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr))
+ continue
+ }
+ token := strings.Split(cs, ";")
+ for i := 0; i < len(token); i++ {
+ ns := token[i]
+ if n, err = strconv.Atoi(ns); err == nil {
+ switch {
+ case n == 0 || n == 100:
+ attr = w.oldattr
+ case 1 <= n && n <= 5:
+ attr |= foregroundIntensity
+ case n == 7:
+ attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
+ case n == 22 || n == 25:
+ attr |= foregroundIntensity
+ case n == 27:
+ attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
+ case 30 <= n && n <= 37:
+ attr &= backgroundMask
+ if (n-30)&1 != 0 {
+ attr |= foregroundRed
+ }
+ if (n-30)&2 != 0 {
+ attr |= foregroundGreen
+ }
+ if (n-30)&4 != 0 {
+ attr |= foregroundBlue
+ }
+ case n == 38: // set foreground color.
+ if i < len(token)-2 && (token[i+1] == "5" || token[i+1] == "05") {
+ if n256, err := strconv.Atoi(token[i+2]); err == nil {
+ if n256foreAttr == nil {
+ n256setup()
+ }
+ attr &= backgroundMask
+ attr |= n256foreAttr[n256]
+ i += 2
+ }
+ } else {
+ attr = attr & (w.oldattr & backgroundMask)
+ }
+ case n == 39: // reset foreground color.
+ attr &= backgroundMask
+ attr |= w.oldattr & foregroundMask
+ case 40 <= n && n <= 47:
+ attr &= foregroundMask
+ if (n-40)&1 != 0 {
+ attr |= backgroundRed
+ }
+ if (n-40)&2 != 0 {
+ attr |= backgroundGreen
+ }
+ if (n-40)&4 != 0 {
+ attr |= backgroundBlue
+ }
+ case n == 48: // set background color.
+ if i < len(token)-2 && token[i+1] == "5" {
+ if n256, err := strconv.Atoi(token[i+2]); err == nil {
+ if n256backAttr == nil {
+ n256setup()
+ }
+ attr &= foregroundMask
+ attr |= n256backAttr[n256]
+ i += 2
+ }
+ } else {
+ attr = attr & (w.oldattr & foregroundMask)
+ }
+ case n == 49: // reset foreground color.
+ attr &= foregroundMask
+ attr |= w.oldattr & backgroundMask
+ case 90 <= n && n <= 97:
+ attr = (attr & backgroundMask)
+ attr |= foregroundIntensity
+ if (n-90)&1 != 0 {
+ attr |= foregroundRed
+ }
+ if (n-90)&2 != 0 {
+ attr |= foregroundGreen
+ }
+ if (n-90)&4 != 0 {
+ attr |= foregroundBlue
+ }
+ case 100 <= n && n <= 107:
+ attr = (attr & foregroundMask)
+ attr |= backgroundIntensity
+ if (n-100)&1 != 0 {
+ attr |= backgroundRed
+ }
+ if (n-100)&2 != 0 {
+ attr |= backgroundGreen
+ }
+ if (n-100)&4 != 0 {
+ attr |= backgroundBlue
+ }
+ }
+ procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr))
+ }
+ }
+ case 'h':
+ var ci consoleCursorInfo
+ cs := buf.String()
+ if cs == "5>" {
+ procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
+ ci.visible = 0
+ procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
+ } else if cs == "?25" {
+ procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
+ ci.visible = 1
+ procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
+ }
+ case 'l':
+ var ci consoleCursorInfo
+ cs := buf.String()
+ if cs == "5>" {
+ procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
+ ci.visible = 1
+ procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
+ } else if cs == "?25" {
+ procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
+ ci.visible = 0
+ procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
+ }
+ case 's':
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+ w.oldpos = csbi.cursorPosition
+ case 'u':
+ procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&w.oldpos)))
+ }
+ }
+
+ return len(data), nil
+}
+
+type consoleColor struct {
+ rgb int
+ red bool
+ green bool
+ blue bool
+ intensity bool
+}
+
+func (c consoleColor) foregroundAttr() (attr word) {
+ if c.red {
+ attr |= foregroundRed
+ }
+ if c.green {
+ attr |= foregroundGreen
+ }
+ if c.blue {
+ attr |= foregroundBlue
+ }
+ if c.intensity {
+ attr |= foregroundIntensity
+ }
+ return
+}
+
+func (c consoleColor) backgroundAttr() (attr word) {
+ if c.red {
+ attr |= backgroundRed
+ }
+ if c.green {
+ attr |= backgroundGreen
+ }
+ if c.blue {
+ attr |= backgroundBlue
+ }
+ if c.intensity {
+ attr |= backgroundIntensity
+ }
+ return
+}
+
+var color16 = []consoleColor{
+ {0x000000, false, false, false, false},
+ {0x000080, false, false, true, false},
+ {0x008000, false, true, false, false},
+ {0x008080, false, true, true, false},
+ {0x800000, true, false, false, false},
+ {0x800080, true, false, true, false},
+ {0x808000, true, true, false, false},
+ {0xc0c0c0, true, true, true, false},
+ {0x808080, false, false, false, true},
+ {0x0000ff, false, false, true, true},
+ {0x00ff00, false, true, false, true},
+ {0x00ffff, false, true, true, true},
+ {0xff0000, true, false, false, true},
+ {0xff00ff, true, false, true, true},
+ {0xffff00, true, true, false, true},
+ {0xffffff, true, true, true, true},
+}
+
+type hsv struct {
+ h, s, v float32
+}
+
+func (a hsv) dist(b hsv) float32 {
+ dh := a.h - b.h
+ switch {
+ case dh > 0.5:
+ dh = 1 - dh
+ case dh < -0.5:
+ dh = -1 - dh
+ }
+ ds := a.s - b.s
+ dv := a.v - b.v
+ return float32(math.Sqrt(float64(dh*dh + ds*ds + dv*dv)))
+}
+
+func toHSV(rgb int) hsv {
+ r, g, b := float32((rgb&0xFF0000)>>16)/256.0,
+ float32((rgb&0x00FF00)>>8)/256.0,
+ float32(rgb&0x0000FF)/256.0
+ min, max := minmax3f(r, g, b)
+ h := max - min
+ if h > 0 {
+ if max == r {
+ h = (g - b) / h
+ if h < 0 {
+ h += 6
+ }
+ } else if max == g {
+ h = 2 + (b-r)/h
+ } else {
+ h = 4 + (r-g)/h
+ }
+ }
+ h /= 6.0
+ s := max - min
+ if max != 0 {
+ s /= max
+ }
+ v := max
+ return hsv{h: h, s: s, v: v}
+}
+
+type hsvTable []hsv
+
+func toHSVTable(rgbTable []consoleColor) hsvTable {
+ t := make(hsvTable, len(rgbTable))
+ for i, c := range rgbTable {
+ t[i] = toHSV(c.rgb)
+ }
+ return t
+}
+
+func (t hsvTable) find(rgb int) consoleColor {
+ hsv := toHSV(rgb)
+ n := 7
+ l := float32(5.0)
+ for i, p := range t {
+ d := hsv.dist(p)
+ if d < l {
+ l, n = d, i
+ }
+ }
+ return color16[n]
+}
+
+func minmax3f(a, b, c float32) (min, max float32) {
+ if a < b {
+ if b < c {
+ return a, c
+ } else if a < c {
+ return a, b
+ } else {
+ return c, b
+ }
+ } else {
+ if a < c {
+ return b, c
+ } else if b < c {
+ return b, a
+ } else {
+ return c, a
+ }
+ }
+}
+
+var n256foreAttr []word
+var n256backAttr []word
+
+func n256setup() {
+ n256foreAttr = make([]word, 256)
+ n256backAttr = make([]word, 256)
+ t := toHSVTable(color16)
+ for i, rgb := range color256 {
+ c := t.find(rgb)
+ n256foreAttr[i] = c.foregroundAttr()
+ n256backAttr[i] = c.backgroundAttr()
+ }
+}
diff --git a/vendor/github.com/mattn/go-colorable/noncolorable.go b/vendor/github.com/mattn/go-colorable/noncolorable.go
new file mode 100644
index 0000000..9721e16
--- /dev/null
+++ b/vendor/github.com/mattn/go-colorable/noncolorable.go
@@ -0,0 +1,55 @@
+package colorable
+
+import (
+ "bytes"
+ "io"
+)
+
+// NonColorable hold writer but remove escape sequence.
+type NonColorable struct {
+ out io.Writer
+}
+
+// NewNonColorable return new instance of Writer which remove escape sequence from Writer.
+func NewNonColorable(w io.Writer) io.Writer {
+ return &NonColorable{out: w}
+}
+
+// Write write data on console
+func (w *NonColorable) Write(data []byte) (n int, err error) {
+ er := bytes.NewReader(data)
+ var bw [1]byte
+loop:
+ for {
+ c1, err := er.ReadByte()
+ if err != nil {
+ break loop
+ }
+ if c1 != 0x1b {
+ bw[0] = c1
+ w.out.Write(bw[:])
+ continue
+ }
+ c2, err := er.ReadByte()
+ if err != nil {
+ break loop
+ }
+ if c2 != 0x5b {
+ continue
+ }
+
+ var buf bytes.Buffer
+ for {
+ c, err := er.ReadByte()
+ if err != nil {
+ break loop
+ }
+ if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
+ break
+ }
+ buf.Write([]byte(string(c)))
+ }
+ }
+
+ return len(data), nil
+}
diff --git a/vendor/github.com/mattn/go-isatty/.travis.yml b/vendor/github.com/mattn/go-isatty/.travis.yml
new file mode 100644
index 0000000..b9f8b23
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/.travis.yml
@@ -0,0 +1,9 @@
+language: go
+go:
+ - tip
+
+before_install:
+ - go get github.com/mattn/goveralls
+ - go get golang.org/x/tools/cmd/cover
+script:
+ - $HOME/gopath/bin/goveralls -repotoken 3gHdORO5k5ziZcWMBxnd9LrMZaJs8m9x5
diff --git a/vendor/github.com/mattn/go-isatty/LICENSE b/vendor/github.com/mattn/go-isatty/LICENSE
new file mode 100644
index 0000000..65dc692
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/LICENSE
@@ -0,0 +1,9 @@
+Copyright (c) Yasuhiro MATSUMOTO
+
+MIT License (Expat)
+
+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-isatty/README.md b/vendor/github.com/mattn/go-isatty/README.md
new file mode 100644
index 0000000..1e69004
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/README.md
@@ -0,0 +1,50 @@
+# go-isatty
+
+[![Godoc Reference](https://godoc.org/github.com/mattn/go-isatty?status.svg)](http://godoc.org/github.com/mattn/go-isatty)
+[![Build Status](https://travis-ci.org/mattn/go-isatty.svg?branch=master)](https://travis-ci.org/mattn/go-isatty)
+[![Coverage Status](https://coveralls.io/repos/github/mattn/go-isatty/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-isatty?branch=master)
+[![Go Report Card](https://goreportcard.com/badge/mattn/go-isatty)](https://goreportcard.com/report/mattn/go-isatty)
+
+isatty for golang
+
+## Usage
+
+```go
+package main
+
+import (
+ "fmt"
+ "github.com/mattn/go-isatty"
+ "os"
+)
+
+func main() {
+ if isatty.IsTerminal(os.Stdout.Fd()) {
+ fmt.Println("Is Terminal")
+ } else if isatty.IsCygwinTerminal(os.Stdout.Fd()) {
+ fmt.Println("Is Cygwin/MSYS2 Terminal")
+ } else {
+ fmt.Println("Is Not Terminal")
+ }
+}
+```
+
+## Installation
+
+```
+$ go get github.com/mattn/go-isatty
+```
+
+## License
+
+MIT
+
+## Author
+
+Yasuhiro Matsumoto (a.k.a mattn)
+
+## Thanks
+
+* k-takata: base idea for IsCygwinTerminal
+
+ https://github.com/k-takata/go-iscygpty
diff --git a/vendor/github.com/mattn/go-isatty/doc.go b/vendor/github.com/mattn/go-isatty/doc.go
new file mode 100644
index 0000000..17d4f90
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/doc.go
@@ -0,0 +1,2 @@
+// Package isatty implements interface to isatty
+package isatty
diff --git a/vendor/github.com/mattn/go-isatty/example_test.go b/vendor/github.com/mattn/go-isatty/example_test.go
new file mode 100644
index 0000000..fa8f7e7
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/example_test.go
@@ -0,0 +1,18 @@
+package isatty_test
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/mattn/go-isatty"
+)
+
+func Example() {
+ if isatty.IsTerminal(os.Stdout.Fd()) {
+ fmt.Println("Is Terminal")
+ } else if isatty.IsCygwinTerminal(os.Stdout.Fd()) {
+ fmt.Println("Is Cygwin/MSYS2 Terminal")
+ } else {
+ fmt.Println("Is Not Terminal")
+ }
+}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_appengine.go b/vendor/github.com/mattn/go-isatty/isatty_appengine.go
new file mode 100644
index 0000000..9584a98
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/isatty_appengine.go
@@ -0,0 +1,15 @@
+// +build appengine
+
+package isatty
+
+// IsTerminal returns true if the file descriptor is terminal which
+// is always false on on appengine classic which is a sandboxed PaaS.
+func IsTerminal(fd uintptr) bool {
+ return false
+}
+
+// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
+// terminal. This is also always false on this environment.
+func IsCygwinTerminal(fd uintptr) bool {
+ return false
+}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_bsd.go b/vendor/github.com/mattn/go-isatty/isatty_bsd.go
new file mode 100644
index 0000000..42f2514
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/isatty_bsd.go
@@ -0,0 +1,18 @@
+// +build darwin freebsd openbsd netbsd dragonfly
+// +build !appengine
+
+package isatty
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+const ioctlReadTermios = syscall.TIOCGETA
+
+// IsTerminal return true if the file descriptor is terminal.
+func IsTerminal(fd uintptr) bool {
+ var termios syscall.Termios
+ _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
+ return err == 0
+}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_linux.go b/vendor/github.com/mattn/go-isatty/isatty_linux.go
new file mode 100644
index 0000000..7384cf9
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/isatty_linux.go
@@ -0,0 +1,18 @@
+// +build linux
+// +build !appengine,!ppc64,!ppc64le
+
+package isatty
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+const ioctlReadTermios = syscall.TCGETS
+
+// IsTerminal return true if the file descriptor is terminal.
+func IsTerminal(fd uintptr) bool {
+ var termios syscall.Termios
+ _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
+ return err == 0
+}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_linux_ppc64x.go b/vendor/github.com/mattn/go-isatty/isatty_linux_ppc64x.go
new file mode 100644
index 0000000..44e5d21
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/isatty_linux_ppc64x.go
@@ -0,0 +1,19 @@
+// +build linux
+// +build ppc64 ppc64le
+
+package isatty
+
+import (
+ "unsafe"
+
+ syscall "golang.org/x/sys/unix"
+)
+
+const ioctlReadTermios = syscall.TCGETS
+
+// IsTerminal return true if the file descriptor is terminal.
+func IsTerminal(fd uintptr) bool {
+ var termios syscall.Termios
+ _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
+ return err == 0
+}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_others.go b/vendor/github.com/mattn/go-isatty/isatty_others.go
new file mode 100644
index 0000000..ff4de3d
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/isatty_others.go
@@ -0,0 +1,10 @@
+// +build !windows
+// +build !appengine
+
+package isatty
+
+// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
+// terminal. This is also always false on this environment.
+func IsCygwinTerminal(fd uintptr) bool {
+ return false
+}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_others_test.go b/vendor/github.com/mattn/go-isatty/isatty_others_test.go
new file mode 100644
index 0000000..a2091cf
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/isatty_others_test.go
@@ -0,0 +1,19 @@
+// +build !windows
+
+package isatty
+
+import (
+ "os"
+ "testing"
+)
+
+func TestTerminal(t *testing.T) {
+ // test for non-panic
+ IsTerminal(os.Stdout.Fd())
+}
+
+func TestCygwinPipeName(t *testing.T) {
+ if IsCygwinTerminal(os.Stdout.Fd()) {
+ t.Fatal("should be false always")
+ }
+}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_solaris.go b/vendor/github.com/mattn/go-isatty/isatty_solaris.go
new file mode 100644
index 0000000..1f0c6bf
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/isatty_solaris.go
@@ -0,0 +1,16 @@
+// +build solaris
+// +build !appengine
+
+package isatty
+
+import (
+ "golang.org/x/sys/unix"
+)
+
+// IsTerminal returns true if the given file descriptor is a terminal.
+// see: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c
+func IsTerminal(fd uintptr) bool {
+ var termio unix.Termio
+ err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio)
+ return err == nil
+}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_windows.go b/vendor/github.com/mattn/go-isatty/isatty_windows.go
new file mode 100644
index 0000000..af51cbc
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/isatty_windows.go
@@ -0,0 +1,94 @@
+// +build windows
+// +build !appengine
+
+package isatty
+
+import (
+ "strings"
+ "syscall"
+ "unicode/utf16"
+ "unsafe"
+)
+
+const (
+ fileNameInfo uintptr = 2
+ fileTypePipe = 3
+)
+
+var (
+ kernel32 = syscall.NewLazyDLL("kernel32.dll")
+ procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
+ procGetFileInformationByHandleEx = kernel32.NewProc("GetFileInformationByHandleEx")
+ procGetFileType = kernel32.NewProc("GetFileType")
+)
+
+func init() {
+ // Check if GetFileInformationByHandleEx is available.
+ if procGetFileInformationByHandleEx.Find() != nil {
+ procGetFileInformationByHandleEx = nil
+ }
+}
+
+// IsTerminal return true if the file descriptor is terminal.
+func IsTerminal(fd uintptr) bool {
+ var st uint32
+ r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
+ return r != 0 && e == 0
+}
+
+// Check pipe name is used for cygwin/msys2 pty.
+// Cygwin/MSYS2 PTY has a name like:
+// \{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master
+func isCygwinPipeName(name string) bool {
+ token := strings.Split(name, "-")
+ if len(token) < 5 {
+ return false
+ }
+
+ if token[0] != `\msys` && token[0] != `\cygwin` {
+ return false
+ }
+
+ if token[1] == "" {
+ return false
+ }
+
+ if !strings.HasPrefix(token[2], "pty") {
+ return false
+ }
+
+ if token[3] != `from` && token[3] != `to` {
+ return false
+ }
+
+ if token[4] != "master" {
+ return false
+ }
+
+ return true
+}
+
+// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
+// terminal.
+func IsCygwinTerminal(fd uintptr) bool {
+ if procGetFileInformationByHandleEx == nil {
+ return false
+ }
+
+ // Cygwin/msys's pty is a pipe.
+ ft, _, e := syscall.Syscall(procGetFileType.Addr(), 1, fd, 0, 0)
+ if ft != fileTypePipe || e != 0 {
+ return false
+ }
+
+ var buf [2 + syscall.MAX_PATH]uint16
+ r, _, e := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(),
+ 4, fd, fileNameInfo, uintptr(unsafe.Pointer(&buf)),
+ uintptr(len(buf)*2), 0, 0)
+ if r == 0 || e != 0 {
+ return false
+ }
+
+ l := *(*uint32)(unsafe.Pointer(&buf))
+ return isCygwinPipeName(string(utf16.Decode(buf[2 : 2+l/2])))
+}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_windows_test.go b/vendor/github.com/mattn/go-isatty/isatty_windows_test.go
new file mode 100644
index 0000000..777e8a6
--- /dev/null
+++ b/vendor/github.com/mattn/go-isatty/isatty_windows_test.go
@@ -0,0 +1,35 @@
+// +build windows
+
+package isatty
+
+import (
+ "testing"
+)
+
+func TestCygwinPipeName(t *testing.T) {
+ tests := []struct {
+ name string
+ result bool
+ }{
+ {``, false},
+ {`\msys-`, false},
+ {`\cygwin-----`, false},
+ {`\msys-x-PTY5-pty1-from-master`, false},
+ {`\cygwin-x-PTY5-from-master`, false},
+ {`\cygwin-x-pty2-from-toaster`, false},
+ {`\cygwin--pty2-from-master`, false},
+ {`\\cygwin-x-pty2-from-master`, false},
+ {`\cygwin-x-pty2-from-master-`, true}, // for the feature
+ {`\cygwin-e022582115c10879-pty4-from-master`, true},
+ {`\msys-e022582115c10879-pty4-to-master`, true},
+ {`\cygwin-e022582115c10879-pty4-to-master`, true},
+ }
+
+ for _, test := range tests {
+ want := test.result
+ got := isCygwinPipeName(test.name)
+ if want != got {
+ t.Fatalf("isatty(%q): got %v, want %v:", test.name, got, want)
+ }
+ }
+}
diff --git a/vendor/github.com/mattn/go-runewidth/.travis.yml b/vendor/github.com/mattn/go-runewidth/.travis.yml
new file mode 100644
index 0000000..5c9c2a3
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/.travis.yml
@@ -0,0 +1,8 @@
+language: go
+go:
+ - tip
+before_install:
+ - go get github.com/mattn/goveralls
+ - go get golang.org/x/tools/cmd/cover
+script:
+ - $HOME/gopath/bin/goveralls -repotoken lAKAWPzcGsD3A8yBX3BGGtRUdJ6CaGERL
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.mkd b/vendor/github.com/mattn/go-runewidth/README.mkd
new file mode 100644
index 0000000..66663a9
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/README.mkd
@@ -0,0 +1,27 @@
+go-runewidth
+============
+
+[![Build Status](https://travis-ci.org/mattn/go-runewidth.png?branch=master)](https://travis-ci.org/mattn/go-runewidth)
+[![Coverage Status](https://coveralls.io/repos/mattn/go-runewidth/badge.png?branch=HEAD)](https://coveralls.io/r/mattn/go-runewidth?branch=HEAD)
+[![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..2164497
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/runewidth.go
@@ -0,0 +1,1223 @@
+package runewidth
+
+var (
+ // EastAsianWidth will be set true if the current locale is CJK
+ EastAsianWidth = IsEastAsian()
+
+ // DefaultCondition is a condition in current locale
+ DefaultCondition = &Condition{EastAsianWidth}
+)
+
+type interval struct {
+ first rune
+ last rune
+}
+
+type table []interval
+
+func inTables(r rune, ts ...table) bool {
+ for _, t := range ts {
+ if inTable(r, t) {
+ return true
+ }
+ }
+ return false
+}
+
+func inTable(r rune, t table) bool {
+ // func (t table) IncludesRune(r rune) bool {
+ if r < t[0].first {
+ return false
+ }
+
+ bot := 0
+ top := len(t) - 1
+ for top >= bot {
+ mid := (bot + top) / 2
+
+ 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},
+ {0x202A, 0x202E}, {0x206A, 0x206F}, {0xD800, 0xDFFF},
+ {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, {0xFFFE, 0xFFFF},
+}
+
+var combining = table{
+ {0x0300, 0x036F}, {0x0483, 0x0489}, {0x0591, 0x05BD},
+ {0x05BF, 0x05BF}, {0x05C1, 0x05C2}, {0x05C4, 0x05C5},
+ {0x05C7, 0x05C7}, {0x0610, 0x061A}, {0x064B, 0x065F},
+ {0x0670, 0x0670}, {0x06D6, 0x06DC}, {0x06DF, 0x06E4},
+ {0x06E7, 0x06E8}, {0x06EA, 0x06ED}, {0x0711, 0x0711},
+ {0x0730, 0x074A}, {0x07A6, 0x07B0}, {0x07EB, 0x07F3},
+ {0x0816, 0x0819}, {0x081B, 0x0823}, {0x0825, 0x0827},
+ {0x0829, 0x082D}, {0x0859, 0x085B}, {0x08D4, 0x08E1},
+ {0x08E3, 0x0903}, {0x093A, 0x093C}, {0x093E, 0x094F},
+ {0x0951, 0x0957}, {0x0962, 0x0963}, {0x0981, 0x0983},
+ {0x09BC, 0x09BC}, {0x09BE, 0x09C4}, {0x09C7, 0x09C8},
+ {0x09CB, 0x09CD}, {0x09D7, 0x09D7}, {0x09E2, 0x09E3},
+ {0x0A01, 0x0A03}, {0x0A3C, 0x0A3C}, {0x0A3E, 0x0A42},
+ {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A51, 0x0A51},
+ {0x0A70, 0x0A71}, {0x0A75, 0x0A75}, {0x0A81, 0x0A83},
+ {0x0ABC, 0x0ABC}, {0x0ABE, 0x0AC5}, {0x0AC7, 0x0AC9},
+ {0x0ACB, 0x0ACD}, {0x0AE2, 0x0AE3}, {0x0B01, 0x0B03},
+ {0x0B3C, 0x0B3C}, {0x0B3E, 0x0B44}, {0x0B47, 0x0B48},
+ {0x0B4B, 0x0B4D}, {0x0B56, 0x0B57}, {0x0B62, 0x0B63},
+ {0x0B82, 0x0B82}, {0x0BBE, 0x0BC2}, {0x0BC6, 0x0BC8},
+ {0x0BCA, 0x0BCD}, {0x0BD7, 0x0BD7}, {0x0C00, 0x0C03},
+ {0x0C3E, 0x0C44}, {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D},
+ {0x0C55, 0x0C56}, {0x0C62, 0x0C63}, {0x0C81, 0x0C83},
+ {0x0CBC, 0x0CBC}, {0x0CBE, 0x0CC4}, {0x0CC6, 0x0CC8},
+ {0x0CCA, 0x0CCD}, {0x0CD5, 0x0CD6}, {0x0CE2, 0x0CE3},
+ {0x0D01, 0x0D03}, {0x0D3E, 0x0D44}, {0x0D46, 0x0D48},
+ {0x0D4A, 0x0D4D}, {0x0D57, 0x0D57}, {0x0D62, 0x0D63},
+ {0x0D82, 0x0D83}, {0x0DCA, 0x0DCA}, {0x0DCF, 0x0DD4},
+ {0x0DD6, 0x0DD6}, {0x0DD8, 0x0DDF}, {0x0DF2, 0x0DF3},
+ {0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E},
+ {0x0EB1, 0x0EB1}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC},
+ {0x0EC8, 0x0ECD}, {0x0F18, 0x0F19}, {0x0F35, 0x0F35},
+ {0x0F37, 0x0F37}, {0x0F39, 0x0F39}, {0x0F3E, 0x0F3F},
+ {0x0F71, 0x0F84}, {0x0F86, 0x0F87}, {0x0F8D, 0x0F97},
+ {0x0F99, 0x0FBC}, {0x0FC6, 0x0FC6}, {0x102B, 0x103E},
+ {0x1056, 0x1059}, {0x105E, 0x1060}, {0x1062, 0x1064},
+ {0x1067, 0x106D}, {0x1071, 0x1074}, {0x1082, 0x108D},
+ {0x108F, 0x108F}, {0x109A, 0x109D}, {0x135D, 0x135F},
+ {0x1712, 0x1714}, {0x1732, 0x1734}, {0x1752, 0x1753},
+ {0x1772, 0x1773}, {0x17B4, 0x17D3}, {0x17DD, 0x17DD},
+ {0x180B, 0x180D}, {0x1885, 0x1886}, {0x18A9, 0x18A9},
+ {0x1920, 0x192B}, {0x1930, 0x193B}, {0x1A17, 0x1A1B},
+ {0x1A55, 0x1A5E}, {0x1A60, 0x1A7C}, {0x1A7F, 0x1A7F},
+ {0x1AB0, 0x1ABE}, {0x1B00, 0x1B04}, {0x1B34, 0x1B44},
+ {0x1B6B, 0x1B73}, {0x1B80, 0x1B82}, {0x1BA1, 0x1BAD},
+ {0x1BE6, 0x1BF3}, {0x1C24, 0x1C37}, {0x1CD0, 0x1CD2},
+ {0x1CD4, 0x1CE8}, {0x1CED, 0x1CED}, {0x1CF2, 0x1CF4},
+ {0x1CF8, 0x1CF9}, {0x1DC0, 0x1DF5}, {0x1DFB, 0x1DFF},
+ {0x20D0, 0x20F0}, {0x2CEF, 0x2CF1}, {0x2D7F, 0x2D7F},
+ {0x2DE0, 0x2DFF}, {0x302A, 0x302F}, {0x3099, 0x309A},
+ {0xA66F, 0xA672}, {0xA674, 0xA67D}, {0xA69E, 0xA69F},
+ {0xA6F0, 0xA6F1}, {0xA802, 0xA802}, {0xA806, 0xA806},
+ {0xA80B, 0xA80B}, {0xA823, 0xA827}, {0xA880, 0xA881},
+ {0xA8B4, 0xA8C5}, {0xA8E0, 0xA8F1}, {0xA926, 0xA92D},
+ {0xA947, 0xA953}, {0xA980, 0xA983}, {0xA9B3, 0xA9C0},
+ {0xA9E5, 0xA9E5}, {0xAA29, 0xAA36}, {0xAA43, 0xAA43},
+ {0xAA4C, 0xAA4D}, {0xAA7B, 0xAA7D}, {0xAAB0, 0xAAB0},
+ {0xAAB2, 0xAAB4}, {0xAAB7, 0xAAB8}, {0xAABE, 0xAABF},
+ {0xAAC1, 0xAAC1}, {0xAAEB, 0xAAEF}, {0xAAF5, 0xAAF6},
+ {0xABE3, 0xABEA}, {0xABEC, 0xABED}, {0xFB1E, 0xFB1E},
+ {0xFE00, 0xFE0F}, {0xFE20, 0xFE2F}, {0x101FD, 0x101FD},
+ {0x102E0, 0x102E0}, {0x10376, 0x1037A}, {0x10A01, 0x10A03},
+ {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F}, {0x10A38, 0x10A3A},
+ {0x10A3F, 0x10A3F}, {0x10AE5, 0x10AE6}, {0x11000, 0x11002},
+ {0x11038, 0x11046}, {0x1107F, 0x11082}, {0x110B0, 0x110BA},
+ {0x11100, 0x11102}, {0x11127, 0x11134}, {0x11173, 0x11173},
+ {0x11180, 0x11182}, {0x111B3, 0x111C0}, {0x111CA, 0x111CC},
+ {0x1122C, 0x11237}, {0x1123E, 0x1123E}, {0x112DF, 0x112EA},
+ {0x11300, 0x11303}, {0x1133C, 0x1133C}, {0x1133E, 0x11344},
+ {0x11347, 0x11348}, {0x1134B, 0x1134D}, {0x11357, 0x11357},
+ {0x11362, 0x11363}, {0x11366, 0x1136C}, {0x11370, 0x11374},
+ {0x11435, 0x11446}, {0x114B0, 0x114C3}, {0x115AF, 0x115B5},
+ {0x115B8, 0x115C0}, {0x115DC, 0x115DD}, {0x11630, 0x11640},
+ {0x116AB, 0x116B7}, {0x1171D, 0x1172B}, {0x11C2F, 0x11C36},
+ {0x11C38, 0x11C3F}, {0x11C92, 0x11CA7}, {0x11CA9, 0x11CB6},
+ {0x16AF0, 0x16AF4}, {0x16B30, 0x16B36}, {0x16F51, 0x16F7E},
+ {0x16F8F, 0x16F92}, {0x1BC9D, 0x1BC9E}, {0x1D165, 0x1D169},
+ {0x1D16D, 0x1D172}, {0x1D17B, 0x1D182}, {0x1D185, 0x1D18B},
+ {0x1D1AA, 0x1D1AD}, {0x1D242, 0x1D244}, {0x1DA00, 0x1DA36},
+ {0x1DA3B, 0x1DA6C}, {0x1DA75, 0x1DA75}, {0x1DA84, 0x1DA84},
+ {0x1DA9B, 0x1DA9F}, {0x1DAA1, 0x1DAAF}, {0x1E000, 0x1E006},
+ {0x1E008, 0x1E018}, {0x1E01B, 0x1E021}, {0x1E023, 0x1E024},
+ {0x1E026, 0x1E02A}, {0x1E8D0, 0x1E8D6}, {0x1E944, 0x1E94A},
+ {0xE0100, 0xE01EF},
+}
+
+var doublewidth = table{
+ {0x1100, 0x115F}, {0x231A, 0x231B}, {0x2329, 0x232A},
+ {0x23E9, 0x23EC}, {0x23F0, 0x23F0}, {0x23F3, 0x23F3},
+ {0x25FD, 0x25FE}, {0x2614, 0x2615}, {0x2648, 0x2653},
+ {0x267F, 0x267F}, {0x2693, 0x2693}, {0x26A1, 0x26A1},
+ {0x26AA, 0x26AB}, {0x26BD, 0x26BE}, {0x26C4, 0x26C5},
+ {0x26CE, 0x26CE}, {0x26D4, 0x26D4}, {0x26EA, 0x26EA},
+ {0x26F2, 0x26F3}, {0x26F5, 0x26F5}, {0x26FA, 0x26FA},
+ {0x26FD, 0x26FD}, {0x2705, 0x2705}, {0x270A, 0x270B},
+ {0x2728, 0x2728}, {0x274C, 0x274C}, {0x274E, 0x274E},
+ {0x2753, 0x2755}, {0x2757, 0x2757}, {0x2795, 0x2797},
+ {0x27B0, 0x27B0}, {0x27BF, 0x27BF}, {0x2B1B, 0x2B1C},
+ {0x2B50, 0x2B50}, {0x2B55, 0x2B55}, {0x2E80, 0x2E99},
+ {0x2E9B, 0x2EF3}, {0x2F00, 0x2FD5}, {0x2FF0, 0x2FFB},
+ {0x3000, 0x303E}, {0x3041, 0x3096}, {0x3099, 0x30FF},
+ {0x3105, 0x312D}, {0x3131, 0x318E}, {0x3190, 0x31BA},
+ {0x31C0, 0x31E3}, {0x31F0, 0x321E}, {0x3220, 0x3247},
+ {0x3250, 0x32FE}, {0x3300, 0x4DBF}, {0x4E00, 0xA48C},
+ {0xA490, 0xA4C6}, {0xA960, 0xA97C}, {0xAC00, 0xD7A3},
+ {0xF900, 0xFAFF}, {0xFE10, 0xFE19}, {0xFE30, 0xFE52},
+ {0xFE54, 0xFE66}, {0xFE68, 0xFE6B}, {0xFF01, 0xFF60},
+ {0xFFE0, 0xFFE6}, {0x16FE0, 0x16FE0}, {0x17000, 0x187EC},
+ {0x18800, 0x18AF2}, {0x1B000, 0x1B001}, {0x1F004, 0x1F004},
+ {0x1F0CF, 0x1F0CF}, {0x1F18E, 0x1F18E}, {0x1F191, 0x1F19A},
+ {0x1F200, 0x1F202}, {0x1F210, 0x1F23B}, {0x1F240, 0x1F248},
+ {0x1F250, 0x1F251}, {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}, {0x1F6EB, 0x1F6EC}, {0x1F6F4, 0x1F6F6},
+ {0x1F910, 0x1F91E}, {0x1F920, 0x1F927}, {0x1F930, 0x1F930},
+ {0x1F933, 0x1F93E}, {0x1F940, 0x1F94B}, {0x1F950, 0x1F95E},
+ {0x1F980, 0x1F991}, {0x1F9C0, 0x1F9C0}, {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 emoji = table{
+ {0x1F1E6, 0x1F1FF}, {0x1F321, 0x1F321}, {0x1F324, 0x1F32C},
+ {0x1F336, 0x1F336}, {0x1F37D, 0x1F37D}, {0x1F396, 0x1F397},
+ {0x1F399, 0x1F39B}, {0x1F39E, 0x1F39F}, {0x1F3CB, 0x1F3CE},
+ {0x1F3D4, 0x1F3DF}, {0x1F3F3, 0x1F3F5}, {0x1F3F7, 0x1F3F7},
+ {0x1F43F, 0x1F43F}, {0x1F441, 0x1F441}, {0x1F4FD, 0x1F4FD},
+ {0x1F549, 0x1F54A}, {0x1F56F, 0x1F570}, {0x1F573, 0x1F579},
+ {0x1F587, 0x1F587}, {0x1F58A, 0x1F58D}, {0x1F590, 0x1F590},
+ {0x1F5A5, 0x1F5A5}, {0x1F5A8, 0x1F5A8}, {0x1F5B1, 0x1F5B2},
+ {0x1F5BC, 0x1F5BC}, {0x1F5C2, 0x1F5C4}, {0x1F5D1, 0x1F5D3},
+ {0x1F5DC, 0x1F5DE}, {0x1F5E1, 0x1F5E1}, {0x1F5E3, 0x1F5E3},
+ {0x1F5E8, 0x1F5E8}, {0x1F5EF, 0x1F5EF}, {0x1F5F3, 0x1F5F3},
+ {0x1F5FA, 0x1F5FA}, {0x1F6CB, 0x1F6CF}, {0x1F6E0, 0x1F6E5},
+ {0x1F6E9, 0x1F6E9}, {0x1F6F0, 0x1F6F0}, {0x1F6F3, 0x1F6F3},
+}
+
+var notassigned = table{
+ {0x0378, 0x0379}, {0x0380, 0x0383}, {0x038B, 0x038B},
+ {0x038D, 0x038D}, {0x03A2, 0x03A2}, {0x0530, 0x0530},
+ {0x0557, 0x0558}, {0x0560, 0x0560}, {0x0588, 0x0588},
+ {0x058B, 0x058C}, {0x0590, 0x0590}, {0x05C8, 0x05CF},
+ {0x05EB, 0x05EF}, {0x05F5, 0x05FF}, {0x061D, 0x061D},
+ {0x070E, 0x070E}, {0x074B, 0x074C}, {0x07B2, 0x07BF},
+ {0x07FB, 0x07FF}, {0x082E, 0x082F}, {0x083F, 0x083F},
+ {0x085C, 0x085D}, {0x085F, 0x089F}, {0x08B5, 0x08B5},
+ {0x08BE, 0x08D3}, {0x0984, 0x0984}, {0x098D, 0x098E},
+ {0x0991, 0x0992}, {0x09A9, 0x09A9}, {0x09B1, 0x09B1},
+ {0x09B3, 0x09B5}, {0x09BA, 0x09BB}, {0x09C5, 0x09C6},
+ {0x09C9, 0x09CA}, {0x09CF, 0x09D6}, {0x09D8, 0x09DB},
+ {0x09DE, 0x09DE}, {0x09E4, 0x09E5}, {0x09FC, 0x0A00},
+ {0x0A04, 0x0A04}, {0x0A0B, 0x0A0E}, {0x0A11, 0x0A12},
+ {0x0A29, 0x0A29}, {0x0A31, 0x0A31}, {0x0A34, 0x0A34},
+ {0x0A37, 0x0A37}, {0x0A3A, 0x0A3B}, {0x0A3D, 0x0A3D},
+ {0x0A43, 0x0A46}, {0x0A49, 0x0A4A}, {0x0A4E, 0x0A50},
+ {0x0A52, 0x0A58}, {0x0A5D, 0x0A5D}, {0x0A5F, 0x0A65},
+ {0x0A76, 0x0A80}, {0x0A84, 0x0A84}, {0x0A8E, 0x0A8E},
+ {0x0A92, 0x0A92}, {0x0AA9, 0x0AA9}, {0x0AB1, 0x0AB1},
+ {0x0AB4, 0x0AB4}, {0x0ABA, 0x0ABB}, {0x0AC6, 0x0AC6},
+ {0x0ACA, 0x0ACA}, {0x0ACE, 0x0ACF}, {0x0AD1, 0x0ADF},
+ {0x0AE4, 0x0AE5}, {0x0AF2, 0x0AF8}, {0x0AFA, 0x0B00},
+ {0x0B04, 0x0B04}, {0x0B0D, 0x0B0E}, {0x0B11, 0x0B12},
+ {0x0B29, 0x0B29}, {0x0B31, 0x0B31}, {0x0B34, 0x0B34},
+ {0x0B3A, 0x0B3B}, {0x0B45, 0x0B46}, {0x0B49, 0x0B4A},
+ {0x0B4E, 0x0B55}, {0x0B58, 0x0B5B}, {0x0B5E, 0x0B5E},
+ {0x0B64, 0x0B65}, {0x0B78, 0x0B81}, {0x0B84, 0x0B84},
+ {0x0B8B, 0x0B8D}, {0x0B91, 0x0B91}, {0x0B96, 0x0B98},
+ {0x0B9B, 0x0B9B}, {0x0B9D, 0x0B9D}, {0x0BA0, 0x0BA2},
+ {0x0BA5, 0x0BA7}, {0x0BAB, 0x0BAD}, {0x0BBA, 0x0BBD},
+ {0x0BC3, 0x0BC5}, {0x0BC9, 0x0BC9}, {0x0BCE, 0x0BCF},
+ {0x0BD1, 0x0BD6}, {0x0BD8, 0x0BE5}, {0x0BFB, 0x0BFF},
+ {0x0C04, 0x0C04}, {0x0C0D, 0x0C0D}, {0x0C11, 0x0C11},
+ {0x0C29, 0x0C29}, {0x0C3A, 0x0C3C}, {0x0C45, 0x0C45},
+ {0x0C49, 0x0C49}, {0x0C4E, 0x0C54}, {0x0C57, 0x0C57},
+ {0x0C5B, 0x0C5F}, {0x0C64, 0x0C65}, {0x0C70, 0x0C77},
+ {0x0C84, 0x0C84}, {0x0C8D, 0x0C8D}, {0x0C91, 0x0C91},
+ {0x0CA9, 0x0CA9}, {0x0CB4, 0x0CB4}, {0x0CBA, 0x0CBB},
+ {0x0CC5, 0x0CC5}, {0x0CC9, 0x0CC9}, {0x0CCE, 0x0CD4},
+ {0x0CD7, 0x0CDD}, {0x0CDF, 0x0CDF}, {0x0CE4, 0x0CE5},
+ {0x0CF0, 0x0CF0}, {0x0CF3, 0x0D00}, {0x0D04, 0x0D04},
+ {0x0D0D, 0x0D0D}, {0x0D11, 0x0D11}, {0x0D3B, 0x0D3C},
+ {0x0D45, 0x0D45}, {0x0D49, 0x0D49}, {0x0D50, 0x0D53},
+ {0x0D64, 0x0D65}, {0x0D80, 0x0D81}, {0x0D84, 0x0D84},
+ {0x0D97, 0x0D99}, {0x0DB2, 0x0DB2}, {0x0DBC, 0x0DBC},
+ {0x0DBE, 0x0DBF}, {0x0DC7, 0x0DC9}, {0x0DCB, 0x0DCE},
+ {0x0DD5, 0x0DD5}, {0x0DD7, 0x0DD7}, {0x0DE0, 0x0DE5},
+ {0x0DF0, 0x0DF1}, {0x0DF5, 0x0E00}, {0x0E3B, 0x0E3E},
+ {0x0E5C, 0x0E80}, {0x0E83, 0x0E83}, {0x0E85, 0x0E86},
+ {0x0E89, 0x0E89}, {0x0E8B, 0x0E8C}, {0x0E8E, 0x0E93},
+ {0x0E98, 0x0E98}, {0x0EA0, 0x0EA0}, {0x0EA4, 0x0EA4},
+ {0x0EA6, 0x0EA6}, {0x0EA8, 0x0EA9}, {0x0EAC, 0x0EAC},
+ {0x0EBA, 0x0EBA}, {0x0EBE, 0x0EBF}, {0x0EC5, 0x0EC5},
+ {0x0EC7, 0x0EC7}, {0x0ECE, 0x0ECF}, {0x0EDA, 0x0EDB},
+ {0x0EE0, 0x0EFF}, {0x0F48, 0x0F48}, {0x0F6D, 0x0F70},
+ {0x0F98, 0x0F98}, {0x0FBD, 0x0FBD}, {0x0FCD, 0x0FCD},
+ {0x0FDB, 0x0FFF}, {0x10C6, 0x10C6}, {0x10C8, 0x10CC},
+ {0x10CE, 0x10CF}, {0x1249, 0x1249}, {0x124E, 0x124F},
+ {0x1257, 0x1257}, {0x1259, 0x1259}, {0x125E, 0x125F},
+ {0x1289, 0x1289}, {0x128E, 0x128F}, {0x12B1, 0x12B1},
+ {0x12B6, 0x12B7}, {0x12BF, 0x12BF}, {0x12C1, 0x12C1},
+ {0x12C6, 0x12C7}, {0x12D7, 0x12D7}, {0x1311, 0x1311},
+ {0x1316, 0x1317}, {0x135B, 0x135C}, {0x137D, 0x137F},
+ {0x139A, 0x139F}, {0x13F6, 0x13F7}, {0x13FE, 0x13FF},
+ {0x169D, 0x169F}, {0x16F9, 0x16FF}, {0x170D, 0x170D},
+ {0x1715, 0x171F}, {0x1737, 0x173F}, {0x1754, 0x175F},
+ {0x176D, 0x176D}, {0x1771, 0x1771}, {0x1774, 0x177F},
+ {0x17DE, 0x17DF}, {0x17EA, 0x17EF}, {0x17FA, 0x17FF},
+ {0x180F, 0x180F}, {0x181A, 0x181F}, {0x1878, 0x187F},
+ {0x18AB, 0x18AF}, {0x18F6, 0x18FF}, {0x191F, 0x191F},
+ {0x192C, 0x192F}, {0x193C, 0x193F}, {0x1941, 0x1943},
+ {0x196E, 0x196F}, {0x1975, 0x197F}, {0x19AC, 0x19AF},
+ {0x19CA, 0x19CF}, {0x19DB, 0x19DD}, {0x1A1C, 0x1A1D},
+ {0x1A5F, 0x1A5F}, {0x1A7D, 0x1A7E}, {0x1A8A, 0x1A8F},
+ {0x1A9A, 0x1A9F}, {0x1AAE, 0x1AAF}, {0x1ABF, 0x1AFF},
+ {0x1B4C, 0x1B4F}, {0x1B7D, 0x1B7F}, {0x1BF4, 0x1BFB},
+ {0x1C38, 0x1C3A}, {0x1C4A, 0x1C4C}, {0x1C89, 0x1CBF},
+ {0x1CC8, 0x1CCF}, {0x1CF7, 0x1CF7}, {0x1CFA, 0x1CFF},
+ {0x1DF6, 0x1DFA}, {0x1F16, 0x1F17}, {0x1F1E, 0x1F1F},
+ {0x1F46, 0x1F47}, {0x1F4E, 0x1F4F}, {0x1F58, 0x1F58},
+ {0x1F5A, 0x1F5A}, {0x1F5C, 0x1F5C}, {0x1F5E, 0x1F5E},
+ {0x1F7E, 0x1F7F}, {0x1FB5, 0x1FB5}, {0x1FC5, 0x1FC5},
+ {0x1FD4, 0x1FD5}, {0x1FDC, 0x1FDC}, {0x1FF0, 0x1FF1},
+ {0x1FF5, 0x1FF5}, {0x1FFF, 0x1FFF}, {0x2065, 0x2065},
+ {0x2072, 0x2073}, {0x208F, 0x208F}, {0x209D, 0x209F},
+ {0x20BF, 0x20CF}, {0x20F1, 0x20FF}, {0x218C, 0x218F},
+ {0x23FF, 0x23FF}, {0x2427, 0x243F}, {0x244B, 0x245F},
+ {0x2B74, 0x2B75}, {0x2B96, 0x2B97}, {0x2BBA, 0x2BBC},
+ {0x2BC9, 0x2BC9}, {0x2BD2, 0x2BEB}, {0x2BF0, 0x2BFF},
+ {0x2C2F, 0x2C2F}, {0x2C5F, 0x2C5F}, {0x2CF4, 0x2CF8},
+ {0x2D26, 0x2D26}, {0x2D28, 0x2D2C}, {0x2D2E, 0x2D2F},
+ {0x2D68, 0x2D6E}, {0x2D71, 0x2D7E}, {0x2D97, 0x2D9F},
+ {0x2DA7, 0x2DA7}, {0x2DAF, 0x2DAF}, {0x2DB7, 0x2DB7},
+ {0x2DBF, 0x2DBF}, {0x2DC7, 0x2DC7}, {0x2DCF, 0x2DCF},
+ {0x2DD7, 0x2DD7}, {0x2DDF, 0x2DDF}, {0x2E45, 0x2E7F},
+ {0x2E9A, 0x2E9A}, {0x2EF4, 0x2EFF}, {0x2FD6, 0x2FEF},
+ {0x2FFC, 0x2FFF}, {0x3040, 0x3040}, {0x3097, 0x3098},
+ {0x3100, 0x3104}, {0x312E, 0x3130}, {0x318F, 0x318F},
+ {0x31BB, 0x31BF}, {0x31E4, 0x31EF}, {0x321F, 0x321F},
+ {0x32FF, 0x32FF}, {0x4DB6, 0x4DBF}, {0x9FD6, 0x9FFF},
+ {0xA48D, 0xA48F}, {0xA4C7, 0xA4CF}, {0xA62C, 0xA63F},
+ {0xA6F8, 0xA6FF}, {0xA7AF, 0xA7AF}, {0xA7B8, 0xA7F6},
+ {0xA82C, 0xA82F}, {0xA83A, 0xA83F}, {0xA878, 0xA87F},
+ {0xA8C6, 0xA8CD}, {0xA8DA, 0xA8DF}, {0xA8FE, 0xA8FF},
+ {0xA954, 0xA95E}, {0xA97D, 0xA97F}, {0xA9CE, 0xA9CE},
+ {0xA9DA, 0xA9DD}, {0xA9FF, 0xA9FF}, {0xAA37, 0xAA3F},
+ {0xAA4E, 0xAA4F}, {0xAA5A, 0xAA5B}, {0xAAC3, 0xAADA},
+ {0xAAF7, 0xAB00}, {0xAB07, 0xAB08}, {0xAB0F, 0xAB10},
+ {0xAB17, 0xAB1F}, {0xAB27, 0xAB27}, {0xAB2F, 0xAB2F},
+ {0xAB66, 0xAB6F}, {0xABEE, 0xABEF}, {0xABFA, 0xABFF},
+ {0xD7A4, 0xD7AF}, {0xD7C7, 0xD7CA}, {0xD7FC, 0xD7FF},
+ {0xFA6E, 0xFA6F}, {0xFADA, 0xFAFF}, {0xFB07, 0xFB12},
+ {0xFB18, 0xFB1C}, {0xFB37, 0xFB37}, {0xFB3D, 0xFB3D},
+ {0xFB3F, 0xFB3F}, {0xFB42, 0xFB42}, {0xFB45, 0xFB45},
+ {0xFBC2, 0xFBD2}, {0xFD40, 0xFD4F}, {0xFD90, 0xFD91},
+ {0xFDC8, 0xFDEF}, {0xFDFE, 0xFDFF}, {0xFE1A, 0xFE1F},
+ {0xFE53, 0xFE53}, {0xFE67, 0xFE67}, {0xFE6C, 0xFE6F},
+ {0xFE75, 0xFE75}, {0xFEFD, 0xFEFE}, {0xFF00, 0xFF00},
+ {0xFFBF, 0xFFC1}, {0xFFC8, 0xFFC9}, {0xFFD0, 0xFFD1},
+ {0xFFD8, 0xFFD9}, {0xFFDD, 0xFFDF}, {0xFFE7, 0xFFE7},
+ {0xFFEF, 0xFFF8}, {0xFFFE, 0xFFFF}, {0x1000C, 0x1000C},
+ {0x10027, 0x10027}, {0x1003B, 0x1003B}, {0x1003E, 0x1003E},
+ {0x1004E, 0x1004F}, {0x1005E, 0x1007F}, {0x100FB, 0x100FF},
+ {0x10103, 0x10106}, {0x10134, 0x10136}, {0x1018F, 0x1018F},
+ {0x1019C, 0x1019F}, {0x101A1, 0x101CF}, {0x101FE, 0x1027F},
+ {0x1029D, 0x1029F}, {0x102D1, 0x102DF}, {0x102FC, 0x102FF},
+ {0x10324, 0x1032F}, {0x1034B, 0x1034F}, {0x1037B, 0x1037F},
+ {0x1039E, 0x1039E}, {0x103C4, 0x103C7}, {0x103D6, 0x103FF},
+ {0x1049E, 0x1049F}, {0x104AA, 0x104AF}, {0x104D4, 0x104D7},
+ {0x104FC, 0x104FF}, {0x10528, 0x1052F}, {0x10564, 0x1056E},
+ {0x10570, 0x105FF}, {0x10737, 0x1073F}, {0x10756, 0x1075F},
+ {0x10768, 0x107FF}, {0x10806, 0x10807}, {0x10809, 0x10809},
+ {0x10836, 0x10836}, {0x10839, 0x1083B}, {0x1083D, 0x1083E},
+ {0x10856, 0x10856}, {0x1089F, 0x108A6}, {0x108B0, 0x108DF},
+ {0x108F3, 0x108F3}, {0x108F6, 0x108FA}, {0x1091C, 0x1091E},
+ {0x1093A, 0x1093E}, {0x10940, 0x1097F}, {0x109B8, 0x109BB},
+ {0x109D0, 0x109D1}, {0x10A04, 0x10A04}, {0x10A07, 0x10A0B},
+ {0x10A14, 0x10A14}, {0x10A18, 0x10A18}, {0x10A34, 0x10A37},
+ {0x10A3B, 0x10A3E}, {0x10A48, 0x10A4F}, {0x10A59, 0x10A5F},
+ {0x10AA0, 0x10ABF}, {0x10AE7, 0x10AEA}, {0x10AF7, 0x10AFF},
+ {0x10B36, 0x10B38}, {0x10B56, 0x10B57}, {0x10B73, 0x10B77},
+ {0x10B92, 0x10B98}, {0x10B9D, 0x10BA8}, {0x10BB0, 0x10BFF},
+ {0x10C49, 0x10C7F}, {0x10CB3, 0x10CBF}, {0x10CF3, 0x10CF9},
+ {0x10D00, 0x10E5F}, {0x10E7F, 0x10FFF}, {0x1104E, 0x11051},
+ {0x11070, 0x1107E}, {0x110C2, 0x110CF}, {0x110E9, 0x110EF},
+ {0x110FA, 0x110FF}, {0x11135, 0x11135}, {0x11144, 0x1114F},
+ {0x11177, 0x1117F}, {0x111CE, 0x111CF}, {0x111E0, 0x111E0},
+ {0x111F5, 0x111FF}, {0x11212, 0x11212}, {0x1123F, 0x1127F},
+ {0x11287, 0x11287}, {0x11289, 0x11289}, {0x1128E, 0x1128E},
+ {0x1129E, 0x1129E}, {0x112AA, 0x112AF}, {0x112EB, 0x112EF},
+ {0x112FA, 0x112FF}, {0x11304, 0x11304}, {0x1130D, 0x1130E},
+ {0x11311, 0x11312}, {0x11329, 0x11329}, {0x11331, 0x11331},
+ {0x11334, 0x11334}, {0x1133A, 0x1133B}, {0x11345, 0x11346},
+ {0x11349, 0x1134A}, {0x1134E, 0x1134F}, {0x11351, 0x11356},
+ {0x11358, 0x1135C}, {0x11364, 0x11365}, {0x1136D, 0x1136F},
+ {0x11375, 0x113FF}, {0x1145A, 0x1145A}, {0x1145C, 0x1145C},
+ {0x1145E, 0x1147F}, {0x114C8, 0x114CF}, {0x114DA, 0x1157F},
+ {0x115B6, 0x115B7}, {0x115DE, 0x115FF}, {0x11645, 0x1164F},
+ {0x1165A, 0x1165F}, {0x1166D, 0x1167F}, {0x116B8, 0x116BF},
+ {0x116CA, 0x116FF}, {0x1171A, 0x1171C}, {0x1172C, 0x1172F},
+ {0x11740, 0x1189F}, {0x118F3, 0x118FE}, {0x11900, 0x11ABF},
+ {0x11AF9, 0x11BFF}, {0x11C09, 0x11C09}, {0x11C37, 0x11C37},
+ {0x11C46, 0x11C4F}, {0x11C6D, 0x11C6F}, {0x11C90, 0x11C91},
+ {0x11CA8, 0x11CA8}, {0x11CB7, 0x11FFF}, {0x1239A, 0x123FF},
+ {0x1246F, 0x1246F}, {0x12475, 0x1247F}, {0x12544, 0x12FFF},
+ {0x1342F, 0x143FF}, {0x14647, 0x167FF}, {0x16A39, 0x16A3F},
+ {0x16A5F, 0x16A5F}, {0x16A6A, 0x16A6D}, {0x16A70, 0x16ACF},
+ {0x16AEE, 0x16AEF}, {0x16AF6, 0x16AFF}, {0x16B46, 0x16B4F},
+ {0x16B5A, 0x16B5A}, {0x16B62, 0x16B62}, {0x16B78, 0x16B7C},
+ {0x16B90, 0x16EFF}, {0x16F45, 0x16F4F}, {0x16F7F, 0x16F8E},
+ {0x16FA0, 0x16FDF}, {0x16FE1, 0x16FFF}, {0x187ED, 0x187FF},
+ {0x18AF3, 0x1AFFF}, {0x1B002, 0x1BBFF}, {0x1BC6B, 0x1BC6F},
+ {0x1BC7D, 0x1BC7F}, {0x1BC89, 0x1BC8F}, {0x1BC9A, 0x1BC9B},
+ {0x1BCA4, 0x1CFFF}, {0x1D0F6, 0x1D0FF}, {0x1D127, 0x1D128},
+ {0x1D1E9, 0x1D1FF}, {0x1D246, 0x1D2FF}, {0x1D357, 0x1D35F},
+ {0x1D372, 0x1D3FF}, {0x1D455, 0x1D455}, {0x1D49D, 0x1D49D},
+ {0x1D4A0, 0x1D4A1}, {0x1D4A3, 0x1D4A4}, {0x1D4A7, 0x1D4A8},
+ {0x1D4AD, 0x1D4AD}, {0x1D4BA, 0x1D4BA}, {0x1D4BC, 0x1D4BC},
+ {0x1D4C4, 0x1D4C4}, {0x1D506, 0x1D506}, {0x1D50B, 0x1D50C},
+ {0x1D515, 0x1D515}, {0x1D51D, 0x1D51D}, {0x1D53A, 0x1D53A},
+ {0x1D53F, 0x1D53F}, {0x1D545, 0x1D545}, {0x1D547, 0x1D549},
+ {0x1D551, 0x1D551}, {0x1D6A6, 0x1D6A7}, {0x1D7CC, 0x1D7CD},
+ {0x1DA8C, 0x1DA9A}, {0x1DAA0, 0x1DAA0}, {0x1DAB0, 0x1DFFF},
+ {0x1E007, 0x1E007}, {0x1E019, 0x1E01A}, {0x1E022, 0x1E022},
+ {0x1E025, 0x1E025}, {0x1E02B, 0x1E7FF}, {0x1E8C5, 0x1E8C6},
+ {0x1E8D7, 0x1E8FF}, {0x1E94B, 0x1E94F}, {0x1E95A, 0x1E95D},
+ {0x1E960, 0x1EDFF}, {0x1EE04, 0x1EE04}, {0x1EE20, 0x1EE20},
+ {0x1EE23, 0x1EE23}, {0x1EE25, 0x1EE26}, {0x1EE28, 0x1EE28},
+ {0x1EE33, 0x1EE33}, {0x1EE38, 0x1EE38}, {0x1EE3A, 0x1EE3A},
+ {0x1EE3C, 0x1EE41}, {0x1EE43, 0x1EE46}, {0x1EE48, 0x1EE48},
+ {0x1EE4A, 0x1EE4A}, {0x1EE4C, 0x1EE4C}, {0x1EE50, 0x1EE50},
+ {0x1EE53, 0x1EE53}, {0x1EE55, 0x1EE56}, {0x1EE58, 0x1EE58},
+ {0x1EE5A, 0x1EE5A}, {0x1EE5C, 0x1EE5C}, {0x1EE5E, 0x1EE5E},
+ {0x1EE60, 0x1EE60}, {0x1EE63, 0x1EE63}, {0x1EE65, 0x1EE66},
+ {0x1EE6B, 0x1EE6B}, {0x1EE73, 0x1EE73}, {0x1EE78, 0x1EE78},
+ {0x1EE7D, 0x1EE7D}, {0x1EE7F, 0x1EE7F}, {0x1EE8A, 0x1EE8A},
+ {0x1EE9C, 0x1EEA0}, {0x1EEA4, 0x1EEA4}, {0x1EEAA, 0x1EEAA},
+ {0x1EEBC, 0x1EEEF}, {0x1EEF2, 0x1EFFF}, {0x1F02C, 0x1F02F},
+ {0x1F094, 0x1F09F}, {0x1F0AF, 0x1F0B0}, {0x1F0C0, 0x1F0C0},
+ {0x1F0D0, 0x1F0D0}, {0x1F0F6, 0x1F0FF}, {0x1F10D, 0x1F10F},
+ {0x1F12F, 0x1F12F}, {0x1F16C, 0x1F16F}, {0x1F1AD, 0x1F1E5},
+ {0x1F203, 0x1F20F}, {0x1F23C, 0x1F23F}, {0x1F249, 0x1F24F},
+ {0x1F252, 0x1F2FF}, {0x1F6D3, 0x1F6DF}, {0x1F6ED, 0x1F6EF},
+ {0x1F6F7, 0x1F6FF}, {0x1F774, 0x1F77F}, {0x1F7D5, 0x1F7FF},
+ {0x1F80C, 0x1F80F}, {0x1F848, 0x1F84F}, {0x1F85A, 0x1F85F},
+ {0x1F888, 0x1F88F}, {0x1F8AE, 0x1F90F}, {0x1F91F, 0x1F91F},
+ {0x1F928, 0x1F92F}, {0x1F931, 0x1F932}, {0x1F93F, 0x1F93F},
+ {0x1F94C, 0x1F94F}, {0x1F95F, 0x1F97F}, {0x1F992, 0x1F9BF},
+ {0x1F9C1, 0x1FFFF}, {0x2A6D7, 0x2A6FF}, {0x2B735, 0x2B73F},
+ {0x2B81E, 0x2B81F}, {0x2CEA2, 0x2F7FF}, {0x2FA1E, 0xE0000},
+ {0xE0002, 0xE001F}, {0xE0080, 0xE00FF}, {0xE01F0, 0xEFFFF},
+ {0xFFFFE, 0xFFFFF},
+}
+
+var neutral = table{
+ {0x0000, 0x001F}, {0x007F, 0x007F}, {0x0080, 0x009F},
+ {0x00A0, 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, 0x00FF},
+ {0x0100, 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, 0x017F}, {0x0180, 0x01BA}, {0x01BB, 0x01BB},
+ {0x01BC, 0x01BF}, {0x01C0, 0x01C3}, {0x01C4, 0x01CD},
+ {0x01CF, 0x01CF}, {0x01D1, 0x01D1}, {0x01D3, 0x01D3},
+ {0x01D5, 0x01D5}, {0x01D7, 0x01D7}, {0x01D9, 0x01D9},
+ {0x01DB, 0x01DB}, {0x01DD, 0x024F}, {0x0250, 0x0250},
+ {0x0252, 0x0260}, {0x0262, 0x0293}, {0x0294, 0x0294},
+ {0x0295, 0x02AF}, {0x02B0, 0x02C1}, {0x02C2, 0x02C3},
+ {0x02C5, 0x02C5}, {0x02C6, 0x02C6}, {0x02C8, 0x02C8},
+ {0x02CC, 0x02CC}, {0x02CE, 0x02CF}, {0x02D1, 0x02D1},
+ {0x02D2, 0x02D7}, {0x02DC, 0x02DC}, {0x02DE, 0x02DE},
+ {0x02E0, 0x02E4}, {0x02E5, 0x02EB}, {0x02EC, 0x02EC},
+ {0x02ED, 0x02ED}, {0x02EE, 0x02EE}, {0x02EF, 0x02FF},
+ {0x0370, 0x0373}, {0x0374, 0x0374}, {0x0375, 0x0375},
+ {0x0376, 0x0377}, {0x037A, 0x037A}, {0x037B, 0x037D},
+ {0x037E, 0x037E}, {0x037F, 0x037F}, {0x0384, 0x0385},
+ {0x0386, 0x0386}, {0x0387, 0x0387}, {0x0388, 0x038A},
+ {0x038C, 0x038C}, {0x038E, 0x0390}, {0x03AA, 0x03B0},
+ {0x03C2, 0x03C2}, {0x03CA, 0x03F5}, {0x03F6, 0x03F6},
+ {0x03F7, 0x03FF}, {0x0400, 0x0400}, {0x0402, 0x040F},
+ {0x0450, 0x0450}, {0x0452, 0x0481}, {0x0482, 0x0482},
+ {0x0483, 0x0487}, {0x0488, 0x0489}, {0x048A, 0x04FF},
+ {0x0500, 0x052F}, {0x0531, 0x0556}, {0x0559, 0x0559},
+ {0x055A, 0x055F}, {0x0561, 0x0587}, {0x0589, 0x0589},
+ {0x058A, 0x058A}, {0x058D, 0x058E}, {0x058F, 0x058F},
+ {0x0591, 0x05BD}, {0x05BE, 0x05BE}, {0x05BF, 0x05BF},
+ {0x05C0, 0x05C0}, {0x05C1, 0x05C2}, {0x05C3, 0x05C3},
+ {0x05C4, 0x05C5}, {0x05C6, 0x05C6}, {0x05C7, 0x05C7},
+ {0x05D0, 0x05EA}, {0x05F0, 0x05F2}, {0x05F3, 0x05F4},
+ {0x0600, 0x0605}, {0x0606, 0x0608}, {0x0609, 0x060A},
+ {0x060B, 0x060B}, {0x060C, 0x060D}, {0x060E, 0x060F},
+ {0x0610, 0x061A}, {0x061B, 0x061B}, {0x061C, 0x061C},
+ {0x061E, 0x061F}, {0x0620, 0x063F}, {0x0640, 0x0640},
+ {0x0641, 0x064A}, {0x064B, 0x065F}, {0x0660, 0x0669},
+ {0x066A, 0x066D}, {0x066E, 0x066F}, {0x0670, 0x0670},
+ {0x0671, 0x06D3}, {0x06D4, 0x06D4}, {0x06D5, 0x06D5},
+ {0x06D6, 0x06DC}, {0x06DD, 0x06DD}, {0x06DE, 0x06DE},
+ {0x06DF, 0x06E4}, {0x06E5, 0x06E6}, {0x06E7, 0x06E8},
+ {0x06E9, 0x06E9}, {0x06EA, 0x06ED}, {0x06EE, 0x06EF},
+ {0x06F0, 0x06F9}, {0x06FA, 0x06FC}, {0x06FD, 0x06FE},
+ {0x06FF, 0x06FF}, {0x0700, 0x070D}, {0x070F, 0x070F},
+ {0x0710, 0x0710}, {0x0711, 0x0711}, {0x0712, 0x072F},
+ {0x0730, 0x074A}, {0x074D, 0x074F}, {0x0750, 0x077F},
+ {0x0780, 0x07A5}, {0x07A6, 0x07B0}, {0x07B1, 0x07B1},
+ {0x07C0, 0x07C9}, {0x07CA, 0x07EA}, {0x07EB, 0x07F3},
+ {0x07F4, 0x07F5}, {0x07F6, 0x07F6}, {0x07F7, 0x07F9},
+ {0x07FA, 0x07FA}, {0x0800, 0x0815}, {0x0816, 0x0819},
+ {0x081A, 0x081A}, {0x081B, 0x0823}, {0x0824, 0x0824},
+ {0x0825, 0x0827}, {0x0828, 0x0828}, {0x0829, 0x082D},
+ {0x0830, 0x083E}, {0x0840, 0x0858}, {0x0859, 0x085B},
+ {0x085E, 0x085E}, {0x08A0, 0x08B4}, {0x08B6, 0x08BD},
+ {0x08D4, 0x08E1}, {0x08E2, 0x08E2}, {0x08E3, 0x08FF},
+ {0x0900, 0x0902}, {0x0903, 0x0903}, {0x0904, 0x0939},
+ {0x093A, 0x093A}, {0x093B, 0x093B}, {0x093C, 0x093C},
+ {0x093D, 0x093D}, {0x093E, 0x0940}, {0x0941, 0x0948},
+ {0x0949, 0x094C}, {0x094D, 0x094D}, {0x094E, 0x094F},
+ {0x0950, 0x0950}, {0x0951, 0x0957}, {0x0958, 0x0961},
+ {0x0962, 0x0963}, {0x0964, 0x0965}, {0x0966, 0x096F},
+ {0x0970, 0x0970}, {0x0971, 0x0971}, {0x0972, 0x097F},
+ {0x0980, 0x0980}, {0x0981, 0x0981}, {0x0982, 0x0983},
+ {0x0985, 0x098C}, {0x098F, 0x0990}, {0x0993, 0x09A8},
+ {0x09AA, 0x09B0}, {0x09B2, 0x09B2}, {0x09B6, 0x09B9},
+ {0x09BC, 0x09BC}, {0x09BD, 0x09BD}, {0x09BE, 0x09C0},
+ {0x09C1, 0x09C4}, {0x09C7, 0x09C8}, {0x09CB, 0x09CC},
+ {0x09CD, 0x09CD}, {0x09CE, 0x09CE}, {0x09D7, 0x09D7},
+ {0x09DC, 0x09DD}, {0x09DF, 0x09E1}, {0x09E2, 0x09E3},
+ {0x09E6, 0x09EF}, {0x09F0, 0x09F1}, {0x09F2, 0x09F3},
+ {0x09F4, 0x09F9}, {0x09FA, 0x09FA}, {0x09FB, 0x09FB},
+ {0x0A01, 0x0A02}, {0x0A03, 0x0A03}, {0x0A05, 0x0A0A},
+ {0x0A0F, 0x0A10}, {0x0A13, 0x0A28}, {0x0A2A, 0x0A30},
+ {0x0A32, 0x0A33}, {0x0A35, 0x0A36}, {0x0A38, 0x0A39},
+ {0x0A3C, 0x0A3C}, {0x0A3E, 0x0A40}, {0x0A41, 0x0A42},
+ {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A51, 0x0A51},
+ {0x0A59, 0x0A5C}, {0x0A5E, 0x0A5E}, {0x0A66, 0x0A6F},
+ {0x0A70, 0x0A71}, {0x0A72, 0x0A74}, {0x0A75, 0x0A75},
+ {0x0A81, 0x0A82}, {0x0A83, 0x0A83}, {0x0A85, 0x0A8D},
+ {0x0A8F, 0x0A91}, {0x0A93, 0x0AA8}, {0x0AAA, 0x0AB0},
+ {0x0AB2, 0x0AB3}, {0x0AB5, 0x0AB9}, {0x0ABC, 0x0ABC},
+ {0x0ABD, 0x0ABD}, {0x0ABE, 0x0AC0}, {0x0AC1, 0x0AC5},
+ {0x0AC7, 0x0AC8}, {0x0AC9, 0x0AC9}, {0x0ACB, 0x0ACC},
+ {0x0ACD, 0x0ACD}, {0x0AD0, 0x0AD0}, {0x0AE0, 0x0AE1},
+ {0x0AE2, 0x0AE3}, {0x0AE6, 0x0AEF}, {0x0AF0, 0x0AF0},
+ {0x0AF1, 0x0AF1}, {0x0AF9, 0x0AF9}, {0x0B01, 0x0B01},
+ {0x0B02, 0x0B03}, {0x0B05, 0x0B0C}, {0x0B0F, 0x0B10},
+ {0x0B13, 0x0B28}, {0x0B2A, 0x0B30}, {0x0B32, 0x0B33},
+ {0x0B35, 0x0B39}, {0x0B3C, 0x0B3C}, {0x0B3D, 0x0B3D},
+ {0x0B3E, 0x0B3E}, {0x0B3F, 0x0B3F}, {0x0B40, 0x0B40},
+ {0x0B41, 0x0B44}, {0x0B47, 0x0B48}, {0x0B4B, 0x0B4C},
+ {0x0B4D, 0x0B4D}, {0x0B56, 0x0B56}, {0x0B57, 0x0B57},
+ {0x0B5C, 0x0B5D}, {0x0B5F, 0x0B61}, {0x0B62, 0x0B63},
+ {0x0B66, 0x0B6F}, {0x0B70, 0x0B70}, {0x0B71, 0x0B71},
+ {0x0B72, 0x0B77}, {0x0B82, 0x0B82}, {0x0B83, 0x0B83},
+ {0x0B85, 0x0B8A}, {0x0B8E, 0x0B90}, {0x0B92, 0x0B95},
+ {0x0B99, 0x0B9A}, {0x0B9C, 0x0B9C}, {0x0B9E, 0x0B9F},
+ {0x0BA3, 0x0BA4}, {0x0BA8, 0x0BAA}, {0x0BAE, 0x0BB9},
+ {0x0BBE, 0x0BBF}, {0x0BC0, 0x0BC0}, {0x0BC1, 0x0BC2},
+ {0x0BC6, 0x0BC8}, {0x0BCA, 0x0BCC}, {0x0BCD, 0x0BCD},
+ {0x0BD0, 0x0BD0}, {0x0BD7, 0x0BD7}, {0x0BE6, 0x0BEF},
+ {0x0BF0, 0x0BF2}, {0x0BF3, 0x0BF8}, {0x0BF9, 0x0BF9},
+ {0x0BFA, 0x0BFA}, {0x0C00, 0x0C00}, {0x0C01, 0x0C03},
+ {0x0C05, 0x0C0C}, {0x0C0E, 0x0C10}, {0x0C12, 0x0C28},
+ {0x0C2A, 0x0C39}, {0x0C3D, 0x0C3D}, {0x0C3E, 0x0C40},
+ {0x0C41, 0x0C44}, {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D},
+ {0x0C55, 0x0C56}, {0x0C58, 0x0C5A}, {0x0C60, 0x0C61},
+ {0x0C62, 0x0C63}, {0x0C66, 0x0C6F}, {0x0C78, 0x0C7E},
+ {0x0C7F, 0x0C7F}, {0x0C80, 0x0C80}, {0x0C81, 0x0C81},
+ {0x0C82, 0x0C83}, {0x0C85, 0x0C8C}, {0x0C8E, 0x0C90},
+ {0x0C92, 0x0CA8}, {0x0CAA, 0x0CB3}, {0x0CB5, 0x0CB9},
+ {0x0CBC, 0x0CBC}, {0x0CBD, 0x0CBD}, {0x0CBE, 0x0CBE},
+ {0x0CBF, 0x0CBF}, {0x0CC0, 0x0CC4}, {0x0CC6, 0x0CC6},
+ {0x0CC7, 0x0CC8}, {0x0CCA, 0x0CCB}, {0x0CCC, 0x0CCD},
+ {0x0CD5, 0x0CD6}, {0x0CDE, 0x0CDE}, {0x0CE0, 0x0CE1},
+ {0x0CE2, 0x0CE3}, {0x0CE6, 0x0CEF}, {0x0CF1, 0x0CF2},
+ {0x0D01, 0x0D01}, {0x0D02, 0x0D03}, {0x0D05, 0x0D0C},
+ {0x0D0E, 0x0D10}, {0x0D12, 0x0D3A}, {0x0D3D, 0x0D3D},
+ {0x0D3E, 0x0D40}, {0x0D41, 0x0D44}, {0x0D46, 0x0D48},
+ {0x0D4A, 0x0D4C}, {0x0D4D, 0x0D4D}, {0x0D4E, 0x0D4E},
+ {0x0D4F, 0x0D4F}, {0x0D54, 0x0D56}, {0x0D57, 0x0D57},
+ {0x0D58, 0x0D5E}, {0x0D5F, 0x0D61}, {0x0D62, 0x0D63},
+ {0x0D66, 0x0D6F}, {0x0D70, 0x0D78}, {0x0D79, 0x0D79},
+ {0x0D7A, 0x0D7F}, {0x0D82, 0x0D83}, {0x0D85, 0x0D96},
+ {0x0D9A, 0x0DB1}, {0x0DB3, 0x0DBB}, {0x0DBD, 0x0DBD},
+ {0x0DC0, 0x0DC6}, {0x0DCA, 0x0DCA}, {0x0DCF, 0x0DD1},
+ {0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6}, {0x0DD8, 0x0DDF},
+ {0x0DE6, 0x0DEF}, {0x0DF2, 0x0DF3}, {0x0DF4, 0x0DF4},
+ {0x0E01, 0x0E30}, {0x0E31, 0x0E31}, {0x0E32, 0x0E33},
+ {0x0E34, 0x0E3A}, {0x0E3F, 0x0E3F}, {0x0E40, 0x0E45},
+ {0x0E46, 0x0E46}, {0x0E47, 0x0E4E}, {0x0E4F, 0x0E4F},
+ {0x0E50, 0x0E59}, {0x0E5A, 0x0E5B}, {0x0E81, 0x0E82},
+ {0x0E84, 0x0E84}, {0x0E87, 0x0E88}, {0x0E8A, 0x0E8A},
+ {0x0E8D, 0x0E8D}, {0x0E94, 0x0E97}, {0x0E99, 0x0E9F},
+ {0x0EA1, 0x0EA3}, {0x0EA5, 0x0EA5}, {0x0EA7, 0x0EA7},
+ {0x0EAA, 0x0EAB}, {0x0EAD, 0x0EB0}, {0x0EB1, 0x0EB1},
+ {0x0EB2, 0x0EB3}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC},
+ {0x0EBD, 0x0EBD}, {0x0EC0, 0x0EC4}, {0x0EC6, 0x0EC6},
+ {0x0EC8, 0x0ECD}, {0x0ED0, 0x0ED9}, {0x0EDC, 0x0EDF},
+ {0x0F00, 0x0F00}, {0x0F01, 0x0F03}, {0x0F04, 0x0F12},
+ {0x0F13, 0x0F13}, {0x0F14, 0x0F14}, {0x0F15, 0x0F17},
+ {0x0F18, 0x0F19}, {0x0F1A, 0x0F1F}, {0x0F20, 0x0F29},
+ {0x0F2A, 0x0F33}, {0x0F34, 0x0F34}, {0x0F35, 0x0F35},
+ {0x0F36, 0x0F36}, {0x0F37, 0x0F37}, {0x0F38, 0x0F38},
+ {0x0F39, 0x0F39}, {0x0F3A, 0x0F3A}, {0x0F3B, 0x0F3B},
+ {0x0F3C, 0x0F3C}, {0x0F3D, 0x0F3D}, {0x0F3E, 0x0F3F},
+ {0x0F40, 0x0F47}, {0x0F49, 0x0F6C}, {0x0F71, 0x0F7E},
+ {0x0F7F, 0x0F7F}, {0x0F80, 0x0F84}, {0x0F85, 0x0F85},
+ {0x0F86, 0x0F87}, {0x0F88, 0x0F8C}, {0x0F8D, 0x0F97},
+ {0x0F99, 0x0FBC}, {0x0FBE, 0x0FC5}, {0x0FC6, 0x0FC6},
+ {0x0FC7, 0x0FCC}, {0x0FCE, 0x0FCF}, {0x0FD0, 0x0FD4},
+ {0x0FD5, 0x0FD8}, {0x0FD9, 0x0FDA}, {0x1000, 0x102A},
+ {0x102B, 0x102C}, {0x102D, 0x1030}, {0x1031, 0x1031},
+ {0x1032, 0x1037}, {0x1038, 0x1038}, {0x1039, 0x103A},
+ {0x103B, 0x103C}, {0x103D, 0x103E}, {0x103F, 0x103F},
+ {0x1040, 0x1049}, {0x104A, 0x104F}, {0x1050, 0x1055},
+ {0x1056, 0x1057}, {0x1058, 0x1059}, {0x105A, 0x105D},
+ {0x105E, 0x1060}, {0x1061, 0x1061}, {0x1062, 0x1064},
+ {0x1065, 0x1066}, {0x1067, 0x106D}, {0x106E, 0x1070},
+ {0x1071, 0x1074}, {0x1075, 0x1081}, {0x1082, 0x1082},
+ {0x1083, 0x1084}, {0x1085, 0x1086}, {0x1087, 0x108C},
+ {0x108D, 0x108D}, {0x108E, 0x108E}, {0x108F, 0x108F},
+ {0x1090, 0x1099}, {0x109A, 0x109C}, {0x109D, 0x109D},
+ {0x109E, 0x109F}, {0x10A0, 0x10C5}, {0x10C7, 0x10C7},
+ {0x10CD, 0x10CD}, {0x10D0, 0x10FA}, {0x10FB, 0x10FB},
+ {0x10FC, 0x10FC}, {0x10FD, 0x10FF}, {0x1160, 0x11FF},
+ {0x1200, 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, 0x135F}, {0x1360, 0x1368},
+ {0x1369, 0x137C}, {0x1380, 0x138F}, {0x1390, 0x1399},
+ {0x13A0, 0x13F5}, {0x13F8, 0x13FD}, {0x1400, 0x1400},
+ {0x1401, 0x166C}, {0x166D, 0x166E}, {0x166F, 0x167F},
+ {0x1680, 0x1680}, {0x1681, 0x169A}, {0x169B, 0x169B},
+ {0x169C, 0x169C}, {0x16A0, 0x16EA}, {0x16EB, 0x16ED},
+ {0x16EE, 0x16F0}, {0x16F1, 0x16F8}, {0x1700, 0x170C},
+ {0x170E, 0x1711}, {0x1712, 0x1714}, {0x1720, 0x1731},
+ {0x1732, 0x1734}, {0x1735, 0x1736}, {0x1740, 0x1751},
+ {0x1752, 0x1753}, {0x1760, 0x176C}, {0x176E, 0x1770},
+ {0x1772, 0x1773}, {0x1780, 0x17B3}, {0x17B4, 0x17B5},
+ {0x17B6, 0x17B6}, {0x17B7, 0x17BD}, {0x17BE, 0x17C5},
+ {0x17C6, 0x17C6}, {0x17C7, 0x17C8}, {0x17C9, 0x17D3},
+ {0x17D4, 0x17D6}, {0x17D7, 0x17D7}, {0x17D8, 0x17DA},
+ {0x17DB, 0x17DB}, {0x17DC, 0x17DC}, {0x17DD, 0x17DD},
+ {0x17E0, 0x17E9}, {0x17F0, 0x17F9}, {0x1800, 0x1805},
+ {0x1806, 0x1806}, {0x1807, 0x180A}, {0x180B, 0x180D},
+ {0x180E, 0x180E}, {0x1810, 0x1819}, {0x1820, 0x1842},
+ {0x1843, 0x1843}, {0x1844, 0x1877}, {0x1880, 0x1884},
+ {0x1885, 0x1886}, {0x1887, 0x18A8}, {0x18A9, 0x18A9},
+ {0x18AA, 0x18AA}, {0x18B0, 0x18F5}, {0x1900, 0x191E},
+ {0x1920, 0x1922}, {0x1923, 0x1926}, {0x1927, 0x1928},
+ {0x1929, 0x192B}, {0x1930, 0x1931}, {0x1932, 0x1932},
+ {0x1933, 0x1938}, {0x1939, 0x193B}, {0x1940, 0x1940},
+ {0x1944, 0x1945}, {0x1946, 0x194F}, {0x1950, 0x196D},
+ {0x1970, 0x1974}, {0x1980, 0x19AB}, {0x19B0, 0x19C9},
+ {0x19D0, 0x19D9}, {0x19DA, 0x19DA}, {0x19DE, 0x19DF},
+ {0x19E0, 0x19FF}, {0x1A00, 0x1A16}, {0x1A17, 0x1A18},
+ {0x1A19, 0x1A1A}, {0x1A1B, 0x1A1B}, {0x1A1E, 0x1A1F},
+ {0x1A20, 0x1A54}, {0x1A55, 0x1A55}, {0x1A56, 0x1A56},
+ {0x1A57, 0x1A57}, {0x1A58, 0x1A5E}, {0x1A60, 0x1A60},
+ {0x1A61, 0x1A61}, {0x1A62, 0x1A62}, {0x1A63, 0x1A64},
+ {0x1A65, 0x1A6C}, {0x1A6D, 0x1A72}, {0x1A73, 0x1A7C},
+ {0x1A7F, 0x1A7F}, {0x1A80, 0x1A89}, {0x1A90, 0x1A99},
+ {0x1AA0, 0x1AA6}, {0x1AA7, 0x1AA7}, {0x1AA8, 0x1AAD},
+ {0x1AB0, 0x1ABD}, {0x1ABE, 0x1ABE}, {0x1B00, 0x1B03},
+ {0x1B04, 0x1B04}, {0x1B05, 0x1B33}, {0x1B34, 0x1B34},
+ {0x1B35, 0x1B35}, {0x1B36, 0x1B3A}, {0x1B3B, 0x1B3B},
+ {0x1B3C, 0x1B3C}, {0x1B3D, 0x1B41}, {0x1B42, 0x1B42},
+ {0x1B43, 0x1B44}, {0x1B45, 0x1B4B}, {0x1B50, 0x1B59},
+ {0x1B5A, 0x1B60}, {0x1B61, 0x1B6A}, {0x1B6B, 0x1B73},
+ {0x1B74, 0x1B7C}, {0x1B80, 0x1B81}, {0x1B82, 0x1B82},
+ {0x1B83, 0x1BA0}, {0x1BA1, 0x1BA1}, {0x1BA2, 0x1BA5},
+ {0x1BA6, 0x1BA7}, {0x1BA8, 0x1BA9}, {0x1BAA, 0x1BAA},
+ {0x1BAB, 0x1BAD}, {0x1BAE, 0x1BAF}, {0x1BB0, 0x1BB9},
+ {0x1BBA, 0x1BBF}, {0x1BC0, 0x1BE5}, {0x1BE6, 0x1BE6},
+ {0x1BE7, 0x1BE7}, {0x1BE8, 0x1BE9}, {0x1BEA, 0x1BEC},
+ {0x1BED, 0x1BED}, {0x1BEE, 0x1BEE}, {0x1BEF, 0x1BF1},
+ {0x1BF2, 0x1BF3}, {0x1BFC, 0x1BFF}, {0x1C00, 0x1C23},
+ {0x1C24, 0x1C2B}, {0x1C2C, 0x1C33}, {0x1C34, 0x1C35},
+ {0x1C36, 0x1C37}, {0x1C3B, 0x1C3F}, {0x1C40, 0x1C49},
+ {0x1C4D, 0x1C4F}, {0x1C50, 0x1C59}, {0x1C5A, 0x1C77},
+ {0x1C78, 0x1C7D}, {0x1C7E, 0x1C7F}, {0x1C80, 0x1C88},
+ {0x1CC0, 0x1CC7}, {0x1CD0, 0x1CD2}, {0x1CD3, 0x1CD3},
+ {0x1CD4, 0x1CE0}, {0x1CE1, 0x1CE1}, {0x1CE2, 0x1CE8},
+ {0x1CE9, 0x1CEC}, {0x1CED, 0x1CED}, {0x1CEE, 0x1CF1},
+ {0x1CF2, 0x1CF3}, {0x1CF4, 0x1CF4}, {0x1CF5, 0x1CF6},
+ {0x1CF8, 0x1CF9}, {0x1D00, 0x1D2B}, {0x1D2C, 0x1D6A},
+ {0x1D6B, 0x1D77}, {0x1D78, 0x1D78}, {0x1D79, 0x1D7F},
+ {0x1D80, 0x1D9A}, {0x1D9B, 0x1DBF}, {0x1DC0, 0x1DF5},
+ {0x1DFB, 0x1DFF}, {0x1E00, 0x1EFF}, {0x1F00, 0x1F15},
+ {0x1F18, 0x1F1D}, {0x1F20, 0x1F45}, {0x1F48, 0x1F4D},
+ {0x1F50, 0x1F57}, {0x1F59, 0x1F59}, {0x1F5B, 0x1F5B},
+ {0x1F5D, 0x1F5D}, {0x1F5F, 0x1F7D}, {0x1F80, 0x1FB4},
+ {0x1FB6, 0x1FBC}, {0x1FBD, 0x1FBD}, {0x1FBE, 0x1FBE},
+ {0x1FBF, 0x1FC1}, {0x1FC2, 0x1FC4}, {0x1FC6, 0x1FCC},
+ {0x1FCD, 0x1FCF}, {0x1FD0, 0x1FD3}, {0x1FD6, 0x1FDB},
+ {0x1FDD, 0x1FDF}, {0x1FE0, 0x1FEC}, {0x1FED, 0x1FEF},
+ {0x1FF2, 0x1FF4}, {0x1FF6, 0x1FFC}, {0x1FFD, 0x1FFE},
+ {0x2000, 0x200A}, {0x200B, 0x200F}, {0x2011, 0x2012},
+ {0x2017, 0x2017}, {0x201A, 0x201A}, {0x201B, 0x201B},
+ {0x201E, 0x201E}, {0x201F, 0x201F}, {0x2023, 0x2023},
+ {0x2028, 0x2028}, {0x2029, 0x2029}, {0x202A, 0x202E},
+ {0x202F, 0x202F}, {0x2031, 0x2031}, {0x2034, 0x2034},
+ {0x2036, 0x2038}, {0x2039, 0x2039}, {0x203A, 0x203A},
+ {0x203C, 0x203D}, {0x203F, 0x2040}, {0x2041, 0x2043},
+ {0x2044, 0x2044}, {0x2045, 0x2045}, {0x2046, 0x2046},
+ {0x2047, 0x2051}, {0x2052, 0x2052}, {0x2053, 0x2053},
+ {0x2054, 0x2054}, {0x2055, 0x205E}, {0x205F, 0x205F},
+ {0x2060, 0x2064}, {0x2066, 0x206F}, {0x2070, 0x2070},
+ {0x2071, 0x2071}, {0x2075, 0x2079}, {0x207A, 0x207C},
+ {0x207D, 0x207D}, {0x207E, 0x207E}, {0x2080, 0x2080},
+ {0x2085, 0x2089}, {0x208A, 0x208C}, {0x208D, 0x208D},
+ {0x208E, 0x208E}, {0x2090, 0x209C}, {0x20A0, 0x20A8},
+ {0x20AA, 0x20AB}, {0x20AD, 0x20BE}, {0x20D0, 0x20DC},
+ {0x20DD, 0x20E0}, {0x20E1, 0x20E1}, {0x20E2, 0x20E4},
+ {0x20E5, 0x20F0}, {0x2100, 0x2101}, {0x2102, 0x2102},
+ {0x2104, 0x2104}, {0x2106, 0x2106}, {0x2107, 0x2107},
+ {0x2108, 0x2108}, {0x210A, 0x2112}, {0x2114, 0x2114},
+ {0x2115, 0x2115}, {0x2117, 0x2117}, {0x2118, 0x2118},
+ {0x2119, 0x211D}, {0x211E, 0x2120}, {0x2123, 0x2123},
+ {0x2124, 0x2124}, {0x2125, 0x2125}, {0x2127, 0x2127},
+ {0x2128, 0x2128}, {0x2129, 0x2129}, {0x212A, 0x212A},
+ {0x212C, 0x212D}, {0x212E, 0x212E}, {0x212F, 0x2134},
+ {0x2135, 0x2138}, {0x2139, 0x2139}, {0x213A, 0x213B},
+ {0x213C, 0x213F}, {0x2140, 0x2144}, {0x2145, 0x2149},
+ {0x214A, 0x214A}, {0x214B, 0x214B}, {0x214C, 0x214D},
+ {0x214E, 0x214E}, {0x214F, 0x214F}, {0x2150, 0x2152},
+ {0x2155, 0x215A}, {0x215F, 0x215F}, {0x216C, 0x216F},
+ {0x217A, 0x2182}, {0x2183, 0x2184}, {0x2185, 0x2188},
+ {0x218A, 0x218B}, {0x219A, 0x219B}, {0x219C, 0x219F},
+ {0x21A0, 0x21A0}, {0x21A1, 0x21A2}, {0x21A3, 0x21A3},
+ {0x21A4, 0x21A5}, {0x21A6, 0x21A6}, {0x21A7, 0x21AD},
+ {0x21AE, 0x21AE}, {0x21AF, 0x21B7}, {0x21BA, 0x21CD},
+ {0x21CE, 0x21CF}, {0x21D0, 0x21D1}, {0x21D3, 0x21D3},
+ {0x21D5, 0x21E6}, {0x21E8, 0x21F3}, {0x21F4, 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, 0x22FF}, {0x2300, 0x2307}, {0x2308, 0x2308},
+ {0x2309, 0x2309}, {0x230A, 0x230A}, {0x230B, 0x230B},
+ {0x230C, 0x2311}, {0x2313, 0x2319}, {0x231C, 0x231F},
+ {0x2320, 0x2321}, {0x2322, 0x2328}, {0x232B, 0x237B},
+ {0x237C, 0x237C}, {0x237D, 0x239A}, {0x239B, 0x23B3},
+ {0x23B4, 0x23DB}, {0x23DC, 0x23E1}, {0x23E2, 0x23E8},
+ {0x23ED, 0x23EF}, {0x23F1, 0x23F2}, {0x23F4, 0x23FE},
+ {0x2400, 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, 0x25F7},
+ {0x25F8, 0x25FC}, {0x25FF, 0x25FF}, {0x2600, 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, 0x2767}, {0x2768, 0x2768}, {0x2769, 0x2769},
+ {0x276A, 0x276A}, {0x276B, 0x276B}, {0x276C, 0x276C},
+ {0x276D, 0x276D}, {0x276E, 0x276E}, {0x276F, 0x276F},
+ {0x2770, 0x2770}, {0x2771, 0x2771}, {0x2772, 0x2772},
+ {0x2773, 0x2773}, {0x2774, 0x2774}, {0x2775, 0x2775},
+ {0x2780, 0x2793}, {0x2794, 0x2794}, {0x2798, 0x27AF},
+ {0x27B1, 0x27BE}, {0x27C0, 0x27C4}, {0x27C5, 0x27C5},
+ {0x27C6, 0x27C6}, {0x27C7, 0x27E5}, {0x27EE, 0x27EE},
+ {0x27EF, 0x27EF}, {0x27F0, 0x27FF}, {0x2800, 0x28FF},
+ {0x2900, 0x297F}, {0x2980, 0x2982}, {0x2983, 0x2983},
+ {0x2984, 0x2984}, {0x2987, 0x2987}, {0x2988, 0x2988},
+ {0x2989, 0x2989}, {0x298A, 0x298A}, {0x298B, 0x298B},
+ {0x298C, 0x298C}, {0x298D, 0x298D}, {0x298E, 0x298E},
+ {0x298F, 0x298F}, {0x2990, 0x2990}, {0x2991, 0x2991},
+ {0x2992, 0x2992}, {0x2993, 0x2993}, {0x2994, 0x2994},
+ {0x2995, 0x2995}, {0x2996, 0x2996}, {0x2997, 0x2997},
+ {0x2998, 0x2998}, {0x2999, 0x29D7}, {0x29D8, 0x29D8},
+ {0x29D9, 0x29D9}, {0x29DA, 0x29DA}, {0x29DB, 0x29DB},
+ {0x29DC, 0x29FB}, {0x29FC, 0x29FC}, {0x29FD, 0x29FD},
+ {0x29FE, 0x29FF}, {0x2A00, 0x2AFF}, {0x2B00, 0x2B1A},
+ {0x2B1D, 0x2B2F}, {0x2B30, 0x2B44}, {0x2B45, 0x2B46},
+ {0x2B47, 0x2B4C}, {0x2B4D, 0x2B4F}, {0x2B51, 0x2B54},
+ {0x2B5A, 0x2B73}, {0x2B76, 0x2B95}, {0x2B98, 0x2BB9},
+ {0x2BBD, 0x2BC8}, {0x2BCA, 0x2BD1}, {0x2BEC, 0x2BEF},
+ {0x2C00, 0x2C2E}, {0x2C30, 0x2C5E}, {0x2C60, 0x2C7B},
+ {0x2C7C, 0x2C7D}, {0x2C7E, 0x2C7F}, {0x2C80, 0x2CE4},
+ {0x2CE5, 0x2CEA}, {0x2CEB, 0x2CEE}, {0x2CEF, 0x2CF1},
+ {0x2CF2, 0x2CF3}, {0x2CF9, 0x2CFC}, {0x2CFD, 0x2CFD},
+ {0x2CFE, 0x2CFF}, {0x2D00, 0x2D25}, {0x2D27, 0x2D27},
+ {0x2D2D, 0x2D2D}, {0x2D30, 0x2D67}, {0x2D6F, 0x2D6F},
+ {0x2D70, 0x2D70}, {0x2D7F, 0x2D7F}, {0x2D80, 0x2D96},
+ {0x2DA0, 0x2DA6}, {0x2DA8, 0x2DAE}, {0x2DB0, 0x2DB6},
+ {0x2DB8, 0x2DBE}, {0x2DC0, 0x2DC6}, {0x2DC8, 0x2DCE},
+ {0x2DD0, 0x2DD6}, {0x2DD8, 0x2DDE}, {0x2DE0, 0x2DFF},
+ {0x2E00, 0x2E01}, {0x2E02, 0x2E02}, {0x2E03, 0x2E03},
+ {0x2E04, 0x2E04}, {0x2E05, 0x2E05}, {0x2E06, 0x2E08},
+ {0x2E09, 0x2E09}, {0x2E0A, 0x2E0A}, {0x2E0B, 0x2E0B},
+ {0x2E0C, 0x2E0C}, {0x2E0D, 0x2E0D}, {0x2E0E, 0x2E16},
+ {0x2E17, 0x2E17}, {0x2E18, 0x2E19}, {0x2E1A, 0x2E1A},
+ {0x2E1B, 0x2E1B}, {0x2E1C, 0x2E1C}, {0x2E1D, 0x2E1D},
+ {0x2E1E, 0x2E1F}, {0x2E20, 0x2E20}, {0x2E21, 0x2E21},
+ {0x2E22, 0x2E22}, {0x2E23, 0x2E23}, {0x2E24, 0x2E24},
+ {0x2E25, 0x2E25}, {0x2E26, 0x2E26}, {0x2E27, 0x2E27},
+ {0x2E28, 0x2E28}, {0x2E29, 0x2E29}, {0x2E2A, 0x2E2E},
+ {0x2E2F, 0x2E2F}, {0x2E30, 0x2E39}, {0x2E3A, 0x2E3B},
+ {0x2E3C, 0x2E3F}, {0x2E40, 0x2E40}, {0x2E41, 0x2E41},
+ {0x2E42, 0x2E42}, {0x2E43, 0x2E44}, {0x303F, 0x303F},
+ {0x4DC0, 0x4DFF}, {0xA4D0, 0xA4F7}, {0xA4F8, 0xA4FD},
+ {0xA4FE, 0xA4FF}, {0xA500, 0xA60B}, {0xA60C, 0xA60C},
+ {0xA60D, 0xA60F}, {0xA610, 0xA61F}, {0xA620, 0xA629},
+ {0xA62A, 0xA62B}, {0xA640, 0xA66D}, {0xA66E, 0xA66E},
+ {0xA66F, 0xA66F}, {0xA670, 0xA672}, {0xA673, 0xA673},
+ {0xA674, 0xA67D}, {0xA67E, 0xA67E}, {0xA67F, 0xA67F},
+ {0xA680, 0xA69B}, {0xA69C, 0xA69D}, {0xA69E, 0xA69F},
+ {0xA6A0, 0xA6E5}, {0xA6E6, 0xA6EF}, {0xA6F0, 0xA6F1},
+ {0xA6F2, 0xA6F7}, {0xA700, 0xA716}, {0xA717, 0xA71F},
+ {0xA720, 0xA721}, {0xA722, 0xA76F}, {0xA770, 0xA770},
+ {0xA771, 0xA787}, {0xA788, 0xA788}, {0xA789, 0xA78A},
+ {0xA78B, 0xA78E}, {0xA78F, 0xA78F}, {0xA790, 0xA7AE},
+ {0xA7B0, 0xA7B7}, {0xA7F7, 0xA7F7}, {0xA7F8, 0xA7F9},
+ {0xA7FA, 0xA7FA}, {0xA7FB, 0xA7FF}, {0xA800, 0xA801},
+ {0xA802, 0xA802}, {0xA803, 0xA805}, {0xA806, 0xA806},
+ {0xA807, 0xA80A}, {0xA80B, 0xA80B}, {0xA80C, 0xA822},
+ {0xA823, 0xA824}, {0xA825, 0xA826}, {0xA827, 0xA827},
+ {0xA828, 0xA82B}, {0xA830, 0xA835}, {0xA836, 0xA837},
+ {0xA838, 0xA838}, {0xA839, 0xA839}, {0xA840, 0xA873},
+ {0xA874, 0xA877}, {0xA880, 0xA881}, {0xA882, 0xA8B3},
+ {0xA8B4, 0xA8C3}, {0xA8C4, 0xA8C5}, {0xA8CE, 0xA8CF},
+ {0xA8D0, 0xA8D9}, {0xA8E0, 0xA8F1}, {0xA8F2, 0xA8F7},
+ {0xA8F8, 0xA8FA}, {0xA8FB, 0xA8FB}, {0xA8FC, 0xA8FC},
+ {0xA8FD, 0xA8FD}, {0xA900, 0xA909}, {0xA90A, 0xA925},
+ {0xA926, 0xA92D}, {0xA92E, 0xA92F}, {0xA930, 0xA946},
+ {0xA947, 0xA951}, {0xA952, 0xA953}, {0xA95F, 0xA95F},
+ {0xA980, 0xA982}, {0xA983, 0xA983}, {0xA984, 0xA9B2},
+ {0xA9B3, 0xA9B3}, {0xA9B4, 0xA9B5}, {0xA9B6, 0xA9B9},
+ {0xA9BA, 0xA9BB}, {0xA9BC, 0xA9BC}, {0xA9BD, 0xA9C0},
+ {0xA9C1, 0xA9CD}, {0xA9CF, 0xA9CF}, {0xA9D0, 0xA9D9},
+ {0xA9DE, 0xA9DF}, {0xA9E0, 0xA9E4}, {0xA9E5, 0xA9E5},
+ {0xA9E6, 0xA9E6}, {0xA9E7, 0xA9EF}, {0xA9F0, 0xA9F9},
+ {0xA9FA, 0xA9FE}, {0xAA00, 0xAA28}, {0xAA29, 0xAA2E},
+ {0xAA2F, 0xAA30}, {0xAA31, 0xAA32}, {0xAA33, 0xAA34},
+ {0xAA35, 0xAA36}, {0xAA40, 0xAA42}, {0xAA43, 0xAA43},
+ {0xAA44, 0xAA4B}, {0xAA4C, 0xAA4C}, {0xAA4D, 0xAA4D},
+ {0xAA50, 0xAA59}, {0xAA5C, 0xAA5F}, {0xAA60, 0xAA6F},
+ {0xAA70, 0xAA70}, {0xAA71, 0xAA76}, {0xAA77, 0xAA79},
+ {0xAA7A, 0xAA7A}, {0xAA7B, 0xAA7B}, {0xAA7C, 0xAA7C},
+ {0xAA7D, 0xAA7D}, {0xAA7E, 0xAA7F}, {0xAA80, 0xAAAF},
+ {0xAAB0, 0xAAB0}, {0xAAB1, 0xAAB1}, {0xAAB2, 0xAAB4},
+ {0xAAB5, 0xAAB6}, {0xAAB7, 0xAAB8}, {0xAAB9, 0xAABD},
+ {0xAABE, 0xAABF}, {0xAAC0, 0xAAC0}, {0xAAC1, 0xAAC1},
+ {0xAAC2, 0xAAC2}, {0xAADB, 0xAADC}, {0xAADD, 0xAADD},
+ {0xAADE, 0xAADF}, {0xAAE0, 0xAAEA}, {0xAAEB, 0xAAEB},
+ {0xAAEC, 0xAAED}, {0xAAEE, 0xAAEF}, {0xAAF0, 0xAAF1},
+ {0xAAF2, 0xAAF2}, {0xAAF3, 0xAAF4}, {0xAAF5, 0xAAF5},
+ {0xAAF6, 0xAAF6}, {0xAB01, 0xAB06}, {0xAB09, 0xAB0E},
+ {0xAB11, 0xAB16}, {0xAB20, 0xAB26}, {0xAB28, 0xAB2E},
+ {0xAB30, 0xAB5A}, {0xAB5B, 0xAB5B}, {0xAB5C, 0xAB5F},
+ {0xAB60, 0xAB65}, {0xAB70, 0xABBF}, {0xABC0, 0xABE2},
+ {0xABE3, 0xABE4}, {0xABE5, 0xABE5}, {0xABE6, 0xABE7},
+ {0xABE8, 0xABE8}, {0xABE9, 0xABEA}, {0xABEB, 0xABEB},
+ {0xABEC, 0xABEC}, {0xABED, 0xABED}, {0xABF0, 0xABF9},
+ {0xD7B0, 0xD7C6}, {0xD7CB, 0xD7FB}, {0xD800, 0xDB7F},
+ {0xDB80, 0xDBFF}, {0xDC00, 0xDFFF}, {0xFB00, 0xFB06},
+ {0xFB13, 0xFB17}, {0xFB1D, 0xFB1D}, {0xFB1E, 0xFB1E},
+ {0xFB1F, 0xFB28}, {0xFB29, 0xFB29}, {0xFB2A, 0xFB36},
+ {0xFB38, 0xFB3C}, {0xFB3E, 0xFB3E}, {0xFB40, 0xFB41},
+ {0xFB43, 0xFB44}, {0xFB46, 0xFB4F}, {0xFB50, 0xFBB1},
+ {0xFBB2, 0xFBC1}, {0xFBD3, 0xFD3D}, {0xFD3E, 0xFD3E},
+ {0xFD3F, 0xFD3F}, {0xFD50, 0xFD8F}, {0xFD92, 0xFDC7},
+ {0xFDF0, 0xFDFB}, {0xFDFC, 0xFDFC}, {0xFDFD, 0xFDFD},
+ {0xFE20, 0xFE2F}, {0xFE70, 0xFE74}, {0xFE76, 0xFEFC},
+ {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, {0xFFFC, 0xFFFC},
+ {0x10000, 0x1000B}, {0x1000D, 0x10026}, {0x10028, 0x1003A},
+ {0x1003C, 0x1003D}, {0x1003F, 0x1004D}, {0x10050, 0x1005D},
+ {0x10080, 0x100FA}, {0x10100, 0x10102}, {0x10107, 0x10133},
+ {0x10137, 0x1013F}, {0x10140, 0x10174}, {0x10175, 0x10178},
+ {0x10179, 0x10189}, {0x1018A, 0x1018B}, {0x1018C, 0x1018E},
+ {0x10190, 0x1019B}, {0x101A0, 0x101A0}, {0x101D0, 0x101FC},
+ {0x101FD, 0x101FD}, {0x10280, 0x1029C}, {0x102A0, 0x102D0},
+ {0x102E0, 0x102E0}, {0x102E1, 0x102FB}, {0x10300, 0x1031F},
+ {0x10320, 0x10323}, {0x10330, 0x10340}, {0x10341, 0x10341},
+ {0x10342, 0x10349}, {0x1034A, 0x1034A}, {0x10350, 0x10375},
+ {0x10376, 0x1037A}, {0x10380, 0x1039D}, {0x1039F, 0x1039F},
+ {0x103A0, 0x103C3}, {0x103C8, 0x103CF}, {0x103D0, 0x103D0},
+ {0x103D1, 0x103D5}, {0x10400, 0x1044F}, {0x10450, 0x1047F},
+ {0x10480, 0x1049D}, {0x104A0, 0x104A9}, {0x104B0, 0x104D3},
+ {0x104D8, 0x104FB}, {0x10500, 0x10527}, {0x10530, 0x10563},
+ {0x1056F, 0x1056F}, {0x10600, 0x10736}, {0x10740, 0x10755},
+ {0x10760, 0x10767}, {0x10800, 0x10805}, {0x10808, 0x10808},
+ {0x1080A, 0x10835}, {0x10837, 0x10838}, {0x1083C, 0x1083C},
+ {0x1083F, 0x1083F}, {0x10840, 0x10855}, {0x10857, 0x10857},
+ {0x10858, 0x1085F}, {0x10860, 0x10876}, {0x10877, 0x10878},
+ {0x10879, 0x1087F}, {0x10880, 0x1089E}, {0x108A7, 0x108AF},
+ {0x108E0, 0x108F2}, {0x108F4, 0x108F5}, {0x108FB, 0x108FF},
+ {0x10900, 0x10915}, {0x10916, 0x1091B}, {0x1091F, 0x1091F},
+ {0x10920, 0x10939}, {0x1093F, 0x1093F}, {0x10980, 0x1099F},
+ {0x109A0, 0x109B7}, {0x109BC, 0x109BD}, {0x109BE, 0x109BF},
+ {0x109C0, 0x109CF}, {0x109D2, 0x109FF}, {0x10A00, 0x10A00},
+ {0x10A01, 0x10A03}, {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F},
+ {0x10A10, 0x10A13}, {0x10A15, 0x10A17}, {0x10A19, 0x10A33},
+ {0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F}, {0x10A40, 0x10A47},
+ {0x10A50, 0x10A58}, {0x10A60, 0x10A7C}, {0x10A7D, 0x10A7E},
+ {0x10A7F, 0x10A7F}, {0x10A80, 0x10A9C}, {0x10A9D, 0x10A9F},
+ {0x10AC0, 0x10AC7}, {0x10AC8, 0x10AC8}, {0x10AC9, 0x10AE4},
+ {0x10AE5, 0x10AE6}, {0x10AEB, 0x10AEF}, {0x10AF0, 0x10AF6},
+ {0x10B00, 0x10B35}, {0x10B39, 0x10B3F}, {0x10B40, 0x10B55},
+ {0x10B58, 0x10B5F}, {0x10B60, 0x10B72}, {0x10B78, 0x10B7F},
+ {0x10B80, 0x10B91}, {0x10B99, 0x10B9C}, {0x10BA9, 0x10BAF},
+ {0x10C00, 0x10C48}, {0x10C80, 0x10CB2}, {0x10CC0, 0x10CF2},
+ {0x10CFA, 0x10CFF}, {0x10E60, 0x10E7E}, {0x11000, 0x11000},
+ {0x11001, 0x11001}, {0x11002, 0x11002}, {0x11003, 0x11037},
+ {0x11038, 0x11046}, {0x11047, 0x1104D}, {0x11052, 0x11065},
+ {0x11066, 0x1106F}, {0x1107F, 0x1107F}, {0x11080, 0x11081},
+ {0x11082, 0x11082}, {0x11083, 0x110AF}, {0x110B0, 0x110B2},
+ {0x110B3, 0x110B6}, {0x110B7, 0x110B8}, {0x110B9, 0x110BA},
+ {0x110BB, 0x110BC}, {0x110BD, 0x110BD}, {0x110BE, 0x110C1},
+ {0x110D0, 0x110E8}, {0x110F0, 0x110F9}, {0x11100, 0x11102},
+ {0x11103, 0x11126}, {0x11127, 0x1112B}, {0x1112C, 0x1112C},
+ {0x1112D, 0x11134}, {0x11136, 0x1113F}, {0x11140, 0x11143},
+ {0x11150, 0x11172}, {0x11173, 0x11173}, {0x11174, 0x11175},
+ {0x11176, 0x11176}, {0x11180, 0x11181}, {0x11182, 0x11182},
+ {0x11183, 0x111B2}, {0x111B3, 0x111B5}, {0x111B6, 0x111BE},
+ {0x111BF, 0x111C0}, {0x111C1, 0x111C4}, {0x111C5, 0x111C9},
+ {0x111CA, 0x111CC}, {0x111CD, 0x111CD}, {0x111D0, 0x111D9},
+ {0x111DA, 0x111DA}, {0x111DB, 0x111DB}, {0x111DC, 0x111DC},
+ {0x111DD, 0x111DF}, {0x111E1, 0x111F4}, {0x11200, 0x11211},
+ {0x11213, 0x1122B}, {0x1122C, 0x1122E}, {0x1122F, 0x11231},
+ {0x11232, 0x11233}, {0x11234, 0x11234}, {0x11235, 0x11235},
+ {0x11236, 0x11237}, {0x11238, 0x1123D}, {0x1123E, 0x1123E},
+ {0x11280, 0x11286}, {0x11288, 0x11288}, {0x1128A, 0x1128D},
+ {0x1128F, 0x1129D}, {0x1129F, 0x112A8}, {0x112A9, 0x112A9},
+ {0x112B0, 0x112DE}, {0x112DF, 0x112DF}, {0x112E0, 0x112E2},
+ {0x112E3, 0x112EA}, {0x112F0, 0x112F9}, {0x11300, 0x11301},
+ {0x11302, 0x11303}, {0x11305, 0x1130C}, {0x1130F, 0x11310},
+ {0x11313, 0x11328}, {0x1132A, 0x11330}, {0x11332, 0x11333},
+ {0x11335, 0x11339}, {0x1133C, 0x1133C}, {0x1133D, 0x1133D},
+ {0x1133E, 0x1133F}, {0x11340, 0x11340}, {0x11341, 0x11344},
+ {0x11347, 0x11348}, {0x1134B, 0x1134D}, {0x11350, 0x11350},
+ {0x11357, 0x11357}, {0x1135D, 0x11361}, {0x11362, 0x11363},
+ {0x11366, 0x1136C}, {0x11370, 0x11374}, {0x11400, 0x11434},
+ {0x11435, 0x11437}, {0x11438, 0x1143F}, {0x11440, 0x11441},
+ {0x11442, 0x11444}, {0x11445, 0x11445}, {0x11446, 0x11446},
+ {0x11447, 0x1144A}, {0x1144B, 0x1144F}, {0x11450, 0x11459},
+ {0x1145B, 0x1145B}, {0x1145D, 0x1145D}, {0x11480, 0x114AF},
+ {0x114B0, 0x114B2}, {0x114B3, 0x114B8}, {0x114B9, 0x114B9},
+ {0x114BA, 0x114BA}, {0x114BB, 0x114BE}, {0x114BF, 0x114C0},
+ {0x114C1, 0x114C1}, {0x114C2, 0x114C3}, {0x114C4, 0x114C5},
+ {0x114C6, 0x114C6}, {0x114C7, 0x114C7}, {0x114D0, 0x114D9},
+ {0x11580, 0x115AE}, {0x115AF, 0x115B1}, {0x115B2, 0x115B5},
+ {0x115B8, 0x115BB}, {0x115BC, 0x115BD}, {0x115BE, 0x115BE},
+ {0x115BF, 0x115C0}, {0x115C1, 0x115D7}, {0x115D8, 0x115DB},
+ {0x115DC, 0x115DD}, {0x11600, 0x1162F}, {0x11630, 0x11632},
+ {0x11633, 0x1163A}, {0x1163B, 0x1163C}, {0x1163D, 0x1163D},
+ {0x1163E, 0x1163E}, {0x1163F, 0x11640}, {0x11641, 0x11643},
+ {0x11644, 0x11644}, {0x11650, 0x11659}, {0x11660, 0x1166C},
+ {0x11680, 0x116AA}, {0x116AB, 0x116AB}, {0x116AC, 0x116AC},
+ {0x116AD, 0x116AD}, {0x116AE, 0x116AF}, {0x116B0, 0x116B5},
+ {0x116B6, 0x116B6}, {0x116B7, 0x116B7}, {0x116C0, 0x116C9},
+ {0x11700, 0x11719}, {0x1171D, 0x1171F}, {0x11720, 0x11721},
+ {0x11722, 0x11725}, {0x11726, 0x11726}, {0x11727, 0x1172B},
+ {0x11730, 0x11739}, {0x1173A, 0x1173B}, {0x1173C, 0x1173E},
+ {0x1173F, 0x1173F}, {0x118A0, 0x118DF}, {0x118E0, 0x118E9},
+ {0x118EA, 0x118F2}, {0x118FF, 0x118FF}, {0x11AC0, 0x11AF8},
+ {0x11C00, 0x11C08}, {0x11C0A, 0x11C2E}, {0x11C2F, 0x11C2F},
+ {0x11C30, 0x11C36}, {0x11C38, 0x11C3D}, {0x11C3E, 0x11C3E},
+ {0x11C3F, 0x11C3F}, {0x11C40, 0x11C40}, {0x11C41, 0x11C45},
+ {0x11C50, 0x11C59}, {0x11C5A, 0x11C6C}, {0x11C70, 0x11C71},
+ {0x11C72, 0x11C8F}, {0x11C92, 0x11CA7}, {0x11CA9, 0x11CA9},
+ {0x11CAA, 0x11CB0}, {0x11CB1, 0x11CB1}, {0x11CB2, 0x11CB3},
+ {0x11CB4, 0x11CB4}, {0x11CB5, 0x11CB6}, {0x12000, 0x12399},
+ {0x12400, 0x1246E}, {0x12470, 0x12474}, {0x12480, 0x12543},
+ {0x13000, 0x1342E}, {0x14400, 0x14646}, {0x16800, 0x16A38},
+ {0x16A40, 0x16A5E}, {0x16A60, 0x16A69}, {0x16A6E, 0x16A6F},
+ {0x16AD0, 0x16AED}, {0x16AF0, 0x16AF4}, {0x16AF5, 0x16AF5},
+ {0x16B00, 0x16B2F}, {0x16B30, 0x16B36}, {0x16B37, 0x16B3B},
+ {0x16B3C, 0x16B3F}, {0x16B40, 0x16B43}, {0x16B44, 0x16B44},
+ {0x16B45, 0x16B45}, {0x16B50, 0x16B59}, {0x16B5B, 0x16B61},
+ {0x16B63, 0x16B77}, {0x16B7D, 0x16B8F}, {0x16F00, 0x16F44},
+ {0x16F50, 0x16F50}, {0x16F51, 0x16F7E}, {0x16F8F, 0x16F92},
+ {0x16F93, 0x16F9F}, {0x1BC00, 0x1BC6A}, {0x1BC70, 0x1BC7C},
+ {0x1BC80, 0x1BC88}, {0x1BC90, 0x1BC99}, {0x1BC9C, 0x1BC9C},
+ {0x1BC9D, 0x1BC9E}, {0x1BC9F, 0x1BC9F}, {0x1BCA0, 0x1BCA3},
+ {0x1D000, 0x1D0F5}, {0x1D100, 0x1D126}, {0x1D129, 0x1D164},
+ {0x1D165, 0x1D166}, {0x1D167, 0x1D169}, {0x1D16A, 0x1D16C},
+ {0x1D16D, 0x1D172}, {0x1D173, 0x1D17A}, {0x1D17B, 0x1D182},
+ {0x1D183, 0x1D184}, {0x1D185, 0x1D18B}, {0x1D18C, 0x1D1A9},
+ {0x1D1AA, 0x1D1AD}, {0x1D1AE, 0x1D1E8}, {0x1D200, 0x1D241},
+ {0x1D242, 0x1D244}, {0x1D245, 0x1D245}, {0x1D300, 0x1D356},
+ {0x1D360, 0x1D371}, {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, 0x1D6C0},
+ {0x1D6C1, 0x1D6C1}, {0x1D6C2, 0x1D6DA}, {0x1D6DB, 0x1D6DB},
+ {0x1D6DC, 0x1D6FA}, {0x1D6FB, 0x1D6FB}, {0x1D6FC, 0x1D714},
+ {0x1D715, 0x1D715}, {0x1D716, 0x1D734}, {0x1D735, 0x1D735},
+ {0x1D736, 0x1D74E}, {0x1D74F, 0x1D74F}, {0x1D750, 0x1D76E},
+ {0x1D76F, 0x1D76F}, {0x1D770, 0x1D788}, {0x1D789, 0x1D789},
+ {0x1D78A, 0x1D7A8}, {0x1D7A9, 0x1D7A9}, {0x1D7AA, 0x1D7C2},
+ {0x1D7C3, 0x1D7C3}, {0x1D7C4, 0x1D7CB}, {0x1D7CE, 0x1D7FF},
+ {0x1D800, 0x1D9FF}, {0x1DA00, 0x1DA36}, {0x1DA37, 0x1DA3A},
+ {0x1DA3B, 0x1DA6C}, {0x1DA6D, 0x1DA74}, {0x1DA75, 0x1DA75},
+ {0x1DA76, 0x1DA83}, {0x1DA84, 0x1DA84}, {0x1DA85, 0x1DA86},
+ {0x1DA87, 0x1DA8B}, {0x1DA9B, 0x1DA9F}, {0x1DAA1, 0x1DAAF},
+ {0x1E000, 0x1E006}, {0x1E008, 0x1E018}, {0x1E01B, 0x1E021},
+ {0x1E023, 0x1E024}, {0x1E026, 0x1E02A}, {0x1E800, 0x1E8C4},
+ {0x1E8C7, 0x1E8CF}, {0x1E8D0, 0x1E8D6}, {0x1E900, 0x1E943},
+ {0x1E944, 0x1E94A}, {0x1E950, 0x1E959}, {0x1E95E, 0x1E95F},
+ {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, 0x1F10C},
+ {0x1F12E, 0x1F12E}, {0x1F16A, 0x1F16B}, {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}, {0x1F6E0, 0x1F6EA},
+ {0x1F6F0, 0x1F6F3}, {0x1F700, 0x1F773}, {0x1F780, 0x1F7D4},
+ {0x1F800, 0x1F80B}, {0x1F810, 0x1F847}, {0x1F850, 0x1F859},
+ {0x1F860, 0x1F887}, {0x1F890, 0x1F8AD}, {0xE0001, 0xE0001},
+ {0xE0020, 0xE007F},
+}
+
+// Condition have flag EastAsianWidth whether the current locale is CJK or not.
+type Condition struct {
+ EastAsianWidth bool
+}
+
+// NewCondition return new instance of Condition which is current locale.
+func NewCondition() *Condition {
+ return &Condition{EastAsianWidth}
+}
+
+// RuneWidth returns the number of cells in r.
+// See http://www.unicode.org/reports/tr11/
+func (c *Condition) RuneWidth(r rune) int {
+ switch {
+ case r < 0 || r > 0x10FFFF ||
+ inTables(r, nonprint, combining, notassigned):
+ return 0
+ case (c.EastAsianWidth && IsAmbiguousWidth(r)) ||
+ inTables(r, doublewidth, emoji):
+ return 2
+ default:
+ return 1
+ }
+}
+
+// StringWidth return width as you can see
+func (c *Condition) StringWidth(s string) (width int) {
+ for _, r := range []rune(s) {
+ width += c.RuneWidth(r)
+ }
+ return width
+}
+
+// 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
+ }
+ r := []rune(s)
+ tw := c.StringWidth(tail)
+ w -= tw
+ width := 0
+ i := 0
+ for ; i < len(r); i++ {
+ cw := c.RuneWidth(r[i])
+ if width+cw > w {
+ break
+ }
+ width += cw
+ }
+ return string(r[0:i]) + tail
+}
+
+// Wrap return string wrapped with w cells
+func (c *Condition) Wrap(s string, w int) string {
+ width := 0
+ out := ""
+ for _, r := range []rune(s) {
+ cw := RuneWidth(r)
+ if r == '\n' {
+ out += string(r)
+ width = 0
+ continue
+ } else if width+cw > w {
+ out += "\n"
+ width = 0
+ out += string(r)
+ width += cw
+ continue
+ }
+ out += string(r)
+ width += cw
+ }
+ return out
+}
+
+// FillLeft return string filled in left by spaces in w cells
+func (c *Condition) FillLeft(s string, w int) string {
+ width := c.StringWidth(s)
+ count := w - width
+ if count > 0 {
+ b := make([]byte, count)
+ for i := range b {
+ b[i] = ' '
+ }
+ return string(b) + s
+ }
+ return s
+}
+
+// FillRight return string filled in left by spaces in w cells
+func (c *Condition) FillRight(s string, w int) string {
+ width := c.StringWidth(s)
+ count := w - width
+ if count > 0 {
+ b := make([]byte, count)
+ for i := range b {
+ b[i] = ' '
+ }
+ return s + string(b)
+ }
+ return s
+}
+
+// RuneWidth returns the number of cells in r.
+// See http://www.unicode.org/reports/tr11/
+func RuneWidth(r rune) int {
+ return DefaultCondition.RuneWidth(r)
+}
+
+// IsAmbiguousWidth returns whether is ambiguous width or not.
+func IsAmbiguousWidth(r rune) bool {
+ return inTables(r, private, ambiguous)
+}
+
+// IsNeutralWidth returns whether is neutral width or not.
+func IsNeutralWidth(r rune) bool {
+ return inTable(r, neutral)
+}
+
+// StringWidth return width as you can see
+func StringWidth(s string) (width int) {
+ return DefaultCondition.StringWidth(s)
+}
+
+// Truncate return string truncated with w cells
+func Truncate(s string, w int, tail string) string {
+ return DefaultCondition.Truncate(s, w, tail)
+}
+
+// Wrap return string wrapped with w cells
+func Wrap(s string, w int) string {
+ return DefaultCondition.Wrap(s, w)
+}
+
+// FillLeft return string filled in left by spaces in w cells
+func FillLeft(s string, w int) string {
+ return DefaultCondition.FillLeft(s, w)
+}
+
+// FillRight return string filled in left by spaces in w cells
+func FillRight(s string, w int) string {
+ return DefaultCondition.FillRight(s, w)
+}
diff --git a/vendor/github.com/mattn/go-runewidth/runewidth_js.go b/vendor/github.com/mattn/go-runewidth/runewidth_js.go
new file mode 100644
index 0000000..0ce32c5
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/runewidth_js.go
@@ -0,0 +1,8 @@
+// +build js
+
+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..c579e9a
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/runewidth_posix.go
@@ -0,0 +1,77 @@
+// +build !windows,!js
+
+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_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_test.go b/vendor/github.com/mattn/go-runewidth/runewidth_test.go
new file mode 100644
index 0000000..b0378a1
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/runewidth_test.go
@@ -0,0 +1,275 @@
+package runewidth
+
+import (
+ "sort"
+ "testing"
+)
+
+var _ sort.Interface = (*table)(nil)
+
+func (t table) Len() int {
+ return len(t)
+}
+
+func (t table) Less(i, j int) bool {
+ return t[i].first < t[j].first
+}
+
+func (t *table) Swap(i, j int) {
+ (*t)[i], (*t)[j] = (*t)[j], (*t)[i]
+}
+
+var tables = []table{
+ private,
+ nonprint,
+ combining,
+ doublewidth,
+ ambiguous,
+ emoji,
+ notassigned,
+ neutral,
+}
+
+func TestSorted(t *testing.T) {
+ for _, tbl := range tables {
+ if !sort.IsSorted(&tbl) {
+ t.Errorf("not sorted")
+ }
+ }
+}
+
+var runewidthtests = []struct {
+ in rune
+ out int
+ eaout int
+}{
+ {'世', 2, 2},
+ {'界', 2, 2},
+ {'セ', 1, 1},
+ {'カ', 1, 1},
+ {'イ', 1, 1},
+ {'☆', 1, 2}, // double width in ambiguous
+ {'\x00', 0, 0},
+ {'\x01', 0, 0},
+ {'\u0300', 0, 0},
+}
+
+func TestRuneWidth(t *testing.T) {
+ c := NewCondition()
+ for _, tt := range runewidthtests {
+ if out := c.RuneWidth(tt.in); out != tt.out {
+ t.Errorf("RuneWidth(%q) = %d, want %d", tt.in, out, tt.out)
+ }
+ }
+ c.EastAsianWidth = true
+ for _, tt := range runewidthtests {
+ if out := c.RuneWidth(tt.in); out != tt.eaout {
+ t.Errorf("RuneWidth(%q) = %d, want %d", tt.in, out, tt.eaout)
+ }
+ }
+}
+
+var isambiguouswidthtests = []struct {
+ in rune
+ out bool
+}{
+ {'世', false},
+ {'■', true},
+ {'界', false},
+ {'○', true},
+ {'㈱', false},
+ {'①', true},
+ {'②', true},
+ {'③', true},
+ {'④', true},
+ {'⑤', true},
+ {'⑥', true},
+ {'⑦', true},
+ {'⑧', true},
+ {'⑨', true},
+ {'⑩', true},
+ {'⑪', true},
+ {'⑫', true},
+ {'⑬', true},
+ {'⑭', true},
+ {'⑮', true},
+ {'⑯', true},
+ {'⑰', true},
+ {'⑱', true},
+ {'⑲', true},
+ {'⑳', true},
+ {'☆', true},
+}
+
+func TestIsAmbiguousWidth(t *testing.T) {
+ for _, tt := range isambiguouswidthtests {
+ if out := IsAmbiguousWidth(tt.in); out != tt.out {
+ t.Errorf("IsAmbiguousWidth(%q) = %v, want %v", tt.in, out, tt.out)
+ }
+ }
+}
+
+var stringwidthtests = []struct {
+ in string
+ out int
+ eaout int
+}{
+ {"■㈱の世界①", 10, 12},
+ {"スター☆", 7, 8},
+ {"つのだ☆HIRO", 11, 12},
+}
+
+func TestStringWidth(t *testing.T) {
+ c := NewCondition()
+ for _, tt := range stringwidthtests {
+ if out := c.StringWidth(tt.in); out != tt.out {
+ t.Errorf("StringWidth(%q) = %q, want %q", tt.in, out, tt.out)
+ }
+ }
+ c.EastAsianWidth = true
+ for _, tt := range stringwidthtests {
+ if out := c.StringWidth(tt.in); out != tt.eaout {
+ t.Errorf("StringWidth(%q) = %q, want %q", tt.in, out, tt.eaout)
+ }
+ }
+}
+
+func TestStringWidthInvalid(t *testing.T) {
+ s := "こんにちわ\x00世界"
+ if out := StringWidth(s); out != 14 {
+ t.Errorf("StringWidth(%q) = %q, want %q", s, out, 14)
+ }
+}
+
+func TestTruncateSmaller(t *testing.T) {
+ s := "あいうえお"
+ expected := "あいうえお"
+
+ if out := Truncate(s, 10, "..."); out != expected {
+ t.Errorf("Truncate(%q) = %q, want %q", s, out, expected)
+ }
+}
+
+func TestTruncate(t *testing.T) {
+ s := "あいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおおおおお"
+ expected := "あいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおお..."
+ out := Truncate(s, 80, "...")
+ if out != expected {
+ t.Errorf("Truncate(%q) = %q, want %q", s, out, expected)
+ }
+ width := StringWidth(out)
+ if width != 79 {
+ t.Errorf("width of Truncate(%q) should be %d, but %d", s, 79, width)
+ }
+}
+
+func TestTruncateFit(t *testing.T) {
+ s := "aあいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおおおおお"
+ expected := "aあいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおお..."
+
+ out := Truncate(s, 80, "...")
+ if out != expected {
+ t.Errorf("Truncate(%q) = %q, want %q", s, out, expected)
+ }
+ width := StringWidth(out)
+ if width != 80 {
+ t.Errorf("width of Truncate(%q) should be %d, but %d", s, 80, width)
+ }
+}
+
+func TestTruncateJustFit(t *testing.T) {
+ s := "あいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおおおお"
+ expected := "あいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおおおお"
+
+ out := Truncate(s, 80, "...")
+ if out != expected {
+ t.Errorf("Truncate(%q) = %q, want %q", s, out, expected)
+ }
+ width := StringWidth(out)
+ if width != 80 {
+ t.Errorf("width of Truncate(%q) should be %d, but %d", s, 80, width)
+ }
+}
+
+func TestWrap(t *testing.T) {
+ s := `東京特許許可局局長はよく柿喰う客だ/東京特許許可局局長はよく柿喰う客だ
+123456789012345678901234567890
+
+END`
+ expected := `東京特許許可局局長はよく柿喰う
+客だ/東京特許許可局局長はよく
+柿喰う客だ
+123456789012345678901234567890
+
+END`
+
+ if out := Wrap(s, 30); out != expected {
+ t.Errorf("Wrap(%q) = %q, want %q", s, out, expected)
+ }
+}
+
+func TestTruncateNoNeeded(t *testing.T) {
+ s := "あいうえおあい"
+ expected := "あいうえおあい"
+
+ if out := Truncate(s, 80, "..."); out != expected {
+ t.Errorf("Truncate(%q) = %q, want %q", s, out, expected)
+ }
+}
+
+var isneutralwidthtests = []struct {
+ in rune
+ out bool
+}{
+ {'→', false},
+ {'┊', false},
+ {'┈', false},
+ {'~', false},
+ {'└', false},
+ {'⣀', true},
+ {'⣀', true},
+}
+
+func TestIsNeutralWidth(t *testing.T) {
+ for _, tt := range isneutralwidthtests {
+ if out := IsNeutralWidth(tt.in); out != tt.out {
+ t.Errorf("IsNeutralWidth(%q) = %v, want %v", tt.in, out, tt.out)
+ }
+ }
+}
+
+func TestFillLeft(t *testing.T) {
+ s := "あxいうえお"
+ expected := " あxいうえお"
+
+ if out := FillLeft(s, 15); out != expected {
+ t.Errorf("FillLeft(%q) = %q, want %q", s, out, expected)
+ }
+}
+
+func TestFillLeftFit(t *testing.T) {
+ s := "あいうえお"
+ expected := "あいうえお"
+
+ if out := FillLeft(s, 10); out != expected {
+ t.Errorf("FillLeft(%q) = %q, want %q", s, out, expected)
+ }
+}
+
+func TestFillRight(t *testing.T) {
+ s := "あxいうえお"
+ expected := "あxいうえお "
+
+ if out := FillRight(s, 15); out != expected {
+ t.Errorf("FillRight(%q) = %q, want %q", s, out, expected)
+ }
+}
+
+func TestFillRightFit(t *testing.T) {
+ s := "あいうえお"
+ expected := "あいうえお"
+
+ if out := FillRight(s, 10); out != expected {
+ t.Errorf("FillRight(%q) = %q, want %q", s, out, expected)
+ }
+}
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..0258876
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/runewidth_windows.go
@@ -0,0 +1,25 @@
+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/miguelmota/go-coinmarketcap/.gitignore b/vendor/github.com/miguelmota/go-coinmarketcap/.gitignore
new file mode 100644
index 0000000..bf2bb1d
--- /dev/null
+++ b/vendor/github.com/miguelmota/go-coinmarketcap/.gitignore
@@ -0,0 +1,26 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
+
+.DS_Store
diff --git a/vendor/github.com/miguelmota/go-coinmarketcap/.travis.yml b/vendor/github.com/miguelmota/go-coinmarketcap/.travis.yml
new file mode 100644
index 0000000..1a5f7a1
--- /dev/null
+++ b/vendor/github.com/miguelmota/go-coinmarketcap/.travis.yml
@@ -0,0 +1,9 @@
+language: go
+
+go:
+ - "1.9.x"
+ - "1.10.x"
+ - "master"
+
+script:
+ - make test
diff --git a/vendor/github.com/miguelmota/go-coinmarketcap/Gopkg.lock b/vendor/github.com/miguelmota/go-coinmarketcap/Gopkg.lock
new file mode 100644
index 0000000..b8f3d3b
--- /dev/null
+++ b/vendor/github.com/miguelmota/go-coinmarketcap/Gopkg.lock
@@ -0,0 +1,24 @@
+# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
+
+
+[[projects]]
+ name = "github.com/anaskhan96/soup"
+ packages = ["."]
+ revision = "7a8d31f81bad1a5abeed0d0219c35e5e295a5a76"
+ version = "v1.0.1"
+
+[[projects]]
+ branch = "master"
+ name = "golang.org/x/net"
+ packages = [
+ "html",
+ "html/atom"
+ ]
+ revision = "dc948dff8834a7fe1ca525f8d04e261c2b56e70d"
+
+[solve-meta]
+ analyzer-name = "dep"
+ analyzer-version = 1
+ inputs-digest = "ef92c4a55490132c4b677cba28dd5f0ee0bb397d0b3581ea46df6c3f4f169646"
+ solver-name = "gps-cdcl"
+ solver-version = 1
diff --git a/vendor/github.com/miguelmota/go-coinmarketcap/Gopkg.toml b/vendor/github.com/miguelmota/go-coinmarketcap/Gopkg.toml
new file mode 100644
index 0000000..f0a6218
--- /dev/null
+++ b/vendor/github.com/miguelmota/go-coinmarketcap/Gopkg.toml
@@ -0,0 +1,34 @@
+# Gopkg.toml example
+#
+# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
+# for detailed Gopkg.toml documentation.
+#
+# required = ["github.com/user/thing/cmd/thing"]
+# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
+#
+# [[constraint]]
+# name = "github.com/user/project"
+# version = "1.0.0"
+#
+# [[constraint]]
+# name = "github.com/user/project2"
+# branch = "dev"
+# source = "github.com/myfork/project2"
+#
+# [[override]]
+# name = "github.com/x/y"
+# version = "2.4.0"
+#
+# [prune]
+# non-go = false
+# go-tests = true
+# unused-packages = true
+
+
+[[constraint]]
+ name = "github.com/anaskhan96/soup"
+ version = "1.0.1"
+
+[prune]
+ go-tests = true
+ unused-packages = true
diff --git a/vendor/github.com/miguelmota/go-coinmarketcap/LICENSE.md b/vendor/github.com/miguelmota/go-coinmarketcap/LICENSE.md
new file mode 100755
index 0000000..eb0736f
--- /dev/null
+++ b/vendor/github.com/miguelmota/go-coinmarketcap/LICENSE.md
@@ -0,0 +1,21 @@
+MIT license
+
+Copyright (C) 2015 Miguel Mota
+
+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/miguelmota/go-coinmarketcap/Makefile b/vendor/github.com/miguelmota/go-coinmarketcap/Makefile
new file mode 100644
index 0000000..10b2bf7
--- /dev/null
+++ b/vendor/github.com/miguelmota/go-coinmarketcap/Makefile
@@ -0,0 +1,5 @@
+all:
+ @echo "no default"
+
+test:
+ go test -v
diff --git a/vendor/github.com/miguelmota/go-coinmarketcap/README.md b/vendor/github.com/miguelmota/go-coinmarketcap/README.md
new file mode 100755
index 0000000..c55fe49
--- /dev/null
+++ b/vendor/github.com/miguelmota/go-coinmarketcap/README.md
@@ -0,0 +1,47 @@
+# go-coinmarketcap
+
+> The Unofficial [CoinMarketCap](https://coinmarketcap.com/) API client for Go.
+
+[![License](http://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/miguelmota/go-coinmarketcap/master/LICENSE.md) [![Build Status](https://travis-ci.org/miguelmota/go-coinmarketcap.svg?branch=master)](https://travis-ci.org/miguelmota/go-coinmarketcap) [![Go Report Card](https://goreportcard.com/badge/github.com/miguelmota/go-coinmarketcap?)](https://goreportcard.com/report/github.com/miguelmota/go-coinmarketcap) [![GoDoc](https://godoc.org/github.com/miguelmota/go-coinmarketcap?status.svg)](https://godoc.org/github.com/miguelmota/go-coinmarketcap)
+
+## Documentation
+
+[https://godoc.org/github.com/miguelmota/go-coinmarketcap](https://godoc.org/github.com/miguelmota/go-coinmarketcap)
+
+## Install
+
+```bash
+go get -u github.com/miguelmota/go-coinmarketcap
+```
+
+## Getting started
+
+```go
+package main
+
+import (
+ "fmt"
+ "log"
+
+ cmc "github.com/miguelmota/go-coinmarketcap"
+)
+
+func main() {
+ coins, err := cmc.GetAllCoinData(0)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ for _, coin := range coins {
+ fmt.Println(coin.Symbol, coin.PriceUSD)
+ }
+}
+```
+
+## Examples
+
+Check out the [`./example`](./example) directory and documentation.
+
+## License
+
+MIT
diff --git a/vendor/github.com/miguelmota/go-coinmarketcap/coinmarketcap.go b/vendor/github.com/miguelmota/go-coinmarketcap/coinmarketcap.go
new file mode 100644
index 0000000..899ff3d
--- /dev/null
+++ b/vendor/github.com/miguelmota/go-coinmarketcap/coinmarketcap.go
@@ -0,0 +1,210 @@
+// Package coinmarketcap Coin Market Cap API client for Go
+package coinmarketcap
+
+import (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "strconv"
+ "strings"
+
+ "github.com/anaskhan96/soup"
+)
+
+var (
+ baseURL = "https://api.coinmarketcap.com/v1"
+ coinGraphURL = "https://graphs2.coinmarketcap.com/currencies"
+ globalMarketGraphURL = "https://graphs2.coinmarketcap.com/global/marketcap-total"
+ altcoinMarketGraphURL = "https://graphs2.coinmarketcap.com/global/marketcap-altcoin"
+)
+
+// GetGlobalMarketData get information about the global market data of the cryptocurrencies
+func GetGlobalMarketData() (GlobalMarketData, error) {
+ url := fmt.Sprintf(baseURL + "/global/")
+
+ resp, err := makeReq(url)
+
+ var data GlobalMarketData
+ err = json.Unmarshal(resp, &data)
+ if err != nil {
+ return GlobalMarketData{}, err
+ }
+
+ return data, nil
+}
+
+// GetGlobalMarketGraphData get graph data points of global market
+func GetGlobalMarketGraphData(start int64, end int64) (MarketGraph, error) {
+ url := fmt.Sprintf("%s/%d/%d", globalMarketGraphURL, start*1000, end*1000)
+ resp, err := makeReq(url)
+ if err != nil {
+ return MarketGraph{}, err
+ }
+ var data MarketGraph
+ err = json.Unmarshal(resp, &data)
+ if err != nil {
+ return MarketGraph{}, err
+ }
+
+ return data, nil
+}
+
+// GetAltcoinMarketGraphData get graph data points of altcoin market
+func GetAltcoinMarketGraphData(start int64, end int64) (MarketGraph, error) {
+ url := fmt.Sprintf("%s/%d/%d", altcoinMarketGraphURL, start*1000, end*1000)
+ resp, err := makeReq(url)
+ if err != nil {
+ return MarketGraph{}, err
+ }
+ var data MarketGraph
+ err = json.Unmarshal(resp, &data)
+ if err != nil {
+ return MarketGraph{}, err
+ }
+
+ return data, nil
+}
+
+// GetCoinData get information about a crypto currency
+func GetCoinData(coin string) (Coin, error) {
+ coin = strings.ToLower(coin)
+ url := fmt.Sprintf("%s/ticker/%s", baseURL, coin)
+ resp, err := makeReq(url)
+ if err != nil {
+ return Coin{}, err
+ }
+ var data []Coin
+ err = json.Unmarshal(resp, &data)
+ if err != nil {
+ return Coin{}, err
+ }
+
+ return data[0], nil
+}
+
+// GetAllCoinData get information about all coins listed in Coin Market Cap
+func GetAllCoinData(limit int) (map[string]Coin, error) {
+ var l string
+ if limit >= 0 {
+ l = fmt.Sprintf("?limit=%v", limit)
+ }
+ url := fmt.Sprintf("%s/ticker/%s", baseURL, l)
+
+ resp, err := makeReq(url)
+
+ var data []Coin
+ err = json.Unmarshal(resp, &data)
+ if err != nil {
+ return nil, err
+ }
+ // creating map from the array
+ allCoins := make(map[string]Coin)
+ for i := 0; i < len(data); i++ {
+ allCoins[data[i].ID] = data[i]
+ }
+
+ return allCoins, nil
+}
+
+// GetCoinGraphData get graph data points for a crypto currency
+func GetCoinGraphData(coin string, start int64, end int64) (CoinGraph, error) {
+ url := fmt.Sprintf("%s/%s/%d/%d", coinGraphURL, strings.ToLower(coin), start*1000, end*1000)
+ resp, err := makeReq(url)
+ if err != nil {
+ return CoinGraph{}, err
+ }
+ var data CoinGraph
+ err = json.Unmarshal(resp, &data)
+ if err != nil {
+ return CoinGraph{}, err
+ }
+
+ return data, nil
+}
+
+// GetCoinPriceUSD get USD price of crypto currency
+func GetCoinPriceUSD(coin string) (float64, error) {
+ data, err := GetCoinData(strings.ToLower(coin))
+ if err != nil {
+ return float64(0), nil
+ }
+ return data.PriceUSD, nil
+}
+
+// GetCoinMarkets get market data for a coin name
+func GetCoinMarkets(coin string) ([]Market, error) {
+ url := fmt.Sprintf("https://coinmarketcap.com/currencies/%s/#markets", strings.ToLower(coin))
+ var markets []Market
+ response, err := soup.Get(url)
+ if err != nil {
+ return nil, err
+ }
+ rows := soup.HTMLParse(response).Find("table", "id", "markets-table").Find("tbody").FindAll("tr")
+ for _, row := range rows {
+ var data []string
+ for _, column := range row.FindAll("td") {
+ attrs := column.Attrs()
+ if attrs["data-sort"] != "" {
+ data = append(data, attrs["data-sort"])
+ } else {
+ data = append(data, column.Text())
+ }
+ }
+ markets = append(markets, Market{
+ Rank: toInt(data[0]),
+ Exchange: data[1],
+ Pair: data[2],
+ VolumeUSD: toFloat(data[3]),
+ Price: toFloat(data[4]),
+ VolumePercent: toFloat(data[5]),
+ Updated: data[6],
+ })
+ }
+ return markets, nil
+}
+
+// doReq HTTP client
+func doReq(req *http.Request) ([]byte, error) {
+ client := &http.Client{}
+ resp, err := client.Do(req)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+ if 200 != resp.StatusCode {
+ return nil, fmt.Errorf("%s", body)
+ }
+
+ return body, nil
+}
+
+// makeReq HTTP request helper
+func makeReq(url string) ([]byte, error) {
+ req, err := http.NewRequest("GET", url, nil)
+ if err != nil {
+ return nil, err
+ }
+ resp, err := doReq(req)
+ if err != nil {
+ return nil, err
+ }
+
+ return resp, err
+}
+
+// toInt helper for parsing strings to int
+func toInt(rawInt string) int {
+ parsed, _ := strconv.Atoi(strings.Replace(strings.Replace(rawInt, "$", "", -1), ",", "", -1))
+ return parsed
+}
+
+// toFloat helper for parsing strings to float
+func toFloat(rawFloat string) float64 {
+ parsed, _ := strconv.ParseFloat(strings.Replace(strings.Replace(strings.Replace(rawFloat, "$", "", -1), ",", "", -1), "%", "", -1), 64)
+ return parsed
+}
diff --git a/vendor/github.com/miguelmota/go-coinmarketcap/coinmarketcap_test.go b/vendor/github.com/miguelmota/go-coinmarketcap/coinmarketcap_test.go
new file mode 100644
index 0000000..8898e07
--- /dev/null
+++ b/vendor/github.com/miguelmota/go-coinmarketcap/coinmarketcap_test.go
@@ -0,0 +1,219 @@
+package coinmarketcap
+
+import (
+ "testing"
+ "time"
+)
+
+func TestGetGlobalMarketData(t *testing.T) {
+ market, err := GetGlobalMarketData()
+ if err != nil {
+ t.FailNow()
+ }
+
+ if market.ActiveAssets == 0 {
+ t.FailNow()
+ }
+ if market.ActiveCurrencies == 0 {
+ t.FailNow()
+ }
+ if market.ActiveMarkets == 0 {
+ t.FailNow()
+ }
+ if market.BitcoinPercentageOfMarketCap == 0 {
+ t.FailNow()
+ }
+ if market.Total24HVolumeUSD == 0 {
+ t.FailNow()
+ }
+ if market.TotalMarketCapUSD == 0 {
+ t.FailNow()
+ }
+}
+
+func TestGetGlobalMarketGraphData(t *testing.T) {
+ var threeMonths int64 = (60 * 60 * 24 * 90)
+ end := time.Now().Unix()
+ start := end - threeMonths
+
+ graph, err := GetGlobalMarketGraphData(start, end)
+ if err != nil {
+ t.FailNow()
+ }
+
+ if graph.MarketCapByAvailableSupply[0][0] == 0 {
+ t.FailNow()
+ }
+
+ if graph.VolumeUSD[0][0] == 0 {
+ t.FailNow()
+ }
+}
+
+func TestGetAltcoinMarketGraphData(t *testing.T) {
+ var threeMonths int64 = (60 * 60 * 24 * 90)
+ end := time.Now().Unix()
+ start := end - threeMonths
+
+ graph, err := GetAltcoinMarketGraphData(start, end)
+ if err != nil {
+ t.FailNow()
+ }
+
+ if graph.MarketCapByAvailableSupply[0][0] == 0 {
+ t.FailNow()
+ }
+
+ if graph.VolumeUSD[0][0] == 0 {
+ t.FailNow()
+ }
+}
+
+func TestGetCoinData(t *testing.T) {
+ coin, err := GetCoinData("ethereum")
+ if err != nil {
+ t.FailNow()
+ }
+
+ if coin.AvailableSupply == 0 {
+ t.FailNow()
+ }
+ if coin.ID == "" {
+ t.FailNow()
+ }
+ if coin.LastUpdated == "" {
+ t.FailNow()
+ }
+ if coin.MarketCapUSD == 0 {
+ t.FailNow()
+ }
+ if coin.Name == "" {
+ t.FailNow()
+ }
+ if coin.PercentChange1H == 0 {
+ t.FailNow()
+ }
+ if coin.PercentChange24H == 0 {
+ t.FailNow()
+ }
+ if coin.PercentChange7D == 0 {
+ t.FailNow()
+ }
+ if coin.PriceBTC == 0 {
+ t.FailNow()
+ }
+ if coin.PriceUSD == 0 {
+ t.FailNow()
+ }
+ if coin.Rank == 0 {
+ t.FailNow()
+ }
+ if coin.Symbol == "" {
+ t.FailNow()
+ }
+ if coin.TotalSupply == 0 {
+ t.FailNow()
+ }
+ if coin.USD24HVolume == 0 {
+ t.FailNow()
+ }
+}
+
+func TestGetAllCoinData(t *testing.T) {
+ coins, err := GetAllCoinData(10)
+ if err != nil {
+ t.FailNow()
+ }
+
+ if len(coins) != 10 {
+ t.FailNow()
+ }
+}
+
+func TestGetCoinGraphData(t *testing.T) {
+ var threeMonths int64 = (60 * 60 * 24 * 90)
+ end := time.Now().Unix()
+ start := end - threeMonths
+
+ graph, err := GetCoinGraphData("ethereum", start, end)
+ if err != nil {
+ t.FailNow()
+ }
+
+ if graph.MarketCapByAvailableSupply[0][0] == 0 {
+ t.FailNow()
+ }
+ if graph.PriceBTC[0][0] == 0 {
+ t.FailNow()
+ }
+ if graph.PriceUSD[0][0] == 0 {
+ t.FailNow()
+ }
+ if graph.VolumeUSD[0][0] == 0 {
+ t.FailNow()
+ }
+}
+
+func TestGetCoinPriceUSD(t *testing.T) {
+ price, err := GetCoinPriceUSD("ethereum")
+ if err != nil {
+ t.FailNow()
+ }
+ if price <= 0 {
+ t.FailNow()
+ }
+}
+
+func TestGetCoinMarkets(t *testing.T) {
+ markets, err := GetCoinMarkets("ethereum")
+ if err != nil {
+ t.FailNow()
+ }
+ if len(markets) == 0 {
+ t.FailNow()
+ }
+
+ market := markets[0]
+ if market.Rank == 0 {
+ t.FailNow()
+ }
+ if market.Exchange == "" {
+ t.FailNow()
+ }
+ if market.Pair == "" {
+ t.FailNow()
+ }
+ if market.VolumeUSD == 0 {
+ t.FailNow()
+ }
+ if market.Price == 0 {
+ t.FailNow()
+ }
+ if market.VolumePercent == 0 {
+ t.FailNow()
+ }
+ if market.Updated == "" {
+ }
+}
+
+func TestDoReq(t *testing.T) {
+ // TODO
+}
+
+func TestMakeReq(t *testing.T) {
+ // TODO
+}
+
+func TestToInt(t *testing.T) {
+ v := toInt("5")
+ if v != 5 {
+ t.FailNow()
+ }
+}
+
+func TestToFloat(t *testing.T) {
+ v := toFloat("5.2")
+ if v != 5.2 {
+ t.FailNow()
+ }
+}
diff --git a/vendor/github.com/miguelmota/go-coinmarketcap/example/all_coins.go b/vendor/github.com/miguelmota/go-coinmarketcap/example/all_coins.go
new file mode 100644
index 0000000..33f8be6
--- /dev/null
+++ b/vendor/github.com/miguelmota/go-coinmarketcap/example/all_coins.go
@@ -0,0 +1,20 @@
+package main
+
+import (
+ "fmt"
+ "log"
+
+ cmc "github.com/miguelmota/go-coinmarketcap"
+)
+
+func main() {
+ // get data for all coins
+ coins, err := cmc.GetAllCoinData(0)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ for _, coin := range coins {
+ fmt.Println(coin.Symbol, coin.PriceUSD)
+ }
+}
diff --git a/vendor/github.com/miguelmota/go-coinmarketcap/example/coin.go b/vendor/github.com/miguelmota/go-coinmarketcap/example/coin.go
new file mode 100644
index 0000000..daad6ca
--- /dev/null
+++ b/vendor/github.com/miguelmota/go-coinmarketcap/example/coin.go
@@ -0,0 +1,18 @@
+package main
+
+import (
+ "fmt"
+ "log"
+
+ cmc "github.com/miguelmota/go-coinmarketcap"
+)
+
+func main() {
+ // Get info about coin
+ coinInfo, err := cmc.GetCoinData("ethereum")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Println(coinInfo)
+}
diff --git a/vendor/github.com/miguelmota/go-coinmarketcap/example/coin_graph.go b/vendor/github.com/miguelmota/go-coinmarketcap/example/coin_graph.go
new file mode 100644
index 0000000..1eee507
--- /dev/null
+++ b/vendor/github.com/miguelmota/go-coinmarketcap/example/coin_graph.go
@@ -0,0 +1,25 @@
+package main
+
+import (
+ "fmt"
+ "log"
+ "time"
+
+ cmc "github.com/miguelmota/go-coinmarketcap"
+)
+
+func main() {
+ threeMonths := int64(60 * 60 * 24 * 90)
+ now := time.Now()
+ secs := now.Unix()
+ start := secs - threeMonths
+ end := secs
+
+ // Get graph data for coin
+ coinGraphData, err := cmc.GetCoinGraphData("ethereum", start, end)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Println(coinGraphData)
+}
diff --git a/vendor/github.com/miguelmota/go-coinmarketcap/example/global_market.go b/vendor/github.com/miguelmota/go-coinmarketcap/example/global_market.go
new file mode 100644
index 0000000..d9cbafd
--- /dev/null
+++ b/vendor/github.com/miguelmota/go-coinmarketcap/example/global_market.go
@@ -0,0 +1,18 @@
+package main
+
+import (
+ "fmt"
+ "log"
+
+ cmc "github.com/miguelmota/go-coinmarketcap"
+)
+
+func main() {
+ // Get global market data
+ marketInfo, err := cmc.GetGlobalMarketData()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Println(marketInfo)
+}
diff --git a/vendor/github.com/miguelmota/go-coinmarketcap/types.go b/vendor/github.com/miguelmota/go-coinmarketcap/types.go
new file mode 100644
index 0000000..93fd77a
--- /dev/null
+++ b/vendor/github.com/miguelmota/go-coinmarketcap/types.go
@@ -0,0 +1,66 @@
+package coinmarketcap
+
+// Interface interface
+type Interface interface {
+ GetGlobalMarketData() (GlobalMarketData, error)
+ GetGlobalMarketGraphData(start int64, end int64) (MarketGraph, error)
+ GetAltcoinMarketGraphData(start int64, end int64) (MarketGraph, error)
+ GetCoinData(coin string) (Coin, error)
+ GetAllCoinData(limit int) (map[string]Coin, error)
+ GetCoinGraphData(coin string, start int64, end int64) (CoinGraph, error)
+ GetCoinPriceUSD(coin string) (float64, error)
+ GetCoinMarkets(coin string) ([]Market, error)
+}
+
+// Coin struct
+type Coin struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+ Symbol string `json:"symbol"`
+ Rank int `json:"rank,string"`
+ PriceUSD float64 `json:"price_usd,string"`
+ PriceBTC float64 `json:"price_btc,string"`
+ USD24HVolume float64 `json:"24h_volume_usd,string"`
+ MarketCapUSD float64 `json:"market_cap_usd,string"`
+ AvailableSupply float64 `json:"available_supply,string"`
+ TotalSupply float64 `json:"total_supply,string"`
+ PercentChange1H float64 `json:"percent_change_1h,string"`
+ PercentChange24H float64 `json:"percent_change_24h,string"`
+ PercentChange7D float64 `json:"percent_change_7d,string"`
+ LastUpdated string `json:"last_updated"`
+}
+
+// GlobalMarketData struct
+type GlobalMarketData struct {
+ TotalMarketCapUSD float64 `json:"total_market_cap_usd"`
+ Total24HVolumeUSD float64 `json:"total_24h_volume_usd"`
+ BitcoinPercentageOfMarketCap float64 `json:"bitcoin_percentage_of_market_cap"`
+ ActiveCurrencies int `json:"active_currencies"`
+ ActiveAssets int `json:"active_assets"`
+ ActiveMarkets int `json:"active_markets"`
+}
+
+// CoinGraph struct
+type CoinGraph struct {
+ MarketCapByAvailableSupply [][]float64 `json:"market_cap_by_available_supply"`
+ PriceBTC [][]float64 `json:"price_btc"`
+ PriceUSD [][]float64 `json:"price_usd"`
+ VolumeUSD [][]float64 `json:"volume_usd"`
+}
+
+// Market struct
+type Market struct {
+ Rank int
+ Exchange string
+ Pair string
+ VolumeUSD float64
+ Price float64
+ VolumePercent float64
+ Updated string
+}
+
+// MarketGraph struct
+type MarketGraph struct {
+ MarketCapByAvailableSupply [][]float64 `json:"market_cap_by_available_supply"`
+ VolumeUSD [][]float64 `json:"volume_usd"`
+}
diff --git a/vendor/github.com/nsf/termbox-go/AUTHORS b/vendor/github.com/nsf/termbox-go/AUTHORS
new file mode 100644
index 0000000..fe26fb0
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/AUTHORS
@@ -0,0 +1,4 @@
+# Please keep this file sorted.
+
+Georg Reinke
+nsf
diff --git a/vendor/github.com/nsf/termbox-go/LICENSE b/vendor/github.com/nsf/termbox-go/LICENSE
new file mode 100644
index 0000000..d9bc068
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/LICENSE
@@ -0,0 +1,19 @@
+Copyright (C) 2012 termbox-go authors
+
+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/nsf/termbox-go/README.md b/vendor/github.com/nsf/termbox-go/README.md
new file mode 100644
index 0000000..40332bb
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/README.md
@@ -0,0 +1,39 @@
+[![GoDoc](https://godoc.org/github.com/nsf/termbox-go?status.svg)](http://godoc.org/github.com/nsf/termbox-go)
+
+## Termbox
+Termbox is a library that provides a minimalistic API which allows the programmer to write text-based user interfaces. The library is crossplatform and has both terminal-based implementations on *nix operating systems and a winapi console based implementation for windows operating systems. The basic idea is an abstraction of the greatest common subset of features available on all major terminals and other terminal-like APIs in a minimalistic fashion. Small API means it is easy to implement, test, maintain and learn it, that's what makes the termbox a distinct library in its area.
+
+### Installation
+Install and update this go package with `go get -u github.com/nsf/termbox-go`
+
+### Examples
+For examples of what can be done take a look at demos in the _demos directory. You can try them with go run: `go run _demos/keyboard.go`
+
+There are also some interesting projects using termbox-go:
+ - [godit](https://github.com/nsf/godit) is an emacsish lightweight text editor written using termbox.
+ - [gomatrix](https://github.com/GeertJohan/gomatrix) connects to The Matrix and displays its data streams in your terminal.
+ - [gotetris](https://github.com/jjinux/gotetris) is an implementation of Tetris.
+ - [sokoban-go](https://github.com/rn2dy/sokoban-go) is an implementation of sokoban game.
+ - [hecate](https://github.com/evanmiller/hecate) is a hex editor designed by Satan.
+ - [httopd](https://github.com/verdverm/httopd) is top for httpd logs.
+ - [mop](https://github.com/mop-tracker/mop) is stock market tracker for hackers.
+ - [termui](https://github.com/gizak/termui) is a terminal dashboard.
+ - [termloop](https://github.com/JoelOtter/termloop) is a terminal game engine.
+ - [xterm-color-chart](https://github.com/kutuluk/xterm-color-chart) is a XTerm 256 color chart.
+ - [gocui](https://github.com/jroimartin/gocui) is a minimalist Go library aimed at creating console user interfaces.
+ - [dry](https://github.com/moncho/dry) is an interactive cli to manage Docker containers.
+ - [pxl](https://github.com/ichinaski/pxl) displays images in the terminal.
+ - [snake-game](https://github.com/DyegoCosta/snake-game) is an implementation of the Snake game.
+ - [gone](https://github.com/guillaumebreton/gone) is a CLI pomodoro® timer.
+ - [Spoof.go](https://github.com/sabey/spoofgo) controllable movement spoofing from the cli
+ - [lf](https://github.com/gokcehan/lf) is a terminal file manager
+ - [rat](https://github.com/ericfreese/rat) lets you compose shell commands to build terminal applications.
+ - [httplab](https://github.com/gchaincl/httplab) An interactive web server.
+ - [tetris](https://github.com/MichaelS11/tetris) Go Tetris with AI option
+ - [wot](https://github.com/kyu-suke/wot) Wait time during command is completed.
+ - [2048-go](https://github.com/1984weed/2048-go) is 2048 in Go
+ - [jv](https://github.com/maxzender/jv) helps you view JSON on the command-line.
+ - [pinger](https://github.com/hirose31/pinger) helps you to monitor numerous hosts using ICMP ECHO_REQUEST.
+ - [vixl44](https://github.com/sebashwa/vixl44) lets you create pixel art inside your terminal using vim movements
+ - [zterm](https://github.com/varunrau/zterm) is a typing game inspired by http://zty.pe/
+ - [cointop](https://github.com/miguelmota/cointop) is an interactive terminal based UI application for tracking cryptocurrencies.
diff --git a/vendor/github.com/nsf/termbox-go/_demos/editbox.go b/vendor/github.com/nsf/termbox-go/_demos/editbox.go
new file mode 100644
index 0000000..e429080
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/_demos/editbox.go
@@ -0,0 +1,300 @@
+package main
+
+import (
+ "github.com/mattn/go-runewidth"
+ "github.com/nsf/termbox-go"
+ "unicode/utf8"
+)
+
+func tbprint(x, y int, fg, bg termbox.Attribute, msg string) {
+ for _, c := range msg {
+ termbox.SetCell(x, y, c, fg, bg)
+ x += runewidth.RuneWidth(c)
+ }
+}
+
+func fill(x, y, w, h int, cell termbox.Cell) {
+ for ly := 0; ly < h; ly++ {
+ for lx := 0; lx < w; lx++ {
+ termbox.SetCell(x+lx, y+ly, cell.Ch, cell.Fg, cell.Bg)
+ }
+ }
+}
+
+func rune_advance_len(r rune, pos int) int {
+ if r == '\t' {
+ return tabstop_length - pos%tabstop_length
+ }
+ return runewidth.RuneWidth(r)
+}
+
+func voffset_coffset(text []byte, boffset int) (voffset, coffset int) {
+ text = text[:boffset]
+ for len(text) > 0 {
+ r, size := utf8.DecodeRune(text)
+ text = text[size:]
+ coffset += 1
+ voffset += rune_advance_len(r, voffset)
+ }
+ return
+}
+
+func byte_slice_grow(s []byte, desired_cap int) []byte {
+ if cap(s) < desired_cap {
+ ns := make([]byte, len(s), desired_cap)
+ copy(ns, s)
+ return ns
+ }
+ return s
+}
+
+func byte_slice_remove(text []byte, from, to int) []byte {
+ size := to - from
+ copy(text[from:], text[to:])
+ text = text[:len(text)-size]
+ return text
+}
+
+func byte_slice_insert(text []byte, offset int, what []byte) []byte {
+ n := len(text) + len(what)
+ text = byte_slice_grow(text, n)
+ text = text[:n]
+ copy(text[offset+len(what):], text[offset:])
+ copy(text[offset:], what)
+ return text
+}
+
+const preferred_horizontal_threshold = 5
+const tabstop_length = 8
+
+type EditBox struct {
+ text []byte
+ line_voffset int
+ cursor_boffset int // cursor offset in bytes
+ cursor_voffset int // visual cursor offset in termbox cells
+ cursor_coffset int // cursor offset in unicode code points
+}
+
+// Draws the EditBox in the given location, 'h' is not used at the moment
+func (eb *EditBox) Draw(x, y, w, h int) {
+ eb.AdjustVOffset(w)
+
+ const coldef = termbox.ColorDefault
+ fill(x, y, w, h, termbox.Cell{Ch: ' '})
+
+ t := eb.text
+ lx := 0
+ tabstop := 0
+ for {
+ rx := lx - eb.line_voffset
+ if len(t) == 0 {
+ break
+ }
+
+ if lx == tabstop {
+ tabstop += tabstop_length
+ }
+
+ if rx >= w {
+ termbox.SetCell(x+w-1, y, '→',
+ coldef, coldef)
+ break
+ }
+
+ r, size := utf8.DecodeRune(t)
+ if r == '\t' {
+ for ; lx < tabstop; lx++ {
+ rx = lx - eb.line_voffset
+ if rx >= w {
+ goto next
+ }
+
+ if rx >= 0 {
+ termbox.SetCell(x+rx, y, ' ', coldef, coldef)
+ }
+ }
+ } else {
+ if rx >= 0 {
+ termbox.SetCell(x+rx, y, r, coldef, coldef)
+ }
+ lx += runewidth.RuneWidth(r)
+ }
+ next:
+ t = t[size:]
+ }
+
+ if eb.line_voffset != 0 {
+ termbox.SetCell(x, y, '←', coldef, coldef)
+ }
+}
+
+// Adjusts line visual offset to a proper value depending on width
+func (eb *EditBox) AdjustVOffset(width int) {
+ ht := preferred_horizontal_threshold
+ max_h_threshold := (width - 1) / 2
+ if ht > max_h_threshold {
+ ht = max_h_threshold
+ }
+
+ threshold := width - 1
+ if eb.line_voffset != 0 {
+ threshold = width - ht
+ }
+ if eb.cursor_voffset-eb.line_voffset >= threshold {
+ eb.line_voffset = eb.cursor_voffset + (ht - width + 1)
+ }
+
+ if eb.line_voffset != 0 && eb.cursor_voffset-eb.line_voffset < ht {
+ eb.line_voffset = eb.cursor_voffset - ht
+ if eb.line_voffset < 0 {
+ eb.line_voffset = 0
+ }
+ }
+}
+
+func (eb *EditBox) MoveCursorTo(boffset int) {
+ eb.cursor_boffset = boffset
+ eb.cursor_voffset, eb.cursor_coffset = voffset_coffset(eb.text, boffset)
+}
+
+func (eb *EditBox) RuneUnderCursor() (rune, int) {
+ return utf8.DecodeRune(eb.text[eb.cursor_boffset:])
+}
+
+func (eb *EditBox) RuneBeforeCursor() (rune, int) {
+ return utf8.DecodeLastRune(eb.text[:eb.cursor_boffset])
+}
+
+func (eb *EditBox) MoveCursorOneRuneBackward() {
+ if eb.cursor_boffset == 0 {
+ return
+ }
+ _, size := eb.RuneBeforeCursor()
+ eb.MoveCursorTo(eb.cursor_boffset - size)
+}
+
+func (eb *EditBox) MoveCursorOneRuneForward() {
+ if eb.cursor_boffset == len(eb.text) {
+ return
+ }
+ _, size := eb.RuneUnderCursor()
+ eb.MoveCursorTo(eb.cursor_boffset + size)
+}
+
+func (eb *EditBox) MoveCursorToBeginningOfTheLine() {
+ eb.MoveCursorTo(0)
+}
+
+func (eb *EditBox) MoveCursorToEndOfTheLine() {
+ eb.MoveCursorTo(len(eb.text))
+}
+
+func (eb *EditBox) DeleteRuneBackward() {
+ if eb.cursor_boffset == 0 {
+ return
+ }
+
+ eb.MoveCursorOneRuneBackward()
+ _, size := eb.RuneUnderCursor()
+ eb.text = byte_slice_remove(eb.text, eb.cursor_boffset, eb.cursor_boffset+size)
+}
+
+func (eb *EditBox) DeleteRuneForward() {
+ if eb.cursor_boffset == len(eb.text) {
+ return
+ }
+ _, size := eb.RuneUnderCursor()
+ eb.text = byte_slice_remove(eb.text, eb.cursor_boffset, eb.cursor_boffset+size)
+}
+
+func (eb *EditBox) DeleteTheRestOfTheLine() {
+ eb.text = eb.text[:eb.cursor_boffset]
+}
+
+func (eb *EditBox) InsertRune(r rune) {
+ var buf [utf8.UTFMax]byte
+ n := utf8.EncodeRune(buf[:], r)
+ eb.text = byte_slice_insert(eb.text, eb.cursor_boffset, buf[:n])
+ eb.MoveCursorOneRuneForward()
+}
+
+// Please, keep in mind that cursor depends on the value of line_voffset, which
+// is being set on Draw() call, so.. call this method after Draw() one.
+func (eb *EditBox) CursorX() int {
+ return eb.cursor_voffset - eb.line_voffset
+}
+
+var edit_box EditBox
+
+const edit_box_width = 30
+
+func redraw_all() {
+ const coldef = termbox.ColorDefault
+ termbox.Clear(coldef, coldef)
+ w, h := termbox.Size()
+
+ midy := h / 2
+ midx := (w - edit_box_width) / 2
+
+ // unicode box drawing chars around the edit box
+ termbox.SetCell(midx-1, midy, '│', coldef, coldef)
+ termbox.SetCell(midx+edit_box_width, midy, '│', coldef, coldef)
+ termbox.SetCell(midx-1, midy-1, '┌', coldef, coldef)
+ termbox.SetCell(midx-1, midy+1, '└', coldef, coldef)
+ termbox.SetCell(midx+edit_box_width, midy-1, '┐', coldef, coldef)
+ termbox.SetCell(midx+edit_box_width, midy+1, '┘', coldef, coldef)
+ fill(midx, midy-1, edit_box_width, 1, termbox.Cell{Ch: '─'})
+ fill(midx, midy+1, edit_box_width, 1, termbox.Cell{Ch: '─'})
+
+ edit_box.Draw(midx, midy, edit_box_width, 1)
+ termbox.SetCursor(midx+edit_box.CursorX(), midy)
+
+ tbprint(midx+6, midy+3, coldef, coldef, "Press ESC to quit")
+ termbox.Flush()
+}
+
+func main() {
+ err := termbox.Init()
+ if err != nil {
+ panic(err)
+ }
+ defer termbox.Close()
+ termbox.SetInputMode(termbox.InputEsc)
+
+ redraw_all()
+mainloop:
+ for {
+ switch ev := termbox.PollEvent(); ev.Type {
+ case termbox.EventKey:
+ switch ev.Key {
+ case termbox.KeyEsc:
+ break mainloop
+ case termbox.KeyArrowLeft, termbox.KeyCtrlB:
+ edit_box.MoveCursorOneRuneBackward()
+ case termbox.KeyArrowRight, termbox.KeyCtrlF:
+ edit_box.MoveCursorOneRuneForward()
+ case termbox.KeyBackspace, termbox.KeyBackspace2:
+ edit_box.DeleteRuneBackward()
+ case termbox.KeyDelete, termbox.KeyCtrlD:
+ edit_box.DeleteRuneForward()
+ case termbox.KeyTab:
+ edit_box.InsertRune('\t')
+ case termbox.KeySpace:
+ edit_box.InsertRune(' ')
+ case termbox.KeyCtrlK:
+ edit_box.DeleteTheRestOfTheLine()
+ case termbox.KeyHome, termbox.KeyCtrlA:
+ edit_box.MoveCursorToBeginningOfTheLine()
+ case termbox.KeyEnd, termbox.KeyCtrlE:
+ edit_box.MoveCursorToEndOfTheLine()
+ default:
+ if ev.Ch != 0 {
+ edit_box.InsertRune(ev.Ch)
+ }
+ }
+ case termbox.EventError:
+ panic(ev.Err)
+ }
+ redraw_all()
+ }
+}
diff --git a/vendor/github.com/nsf/termbox-go/_demos/interrupt.go b/vendor/github.com/nsf/termbox-go/_demos/interrupt.go
new file mode 100644
index 0000000..5534521
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/_demos/interrupt.go
@@ -0,0 +1,69 @@
+package main
+
+import (
+ "fmt"
+ "github.com/nsf/termbox-go"
+ "time"
+)
+
+func tbPrint(x, y int, fg, bg termbox.Attribute, msg string) {
+ for _, c := range msg {
+ termbox.SetCell(x, y, c, fg, bg)
+ x++
+ }
+}
+
+func draw(i int) {
+ termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
+ defer termbox.Flush()
+
+ w, h := termbox.Size()
+ s := fmt.Sprintf("count = %d", i)
+
+ tbPrint((w/2)-(len(s)/2), h/2, termbox.ColorRed, termbox.ColorDefault, s)
+}
+
+func main() {
+ err := termbox.Init()
+ if err != nil {
+ panic(err)
+ }
+ termbox.SetInputMode(termbox.InputEsc)
+
+ go func() {
+ time.Sleep(5 * time.Second)
+ termbox.Interrupt()
+
+ // This should never run - the Interrupt(), above, should cause the event
+ // loop below to exit, which then exits the process. If something goes
+ // wrong, this panic will trigger and show what happened.
+ time.Sleep(1 * time.Second)
+ panic("this should never run")
+ }()
+
+ var count int
+
+ draw(count)
+mainloop:
+ for {
+ switch ev := termbox.PollEvent(); ev.Type {
+ case termbox.EventKey:
+ if ev.Ch == '+' {
+ count++
+ } else if ev.Ch == '-' {
+ count--
+ }
+
+ case termbox.EventError:
+ panic(ev.Err)
+
+ case termbox.EventInterrupt:
+ break mainloop
+ }
+
+ draw(count)
+ }
+ termbox.Close()
+
+ fmt.Println("Finished")
+}
diff --git a/vendor/github.com/nsf/termbox-go/_demos/keyboard.go b/vendor/github.com/nsf/termbox-go/_demos/keyboard.go
new file mode 100644
index 0000000..b6a258e
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/_demos/keyboard.go
@@ -0,0 +1,722 @@
+package main
+
+import "github.com/nsf/termbox-go"
+import "fmt"
+
+type key struct {
+ x int
+ y int
+ ch rune
+}
+
+var K_ESC = []key{{1, 1, 'E'}, {2, 1, 'S'}, {3, 1, 'C'}}
+var K_F1 = []key{{6, 1, 'F'}, {7, 1, '1'}}
+var K_F2 = []key{{9, 1, 'F'}, {10, 1, '2'}}
+var K_F3 = []key{{12, 1, 'F'}, {13, 1, '3'}}
+var K_F4 = []key{{15, 1, 'F'}, {16, 1, '4'}}
+var K_F5 = []key{{19, 1, 'F'}, {20, 1, '5'}}
+var K_F6 = []key{{22, 1, 'F'}, {23, 1, '6'}}
+var K_F7 = []key{{25, 1, 'F'}, {26, 1, '7'}}
+var K_F8 = []key{{28, 1, 'F'}, {29, 1, '8'}}
+var K_F9 = []key{{33, 1, 'F'}, {34, 1, '9'}}
+var K_F10 = []key{{36, 1, 'F'}, {37, 1, '1'}, {38, 1, '0'}}
+var K_F11 = []key{{40, 1, 'F'}, {41, 1, '1'}, {42, 1, '1'}}
+var K_F12 = []key{{44, 1, 'F'}, {45, 1, '1'}, {46, 1, '2'}}
+var K_PRN = []key{{50, 1, 'P'}, {51, 1, 'R'}, {52, 1, 'N'}}
+var K_SCR = []key{{54, 1, 'S'}, {55, 1, 'C'}, {56, 1, 'R'}}
+var K_BRK = []key{{58, 1, 'B'}, {59, 1, 'R'}, {60, 1, 'K'}}
+var K_LED1 = []key{{66, 1, '-'}}
+var K_LED2 = []key{{70, 1, '-'}}
+var K_LED3 = []key{{74, 1, '-'}}
+var K_TILDE = []key{{1, 4, '`'}}
+var K_TILDE_SHIFT = []key{{1, 4, '~'}}
+var K_1 = []key{{4, 4, '1'}}
+var K_1_SHIFT = []key{{4, 4, '!'}}
+var K_2 = []key{{7, 4, '2'}}
+var K_2_SHIFT = []key{{7, 4, '@'}}
+var K_3 = []key{{10, 4, '3'}}
+var K_3_SHIFT = []key{{10, 4, '#'}}
+var K_4 = []key{{13, 4, '4'}}
+var K_4_SHIFT = []key{{13, 4, '$'}}
+var K_5 = []key{{16, 4, '5'}}
+var K_5_SHIFT = []key{{16, 4, '%'}}
+var K_6 = []key{{19, 4, '6'}}
+var K_6_SHIFT = []key{{19, 4, '^'}}
+var K_7 = []key{{22, 4, '7'}}
+var K_7_SHIFT = []key{{22, 4, '&'}}
+var K_8 = []key{{25, 4, '8'}}
+var K_8_SHIFT = []key{{25, 4, '*'}}
+var K_9 = []key{{28, 4, '9'}}
+var K_9_SHIFT = []key{{28, 4, '('}}
+var K_0 = []key{{31, 4, '0'}}
+var K_0_SHIFT = []key{{31, 4, ')'}}
+var K_MINUS = []key{{34, 4, '-'}}
+var K_MINUS_SHIFT = []key{{34, 4, '_'}}
+var K_EQUALS = []key{{37, 4, '='}}
+var K_EQUALS_SHIFT = []key{{37, 4, '+'}}
+var K_BACKSLASH = []key{{40, 4, '\\'}}
+var K_BACKSLASH_SHIFT = []key{{40, 4, '|'}}
+var K_BACKSPACE = []key{{44, 4, 0x2190}, {45, 4, 0x2500}, {46, 4, 0x2500}}
+var K_INS = []key{{50, 4, 'I'}, {51, 4, 'N'}, {52, 4, 'S'}}
+var K_HOM = []key{{54, 4, 'H'}, {55, 4, 'O'}, {56, 4, 'M'}}
+var K_PGU = []key{{58, 4, 'P'}, {59, 4, 'G'}, {60, 4, 'U'}}
+var K_K_NUMLOCK = []key{{65, 4, 'N'}}
+var K_K_SLASH = []key{{68, 4, '/'}}
+var K_K_STAR = []key{{71, 4, '*'}}
+var K_K_MINUS = []key{{74, 4, '-'}}
+var K_TAB = []key{{1, 6, 'T'}, {2, 6, 'A'}, {3, 6, 'B'}}
+var K_q = []key{{6, 6, 'q'}}
+var K_Q = []key{{6, 6, 'Q'}}
+var K_w = []key{{9, 6, 'w'}}
+var K_W = []key{{9, 6, 'W'}}
+var K_e = []key{{12, 6, 'e'}}
+var K_E = []key{{12, 6, 'E'}}
+var K_r = []key{{15, 6, 'r'}}
+var K_R = []key{{15, 6, 'R'}}
+var K_t = []key{{18, 6, 't'}}
+var K_T = []key{{18, 6, 'T'}}
+var K_y = []key{{21, 6, 'y'}}
+var K_Y = []key{{21, 6, 'Y'}}
+var K_u = []key{{24, 6, 'u'}}
+var K_U = []key{{24, 6, 'U'}}
+var K_i = []key{{27, 6, 'i'}}
+var K_I = []key{{27, 6, 'I'}}
+var K_o = []key{{30, 6, 'o'}}
+var K_O = []key{{30, 6, 'O'}}
+var K_p = []key{{33, 6, 'p'}}
+var K_P = []key{{33, 6, 'P'}}
+var K_LSQB = []key{{36, 6, '['}}
+var K_LCUB = []key{{36, 6, '{'}}
+var K_RSQB = []key{{39, 6, ']'}}
+var K_RCUB = []key{{39, 6, '}'}}
+var K_ENTER = []key{
+ {43, 6, 0x2591}, {44, 6, 0x2591}, {45, 6, 0x2591}, {46, 6, 0x2591},
+ {43, 7, 0x2591}, {44, 7, 0x2591}, {45, 7, 0x21B5}, {46, 7, 0x2591},
+ {41, 8, 0x2591}, {42, 8, 0x2591}, {43, 8, 0x2591}, {44, 8, 0x2591},
+ {45, 8, 0x2591}, {46, 8, 0x2591},
+}
+var K_DEL = []key{{50, 6, 'D'}, {51, 6, 'E'}, {52, 6, 'L'}}
+var K_END = []key{{54, 6, 'E'}, {55, 6, 'N'}, {56, 6, 'D'}}
+var K_PGD = []key{{58, 6, 'P'}, {59, 6, 'G'}, {60, 6, 'D'}}
+var K_K_7 = []key{{65, 6, '7'}}
+var K_K_8 = []key{{68, 6, '8'}}
+var K_K_9 = []key{{71, 6, '9'}}
+var K_K_PLUS = []key{{74, 6, ' '}, {74, 7, '+'}, {74, 8, ' '}}
+var K_CAPS = []key{{1, 8, 'C'}, {2, 8, 'A'}, {3, 8, 'P'}, {4, 8, 'S'}}
+var K_a = []key{{7, 8, 'a'}}
+var K_A = []key{{7, 8, 'A'}}
+var K_s = []key{{10, 8, 's'}}
+var K_S = []key{{10, 8, 'S'}}
+var K_d = []key{{13, 8, 'd'}}
+var K_D = []key{{13, 8, 'D'}}
+var K_f = []key{{16, 8, 'f'}}
+var K_F = []key{{16, 8, 'F'}}
+var K_g = []key{{19, 8, 'g'}}
+var K_G = []key{{19, 8, 'G'}}
+var K_h = []key{{22, 8, 'h'}}
+var K_H = []key{{22, 8, 'H'}}
+var K_j = []key{{25, 8, 'j'}}
+var K_J = []key{{25, 8, 'J'}}
+var K_k = []key{{28, 8, 'k'}}
+var K_K = []key{{28, 8, 'K'}}
+var K_l = []key{{31, 8, 'l'}}
+var K_L = []key{{31, 8, 'L'}}
+var K_SEMICOLON = []key{{34, 8, ';'}}
+var K_PARENTHESIS = []key{{34, 8, ':'}}
+var K_QUOTE = []key{{37, 8, '\''}}
+var K_DOUBLEQUOTE = []key{{37, 8, '"'}}
+var K_K_4 = []key{{65, 8, '4'}}
+var K_K_5 = []key{{68, 8, '5'}}
+var K_K_6 = []key{{71, 8, '6'}}
+var K_LSHIFT = []key{{1, 10, 'S'}, {2, 10, 'H'}, {3, 10, 'I'}, {4, 10, 'F'}, {5, 10, 'T'}}
+var K_z = []key{{9, 10, 'z'}}
+var K_Z = []key{{9, 10, 'Z'}}
+var K_x = []key{{12, 10, 'x'}}
+var K_X = []key{{12, 10, 'X'}}
+var K_c = []key{{15, 10, 'c'}}
+var K_C = []key{{15, 10, 'C'}}
+var K_v = []key{{18, 10, 'v'}}
+var K_V = []key{{18, 10, 'V'}}
+var K_b = []key{{21, 10, 'b'}}
+var K_B = []key{{21, 10, 'B'}}
+var K_n = []key{{24, 10, 'n'}}
+var K_N = []key{{24, 10, 'N'}}
+var K_m = []key{{27, 10, 'm'}}
+var K_M = []key{{27, 10, 'M'}}
+var K_COMMA = []key{{30, 10, ','}}
+var K_LANB = []key{{30, 10, '<'}}
+var K_PERIOD = []key{{33, 10, '.'}}
+var K_RANB = []key{{33, 10, '>'}}
+var K_SLASH = []key{{36, 10, '/'}}
+var K_QUESTION = []key{{36, 10, '?'}}
+var K_RSHIFT = []key{{42, 10, 'S'}, {43, 10, 'H'}, {44, 10, 'I'}, {45, 10, 'F'}, {46, 10, 'T'}}
+var K_ARROW_UP = []key{{54, 10, '('}, {55, 10, 0x2191}, {56, 10, ')'}}
+var K_K_1 = []key{{65, 10, '1'}}
+var K_K_2 = []key{{68, 10, '2'}}
+var K_K_3 = []key{{71, 10, '3'}}
+var K_K_ENTER = []key{{74, 10, 0x2591}, {74, 11, 0x2591}, {74, 12, 0x2591}}
+var K_LCTRL = []key{{1, 12, 'C'}, {2, 12, 'T'}, {3, 12, 'R'}, {4, 12, 'L'}}
+var K_LWIN = []key{{6, 12, 'W'}, {7, 12, 'I'}, {8, 12, 'N'}}
+var K_LALT = []key{{10, 12, 'A'}, {11, 12, 'L'}, {12, 12, 'T'}}
+var K_SPACE = []key{
+ {14, 12, ' '}, {15, 12, ' '}, {16, 12, ' '}, {17, 12, ' '}, {18, 12, ' '},
+ {19, 12, 'S'}, {20, 12, 'P'}, {21, 12, 'A'}, {22, 12, 'C'}, {23, 12, 'E'},
+ {24, 12, ' '}, {25, 12, ' '}, {26, 12, ' '}, {27, 12, ' '}, {28, 12, ' '},
+}
+var K_RALT = []key{{30, 12, 'A'}, {31, 12, 'L'}, {32, 12, 'T'}}
+var K_RWIN = []key{{34, 12, 'W'}, {35, 12, 'I'}, {36, 12, 'N'}}
+var K_RPROP = []key{{38, 12, 'P'}, {39, 12, 'R'}, {40, 12, 'O'}, {41, 12, 'P'}}
+var K_RCTRL = []key{{43, 12, 'C'}, {44, 12, 'T'}, {45, 12, 'R'}, {46, 12, 'L'}}
+var K_ARROW_LEFT = []key{{50, 12, '('}, {51, 12, 0x2190}, {52, 12, ')'}}
+var K_ARROW_DOWN = []key{{54, 12, '('}, {55, 12, 0x2193}, {56, 12, ')'}}
+var K_ARROW_RIGHT = []key{{58, 12, '('}, {59, 12, 0x2192}, {60, 12, ')'}}
+var K_K_0 = []key{{65, 12, ' '}, {66, 12, '0'}, {67, 12, ' '}, {68, 12, ' '}}
+var K_K_PERIOD = []key{{71, 12, '.'}}
+
+type combo struct {
+ keys [][]key
+}
+
+var combos = []combo{
+ {[][]key{K_TILDE, K_2, K_SPACE, K_LCTRL, K_RCTRL}},
+ {[][]key{K_A, K_LCTRL, K_RCTRL}},
+ {[][]key{K_B, K_LCTRL, K_RCTRL}},
+ {[][]key{K_C, K_LCTRL, K_RCTRL}},
+ {[][]key{K_D, K_LCTRL, K_RCTRL}},
+ {[][]key{K_E, K_LCTRL, K_RCTRL}},
+ {[][]key{K_F, K_LCTRL, K_RCTRL}},
+ {[][]key{K_G, K_LCTRL, K_RCTRL}},
+ {[][]key{K_H, K_BACKSPACE, K_LCTRL, K_RCTRL}},
+ {[][]key{K_I, K_TAB, K_LCTRL, K_RCTRL}},
+ {[][]key{K_J, K_LCTRL, K_RCTRL}},
+ {[][]key{K_K, K_LCTRL, K_RCTRL}},
+ {[][]key{K_L, K_LCTRL, K_RCTRL}},
+ {[][]key{K_M, K_ENTER, K_K_ENTER, K_LCTRL, K_RCTRL}},
+ {[][]key{K_N, K_LCTRL, K_RCTRL}},
+ {[][]key{K_O, K_LCTRL, K_RCTRL}},
+ {[][]key{K_P, K_LCTRL, K_RCTRL}},
+ {[][]key{K_Q, K_LCTRL, K_RCTRL}},
+ {[][]key{K_R, K_LCTRL, K_RCTRL}},
+ {[][]key{K_S, K_LCTRL, K_RCTRL}},
+ {[][]key{K_T, K_LCTRL, K_RCTRL}},
+ {[][]key{K_U, K_LCTRL, K_RCTRL}},
+ {[][]key{K_V, K_LCTRL, K_RCTRL}},
+ {[][]key{K_W, K_LCTRL, K_RCTRL}},
+ {[][]key{K_X, K_LCTRL, K_RCTRL}},
+ {[][]key{K_Y, K_LCTRL, K_RCTRL}},
+ {[][]key{K_Z, K_LCTRL, K_RCTRL}},
+ {[][]key{K_LSQB, K_ESC, K_3, K_LCTRL, K_RCTRL}},
+ {[][]key{K_4, K_BACKSLASH, K_LCTRL, K_RCTRL}},
+ {[][]key{K_RSQB, K_5, K_LCTRL, K_RCTRL}},
+ {[][]key{K_6, K_LCTRL, K_RCTRL}},
+ {[][]key{K_7, K_SLASH, K_MINUS_SHIFT, K_LCTRL, K_RCTRL}},
+ {[][]key{K_SPACE}},
+ {[][]key{K_1_SHIFT, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_DOUBLEQUOTE, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_3_SHIFT, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_4_SHIFT, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_5_SHIFT, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_7_SHIFT, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_QUOTE}},
+ {[][]key{K_9_SHIFT, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_0_SHIFT, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_8_SHIFT, K_K_STAR, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_EQUALS_SHIFT, K_K_PLUS, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_COMMA}},
+ {[][]key{K_MINUS, K_K_MINUS}},
+ {[][]key{K_PERIOD, K_K_PERIOD}},
+ {[][]key{K_SLASH, K_K_SLASH}},
+ {[][]key{K_0, K_K_0}},
+ {[][]key{K_1, K_K_1}},
+ {[][]key{K_2, K_K_2}},
+ {[][]key{K_3, K_K_3}},
+ {[][]key{K_4, K_K_4}},
+ {[][]key{K_5, K_K_5}},
+ {[][]key{K_6, K_K_6}},
+ {[][]key{K_7, K_K_7}},
+ {[][]key{K_8, K_K_8}},
+ {[][]key{K_9, K_K_9}},
+ {[][]key{K_PARENTHESIS, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_SEMICOLON}},
+ {[][]key{K_LANB, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_EQUALS}},
+ {[][]key{K_RANB, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_QUESTION, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_2_SHIFT, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_A, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_B, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_C, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_D, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_E, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_F, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_G, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_H, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_I, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_J, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_K, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_L, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_M, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_N, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_O, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_P, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_Q, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_R, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_S, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_T, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_U, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_V, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_W, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_X, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_Y, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_Z, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_LSQB}},
+ {[][]key{K_BACKSLASH}},
+ {[][]key{K_RSQB}},
+ {[][]key{K_6_SHIFT, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_MINUS_SHIFT, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_TILDE}},
+ {[][]key{K_a}},
+ {[][]key{K_b}},
+ {[][]key{K_c}},
+ {[][]key{K_d}},
+ {[][]key{K_e}},
+ {[][]key{K_f}},
+ {[][]key{K_g}},
+ {[][]key{K_h}},
+ {[][]key{K_i}},
+ {[][]key{K_j}},
+ {[][]key{K_k}},
+ {[][]key{K_l}},
+ {[][]key{K_m}},
+ {[][]key{K_n}},
+ {[][]key{K_o}},
+ {[][]key{K_p}},
+ {[][]key{K_q}},
+ {[][]key{K_r}},
+ {[][]key{K_s}},
+ {[][]key{K_t}},
+ {[][]key{K_u}},
+ {[][]key{K_v}},
+ {[][]key{K_w}},
+ {[][]key{K_x}},
+ {[][]key{K_y}},
+ {[][]key{K_z}},
+ {[][]key{K_LCUB, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_BACKSLASH_SHIFT, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_RCUB, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_TILDE_SHIFT, K_LSHIFT, K_RSHIFT}},
+ {[][]key{K_8, K_BACKSPACE, K_LCTRL, K_RCTRL}},
+}
+
+var func_combos = []combo{
+ {[][]key{K_F1}},
+ {[][]key{K_F2}},
+ {[][]key{K_F3}},
+ {[][]key{K_F4}},
+ {[][]key{K_F5}},
+ {[][]key{K_F6}},
+ {[][]key{K_F7}},
+ {[][]key{K_F8}},
+ {[][]key{K_F9}},
+ {[][]key{K_F10}},
+ {[][]key{K_F11}},
+ {[][]key{K_F12}},
+ {[][]key{K_INS}},
+ {[][]key{K_DEL}},
+ {[][]key{K_HOM}},
+ {[][]key{K_END}},
+ {[][]key{K_PGU}},
+ {[][]key{K_PGD}},
+ {[][]key{K_ARROW_UP}},
+ {[][]key{K_ARROW_DOWN}},
+ {[][]key{K_ARROW_LEFT}},
+ {[][]key{K_ARROW_RIGHT}},
+}
+
+func print_tb(x, y int, fg, bg termbox.Attribute, msg string) {
+ for _, c := range msg {
+ termbox.SetCell(x, y, c, fg, bg)
+ x++
+ }
+}
+
+func printf_tb(x, y int, fg, bg termbox.Attribute, format string, args ...interface{}) {
+ s := fmt.Sprintf(format, args...)
+ print_tb(x, y, fg, bg, s)
+}
+
+func draw_key(k []key, fg, bg termbox.Attribute) {
+ for _, k := range k {
+ termbox.SetCell(k.x+2, k.y+4, k.ch, fg, bg)
+ }
+}
+
+func draw_keyboard() {
+ termbox.SetCell(0, 0, 0x250C, termbox.ColorWhite, termbox.ColorBlack)
+ termbox.SetCell(79, 0, 0x2510, termbox.ColorWhite, termbox.ColorBlack)
+ termbox.SetCell(0, 23, 0x2514, termbox.ColorWhite, termbox.ColorBlack)
+ termbox.SetCell(79, 23, 0x2518, termbox.ColorWhite, termbox.ColorBlack)
+
+ for i := 1; i < 79; i++ {
+ termbox.SetCell(i, 0, 0x2500, termbox.ColorWhite, termbox.ColorBlack)
+ termbox.SetCell(i, 23, 0x2500, termbox.ColorWhite, termbox.ColorBlack)
+ termbox.SetCell(i, 17, 0x2500, termbox.ColorWhite, termbox.ColorBlack)
+ termbox.SetCell(i, 4, 0x2500, termbox.ColorWhite, termbox.ColorBlack)
+ }
+ for i := 1; i < 23; i++ {
+ termbox.SetCell(0, i, 0x2502, termbox.ColorWhite, termbox.ColorBlack)
+ termbox.SetCell(79, i, 0x2502, termbox.ColorWhite, termbox.ColorBlack)
+ }
+ termbox.SetCell(0, 17, 0x251C, termbox.ColorWhite, termbox.ColorBlack)
+ termbox.SetCell(79, 17, 0x2524, termbox.ColorWhite, termbox.ColorBlack)
+ termbox.SetCell(0, 4, 0x251C, termbox.ColorWhite, termbox.ColorBlack)
+ termbox.SetCell(79, 4, 0x2524, termbox.ColorWhite, termbox.ColorBlack)
+ for i := 5; i < 17; i++ {
+ termbox.SetCell(1, i, 0x2588, termbox.ColorYellow, termbox.ColorYellow)
+ termbox.SetCell(78, i, 0x2588, termbox.ColorYellow, termbox.ColorYellow)
+ }
+
+ draw_key(K_ESC, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_F1, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_F2, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_F3, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_F4, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_F5, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_F6, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_F7, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_F8, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_F9, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_F10, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_F11, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_F12, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_PRN, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_SCR, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_BRK, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_LED1, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_LED2, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_LED3, termbox.ColorWhite, termbox.ColorBlue)
+
+ draw_key(K_TILDE, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_1, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_2, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_3, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_4, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_5, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_6, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_7, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_8, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_9, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_0, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_MINUS, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_EQUALS, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_BACKSLASH, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_BACKSPACE, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_INS, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_HOM, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_PGU, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_K_NUMLOCK, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_K_SLASH, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_K_STAR, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_K_MINUS, termbox.ColorWhite, termbox.ColorBlue)
+
+ draw_key(K_TAB, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_q, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_w, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_e, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_r, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_t, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_y, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_u, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_i, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_o, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_p, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_LSQB, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_RSQB, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_ENTER, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_DEL, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_END, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_PGD, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_K_7, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_K_8, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_K_9, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_K_PLUS, termbox.ColorWhite, termbox.ColorBlue)
+
+ draw_key(K_CAPS, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_a, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_s, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_d, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_f, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_g, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_h, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_j, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_k, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_l, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_SEMICOLON, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_QUOTE, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_K_4, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_K_5, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_K_6, termbox.ColorWhite, termbox.ColorBlue)
+
+ draw_key(K_LSHIFT, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_z, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_x, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_c, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_v, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_b, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_n, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_m, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_COMMA, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_PERIOD, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_SLASH, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_RSHIFT, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_ARROW_UP, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_K_1, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_K_2, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_K_3, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_K_ENTER, termbox.ColorWhite, termbox.ColorBlue)
+
+ draw_key(K_LCTRL, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_LWIN, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_LALT, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_SPACE, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_RCTRL, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_RPROP, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_RWIN, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_RALT, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_ARROW_LEFT, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_ARROW_DOWN, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_ARROW_RIGHT, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_K_0, termbox.ColorWhite, termbox.ColorBlue)
+ draw_key(K_K_PERIOD, termbox.ColorWhite, termbox.ColorBlue)
+
+ printf_tb(33, 1, termbox.ColorMagenta|termbox.AttrBold, termbox.ColorBlack, "Keyboard demo!")
+ printf_tb(21, 2, termbox.ColorMagenta, termbox.ColorBlack, "(press CTRL+X and then CTRL+Q to exit)")
+ printf_tb(15, 3, termbox.ColorMagenta, termbox.ColorBlack, "(press CTRL+X and then CTRL+C to change input mode)")
+
+ inputmode := termbox.SetInputMode(termbox.InputCurrent)
+ inputmode_str := ""
+ switch {
+ case inputmode&termbox.InputEsc != 0:
+ inputmode_str = "termbox.InputEsc"
+ case inputmode&termbox.InputAlt != 0:
+ inputmode_str = "termbox.InputAlt"
+ }
+
+ if inputmode&termbox.InputMouse != 0 {
+ inputmode_str += " | termbox.InputMouse"
+ }
+ printf_tb(3, 18, termbox.ColorWhite, termbox.ColorBlack, "Input mode: %s", inputmode_str)
+}
+
+var fcmap = []string{
+ "CTRL+2, CTRL+~",
+ "CTRL+A",
+ "CTRL+B",
+ "CTRL+C",
+ "CTRL+D",
+ "CTRL+E",
+ "CTRL+F",
+ "CTRL+G",
+ "CTRL+H, BACKSPACE",
+ "CTRL+I, TAB",
+ "CTRL+J",
+ "CTRL+K",
+ "CTRL+L",
+ "CTRL+M, ENTER",
+ "CTRL+N",
+ "CTRL+O",
+ "CTRL+P",
+ "CTRL+Q",
+ "CTRL+R",
+ "CTRL+S",
+ "CTRL+T",
+ "CTRL+U",
+ "CTRL+V",
+ "CTRL+W",
+ "CTRL+X",
+ "CTRL+Y",
+ "CTRL+Z",
+ "CTRL+3, ESC, CTRL+[",
+ "CTRL+4, CTRL+\\",
+ "CTRL+5, CTRL+]",
+ "CTRL+6",
+ "CTRL+7, CTRL+/, CTRL+_",
+ "SPACE",
+}
+
+var fkmap = []string{
+ "F1",
+ "F2",
+ "F3",
+ "F4",
+ "F5",
+ "F6",
+ "F7",
+ "F8",
+ "F9",
+ "F10",
+ "F11",
+ "F12",
+ "INSERT",
+ "DELETE",
+ "HOME",
+ "END",
+ "PGUP",
+ "PGDN",
+ "ARROW UP",
+ "ARROW DOWN",
+ "ARROW LEFT",
+ "ARROW RIGHT",
+}
+
+func funckeymap(k termbox.Key) string {
+ if k == termbox.KeyCtrl8 {
+ return "CTRL+8, BACKSPACE 2" /* 0x7F */
+ } else if k >= termbox.KeyArrowRight && k <= 0xFFFF {
+ return fkmap[0xFFFF-k]
+ } else if k <= termbox.KeySpace {
+ return fcmap[k]
+ }
+ return "UNKNOWN"
+}
+
+func pretty_print_press(ev *termbox.Event) {
+ printf_tb(3, 19, termbox.ColorWhite, termbox.ColorBlack, "Key: ")
+ printf_tb(8, 19, termbox.ColorYellow, termbox.ColorBlack, "decimal: %d", ev.Key)
+ printf_tb(8, 20, termbox.ColorGreen, termbox.ColorBlack, "hex: 0x%X", ev.Key)
+ printf_tb(8, 21, termbox.ColorCyan, termbox.ColorBlack, "octal: 0%o", ev.Key)
+ printf_tb(8, 22, termbox.ColorRed, termbox.ColorBlack, "string: %s", funckeymap(ev.Key))
+
+ printf_tb(54, 19, termbox.ColorWhite, termbox.ColorBlack, "Char: ")
+ printf_tb(60, 19, termbox.ColorYellow, termbox.ColorBlack, "decimal: %d", ev.Ch)
+ printf_tb(60, 20, termbox.ColorGreen, termbox.ColorBlack, "hex: 0x%X", ev.Ch)
+ printf_tb(60, 21, termbox.ColorCyan, termbox.ColorBlack, "octal: 0%o", ev.Ch)
+ printf_tb(60, 22, termbox.ColorRed, termbox.ColorBlack, "string: %s", string(ev.Ch))
+
+ modifier := "none"
+ if ev.Mod != 0 {
+ modifier = "termbox.ModAlt"
+ }
+ printf_tb(54, 18, termbox.ColorWhite, termbox.ColorBlack, "Modifier: %s", modifier)
+}
+
+func pretty_print_resize(ev *termbox.Event) {
+ printf_tb(3, 19, termbox.ColorWhite, termbox.ColorBlack, "Resize event: %d x %d", ev.Width, ev.Height)
+}
+
+var counter = 0
+
+func pretty_print_mouse(ev *termbox.Event) {
+ printf_tb(3, 19, termbox.ColorWhite, termbox.ColorBlack, "Mouse event: %d x %d", ev.MouseX, ev.MouseY)
+ button := ""
+ switch ev.Key {
+ case termbox.MouseLeft:
+ button = "MouseLeft: %d"
+ case termbox.MouseMiddle:
+ button = "MouseMiddle: %d"
+ case termbox.MouseRight:
+ button = "MouseRight: %d"
+ case termbox.MouseWheelUp:
+ button = "MouseWheelUp: %d"
+ case termbox.MouseWheelDown:
+ button = "MouseWheelDown: %d"
+ case termbox.MouseRelease:
+ button = "MouseRelease: %d"
+ }
+ if ev.Mod&termbox.ModMotion != 0 {
+ button += "*"
+ }
+ counter++
+ printf_tb(43, 19, termbox.ColorWhite, termbox.ColorBlack, "Key: ")
+ printf_tb(48, 19, termbox.ColorYellow, termbox.ColorBlack, button, counter)
+}
+
+func dispatch_press(ev *termbox.Event) {
+ if ev.Mod&termbox.ModAlt != 0 {
+ draw_key(K_LALT, termbox.ColorWhite, termbox.ColorRed)
+ draw_key(K_RALT, termbox.ColorWhite, termbox.ColorRed)
+ }
+
+ var k *combo
+ if ev.Key >= termbox.KeyArrowRight {
+ k = &func_combos[0xFFFF-ev.Key]
+ } else if ev.Ch < 128 {
+ if ev.Ch == 0 && ev.Key < 128 {
+ k = &combos[ev.Key]
+ } else {
+ k = &combos[ev.Ch]
+ }
+ }
+ if k == nil {
+ return
+ }
+
+ keys := k.keys
+ for _, k := range keys {
+ draw_key(k, termbox.ColorWhite, termbox.ColorRed)
+ }
+}
+
+func main() {
+ err := termbox.Init()
+ if err != nil {
+ panic(err)
+ }
+ defer termbox.Close()
+
+ termbox.SetInputMode(termbox.InputEsc | termbox.InputMouse)
+
+ termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
+ draw_keyboard()
+ termbox.Flush()
+ inputmode := 0
+ ctrlxpressed := false
+loop:
+ for {
+ switch ev := termbox.PollEvent(); ev.Type {
+ case termbox.EventKey:
+ if ev.Key == termbox.KeyCtrlS && ctrlxpressed {
+ termbox.Sync()
+ }
+ if ev.Key == termbox.KeyCtrlQ && ctrlxpressed {
+ break loop
+ }
+ if ev.Key == termbox.KeyCtrlC && ctrlxpressed {
+ chmap := []termbox.InputMode{
+ termbox.InputEsc | termbox.InputMouse,
+ termbox.InputAlt | termbox.InputMouse,
+ termbox.InputEsc,
+ termbox.InputAlt,
+ }
+ inputmode++
+ if inputmode >= len(chmap) {
+ inputmode = 0
+ }
+ termbox.SetInputMode(chmap[inputmode])
+ }
+ if ev.Key == termbox.KeyCtrlX {
+ ctrlxpressed = true
+ } else {
+ ctrlxpressed = false
+ }
+
+ termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
+ draw_keyboard()
+ dispatch_press(&ev)
+ pretty_print_press(&ev)
+ termbox.Flush()
+ case termbox.EventResize:
+ termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
+ draw_keyboard()
+ pretty_print_resize(&ev)
+ termbox.Flush()
+ case termbox.EventMouse:
+ termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
+ draw_keyboard()
+ pretty_print_mouse(&ev)
+ termbox.Flush()
+ case termbox.EventError:
+ panic(ev.Err)
+ }
+ }
+}
diff --git a/vendor/github.com/nsf/termbox-go/_demos/output.go b/vendor/github.com/nsf/termbox-go/_demos/output.go
new file mode 100644
index 0000000..2b9479b
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/_demos/output.go
@@ -0,0 +1,228 @@
+package main
+
+import "github.com/mattn/go-runewidth"
+import "github.com/nsf/termbox-go"
+
+const chars = "nnnnnnnnnbbbbbbbbbuuuuuuuuuBBBBBBBBB"
+
+var output_mode = termbox.OutputNormal
+
+func next_char(current int) int {
+ current++
+ if current >= len(chars) {
+ return 0
+ }
+ return current
+}
+
+func print_combinations_table(sx, sy int, attrs []termbox.Attribute) {
+ var bg termbox.Attribute
+ current_char := 0
+ y := sy
+
+ all_attrs := []termbox.Attribute{
+ 0,
+ termbox.AttrBold,
+ termbox.AttrUnderline,
+ termbox.AttrBold | termbox.AttrUnderline,
+ }
+
+ draw_line := func() {
+ x := sx
+ for _, a := range all_attrs {
+ for c := termbox.ColorDefault; c <= termbox.ColorWhite; c++ {
+ fg := a | c
+ termbox.SetCell(x, y, rune(chars[current_char]), fg, bg)
+ current_char = next_char(current_char)
+ x++
+ }
+ }
+ }
+
+ for _, a := range attrs {
+ for c := termbox.ColorDefault; c <= termbox.ColorWhite; c++ {
+ bg = a | c
+ draw_line()
+ y++
+ }
+ }
+}
+
+func print_wide(x, y int, s string) {
+ red := false
+ for _, r := range s {
+ c := termbox.ColorDefault
+ if red {
+ c = termbox.ColorRed
+ }
+ termbox.SetCell(x, y, r, termbox.ColorDefault, c)
+ w := runewidth.RuneWidth(r)
+ if w == 0 || (w == 2 && runewidth.IsAmbiguousWidth(r)) {
+ w = 1
+ }
+ x += w
+
+ red = !red
+ }
+}
+
+const hello_world = "こんにちは世界"
+
+func draw_all() {
+ termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
+
+ switch output_mode {
+
+ case termbox.OutputNormal:
+ print_combinations_table(1, 1, []termbox.Attribute{
+ 0,
+ termbox.AttrBold,
+ })
+ print_combinations_table(2+len(chars), 1, []termbox.Attribute{
+ termbox.AttrReverse,
+ })
+ print_wide(2+len(chars), 11, hello_world)
+
+ case termbox.OutputGrayscale:
+ for y := 0; y < 26; y++ {
+ for x := 0; x < 26; x++ {
+ termbox.SetCell(x, y, 'n',
+ termbox.Attribute(x+1),
+ termbox.Attribute(y+1))
+ termbox.SetCell(x+27, y, 'b',
+ termbox.Attribute(x+1)|termbox.AttrBold,
+ termbox.Attribute(26-y))
+ termbox.SetCell(x+54, y, 'u',
+ termbox.Attribute(x+1)|termbox.AttrUnderline,
+ termbox.Attribute(y+1))
+ }
+ termbox.SetCell(82, y, 'd',
+ termbox.Attribute(y+1),
+ termbox.ColorDefault)
+ termbox.SetCell(83, y, 'd',
+ termbox.ColorDefault,
+ termbox.Attribute(26-y))
+ }
+
+ case termbox.Output216:
+ for r := 0; r < 6; r++ {
+ for g := 0; g < 6; g++ {
+ for b := 0; b < 6; b++ {
+ y := r
+ x := g + 6*b
+ c1 := termbox.Attribute(1 + r*36 + g*6 + b)
+ bg := termbox.Attribute(1 + g*36 + b*6 + r)
+ c2 := termbox.Attribute(1 + b*36 + r*6 + g)
+ bc1 := c1 | termbox.AttrBold
+ uc1 := c1 | termbox.AttrUnderline
+ bc2 := c2 | termbox.AttrBold
+ uc2 := c2 | termbox.AttrUnderline
+ termbox.SetCell(x, y, 'n', c1, bg)
+ termbox.SetCell(x, y+6, 'b', bc1, bg)
+ termbox.SetCell(x, y+12, 'u', uc1, bg)
+ termbox.SetCell(x, y+18, 'B', bc1|uc1, bg)
+ termbox.SetCell(x+37, y, 'n', c2, bg)
+ termbox.SetCell(x+37, y+6, 'b', bc2, bg)
+ termbox.SetCell(x+37, y+12, 'u', uc2, bg)
+ termbox.SetCell(x+37, y+18, 'B', bc2|uc2, bg)
+ }
+ c1 := termbox.Attribute(1 + g*6 + r*36)
+ c2 := termbox.Attribute(6 + g*6 + r*36)
+ termbox.SetCell(74+g, r, 'd', c1, termbox.ColorDefault)
+ termbox.SetCell(74+g, r+6, 'd', c2, termbox.ColorDefault)
+ termbox.SetCell(74+g, r+12, 'd', termbox.ColorDefault, c1)
+ termbox.SetCell(74+g, r+18, 'd', termbox.ColorDefault, c2)
+ }
+ }
+
+ case termbox.Output256:
+ for y := 0; y < 4; y++ {
+ for x := 0; x < 8; x++ {
+ for z := 0; z < 8; z++ {
+ bg := termbox.Attribute(1 + y*64 + x*8 + z)
+ c1 := termbox.Attribute(256 - y*64 - x*8 - z)
+ c2 := termbox.Attribute(1 + y*64 + z*8 + x)
+ c3 := termbox.Attribute(256 - y*64 - z*8 - x)
+ c4 := termbox.Attribute(1 + y*64 + x*4 + z*4)
+ bold := c2 | termbox.AttrBold
+ under := c3 | termbox.AttrUnderline
+ both := c1 | termbox.AttrBold | termbox.AttrUnderline
+ termbox.SetCell(z+8*x, y, ' ', 0, bg)
+ termbox.SetCell(z+8*x, y+5, 'n', c4, bg)
+ termbox.SetCell(z+8*x, y+10, 'b', bold, bg)
+ termbox.SetCell(z+8*x, y+15, 'u', under, bg)
+ termbox.SetCell(z+8*x, y+20, 'B', both, bg)
+ }
+ }
+ }
+ for x := 0; x < 12; x++ {
+ for y := 0; y < 2; y++ {
+ c1 := termbox.Attribute(233 + y*12 + x)
+ termbox.SetCell(66+x, y, 'd', c1, termbox.ColorDefault)
+ termbox.SetCell(66+x, 2+y, 'd', termbox.ColorDefault, c1)
+ }
+ }
+ for x := 0; x < 6; x++ {
+ for y := 0; y < 6; y++ {
+ c1 := termbox.Attribute(17 + x*6 + y*36)
+ c2 := termbox.Attribute(17 + 5 + x*6 + y*36)
+ termbox.SetCell(66+x, 6+y, 'd', c1, termbox.ColorDefault)
+ termbox.SetCell(66+x, 12+y, 'd', c2, termbox.ColorDefault)
+ termbox.SetCell(72+x, 6+y, 'd', termbox.ColorDefault, c1)
+ termbox.SetCell(72+x, 12+y, 'd', termbox.ColorDefault, c2)
+ }
+ }
+
+ }
+
+ termbox.Flush()
+}
+
+var available_modes = []termbox.OutputMode{
+ termbox.OutputNormal,
+ termbox.OutputGrayscale,
+ termbox.Output216,
+ termbox.Output256,
+}
+
+var output_mode_index = 0
+
+func switch_output_mode(direction int) {
+ output_mode_index += direction
+ if output_mode_index < 0 {
+ output_mode_index = len(available_modes) - 1
+ } else if output_mode_index >= len(available_modes) {
+ output_mode_index = 0
+ }
+ output_mode = termbox.SetOutputMode(available_modes[output_mode_index])
+ termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
+ termbox.Sync()
+}
+
+func main() {
+ err := termbox.Init()
+ if err != nil {
+ panic(err)
+ }
+ defer termbox.Close()
+
+ draw_all()
+loop:
+ for {
+ switch ev := termbox.PollEvent(); ev.Type {
+ case termbox.EventKey:
+ switch ev.Key {
+ case termbox.KeyEsc:
+ break loop
+ case termbox.KeyArrowUp, termbox.KeyArrowRight:
+ switch_output_mode(1)
+ draw_all()
+ case termbox.KeyArrowDown, termbox.KeyArrowLeft:
+ switch_output_mode(-1)
+ draw_all()
+ }
+ case termbox.EventResize:
+ draw_all()
+ }
+ }
+}
diff --git a/vendor/github.com/nsf/termbox-go/_demos/paint.go b/vendor/github.com/nsf/termbox-go/_demos/paint.go
new file mode 100644
index 0000000..fbafd18
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/_demos/paint.go
@@ -0,0 +1,105 @@
+package main
+
+import (
+ "github.com/nsf/termbox-go"
+)
+
+var curCol = 0
+var curRune = 0
+var backbuf []termbox.Cell
+var bbw, bbh int
+
+var runes = []rune{' ', '░', '▒', '▓', '█'}
+var colors = []termbox.Attribute{
+ termbox.ColorBlack,
+ termbox.ColorRed,
+ termbox.ColorGreen,
+ termbox.ColorYellow,
+ termbox.ColorBlue,
+ termbox.ColorMagenta,
+ termbox.ColorCyan,
+ termbox.ColorWhite,
+}
+
+type attrFunc func(int) (rune, termbox.Attribute, termbox.Attribute)
+
+func updateAndDrawButtons(current *int, x, y int, mx, my int, n int, attrf attrFunc) {
+ lx, ly := x, y
+ for i := 0; i < n; i++ {
+ if lx <= mx && mx <= lx+3 && ly <= my && my <= ly+1 {
+ *current = i
+ }
+ r, fg, bg := attrf(i)
+ termbox.SetCell(lx+0, ly+0, r, fg, bg)
+ termbox.SetCell(lx+1, ly+0, r, fg, bg)
+ termbox.SetCell(lx+2, ly+0, r, fg, bg)
+ termbox.SetCell(lx+3, ly+0, r, fg, bg)
+ termbox.SetCell(lx+0, ly+1, r, fg, bg)
+ termbox.SetCell(lx+1, ly+1, r, fg, bg)
+ termbox.SetCell(lx+2, ly+1, r, fg, bg)
+ termbox.SetCell(lx+3, ly+1, r, fg, bg)
+ lx += 4
+ }
+ lx, ly = x, y
+ for i := 0; i < n; i++ {
+ if *current == i {
+ fg := termbox.ColorRed | termbox.AttrBold
+ bg := termbox.ColorDefault
+ termbox.SetCell(lx+0, ly+2, '^', fg, bg)
+ termbox.SetCell(lx+1, ly+2, '^', fg, bg)
+ termbox.SetCell(lx+2, ly+2, '^', fg, bg)
+ termbox.SetCell(lx+3, ly+2, '^', fg, bg)
+ }
+ lx += 4
+ }
+}
+
+func update_and_redraw_all(mx, my int) {
+ termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
+ if mx != -1 && my != -1 {
+ backbuf[bbw*my+mx] = termbox.Cell{Ch: runes[curRune], Fg: colors[curCol]}
+ }
+ copy(termbox.CellBuffer(), backbuf)
+ _, h := termbox.Size()
+ updateAndDrawButtons(&curRune, 0, 0, mx, my, len(runes), func(i int) (rune, termbox.Attribute, termbox.Attribute) {
+ return runes[i], termbox.ColorDefault, termbox.ColorDefault
+ })
+ updateAndDrawButtons(&curCol, 0, h-3, mx, my, len(colors), func(i int) (rune, termbox.Attribute, termbox.Attribute) {
+ return ' ', termbox.ColorDefault, colors[i]
+ })
+ termbox.Flush()
+}
+
+func reallocBackBuffer(w, h int) {
+ bbw, bbh = w, h
+ backbuf = make([]termbox.Cell, w*h)
+}
+
+func main() {
+ err := termbox.Init()
+ if err != nil {
+ panic(err)
+ }
+ defer termbox.Close()
+ termbox.SetInputMode(termbox.InputEsc | termbox.InputMouse)
+ reallocBackBuffer(termbox.Size())
+ update_and_redraw_all(-1, -1)
+
+mainloop:
+ for {
+ mx, my := -1, -1
+ switch ev := termbox.PollEvent(); ev.Type {
+ case termbox.EventKey:
+ if ev.Key == termbox.KeyEsc {
+ break mainloop
+ }
+ case termbox.EventMouse:
+ if ev.Key == termbox.MouseLeft {
+ mx, my = ev.MouseX, ev.MouseY
+ }
+ case termbox.EventResize:
+ reallocBackBuffer(ev.Width, ev.Height)
+ }
+ update_and_redraw_all(mx, my)
+ }
+}
diff --git a/vendor/github.com/nsf/termbox-go/_demos/random_output.go b/vendor/github.com/nsf/termbox-go/_demos/random_output.go
new file mode 100644
index 0000000..efcf0b7
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/_demos/random_output.go
@@ -0,0 +1,46 @@
+package main
+
+import "github.com/nsf/termbox-go"
+import "math/rand"
+import "time"
+
+func draw() {
+ w, h := termbox.Size()
+ termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
+ for y := 0; y < h; y++ {
+ for x := 0; x < w; x++ {
+ termbox.SetCell(x, y, ' ', termbox.ColorDefault,
+ termbox.Attribute(rand.Int()%8)+1)
+ }
+ }
+ termbox.Flush()
+}
+
+func main() {
+ err := termbox.Init()
+ if err != nil {
+ panic(err)
+ }
+ defer termbox.Close()
+
+ event_queue := make(chan termbox.Event)
+ go func() {
+ for {
+ event_queue <- termbox.PollEvent()
+ }
+ }()
+
+ draw()
+loop:
+ for {
+ select {
+ case ev := <-event_queue:
+ if ev.Type == termbox.EventKey && ev.Key == termbox.KeyEsc {
+ break loop
+ }
+ default:
+ draw()
+ time.Sleep(10 * time.Millisecond)
+ }
+ }
+}
diff --git a/vendor/github.com/nsf/termbox-go/_demos/raw_input.go b/vendor/github.com/nsf/termbox-go/_demos/raw_input.go
new file mode 100644
index 0000000..97a4897
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/_demos/raw_input.go
@@ -0,0 +1,109 @@
+package main
+
+import (
+ "fmt"
+ "github.com/nsf/termbox-go"
+ "strings"
+)
+
+func tbprint(x, y int, fg, bg termbox.Attribute, msg string) {
+ for _, c := range msg {
+ termbox.SetCell(x, y, c, fg, bg)
+ x++
+ }
+}
+
+var current string
+var curev termbox.Event
+
+func mouse_button_str(k termbox.Key) string {
+ switch k {
+ case termbox.MouseLeft:
+ return "MouseLeft"
+ case termbox.MouseMiddle:
+ return "MouseMiddle"
+ case termbox.MouseRight:
+ return "MouseRight"
+ case termbox.MouseRelease:
+ return "MouseRelease"
+ case termbox.MouseWheelUp:
+ return "MouseWheelUp"
+ case termbox.MouseWheelDown:
+ return "MouseWheelDown"
+ }
+ return "Key"
+}
+
+func mod_str(m termbox.Modifier) string {
+ var out []string
+ if m&termbox.ModAlt != 0 {
+ out = append(out, "ModAlt")
+ }
+ if m&termbox.ModMotion != 0 {
+ out = append(out, "ModMotion")
+ }
+ return strings.Join(out, " | ")
+}
+
+func redraw_all() {
+ const coldef = termbox.ColorDefault
+ termbox.Clear(coldef, coldef)
+ tbprint(0, 0, termbox.ColorMagenta, coldef, "Press 'q' to quit")
+ tbprint(0, 1, coldef, coldef, current)
+ switch curev.Type {
+ case termbox.EventKey:
+ tbprint(0, 2, coldef, coldef,
+ fmt.Sprintf("EventKey: k: %d, c: %c, mod: %s", curev.Key, curev.Ch, mod_str(curev.Mod)))
+ case termbox.EventMouse:
+ tbprint(0, 2, coldef, coldef,
+ fmt.Sprintf("EventMouse: x: %d, y: %d, b: %s, mod: %s",
+ curev.MouseX, curev.MouseY, mouse_button_str(curev.Key), mod_str(curev.Mod)))
+ case termbox.EventNone:
+ tbprint(0, 2, coldef, coldef, "EventNone")
+ }
+ tbprint(0, 3, coldef, coldef, fmt.Sprintf("%d", curev.N))
+ termbox.Flush()
+}
+
+func main() {
+ err := termbox.Init()
+ if err != nil {
+ panic(err)
+ }
+ defer termbox.Close()
+ termbox.SetInputMode(termbox.InputAlt | termbox.InputMouse)
+ redraw_all()
+
+ data := make([]byte, 0, 64)
+mainloop:
+ for {
+ if cap(data)-len(data) < 32 {
+ newdata := make([]byte, len(data), len(data)+32)
+ copy(newdata, data)
+ data = newdata
+ }
+ beg := len(data)
+ d := data[beg : beg+32]
+ switch ev := termbox.PollRawEvent(d); ev.Type {
+ case termbox.EventRaw:
+ data = data[:beg+ev.N]
+ current = fmt.Sprintf("%q", data)
+ if current == `"q"` {
+ break mainloop
+ }
+
+ for {
+ ev := termbox.ParseEvent(data)
+ if ev.N == 0 {
+ break
+ }
+ curev = ev
+ copy(data, data[curev.N:])
+ data = data[:len(data)-curev.N]
+ }
+ case termbox.EventError:
+ panic(ev.Err)
+ }
+ redraw_all()
+ }
+}
diff --git a/vendor/github.com/nsf/termbox-go/api.go b/vendor/github.com/nsf/termbox-go/api.go
new file mode 100644
index 0000000..d530ab5
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/api.go
@@ -0,0 +1,489 @@
+// +build !windows
+
+package termbox
+
+import "github.com/mattn/go-runewidth"
+import "fmt"
+import "os"
+import "os/signal"
+import "syscall"
+import "runtime"
+import "time"
+
+// public API
+
+// Initializes termbox library. This function should be called before any other functions.
+// After successful initialization, the library must be finalized using 'Close' function.
+//
+// Example usage:
+// err := termbox.Init()
+// if err != nil {
+// panic(err)
+// }
+// defer termbox.Close()
+func Init() error {
+ var err error
+
+ out, err = os.OpenFile("/dev/tty", syscall.O_WRONLY, 0)
+ if err != nil {
+ return err
+ }
+ in, err = syscall.Open("/dev/tty", syscall.O_RDONLY, 0)
+ if err != nil {
+ return err
+ }
+
+ err = setup_term()
+ if err != nil {
+ return fmt.Errorf("termbox: error while reading terminfo data: %v", err)
+ }
+
+ signal.Notify(sigwinch, syscall.SIGWINCH)
+ signal.Notify(sigio, syscall.SIGIO)
+
+ _, err = fcntl(in, syscall.F_SETFL, syscall.O_ASYNC|syscall.O_NONBLOCK)
+ if err != nil {
+ return err
+ }
+ _, err = fcntl(in, syscall.F_SETOWN, syscall.Getpid())
+ if runtime.GOOS != "darwin" && err != nil {
+ return err
+ }
+ err = tcgetattr(out.Fd(), &orig_tios)
+ if err != nil {
+ return err
+ }
+
+ tios := orig_tios
+ tios.Iflag &^= syscall_IGNBRK | syscall_BRKINT | syscall_PARMRK |
+ syscall_ISTRIP | syscall_INLCR | syscall_IGNCR |
+ syscall_ICRNL | syscall_IXON
+ tios.Lflag &^= syscall_ECHO | syscall_ECHONL | syscall_ICANON |
+ syscall_ISIG | syscall_IEXTEN
+ tios.Cflag &^= syscall_CSIZE | syscall_PARENB
+ tios.Cflag |= syscall_CS8
+ tios.Cc[syscall_VMIN] = 1
+ tios.Cc[syscall_VTIME] = 0
+
+ err = tcsetattr(out.Fd(), &tios)
+ if err != nil {
+ return err
+ }
+
+ out.WriteString(funcs[t_enter_ca])
+ out.WriteString(funcs[t_enter_keypad])
+ out.WriteString(funcs[t_hide_cursor])
+ out.WriteString(funcs[t_clear_screen])
+
+ termw, termh = get_term_size(out.Fd())
+ back_buffer.init(termw, termh)
+ front_buffer.init(termw, termh)
+ back_buffer.clear()
+ front_buffer.clear()
+
+ go func() {
+ buf := make([]byte, 128)
+ for {
+ select {
+ case <-sigio:
+ for {
+ n, err := syscall.Read(in, buf)
+ if err == syscall.EAGAIN || err == syscall.EWOULDBLOCK {
+ break
+ }
+ select {
+ case input_comm <- input_event{buf[:n], err}:
+ ie := <-input_comm
+ buf = ie.data[:128]
+ case <-quit:
+ return
+ }
+ }
+ case <-quit:
+ return
+ }
+ }
+ }()
+
+ IsInit = true
+ return nil
+}
+
+// Interrupt an in-progress call to PollEvent by causing it to return
+// EventInterrupt. Note that this function will block until the PollEvent
+// function has successfully been interrupted.
+func Interrupt() {
+ interrupt_comm <- struct{}{}
+}
+
+// Finalizes termbox library, should be called after successful initialization
+// when termbox's functionality isn't required anymore.
+func Close() {
+ quit <- 1
+ out.WriteString(funcs[t_show_cursor])
+ out.WriteString(funcs[t_sgr0])
+ out.WriteString(funcs[t_clear_screen])
+ out.WriteString(funcs[t_exit_ca])
+ out.WriteString(funcs[t_exit_keypad])
+ out.WriteString(funcs[t_exit_mouse])
+ tcsetattr(out.Fd(), &orig_tios)
+
+ out.Close()
+ syscall.Close(in)
+
+ // reset the state, so that on next Init() it will work again
+ termw = 0
+ termh = 0
+ input_mode = InputEsc
+ out = nil
+ in = 0
+ lastfg = attr_invalid
+ lastbg = attr_invalid
+ lastx = coord_invalid
+ lasty = coord_invalid
+ cursor_x = cursor_hidden
+ cursor_y = cursor_hidden
+ foreground = ColorDefault
+ background = ColorDefault
+ IsInit = false
+}
+
+// Synchronizes the internal back buffer with the terminal.
+func Flush() error {
+ // invalidate cursor position
+ lastx = coord_invalid
+ lasty = coord_invalid
+
+ update_size_maybe()
+
+ for y := 0; y < front_buffer.height; y++ {
+ line_offset := y * front_buffer.width
+ for x := 0; x < front_buffer.width; {
+ cell_offset := line_offset + x
+ back := &back_buffer.cells[cell_offset]
+ front := &front_buffer.cells[cell_offset]
+ if back.Ch < ' ' {
+ back.Ch = ' '
+ }
+ w := runewidth.RuneWidth(back.Ch)
+ if w == 0 || w == 2 && runewidth.IsAmbiguousWidth(back.Ch) {
+ w = 1
+ }
+ if *back == *front {
+ x += w
+ continue
+ }
+ *front = *back
+ send_attr(back.Fg, back.Bg)
+
+ if w == 2 && x == front_buffer.width-1 {
+ // there's not enough space for 2-cells rune,
+ // let's just put a space in there
+ send_char(x, y, ' ')
+ } else {
+ send_char(x, y, back.Ch)
+ if w == 2 {
+ next := cell_offset + 1
+ front_buffer.cells[next] = Cell{
+ Ch: 0,
+ Fg: back.Fg,
+ Bg: back.Bg,
+ }
+ }
+ }
+ x += w
+ }
+ }
+ if !is_cursor_hidden(cursor_x, cursor_y) {
+ write_cursor(cursor_x, cursor_y)
+ }
+ return flush()
+}
+
+// Sets the position of the cursor. See also HideCursor().
+func SetCursor(x, y int) {
+ if is_cursor_hidden(cursor_x, cursor_y) && !is_cursor_hidden(x, y) {
+ outbuf.WriteString(funcs[t_show_cursor])
+ }
+
+ if !is_cursor_hidden(cursor_x, cursor_y) && is_cursor_hidden(x, y) {
+ outbuf.WriteString(funcs[t_hide_cursor])
+ }
+
+ cursor_x, cursor_y = x, y
+ if !is_cursor_hidden(cursor_x, cursor_y) {
+ write_cursor(cursor_x, cursor_y)
+ }
+}
+
+// The shortcut for SetCursor(-1, -1).
+func HideCursor() {
+ SetCursor(cursor_hidden, cursor_hidden)
+}
+
+// Changes cell's parameters in the internal back buffer at the specified
+// position.
+func SetCell(x, y int, ch rune, fg, bg Attribute) {
+ if x < 0 || x >= back_buffer.width {
+ return
+ }
+ if y < 0 || y >= back_buffer.height {
+ return
+ }
+
+ back_buffer.cells[y*back_buffer.width+x] = Cell{ch, fg, bg}
+}
+
+// Returns a slice into the termbox's back buffer. You can get its dimensions
+// using 'Size' function. The slice remains valid as long as no 'Clear' or
+// 'Flush' function calls were made after call to this function.
+func CellBuffer() []Cell {
+ return back_buffer.cells
+}
+
+// After getting a raw event from PollRawEvent function call, you can parse it
+// again into an ordinary one using termbox logic. That is parse an event as
+// termbox would do it. Returned event in addition to usual Event struct fields
+// sets N field to the amount of bytes used within 'data' slice. If the length
+// of 'data' slice is zero or event cannot be parsed for some other reason, the
+// function will return a special event type: EventNone.
+//
+// IMPORTANT: EventNone may contain a non-zero N, which means you should skip
+// these bytes, because termbox cannot recognize them.
+//
+// NOTE: This API is experimental and may change in future.
+func ParseEvent(data []byte) Event {
+ event := Event{Type: EventKey}
+ status := extract_event(data, &event, false)
+ if status != event_extracted {
+ return Event{Type: EventNone, N: event.N}
+ }
+ return event
+}
+
+// Wait for an event and return it. This is a blocking function call. Instead
+// of EventKey and EventMouse it returns EventRaw events. Raw event is written
+// into `data` slice and Event's N field is set to the amount of bytes written.
+// The minimum required length of the 'data' slice is 1. This requirement may
+// vary on different platforms.
+//
+// NOTE: This API is experimental and may change in future.
+func PollRawEvent(data []byte) Event {
+ if len(data) == 0 {
+ panic("len(data) >= 1 is a requirement")
+ }
+
+ var event Event
+ if extract_raw_event(data, &event) {
+ return event
+ }
+
+ for {
+ select {
+ case ev := <-input_comm:
+ if ev.err != nil {
+ return Event{Type: EventError, Err: ev.err}
+ }
+
+ inbuf = append(inbuf, ev.data...)
+ input_comm <- ev
+ if extract_raw_event(data, &event) {
+ return event
+ }
+ case <-interrupt_comm:
+ event.Type = EventInterrupt
+ return event
+
+ case <-sigwinch:
+ event.Type = EventResize
+ event.Width, event.Height = get_term_size(out.Fd())
+ return event
+ }
+ }
+}
+
+// Wait for an event and return it. This is a blocking function call.
+func PollEvent() Event {
+ // Constant governing macOS specific behavior. See https://github.com/nsf/termbox-go/issues/132
+ // This is an arbitrary delay which hopefully will be enough time for any lagging
+ // partial escape sequences to come through.
+ const esc_wait_delay = 100 * time.Millisecond
+
+ var event Event
+ var esc_wait_timer *time.Timer
+ var esc_timeout <-chan time.Time
+
+ // try to extract event from input buffer, return on success
+ event.Type = EventKey
+ status := extract_event(inbuf, &event, true)
+ if event.N != 0 {
+ copy(inbuf, inbuf[event.N:])
+ inbuf = inbuf[:len(inbuf)-event.N]
+ }
+ if status == event_extracted {
+ return event
+ } else if status == esc_wait {
+ esc_wait_timer = time.NewTimer(esc_wait_delay)
+ esc_timeout = esc_wait_timer.C
+ }
+
+ for {
+ select {
+ case ev := <-input_comm:
+ if esc_wait_timer != nil {
+ if !esc_wait_timer.Stop() {
+ <-esc_wait_timer.C
+ }
+ esc_wait_timer = nil
+ }
+
+ if ev.err != nil {
+ return Event{Type: EventError, Err: ev.err}
+ }
+
+ inbuf = append(inbuf, ev.data...)
+ input_comm <- ev
+ status := extract_event(inbuf, &event, true)
+ if event.N != 0 {
+ copy(inbuf, inbuf[event.N:])
+ inbuf = inbuf[:len(inbuf)-event.N]
+ }
+ if status == event_extracted {
+ return event
+ } else if status == esc_wait {
+ esc_wait_timer = time.NewTimer(esc_wait_delay)
+ esc_timeout = esc_wait_timer.C
+ }
+ case <-esc_timeout:
+ esc_wait_timer = nil
+
+ status := extract_event(inbuf, &event, false)
+ if event.N != 0 {
+ copy(inbuf, inbuf[event.N:])
+ inbuf = inbuf[:len(inbuf)-event.N]
+ }
+ if status == event_extracted {
+ return event
+ }
+ case <-interrupt_comm:
+ event.Type = EventInterrupt
+ return event
+
+ case <-sigwinch:
+ event.Type = EventResize
+ event.Width, event.Height = get_term_size(out.Fd())
+ return event
+ }
+ }
+}
+
+// Returns the size of the internal back buffer (which is mostly the same as
+// terminal's window size in characters). But it doesn't always match the size
+// of the terminal window, after the terminal size has changed, the internal
+// back buffer will get in sync only after Clear or Flush function calls.
+func Size() (width int, height int) {
+ return termw, termh
+}
+
+// Clears the internal back buffer.
+func Clear(fg, bg Attribute) error {
+ foreground, background = fg, bg
+ err := update_size_maybe()
+ back_buffer.clear()
+ return err
+}
+
+// Sets termbox input mode. Termbox has two input modes:
+//
+// 1. Esc input mode. When ESC sequence is in the buffer and it doesn't match
+// any known sequence. ESC means KeyEsc. This is the default input mode.
+//
+// 2. Alt input mode. When ESC sequence is in the buffer and it doesn't match
+// any known sequence. ESC enables ModAlt modifier for the next keyboard event.
+//
+// Both input modes can be OR'ed with Mouse mode. Setting Mouse mode bit up will
+// enable mouse button press/release and drag events.
+//
+// If 'mode' is InputCurrent, returns the current input mode. See also Input*
+// constants.
+func SetInputMode(mode InputMode) InputMode {
+ if mode == InputCurrent {
+ return input_mode
+ }
+ if mode&(InputEsc|InputAlt) == 0 {
+ mode |= InputEsc
+ }
+ if mode&(InputEsc|InputAlt) == InputEsc|InputAlt {
+ mode &^= InputAlt
+ }
+ if mode&InputMouse != 0 {
+ out.WriteString(funcs[t_enter_mouse])
+ } else {
+ out.WriteString(funcs[t_exit_mouse])
+ }
+
+ input_mode = mode
+ return input_mode
+}
+
+// Sets the termbox output mode. Termbox has four output options:
+//
+// 1. OutputNormal => [1..8]
+// This mode provides 8 different colors:
+// black, red, green, yellow, blue, magenta, cyan, white
+// Shortcut: ColorBlack, ColorRed, ...
+// Attributes: AttrBold, AttrUnderline, AttrReverse
+//
+// Example usage:
+// SetCell(x, y, '@', ColorBlack | AttrBold, ColorRed);
+//
+// 2. Output256 => [1..256]
+// In this mode you can leverage the 256 terminal mode:
+// 0x01 - 0x08: the 8 colors as in OutputNormal
+// 0x09 - 0x10: Color* | AttrBold
+// 0x11 - 0xe8: 216 different colors
+// 0xe9 - 0x1ff: 24 different shades of grey
+//
+// Example usage:
+// SetCell(x, y, '@', 184, 240);
+// SetCell(x, y, '@', 0xb8, 0xf0);
+//
+// 3. Output216 => [1..216]
+// This mode supports the 3rd range of the 256 mode only.
+// But you don't need to provide an offset.
+//
+// 4. OutputGrayscale => [1..26]
+// This mode supports the 4th range of the 256 mode
+// and black and white colors from 3th range of the 256 mode
+// But you don't need to provide an offset.
+//
+// In all modes, 0x00 represents the default color.
+//
+// `go run _demos/output.go` to see its impact on your terminal.
+//
+// If 'mode' is OutputCurrent, it returns the current output mode.
+//
+// Note that this may return a different OutputMode than the one requested,
+// as the requested mode may not be available on the target platform.
+func SetOutputMode(mode OutputMode) OutputMode {
+ if mode == OutputCurrent {
+ return output_mode
+ }
+
+ output_mode = mode
+ return output_mode
+}
+
+// Sync comes handy when something causes desync between termbox's understanding
+// of a terminal buffer and the reality. Such as a third party process. Sync
+// forces a complete resync between the termbox and a terminal, it may not be
+// visually pretty though.
+func Sync() error {
+ front_buffer.clear()
+ err := send_clear()
+ if err != nil {
+ return err
+ }
+
+ return Flush()
+}
diff --git a/vendor/github.com/nsf/termbox-go/api_common.go b/vendor/github.com/nsf/termbox-go/api_common.go
new file mode 100644
index 0000000..5ca1371
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/api_common.go
@@ -0,0 +1,187 @@
+// termbox is a library for creating cross-platform text-based interfaces
+package termbox
+
+// public API, common OS agnostic part
+
+type (
+ InputMode int
+ OutputMode int
+ EventType uint8
+ Modifier uint8
+ Key uint16
+ Attribute uint16
+)
+
+// This type represents a termbox event. The 'Mod', 'Key' and 'Ch' fields are
+// valid if 'Type' is EventKey. The 'Width' and 'Height' fields are valid if
+// 'Type' is EventResize. The 'Err' field is valid if 'Type' is EventError.
+type Event struct {
+ Type EventType // one of Event* constants
+ Mod Modifier // one of Mod* constants or 0
+ Key Key // one of Key* constants, invalid if 'Ch' is not 0
+ Ch rune // a unicode character
+ Width int // width of the screen
+ Height int // height of the screen
+ Err error // error in case if input failed
+ MouseX int // x coord of mouse
+ MouseY int // y coord of mouse
+ N int // number of bytes written when getting a raw event
+}
+
+// A cell, single conceptual entity on the screen. The screen is basically a 2d
+// array of cells. 'Ch' is a unicode character, 'Fg' and 'Bg' are foreground
+// and background attributes respectively.
+type Cell struct {
+ Ch rune
+ Fg Attribute
+ Bg Attribute
+}
+
+// To know if termbox has been initialized or not
+var (
+ IsInit bool = false
+)
+
+// Key constants, see Event.Key field.
+const (
+ KeyF1 Key = 0xFFFF - iota
+ KeyF2
+ KeyF3
+ KeyF4
+ KeyF5
+ KeyF6
+ KeyF7
+ KeyF8
+ KeyF9
+ KeyF10
+ KeyF11
+ KeyF12
+ KeyInsert
+ KeyDelete
+ KeyHome
+ KeyEnd
+ KeyPgup
+ KeyPgdn
+ KeyArrowUp
+ KeyArrowDown
+ KeyArrowLeft
+ KeyArrowRight
+ key_min // see terminfo
+ MouseLeft
+ MouseMiddle
+ MouseRight
+ MouseRelease
+ MouseWheelUp
+ MouseWheelDown
+)
+
+const (
+ KeyCtrlTilde Key = 0x00
+ KeyCtrl2 Key = 0x00
+ KeyCtrlSpace Key = 0x00
+ KeyCtrlA Key = 0x01
+ KeyCtrlB Key = 0x02
+ KeyCtrlC Key = 0x03
+ KeyCtrlD Key = 0x04
+ KeyCtrlE Key = 0x05
+ KeyCtrlF Key = 0x06
+ KeyCtrlG Key = 0x07
+ KeyBackspace Key = 0x08
+ KeyCtrlH Key = 0x08
+ KeyTab Key = 0x09
+ KeyCtrlI Key = 0x09
+ KeyCtrlJ Key = 0x0A
+ KeyCtrlK Key = 0x0B
+ KeyCtrlL Key = 0x0C
+ KeyEnter Key = 0x0D
+ KeyCtrlM Key = 0x0D
+ KeyCtrlN Key = 0x0E
+ KeyCtrlO Key = 0x0F
+ KeyCtrlP Key = 0x10
+ KeyCtrlQ Key = 0x11
+ KeyCtrlR Key = 0x12
+ KeyCtrlS Key = 0x13
+ KeyCtrlT Key = 0x14
+ KeyCtrlU Key = 0x15
+ KeyCtrlV Key = 0x16
+ KeyCtrlW Key = 0x17
+ KeyCtrlX Key = 0x18
+ KeyCtrlY Key = 0x19
+ KeyCtrlZ Key = 0x1A
+ KeyEsc Key = 0x1B
+ KeyCtrlLsqBracket Key = 0x1B
+ KeyCtrl3 Key = 0x1B
+ KeyCtrl4 Key = 0x1C
+ KeyCtrlBackslash Key = 0x1C
+ KeyCtrl5 Key = 0x1D
+ KeyCtrlRsqBracket Key = 0x1D
+ KeyCtrl6 Key = 0x1E
+ KeyCtrl7 Key = 0x1F
+ KeyCtrlSlash Key = 0x1F
+ KeyCtrlUnderscore Key = 0x1F
+ KeySpace Key = 0x20
+ KeyBackspace2 Key = 0x7F
+ KeyCtrl8 Key = 0x7F
+)
+
+// Alt modifier constant, see Event.Mod field and SetInputMode function.
+const (
+ ModAlt Modifier = 1 << iota
+ ModMotion
+)
+
+// Cell colors, you can combine a color with multiple attributes using bitwise
+// OR ('|').
+const (
+ ColorDefault Attribute = iota
+ ColorBlack
+ ColorRed
+ ColorGreen
+ ColorYellow
+ ColorBlue
+ ColorMagenta
+ ColorCyan
+ ColorWhite
+)
+
+// Cell attributes, it is possible to use multiple attributes by combining them
+// using bitwise OR ('|'). Although, colors cannot be combined. But you can
+// combine attributes and a single color.
+//
+// It's worth mentioning that some platforms don't support certain attributes.
+// For example windows console doesn't support AttrUnderline. And on some
+// terminals applying AttrBold to background may result in blinking text. Use
+// them with caution and test your code on various terminals.
+const (
+ AttrBold Attribute = 1 << (iota + 9)
+ AttrUnderline
+ AttrReverse
+)
+
+// Input mode. See SetInputMode function.
+const (
+ InputEsc InputMode = 1 << iota
+ InputAlt
+ InputMouse
+ InputCurrent InputMode = 0
+)
+
+// Output mode. See SetOutputMode function.
+const (
+ OutputCurrent OutputMode = iota
+ OutputNormal
+ Output256
+ Output216
+ OutputGrayscale
+)
+
+// Event type. See Event.Type field.
+const (
+ EventKey EventType = iota
+ EventResize
+ EventMouse
+ EventError
+ EventInterrupt
+ EventRaw
+ EventNone
+)
diff --git a/vendor/github.com/nsf/termbox-go/api_windows.go b/vendor/github.com/nsf/termbox-go/api_windows.go
new file mode 100644
index 0000000..7def30a
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/api_windows.go
@@ -0,0 +1,239 @@
+package termbox
+
+import (
+ "syscall"
+)
+
+// public API
+
+// Initializes termbox library. This function should be called before any other functions.
+// After successful initialization, the library must be finalized using 'Close' function.
+//
+// Example usage:
+// err := termbox.Init()
+// if err != nil {
+// panic(err)
+// }
+// defer termbox.Close()
+func Init() error {
+ var err error
+
+ interrupt, err = create_event()
+ if err != nil {
+ return err
+ }
+
+ in, err = syscall.Open("CONIN$", syscall.O_RDWR, 0)
+ if err != nil {
+ return err
+ }
+ out, err = syscall.Open("CONOUT$", syscall.O_RDWR, 0)
+ if err != nil {
+ return err
+ }
+
+ err = get_console_mode(in, &orig_mode)
+ if err != nil {
+ return err
+ }
+
+ err = set_console_mode(in, enable_window_input)
+ if err != nil {
+ return err
+ }
+
+ orig_size = get_term_size(out)
+ win_size := get_win_size(out)
+
+ err = set_console_screen_buffer_size(out, win_size)
+ if err != nil {
+ return err
+ }
+
+ err = get_console_cursor_info(out, &orig_cursor_info)
+ if err != nil {
+ return err
+ }
+
+ show_cursor(false)
+ term_size = get_term_size(out)
+ back_buffer.init(int(term_size.x), int(term_size.y))
+ front_buffer.init(int(term_size.x), int(term_size.y))
+ back_buffer.clear()
+ front_buffer.clear()
+ clear()
+
+ diffbuf = make([]diff_msg, 0, 32)
+
+ go input_event_producer()
+ IsInit = true
+ return nil
+}
+
+// Finalizes termbox library, should be called after successful initialization
+// when termbox's functionality isn't required anymore.
+func Close() {
+ // we ignore errors here, because we can't really do anything about them
+ Clear(0, 0)
+ Flush()
+
+ // stop event producer
+ cancel_comm <- true
+ set_event(interrupt)
+ select {
+ case <-input_comm:
+ default:
+ }
+ <-cancel_done_comm
+
+ set_console_cursor_info(out, &orig_cursor_info)
+ set_console_cursor_position(out, coord{})
+ set_console_screen_buffer_size(out, orig_size)
+ set_console_mode(in, orig_mode)
+ syscall.Close(in)
+ syscall.Close(out)
+ syscall.Close(interrupt)
+ IsInit = false
+}
+
+// Interrupt an in-progress call to PollEvent by causing it to return
+// EventInterrupt. Note that this function will block until the PollEvent
+// function has successfully been interrupted.
+func Interrupt() {
+ interrupt_comm <- struct{}{}
+}
+
+// Synchronizes the internal back buffer with the terminal.
+func Flush() error {
+ update_size_maybe()
+ prepare_diff_messages()
+ for _, diff := range diffbuf {
+ r := small_rect{
+ left: 0,
+ top: diff.pos,
+ right: term_size.x - 1,
+ bottom: diff.pos + diff.lines - 1,
+ }
+ write_console_output(out, diff.chars, r)
+ }
+ if !is_cursor_hidden(cursor_x, cursor_y) {
+ move_cursor(cursor_x, cursor_y)
+ }
+ return nil
+}
+
+// Sets the position of the cursor. See also HideCursor().
+func SetCursor(x, y int) {
+ if is_cursor_hidden(cursor_x, cursor_y) && !is_cursor_hidden(x, y) {
+ show_cursor(true)
+ }
+
+ if !is_cursor_hidden(cursor_x, cursor_y) && is_cursor_hidden(x, y) {
+ show_cursor(false)
+ }
+
+ cursor_x, cursor_y = x, y
+ if !is_cursor_hidden(cursor_x, cursor_y) {
+ move_cursor(cursor_x, cursor_y)
+ }
+}
+
+// The shortcut for SetCursor(-1, -1).
+func HideCursor() {
+ SetCursor(cursor_hidden, cursor_hidden)
+}
+
+// Changes cell's parameters in the internal back buffer at the specified
+// position.
+func SetCell(x, y int, ch rune, fg, bg Attribute) {
+ if x < 0 || x >= back_buffer.width {
+ return
+ }
+ if y < 0 || y >= back_buffer.height {
+ return
+ }
+
+ back_buffer.cells[y*back_buffer.width+x] = Cell{ch, fg, bg}
+}
+
+// Returns a slice into the termbox's back buffer. You can get its dimensions
+// using 'Size' function. The slice remains valid as long as no 'Clear' or
+// 'Flush' function calls were made after call to this function.
+func CellBuffer() []Cell {
+ return back_buffer.cells
+}
+
+// Wait for an event and return it. This is a blocking function call.
+func PollEvent() Event {
+ select {
+ case ev := <-input_comm:
+ return ev
+ case <-interrupt_comm:
+ return Event{Type: EventInterrupt}
+ }
+}
+
+// Returns the size of the internal back buffer (which is mostly the same as
+// console's window size in characters). But it doesn't always match the size
+// of the console window, after the console size has changed, the internal back
+// buffer will get in sync only after Clear or Flush function calls.
+func Size() (int, int) {
+ return int(term_size.x), int(term_size.y)
+}
+
+// Clears the internal back buffer.
+func Clear(fg, bg Attribute) error {
+ foreground, background = fg, bg
+ update_size_maybe()
+ back_buffer.clear()
+ return nil
+}
+
+// Sets termbox input mode. Termbox has two input modes:
+//
+// 1. Esc input mode. When ESC sequence is in the buffer and it doesn't match
+// any known sequence. ESC means KeyEsc. This is the default input mode.
+//
+// 2. Alt input mode. When ESC sequence is in the buffer and it doesn't match
+// any known sequence. ESC enables ModAlt modifier for the next keyboard event.
+//
+// Both input modes can be OR'ed with Mouse mode. Setting Mouse mode bit up will
+// enable mouse button press/release and drag events.
+//
+// If 'mode' is InputCurrent, returns the current input mode. See also Input*
+// constants.
+func SetInputMode(mode InputMode) InputMode {
+ if mode == InputCurrent {
+ return input_mode
+ }
+ if mode&InputMouse != 0 {
+ err := set_console_mode(in, enable_window_input|enable_mouse_input|enable_extended_flags)
+ if err != nil {
+ panic(err)
+ }
+ } else {
+ err := set_console_mode(in, enable_window_input)
+ if err != nil {
+ panic(err)
+ }
+ }
+
+ input_mode = mode
+ return input_mode
+}
+
+// Sets the termbox output mode.
+//
+// Windows console does not support extra colour modes,
+// so this will always set and return OutputNormal.
+func SetOutputMode(mode OutputMode) OutputMode {
+ return OutputNormal
+}
+
+// Sync comes handy when something causes desync between termbox's understanding
+// of a terminal buffer and the reality. Such as a third party process. Sync
+// forces a complete resync between the termbox and a terminal, it may not be
+// visually pretty though. At the moment on Windows it does nothing.
+func Sync() error {
+ return nil
+}
diff --git a/vendor/github.com/nsf/termbox-go/collect_terminfo.py b/vendor/github.com/nsf/termbox-go/collect_terminfo.py
new file mode 100755
index 0000000..5e50975
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/collect_terminfo.py
@@ -0,0 +1,110 @@
+#!/usr/bin/env python
+
+import sys, os, subprocess
+
+def escaped(s):
+ return repr(s)[1:-1]
+
+def tput(term, name):
+ try:
+ return subprocess.check_output(['tput', '-T%s' % term, name]).decode()
+ except subprocess.CalledProcessError as e:
+ return e.output.decode()
+
+
+def w(s):
+ if s == None:
+ return
+ sys.stdout.write(s)
+
+terminals = {
+ 'xterm' : 'xterm',
+ 'rxvt-256color' : 'rxvt_256color',
+ 'rxvt-unicode' : 'rxvt_unicode',
+ 'linux' : 'linux',
+ 'Eterm' : 'eterm',
+ 'screen' : 'screen'
+}
+
+keys = [
+ "F1", "kf1",
+ "F2", "kf2",
+ "F3", "kf3",
+ "F4", "kf4",
+ "F5", "kf5",
+ "F6", "kf6",
+ "F7", "kf7",
+ "F8", "kf8",
+ "F9", "kf9",
+ "F10", "kf10",
+ "F11", "kf11",
+ "F12", "kf12",
+ "INSERT", "kich1",
+ "DELETE", "kdch1",
+ "HOME", "khome",
+ "END", "kend",
+ "PGUP", "kpp",
+ "PGDN", "knp",
+ "KEY_UP", "kcuu1",
+ "KEY_DOWN", "kcud1",
+ "KEY_LEFT", "kcub1",
+ "KEY_RIGHT", "kcuf1"
+]
+
+funcs = [
+ "T_ENTER_CA", "smcup",
+ "T_EXIT_CA", "rmcup",
+ "T_SHOW_CURSOR", "cnorm",
+ "T_HIDE_CURSOR", "civis",
+ "T_CLEAR_SCREEN", "clear",
+ "T_SGR0", "sgr0",
+ "T_UNDERLINE", "smul",
+ "T_BOLD", "bold",
+ "T_BLINK", "blink",
+ "T_REVERSE", "rev",
+ "T_ENTER_KEYPAD", "smkx",
+ "T_EXIT_KEYPAD", "rmkx"
+]
+
+def iter_pairs(iterable):
+ iterable = iter(iterable)
+ while True:
+ yield (next(iterable), next(iterable))
+
+def do_term(term, nick):
+ w("// %s\n" % term)
+ w("var %s_keys = []string{\n\t" % nick)
+ for k, v in iter_pairs(keys):
+ w('"')
+ w(escaped(tput(term, v)))
+ w('",')
+ w("\n}\n")
+ w("var %s_funcs = []string{\n\t" % nick)
+ for k,v in iter_pairs(funcs):
+ w('"')
+ if v == "sgr":
+ w("\\033[3%d;4%dm")
+ elif v == "cup":
+ w("\\033[%d;%dH")
+ else:
+ w(escaped(tput(term, v)))
+ w('", ')
+ w("\n}\n\n")
+
+def do_terms(d):
+ w("var terms = []struct {\n")
+ w("\tname string\n")
+ w("\tkeys []string\n")
+ w("\tfuncs []string\n")
+ w("}{\n")
+ for k, v in d.items():
+ w('\t{"%s", %s_keys, %s_funcs},\n' % (k, v, v))
+ w("}\n\n")
+
+w("// +build !windows\n\npackage termbox\n\n")
+
+for k,v in terminals.items():
+ do_term(k, v)
+
+do_terms(terminals)
+
diff --git a/vendor/github.com/nsf/termbox-go/escwait.go b/vendor/github.com/nsf/termbox-go/escwait.go
new file mode 100644
index 0000000..b7bbb89
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/escwait.go
@@ -0,0 +1,11 @@
+// +build !darwin
+
+package termbox
+
+// On all systems other than macOS, disable behavior which will wait before
+// deciding that the escape key was pressed, to account for partially send
+// escape sequences, especially with regard to lengthy mouse sequences.
+// See https://github.com/nsf/termbox-go/issues/132
+func enable_wait_for_escape_sequence() bool {
+ return false
+}
diff --git a/vendor/github.com/nsf/termbox-go/escwait_darwin.go b/vendor/github.com/nsf/termbox-go/escwait_darwin.go
new file mode 100644
index 0000000..dde69b6
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/escwait_darwin.go
@@ -0,0 +1,9 @@
+package termbox
+
+// On macOS, enable behavior which will wait before deciding that the escape
+// key was pressed, to account for partially send escape sequences, especially
+// with regard to lengthy mouse sequences.
+// See https://github.com/nsf/termbox-go/issues/132
+func enable_wait_for_escape_sequence() bool {
+ return true
+}
diff --git a/vendor/github.com/nsf/termbox-go/syscalls.go b/vendor/github.com/nsf/termbox-go/syscalls.go
new file mode 100644
index 0000000..4f52bb9
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/syscalls.go
@@ -0,0 +1,39 @@
+// +build ignore
+
+package termbox
+
+/*
+#include
+#include
+*/
+import "C"
+
+type syscall_Termios C.struct_termios
+
+const (
+ syscall_IGNBRK = C.IGNBRK
+ syscall_BRKINT = C.BRKINT
+ syscall_PARMRK = C.PARMRK
+ syscall_ISTRIP = C.ISTRIP
+ syscall_INLCR = C.INLCR
+ syscall_IGNCR = C.IGNCR
+ syscall_ICRNL = C.ICRNL
+ syscall_IXON = C.IXON
+ syscall_OPOST = C.OPOST
+ syscall_ECHO = C.ECHO
+ syscall_ECHONL = C.ECHONL
+ syscall_ICANON = C.ICANON
+ syscall_ISIG = C.ISIG
+ syscall_IEXTEN = C.IEXTEN
+ syscall_CSIZE = C.CSIZE
+ syscall_PARENB = C.PARENB
+ syscall_CS8 = C.CS8
+ syscall_VMIN = C.VMIN
+ syscall_VTIME = C.VTIME
+
+ // on darwin change these to (on *bsd too?):
+ // C.TIOCGETA
+ // C.TIOCSETA
+ syscall_TCGETS = C.TCGETS
+ syscall_TCSETS = C.TCSETS
+)
diff --git a/vendor/github.com/nsf/termbox-go/syscalls_darwin.go b/vendor/github.com/nsf/termbox-go/syscalls_darwin.go
new file mode 100644
index 0000000..25b78f7
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/syscalls_darwin.go
@@ -0,0 +1,41 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs syscalls.go
+
+// +build !amd64
+
+package termbox
+
+type syscall_Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed uint32
+ Ospeed uint32
+}
+
+const (
+ syscall_IGNBRK = 0x1
+ syscall_BRKINT = 0x2
+ syscall_PARMRK = 0x8
+ syscall_ISTRIP = 0x20
+ syscall_INLCR = 0x40
+ syscall_IGNCR = 0x80
+ syscall_ICRNL = 0x100
+ syscall_IXON = 0x200
+ syscall_OPOST = 0x1
+ syscall_ECHO = 0x8
+ syscall_ECHONL = 0x10
+ syscall_ICANON = 0x100
+ syscall_ISIG = 0x80
+ syscall_IEXTEN = 0x400
+ syscall_CSIZE = 0x300
+ syscall_PARENB = 0x1000
+ syscall_CS8 = 0x300
+ syscall_VMIN = 0x10
+ syscall_VTIME = 0x11
+
+ syscall_TCGETS = 0x402c7413
+ syscall_TCSETS = 0x802c7414
+)
diff --git a/vendor/github.com/nsf/termbox-go/syscalls_darwin_amd64.go b/vendor/github.com/nsf/termbox-go/syscalls_darwin_amd64.go
new file mode 100644
index 0000000..11f25be
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/syscalls_darwin_amd64.go
@@ -0,0 +1,40 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs syscalls.go
+
+package termbox
+
+type syscall_Termios struct {
+ Iflag uint64
+ Oflag uint64
+ Cflag uint64
+ Lflag uint64
+ Cc [20]uint8
+ Pad_cgo_0 [4]byte
+ Ispeed uint64
+ Ospeed uint64
+}
+
+const (
+ syscall_IGNBRK = 0x1
+ syscall_BRKINT = 0x2
+ syscall_PARMRK = 0x8
+ syscall_ISTRIP = 0x20
+ syscall_INLCR = 0x40
+ syscall_IGNCR = 0x80
+ syscall_ICRNL = 0x100
+ syscall_IXON = 0x200
+ syscall_OPOST = 0x1
+ syscall_ECHO = 0x8
+ syscall_ECHONL = 0x10
+ syscall_ICANON = 0x100
+ syscall_ISIG = 0x80
+ syscall_IEXTEN = 0x400
+ syscall_CSIZE = 0x300
+ syscall_PARENB = 0x1000
+ syscall_CS8 = 0x300
+ syscall_VMIN = 0x10
+ syscall_VTIME = 0x11
+
+ syscall_TCGETS = 0x40487413
+ syscall_TCSETS = 0x80487414
+)
diff --git a/vendor/github.com/nsf/termbox-go/syscalls_dragonfly.go b/vendor/github.com/nsf/termbox-go/syscalls_dragonfly.go
new file mode 100644
index 0000000..e03624e
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/syscalls_dragonfly.go
@@ -0,0 +1,39 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs syscalls.go
+
+package termbox
+
+type syscall_Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed uint32
+ Ospeed uint32
+}
+
+const (
+ syscall_IGNBRK = 0x1
+ syscall_BRKINT = 0x2
+ syscall_PARMRK = 0x8
+ syscall_ISTRIP = 0x20
+ syscall_INLCR = 0x40
+ syscall_IGNCR = 0x80
+ syscall_ICRNL = 0x100
+ syscall_IXON = 0x200
+ syscall_OPOST = 0x1
+ syscall_ECHO = 0x8
+ syscall_ECHONL = 0x10
+ syscall_ICANON = 0x100
+ syscall_ISIG = 0x80
+ syscall_IEXTEN = 0x400
+ syscall_CSIZE = 0x300
+ syscall_PARENB = 0x1000
+ syscall_CS8 = 0x300
+ syscall_VMIN = 0x10
+ syscall_VTIME = 0x11
+
+ syscall_TCGETS = 0x402c7413
+ syscall_TCSETS = 0x802c7414
+)
diff --git a/vendor/github.com/nsf/termbox-go/syscalls_freebsd.go b/vendor/github.com/nsf/termbox-go/syscalls_freebsd.go
new file mode 100644
index 0000000..e03624e
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/syscalls_freebsd.go
@@ -0,0 +1,39 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs syscalls.go
+
+package termbox
+
+type syscall_Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed uint32
+ Ospeed uint32
+}
+
+const (
+ syscall_IGNBRK = 0x1
+ syscall_BRKINT = 0x2
+ syscall_PARMRK = 0x8
+ syscall_ISTRIP = 0x20
+ syscall_INLCR = 0x40
+ syscall_IGNCR = 0x80
+ syscall_ICRNL = 0x100
+ syscall_IXON = 0x200
+ syscall_OPOST = 0x1
+ syscall_ECHO = 0x8
+ syscall_ECHONL = 0x10
+ syscall_ICANON = 0x100
+ syscall_ISIG = 0x80
+ syscall_IEXTEN = 0x400
+ syscall_CSIZE = 0x300
+ syscall_PARENB = 0x1000
+ syscall_CS8 = 0x300
+ syscall_VMIN = 0x10
+ syscall_VTIME = 0x11
+
+ syscall_TCGETS = 0x402c7413
+ syscall_TCSETS = 0x802c7414
+)
diff --git a/vendor/github.com/nsf/termbox-go/syscalls_linux.go b/vendor/github.com/nsf/termbox-go/syscalls_linux.go
new file mode 100644
index 0000000..b88960d
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/syscalls_linux.go
@@ -0,0 +1,33 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs syscalls.go
+
+package termbox
+
+import "syscall"
+
+type syscall_Termios syscall.Termios
+
+const (
+ syscall_IGNBRK = syscall.IGNBRK
+ syscall_BRKINT = syscall.BRKINT
+ syscall_PARMRK = syscall.PARMRK
+ syscall_ISTRIP = syscall.ISTRIP
+ syscall_INLCR = syscall.INLCR
+ syscall_IGNCR = syscall.IGNCR
+ syscall_ICRNL = syscall.ICRNL
+ syscall_IXON = syscall.IXON
+ syscall_OPOST = syscall.OPOST
+ syscall_ECHO = syscall.ECHO
+ syscall_ECHONL = syscall.ECHONL
+ syscall_ICANON = syscall.ICANON
+ syscall_ISIG = syscall.ISIG
+ syscall_IEXTEN = syscall.IEXTEN
+ syscall_CSIZE = syscall.CSIZE
+ syscall_PARENB = syscall.PARENB
+ syscall_CS8 = syscall.CS8
+ syscall_VMIN = syscall.VMIN
+ syscall_VTIME = syscall.VTIME
+
+ syscall_TCGETS = syscall.TCGETS
+ syscall_TCSETS = syscall.TCSETS
+)
diff --git a/vendor/github.com/nsf/termbox-go/syscalls_netbsd.go b/vendor/github.com/nsf/termbox-go/syscalls_netbsd.go
new file mode 100644
index 0000000..49a3355
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/syscalls_netbsd.go
@@ -0,0 +1,39 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs syscalls.go
+
+package termbox
+
+type syscall_Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed int32
+ Ospeed int32
+}
+
+const (
+ syscall_IGNBRK = 0x1
+ syscall_BRKINT = 0x2
+ syscall_PARMRK = 0x8
+ syscall_ISTRIP = 0x20
+ syscall_INLCR = 0x40
+ syscall_IGNCR = 0x80
+ syscall_ICRNL = 0x100
+ syscall_IXON = 0x200
+ syscall_OPOST = 0x1
+ syscall_ECHO = 0x8
+ syscall_ECHONL = 0x10
+ syscall_ICANON = 0x100
+ syscall_ISIG = 0x80
+ syscall_IEXTEN = 0x400
+ syscall_CSIZE = 0x300
+ syscall_PARENB = 0x1000
+ syscall_CS8 = 0x300
+ syscall_VMIN = 0x10
+ syscall_VTIME = 0x11
+
+ syscall_TCGETS = 0x402c7413
+ syscall_TCSETS = 0x802c7414
+)
diff --git a/vendor/github.com/nsf/termbox-go/syscalls_openbsd.go b/vendor/github.com/nsf/termbox-go/syscalls_openbsd.go
new file mode 100644
index 0000000..49a3355
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/syscalls_openbsd.go
@@ -0,0 +1,39 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs syscalls.go
+
+package termbox
+
+type syscall_Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed int32
+ Ospeed int32
+}
+
+const (
+ syscall_IGNBRK = 0x1
+ syscall_BRKINT = 0x2
+ syscall_PARMRK = 0x8
+ syscall_ISTRIP = 0x20
+ syscall_INLCR = 0x40
+ syscall_IGNCR = 0x80
+ syscall_ICRNL = 0x100
+ syscall_IXON = 0x200
+ syscall_OPOST = 0x1
+ syscall_ECHO = 0x8
+ syscall_ECHONL = 0x10
+ syscall_ICANON = 0x100
+ syscall_ISIG = 0x80
+ syscall_IEXTEN = 0x400
+ syscall_CSIZE = 0x300
+ syscall_PARENB = 0x1000
+ syscall_CS8 = 0x300
+ syscall_VMIN = 0x10
+ syscall_VTIME = 0x11
+
+ syscall_TCGETS = 0x402c7413
+ syscall_TCSETS = 0x802c7414
+)
diff --git a/vendor/github.com/nsf/termbox-go/syscalls_windows.go b/vendor/github.com/nsf/termbox-go/syscalls_windows.go
new file mode 100644
index 0000000..472d002
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/syscalls_windows.go
@@ -0,0 +1,61 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -DUNICODE syscalls.go
+
+package termbox
+
+const (
+ foreground_blue = 0x1
+ foreground_green = 0x2
+ foreground_red = 0x4
+ foreground_intensity = 0x8
+ background_blue = 0x10
+ background_green = 0x20
+ background_red = 0x40
+ background_intensity = 0x80
+ std_input_handle = -0xa
+ std_output_handle = -0xb
+ key_event = 0x1
+ mouse_event = 0x2
+ window_buffer_size_event = 0x4
+ enable_window_input = 0x8
+ enable_mouse_input = 0x10
+ enable_extended_flags = 0x80
+
+ vk_f1 = 0x70
+ vk_f2 = 0x71
+ vk_f3 = 0x72
+ vk_f4 = 0x73
+ vk_f5 = 0x74
+ vk_f6 = 0x75
+ vk_f7 = 0x76
+ vk_f8 = 0x77
+ vk_f9 = 0x78
+ vk_f10 = 0x79
+ vk_f11 = 0x7a
+ vk_f12 = 0x7b
+ vk_insert = 0x2d
+ vk_delete = 0x2e
+ vk_home = 0x24
+ vk_end = 0x23
+ vk_pgup = 0x21
+ vk_pgdn = 0x22
+ vk_arrow_up = 0x26
+ vk_arrow_down = 0x28
+ vk_arrow_left = 0x25
+ vk_arrow_right = 0x27
+ vk_backspace = 0x8
+ vk_tab = 0x9
+ vk_enter = 0xd
+ vk_esc = 0x1b
+ vk_space = 0x20
+
+ left_alt_pressed = 0x2
+ left_ctrl_pressed = 0x8
+ right_alt_pressed = 0x1
+ right_ctrl_pressed = 0x4
+ shift_pressed = 0x10
+
+ generic_read = 0x80000000
+ generic_write = 0x40000000
+ console_textmode_buffer = 0x1
+)
diff --git a/vendor/github.com/nsf/termbox-go/termbox.go b/vendor/github.com/nsf/termbox-go/termbox.go
new file mode 100644
index 0000000..fbe4c3d
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/termbox.go
@@ -0,0 +1,529 @@
+// +build !windows
+
+package termbox
+
+import "unicode/utf8"
+import "bytes"
+import "syscall"
+import "unsafe"
+import "strings"
+import "strconv"
+import "os"
+import "io"
+
+// private API
+
+const (
+ t_enter_ca = iota
+ t_exit_ca
+ t_show_cursor
+ t_hide_cursor
+ t_clear_screen
+ t_sgr0
+ t_underline
+ t_bold
+ t_blink
+ t_reverse
+ t_enter_keypad
+ t_exit_keypad
+ t_enter_mouse
+ t_exit_mouse
+ t_max_funcs
+)
+
+const (
+ coord_invalid = -2
+ attr_invalid = Attribute(0xFFFF)
+)
+
+type input_event struct {
+ data []byte
+ err error
+}
+
+type extract_event_res int
+
+const (
+ event_not_extracted extract_event_res = iota
+ event_extracted
+ esc_wait
+)
+
+var (
+ // term specific sequences
+ keys []string
+ funcs []string
+
+ // termbox inner state
+ orig_tios syscall_Termios
+ back_buffer cellbuf
+ front_buffer cellbuf
+ termw int
+ termh int
+ input_mode = InputEsc
+ output_mode = OutputNormal
+ out *os.File
+ in int
+ lastfg = attr_invalid
+ lastbg = attr_invalid
+ lastx = coord_invalid
+ lasty = coord_invalid
+ cursor_x = cursor_hidden
+ cursor_y = cursor_hidden
+ foreground = ColorDefault
+ background = ColorDefault
+ inbuf = make([]byte, 0, 64)
+ outbuf bytes.Buffer
+ sigwinch = make(chan os.Signal, 1)
+ sigio = make(chan os.Signal, 1)
+ quit = make(chan int)
+ input_comm = make(chan input_event)
+ interrupt_comm = make(chan struct{})
+ intbuf = make([]byte, 0, 16)
+
+ // grayscale indexes
+ grayscale = []Attribute{
+ 0, 17, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244,
+ 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 232,
+ }
+)
+
+func write_cursor(x, y int) {
+ outbuf.WriteString("\033[")
+ outbuf.Write(strconv.AppendUint(intbuf, uint64(y+1), 10))
+ outbuf.WriteString(";")
+ outbuf.Write(strconv.AppendUint(intbuf, uint64(x+1), 10))
+ outbuf.WriteString("H")
+}
+
+func write_sgr_fg(a Attribute) {
+ switch output_mode {
+ case Output256, Output216, OutputGrayscale:
+ outbuf.WriteString("\033[38;5;")
+ outbuf.Write(strconv.AppendUint(intbuf, uint64(a-1), 10))
+ outbuf.WriteString("m")
+ default:
+ outbuf.WriteString("\033[3")
+ outbuf.Write(strconv.AppendUint(intbuf, uint64(a-1), 10))
+ outbuf.WriteString("m")
+ }
+}
+
+func write_sgr_bg(a Attribute) {
+ switch output_mode {
+ case Output256, Output216, OutputGrayscale:
+ outbuf.WriteString("\033[48;5;")
+ outbuf.Write(strconv.AppendUint(intbuf, uint64(a-1), 10))
+ outbuf.WriteString("m")
+ default:
+ outbuf.WriteString("\033[4")
+ outbuf.Write(strconv.AppendUint(intbuf, uint64(a-1), 10))
+ outbuf.WriteString("m")
+ }
+}
+
+func write_sgr(fg, bg Attribute) {
+ switch output_mode {
+ case Output256, Output216, OutputGrayscale:
+ outbuf.WriteString("\033[38;5;")
+ outbuf.Write(strconv.AppendUint(intbuf, uint64(fg-1), 10))
+ outbuf.WriteString("m")
+ outbuf.WriteString("\033[48;5;")
+ outbuf.Write(strconv.AppendUint(intbuf, uint64(bg-1), 10))
+ outbuf.WriteString("m")
+ default:
+ outbuf.WriteString("\033[3")
+ outbuf.Write(strconv.AppendUint(intbuf, uint64(fg-1), 10))
+ outbuf.WriteString(";4")
+ outbuf.Write(strconv.AppendUint(intbuf, uint64(bg-1), 10))
+ outbuf.WriteString("m")
+ }
+}
+
+type winsize struct {
+ rows uint16
+ cols uint16
+ xpixels uint16
+ ypixels uint16
+}
+
+func get_term_size(fd uintptr) (int, int) {
+ var sz winsize
+ _, _, _ = syscall.Syscall(syscall.SYS_IOCTL,
+ fd, uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&sz)))
+ return int(sz.cols), int(sz.rows)
+}
+
+func send_attr(fg, bg Attribute) {
+ if fg == lastfg && bg == lastbg {
+ return
+ }
+
+ outbuf.WriteString(funcs[t_sgr0])
+
+ var fgcol, bgcol Attribute
+
+ switch output_mode {
+ case Output256:
+ fgcol = fg & 0x1FF
+ bgcol = bg & 0x1FF
+ case Output216:
+ fgcol = fg & 0xFF
+ bgcol = bg & 0xFF
+ if fgcol > 216 {
+ fgcol = ColorDefault
+ }
+ if bgcol > 216 {
+ bgcol = ColorDefault
+ }
+ if fgcol != ColorDefault {
+ fgcol += 0x10
+ }
+ if bgcol != ColorDefault {
+ bgcol += 0x10
+ }
+ case OutputGrayscale:
+ fgcol = fg & 0x1F
+ bgcol = bg & 0x1F
+ if fgcol > 26 {
+ fgcol = ColorDefault
+ }
+ if bgcol > 26 {
+ bgcol = ColorDefault
+ }
+ if fgcol != ColorDefault {
+ fgcol = grayscale[fgcol]
+ }
+ if bgcol != ColorDefault {
+ bgcol = grayscale[bgcol]
+ }
+ default:
+ fgcol = fg & 0x0F
+ bgcol = bg & 0x0F
+ }
+
+ if fgcol != ColorDefault {
+ if bgcol != ColorDefault {
+ write_sgr(fgcol, bgcol)
+ } else {
+ write_sgr_fg(fgcol)
+ }
+ } else if bgcol != ColorDefault {
+ write_sgr_bg(bgcol)
+ }
+
+ if fg&AttrBold != 0 {
+ outbuf.WriteString(funcs[t_bold])
+ }
+ if bg&AttrBold != 0 {
+ outbuf.WriteString(funcs[t_blink])
+ }
+ if fg&AttrUnderline != 0 {
+ outbuf.WriteString(funcs[t_underline])
+ }
+ if fg&AttrReverse|bg&AttrReverse != 0 {
+ outbuf.WriteString(funcs[t_reverse])
+ }
+
+ lastfg, lastbg = fg, bg
+}
+
+func send_char(x, y int, ch rune) {
+ var buf [8]byte
+ n := utf8.EncodeRune(buf[:], ch)
+ if x-1 != lastx || y != lasty {
+ write_cursor(x, y)
+ }
+ lastx, lasty = x, y
+ outbuf.Write(buf[:n])
+}
+
+func flush() error {
+ _, err := io.Copy(out, &outbuf)
+ outbuf.Reset()
+ return err
+}
+
+func send_clear() error {
+ send_attr(foreground, background)
+ outbuf.WriteString(funcs[t_clear_screen])
+ if !is_cursor_hidden(cursor_x, cursor_y) {
+ write_cursor(cursor_x, cursor_y)
+ }
+
+ // we need to invalidate cursor position too and these two vars are
+ // used only for simple cursor positioning optimization, cursor
+ // actually may be in the correct place, but we simply discard
+ // optimization once and it gives us simple solution for the case when
+ // cursor moved
+ lastx = coord_invalid
+ lasty = coord_invalid
+
+ return flush()
+}
+
+func update_size_maybe() error {
+ w, h := get_term_size(out.Fd())
+ if w != termw || h != termh {
+ termw, termh = w, h
+ back_buffer.resize(termw, termh)
+ front_buffer.resize(termw, termh)
+ front_buffer.clear()
+ return send_clear()
+ }
+ return nil
+}
+
+func tcsetattr(fd uintptr, termios *syscall_Termios) error {
+ r, _, e := syscall.Syscall(syscall.SYS_IOCTL,
+ fd, uintptr(syscall_TCSETS), uintptr(unsafe.Pointer(termios)))
+ if r != 0 {
+ return os.NewSyscallError("SYS_IOCTL", e)
+ }
+ return nil
+}
+
+func tcgetattr(fd uintptr, termios *syscall_Termios) error {
+ r, _, e := syscall.Syscall(syscall.SYS_IOCTL,
+ fd, uintptr(syscall_TCGETS), uintptr(unsafe.Pointer(termios)))
+ if r != 0 {
+ return os.NewSyscallError("SYS_IOCTL", e)
+ }
+ return nil
+}
+
+func parse_mouse_event(event *Event, buf string) (int, bool) {
+ if strings.HasPrefix(buf, "\033[M") && len(buf) >= 6 {
+ // X10 mouse encoding, the simplest one
+ // \033 [ M Cb Cx Cy
+ b := buf[3] - 32
+ switch b & 3 {
+ case 0:
+ if b&64 != 0 {
+ event.Key = MouseWheelUp
+ } else {
+ event.Key = MouseLeft
+ }
+ case 1:
+ if b&64 != 0 {
+ event.Key = MouseWheelDown
+ } else {
+ event.Key = MouseMiddle
+ }
+ case 2:
+ event.Key = MouseRight
+ case 3:
+ event.Key = MouseRelease
+ default:
+ return 6, false
+ }
+ event.Type = EventMouse // KeyEvent by default
+ if b&32 != 0 {
+ event.Mod |= ModMotion
+ }
+
+ // the coord is 1,1 for upper left
+ event.MouseX = int(buf[4]) - 1 - 32
+ event.MouseY = int(buf[5]) - 1 - 32
+ return 6, true
+ } else if strings.HasPrefix(buf, "\033[<") || strings.HasPrefix(buf, "\033[") {
+ // xterm 1006 extended mode or urxvt 1015 extended mode
+ // xterm: \033 [ < Cb ; Cx ; Cy (M or m)
+ // urxvt: \033 [ Cb ; Cx ; Cy M
+
+ // find the first M or m, that's where we stop
+ mi := strings.IndexAny(buf, "Mm")
+ if mi == -1 {
+ return 0, false
+ }
+
+ // whether it's a capital M or not
+ isM := buf[mi] == 'M'
+
+ // whether it's urxvt or not
+ isU := false
+
+ // buf[2] is safe here, because having M or m found means we have at
+ // least 3 bytes in a string
+ if buf[2] == '<' {
+ buf = buf[3:mi]
+ } else {
+ isU = true
+ buf = buf[2:mi]
+ }
+
+ s1 := strings.Index(buf, ";")
+ s2 := strings.LastIndex(buf, ";")
+ // not found or only one ';'
+ if s1 == -1 || s2 == -1 || s1 == s2 {
+ return 0, false
+ }
+
+ n1, err := strconv.ParseInt(buf[0:s1], 10, 64)
+ if err != nil {
+ return 0, false
+ }
+ n2, err := strconv.ParseInt(buf[s1+1:s2], 10, 64)
+ if err != nil {
+ return 0, false
+ }
+ n3, err := strconv.ParseInt(buf[s2+1:], 10, 64)
+ if err != nil {
+ return 0, false
+ }
+
+ // on urxvt, first number is encoded exactly as in X10, but we need to
+ // make it zero-based, on xterm it is zero-based already
+ if isU {
+ n1 -= 32
+ }
+ switch n1 & 3 {
+ case 0:
+ if n1&64 != 0 {
+ event.Key = MouseWheelUp
+ } else {
+ event.Key = MouseLeft
+ }
+ case 1:
+ if n1&64 != 0 {
+ event.Key = MouseWheelDown
+ } else {
+ event.Key = MouseMiddle
+ }
+ case 2:
+ event.Key = MouseRight
+ case 3:
+ event.Key = MouseRelease
+ default:
+ return mi + 1, false
+ }
+ if !isM {
+ // on xterm mouse release is signaled by lowercase m
+ event.Key = MouseRelease
+ }
+
+ event.Type = EventMouse // KeyEvent by default
+ if n1&32 != 0 {
+ event.Mod |= ModMotion
+ }
+
+ event.MouseX = int(n2) - 1
+ event.MouseY = int(n3) - 1
+ return mi + 1, true
+ }
+
+ return 0, false
+}
+
+func parse_escape_sequence(event *Event, buf []byte) (int, bool) {
+ bufstr := string(buf)
+ for i, key := range keys {
+ if strings.HasPrefix(bufstr, key) {
+ event.Ch = 0
+ event.Key = Key(0xFFFF - i)
+ return len(key), true
+ }
+ }
+
+ // if none of the keys match, let's try mouse sequences
+ return parse_mouse_event(event, bufstr)
+}
+
+func extract_raw_event(data []byte, event *Event) bool {
+ if len(inbuf) == 0 {
+ return false
+ }
+
+ n := len(data)
+ if n == 0 {
+ return false
+ }
+
+ n = copy(data, inbuf)
+ copy(inbuf, inbuf[n:])
+ inbuf = inbuf[:len(inbuf)-n]
+
+ event.N = n
+ event.Type = EventRaw
+ return true
+}
+
+func extract_event(inbuf []byte, event *Event, allow_esc_wait bool) extract_event_res {
+ if len(inbuf) == 0 {
+ event.N = 0
+ return event_not_extracted
+ }
+
+ if inbuf[0] == '\033' {
+ // possible escape sequence
+ if n, ok := parse_escape_sequence(event, inbuf); n != 0 {
+ event.N = n
+ if ok {
+ return event_extracted
+ } else {
+ return event_not_extracted
+ }
+ }
+
+ // possible partially read escape sequence; trigger a wait if appropriate
+ if enable_wait_for_escape_sequence() && allow_esc_wait {
+ event.N = 0
+ return esc_wait
+ }
+
+ // it's not escape sequence, then it's Alt or Esc, check input_mode
+ switch {
+ case input_mode&InputEsc != 0:
+ // if we're in escape mode, fill Esc event, pop buffer, return success
+ event.Ch = 0
+ event.Key = KeyEsc
+ event.Mod = 0
+ event.N = 1
+ return event_extracted
+ case input_mode&InputAlt != 0:
+ // if we're in alt mode, set Alt modifier to event and redo parsing
+ event.Mod = ModAlt
+ status := extract_event(inbuf[1:], event, false)
+ if status == event_extracted {
+ event.N++
+ } else {
+ event.N = 0
+ }
+ return status
+ default:
+ panic("unreachable")
+ }
+ }
+
+ // if we're here, this is not an escape sequence and not an alt sequence
+ // so, it's a FUNCTIONAL KEY or a UNICODE character
+
+ // first of all check if it's a functional key
+ if Key(inbuf[0]) <= KeySpace || Key(inbuf[0]) == KeyBackspace2 {
+ // fill event, pop buffer, return success
+ event.Ch = 0
+ event.Key = Key(inbuf[0])
+ event.N = 1
+ return event_extracted
+ }
+
+ // the only possible option is utf8 rune
+ if r, n := utf8.DecodeRune(inbuf); r != utf8.RuneError {
+ event.Ch = r
+ event.Key = 0
+ event.N = n
+ return event_extracted
+ }
+
+ return event_not_extracted
+}
+
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
+ r, _, e := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), uintptr(cmd),
+ uintptr(arg))
+ val = int(r)
+ if e != 0 {
+ err = e
+ }
+ return
+}
diff --git a/vendor/github.com/nsf/termbox-go/termbox_common.go b/vendor/github.com/nsf/termbox-go/termbox_common.go
new file mode 100644
index 0000000..c3355cc
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/termbox_common.go
@@ -0,0 +1,59 @@
+package termbox
+
+// private API, common OS agnostic part
+
+type cellbuf struct {
+ width int
+ height int
+ cells []Cell
+}
+
+func (this *cellbuf) init(width, height int) {
+ this.width = width
+ this.height = height
+ this.cells = make([]Cell, width*height)
+}
+
+func (this *cellbuf) resize(width, height int) {
+ if this.width == width && this.height == height {
+ return
+ }
+
+ oldw := this.width
+ oldh := this.height
+ oldcells := this.cells
+
+ this.init(width, height)
+ this.clear()
+
+ minw, minh := oldw, oldh
+
+ if width < minw {
+ minw = width
+ }
+ if height < minh {
+ minh = height
+ }
+
+ for i := 0; i < minh; i++ {
+ srco, dsto := i*oldw, i*width
+ src := oldcells[srco : srco+minw]
+ dst := this.cells[dsto : dsto+minw]
+ copy(dst, src)
+ }
+}
+
+func (this *cellbuf) clear() {
+ for i := range this.cells {
+ c := &this.cells[i]
+ c.Ch = ' '
+ c.Fg = foreground
+ c.Bg = background
+ }
+}
+
+const cursor_hidden = -1
+
+func is_cursor_hidden(x, y int) bool {
+ return x == cursor_hidden || y == cursor_hidden
+}
diff --git a/vendor/github.com/nsf/termbox-go/termbox_windows.go b/vendor/github.com/nsf/termbox-go/termbox_windows.go
new file mode 100644
index 0000000..7752a17
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/termbox_windows.go
@@ -0,0 +1,915 @@
+package termbox
+
+import "math"
+import "syscall"
+import "unsafe"
+import "unicode/utf16"
+import "github.com/mattn/go-runewidth"
+
+type (
+ wchar uint16
+ short int16
+ dword uint32
+ word uint16
+ char_info struct {
+ char wchar
+ attr word
+ }
+ coord struct {
+ x short
+ y short
+ }
+ small_rect struct {
+ left short
+ top short
+ right short
+ bottom short
+ }
+ console_screen_buffer_info struct {
+ size coord
+ cursor_position coord
+ attributes word
+ window small_rect
+ maximum_window_size coord
+ }
+ console_cursor_info struct {
+ size dword
+ visible int32
+ }
+ input_record struct {
+ event_type word
+ _ [2]byte
+ event [16]byte
+ }
+ key_event_record struct {
+ key_down int32
+ repeat_count word
+ virtual_key_code word
+ virtual_scan_code word
+ unicode_char wchar
+ control_key_state dword
+ }
+ window_buffer_size_record struct {
+ size coord
+ }
+ mouse_event_record struct {
+ mouse_pos coord
+ button_state dword
+ control_key_state dword
+ event_flags dword
+ }
+ console_font_info struct {
+ font uint32
+ font_size coord
+ }
+)
+
+const (
+ mouse_lmb = 0x1
+ mouse_rmb = 0x2
+ mouse_mmb = 0x4 | 0x8 | 0x10
+ SM_CXMIN = 28
+ SM_CYMIN = 29
+)
+
+func (this coord) uintptr() uintptr {
+ return uintptr(*(*int32)(unsafe.Pointer(&this)))
+}
+
+var kernel32 = syscall.NewLazyDLL("kernel32.dll")
+var moduser32 = syscall.NewLazyDLL("user32.dll")
+var is_cjk = runewidth.IsEastAsian()
+
+var (
+ proc_set_console_active_screen_buffer = kernel32.NewProc("SetConsoleActiveScreenBuffer")
+ proc_set_console_screen_buffer_size = kernel32.NewProc("SetConsoleScreenBufferSize")
+ proc_create_console_screen_buffer = kernel32.NewProc("CreateConsoleScreenBuffer")
+ proc_get_console_screen_buffer_info = kernel32.NewProc("GetConsoleScreenBufferInfo")
+ proc_write_console_output = kernel32.NewProc("WriteConsoleOutputW")
+ proc_write_console_output_character = kernel32.NewProc("WriteConsoleOutputCharacterW")
+ proc_write_console_output_attribute = kernel32.NewProc("WriteConsoleOutputAttribute")
+ proc_set_console_cursor_info = kernel32.NewProc("SetConsoleCursorInfo")
+ proc_set_console_cursor_position = kernel32.NewProc("SetConsoleCursorPosition")
+ proc_get_console_cursor_info = kernel32.NewProc("GetConsoleCursorInfo")
+ proc_read_console_input = kernel32.NewProc("ReadConsoleInputW")
+ proc_get_console_mode = kernel32.NewProc("GetConsoleMode")
+ proc_set_console_mode = kernel32.NewProc("SetConsoleMode")
+ proc_fill_console_output_character = kernel32.NewProc("FillConsoleOutputCharacterW")
+ proc_fill_console_output_attribute = kernel32.NewProc("FillConsoleOutputAttribute")
+ proc_create_event = kernel32.NewProc("CreateEventW")
+ proc_wait_for_multiple_objects = kernel32.NewProc("WaitForMultipleObjects")
+ proc_set_event = kernel32.NewProc("SetEvent")
+ proc_get_current_console_font = kernel32.NewProc("GetCurrentConsoleFont")
+ get_system_metrics = moduser32.NewProc("GetSystemMetrics")
+)
+
+func set_console_active_screen_buffer(h syscall.Handle) (err error) {
+ r0, _, e1 := syscall.Syscall(proc_set_console_active_screen_buffer.Addr(),
+ 1, uintptr(h), 0, 0)
+ if int(r0) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func set_console_screen_buffer_size(h syscall.Handle, size coord) (err error) {
+ r0, _, e1 := syscall.Syscall(proc_set_console_screen_buffer_size.Addr(),
+ 2, uintptr(h), size.uintptr(), 0)
+ if int(r0) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func create_console_screen_buffer() (h syscall.Handle, err error) {
+ r0, _, e1 := syscall.Syscall6(proc_create_console_screen_buffer.Addr(),
+ 5, uintptr(generic_read|generic_write), 0, 0, console_textmode_buffer, 0, 0)
+ if int(r0) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return syscall.Handle(r0), err
+}
+
+func get_console_screen_buffer_info(h syscall.Handle, info *console_screen_buffer_info) (err error) {
+ r0, _, e1 := syscall.Syscall(proc_get_console_screen_buffer_info.Addr(),
+ 2, uintptr(h), uintptr(unsafe.Pointer(info)), 0)
+ if int(r0) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func write_console_output(h syscall.Handle, chars []char_info, dst small_rect) (err error) {
+ tmp_coord = coord{dst.right - dst.left + 1, dst.bottom - dst.top + 1}
+ tmp_rect = dst
+ r0, _, e1 := syscall.Syscall6(proc_write_console_output.Addr(),
+ 5, uintptr(h), uintptr(unsafe.Pointer(&chars[0])), tmp_coord.uintptr(),
+ tmp_coord0.uintptr(), uintptr(unsafe.Pointer(&tmp_rect)), 0)
+ if int(r0) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func write_console_output_character(h syscall.Handle, chars []wchar, pos coord) (err error) {
+ r0, _, e1 := syscall.Syscall6(proc_write_console_output_character.Addr(),
+ 5, uintptr(h), uintptr(unsafe.Pointer(&chars[0])), uintptr(len(chars)),
+ pos.uintptr(), uintptr(unsafe.Pointer(&tmp_arg)), 0)
+ if int(r0) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func write_console_output_attribute(h syscall.Handle, attrs []word, pos coord) (err error) {
+ r0, _, e1 := syscall.Syscall6(proc_write_console_output_attribute.Addr(),
+ 5, uintptr(h), uintptr(unsafe.Pointer(&attrs[0])), uintptr(len(attrs)),
+ pos.uintptr(), uintptr(unsafe.Pointer(&tmp_arg)), 0)
+ if int(r0) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func set_console_cursor_info(h syscall.Handle, info *console_cursor_info) (err error) {
+ r0, _, e1 := syscall.Syscall(proc_set_console_cursor_info.Addr(),
+ 2, uintptr(h), uintptr(unsafe.Pointer(info)), 0)
+ if int(r0) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func get_console_cursor_info(h syscall.Handle, info *console_cursor_info) (err error) {
+ r0, _, e1 := syscall.Syscall(proc_get_console_cursor_info.Addr(),
+ 2, uintptr(h), uintptr(unsafe.Pointer(info)), 0)
+ if int(r0) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func set_console_cursor_position(h syscall.Handle, pos coord) (err error) {
+ r0, _, e1 := syscall.Syscall(proc_set_console_cursor_position.Addr(),
+ 2, uintptr(h), pos.uintptr(), 0)
+ if int(r0) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func read_console_input(h syscall.Handle, record *input_record) (err error) {
+ r0, _, e1 := syscall.Syscall6(proc_read_console_input.Addr(),
+ 4, uintptr(h), uintptr(unsafe.Pointer(record)), 1, uintptr(unsafe.Pointer(&tmp_arg)), 0, 0)
+ if int(r0) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func get_console_mode(h syscall.Handle, mode *dword) (err error) {
+ r0, _, e1 := syscall.Syscall(proc_get_console_mode.Addr(),
+ 2, uintptr(h), uintptr(unsafe.Pointer(mode)), 0)
+ if int(r0) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func set_console_mode(h syscall.Handle, mode dword) (err error) {
+ r0, _, e1 := syscall.Syscall(proc_set_console_mode.Addr(),
+ 2, uintptr(h), uintptr(mode), 0)
+ if int(r0) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func fill_console_output_character(h syscall.Handle, char wchar, n int) (err error) {
+ r0, _, e1 := syscall.Syscall6(proc_fill_console_output_character.Addr(),
+ 5, uintptr(h), uintptr(char), uintptr(n), tmp_coord.uintptr(),
+ uintptr(unsafe.Pointer(&tmp_arg)), 0)
+ if int(r0) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func fill_console_output_attribute(h syscall.Handle, attr word, n int) (err error) {
+ r0, _, e1 := syscall.Syscall6(proc_fill_console_output_attribute.Addr(),
+ 5, uintptr(h), uintptr(attr), uintptr(n), tmp_coord.uintptr(),
+ uintptr(unsafe.Pointer(&tmp_arg)), 0)
+ if int(r0) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func create_event() (out syscall.Handle, err error) {
+ r0, _, e1 := syscall.Syscall6(proc_create_event.Addr(),
+ 4, 0, 0, 0, 0, 0, 0)
+ if int(r0) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return syscall.Handle(r0), err
+}
+
+func wait_for_multiple_objects(objects []syscall.Handle) (err error) {
+ r0, _, e1 := syscall.Syscall6(proc_wait_for_multiple_objects.Addr(),
+ 4, uintptr(len(objects)), uintptr(unsafe.Pointer(&objects[0])),
+ 0, 0xFFFFFFFF, 0, 0)
+ if uint32(r0) == 0xFFFFFFFF {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func set_event(ev syscall.Handle) (err error) {
+ r0, _, e1 := syscall.Syscall(proc_set_event.Addr(),
+ 1, uintptr(ev), 0, 0)
+ if int(r0) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func get_current_console_font(h syscall.Handle, info *console_font_info) (err error) {
+ r0, _, e1 := syscall.Syscall(proc_get_current_console_font.Addr(),
+ 3, uintptr(h), 0, uintptr(unsafe.Pointer(info)))
+ if int(r0) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+type diff_msg struct {
+ pos short
+ lines short
+ chars []char_info
+}
+
+type input_event struct {
+ event Event
+ err error
+}
+
+var (
+ orig_cursor_info console_cursor_info
+ orig_size coord
+ orig_mode dword
+ orig_screen syscall.Handle
+ back_buffer cellbuf
+ front_buffer cellbuf
+ term_size coord
+ input_mode = InputEsc
+ cursor_x = cursor_hidden
+ cursor_y = cursor_hidden
+ foreground = ColorDefault
+ background = ColorDefault
+ in syscall.Handle
+ out syscall.Handle
+ interrupt syscall.Handle
+ charbuf []char_info
+ diffbuf []diff_msg
+ beg_x = -1
+ beg_y = -1
+ beg_i = -1
+ input_comm = make(chan Event)
+ interrupt_comm = make(chan struct{})
+ cancel_comm = make(chan bool, 1)
+ cancel_done_comm = make(chan bool)
+ alt_mode_esc = false
+
+ // these ones just to prevent heap allocs at all costs
+ tmp_info console_screen_buffer_info
+ tmp_arg dword
+ tmp_coord0 = coord{0, 0}
+ tmp_coord = coord{0, 0}
+ tmp_rect = small_rect{0, 0, 0, 0}
+ tmp_finfo console_font_info
+)
+
+func get_cursor_position(out syscall.Handle) coord {
+ err := get_console_screen_buffer_info(out, &tmp_info)
+ if err != nil {
+ panic(err)
+ }
+ return tmp_info.cursor_position
+}
+
+func get_term_size(out syscall.Handle) coord {
+ err := get_console_screen_buffer_info(out, &tmp_info)
+ if err != nil {
+ panic(err)
+ }
+ return tmp_info.size
+}
+
+func get_win_min_size(out syscall.Handle) coord {
+ x, _, err := get_system_metrics.Call(SM_CXMIN)
+ y, _, err := get_system_metrics.Call(SM_CYMIN)
+
+ if x == 0 || y == 0 {
+ if err != nil {
+ panic(err)
+ }
+ }
+
+ err1 := get_current_console_font(out, &tmp_finfo)
+ if err1 != nil {
+ panic(err1)
+ }
+
+ return coord{
+ x: short(math.Ceil(float64(x) / float64(tmp_finfo.font_size.x))),
+ y: short(math.Ceil(float64(y) / float64(tmp_finfo.font_size.y))),
+ }
+}
+
+func get_win_size(out syscall.Handle) coord {
+ err := get_console_screen_buffer_info(out, &tmp_info)
+ if err != nil {
+ panic(err)
+ }
+
+ min_size := get_win_min_size(out)
+
+ size := coord{
+ x: tmp_info.window.right - tmp_info.window.left + 1,
+ y: tmp_info.window.bottom - tmp_info.window.top + 1,
+ }
+
+ if size.x < min_size.x {
+ size.x = min_size.x
+ }
+
+ if size.y < min_size.y {
+ size.y = min_size.y
+ }
+
+ return size
+}
+
+func update_size_maybe() {
+ size := get_win_size(out)
+ if size.x != term_size.x || size.y != term_size.y {
+ set_console_screen_buffer_size(out, size)
+ term_size = size
+ back_buffer.resize(int(size.x), int(size.y))
+ front_buffer.resize(int(size.x), int(size.y))
+ front_buffer.clear()
+ clear()
+
+ area := int(size.x) * int(size.y)
+ if cap(charbuf) < area {
+ charbuf = make([]char_info, 0, area)
+ }
+ }
+}
+
+var color_table_bg = []word{
+ 0, // default (black)
+ 0, // black
+ background_red,
+ background_green,
+ background_red | background_green, // yellow
+ background_blue,
+ background_red | background_blue, // magenta
+ background_green | background_blue, // cyan
+ background_red | background_blue | background_green, // white
+}
+
+var color_table_fg = []word{
+ foreground_red | foreground_blue | foreground_green, // default (white)
+ 0,
+ foreground_red,
+ foreground_green,
+ foreground_red | foreground_green, // yellow
+ foreground_blue,
+ foreground_red | foreground_blue, // magenta
+ foreground_green | foreground_blue, // cyan
+ foreground_red | foreground_blue | foreground_green, // white
+}
+
+const (
+ replacement_char = '\uFFFD'
+ max_rune = '\U0010FFFF'
+ surr1 = 0xd800
+ surr2 = 0xdc00
+ surr3 = 0xe000
+ surr_self = 0x10000
+)
+
+func append_diff_line(y int) int {
+ n := 0
+ for x := 0; x < front_buffer.width; {
+ cell_offset := y*front_buffer.width + x
+ back := &back_buffer.cells[cell_offset]
+ front := &front_buffer.cells[cell_offset]
+ attr, char := cell_to_char_info(*back)
+ charbuf = append(charbuf, char_info{attr: attr, char: char[0]})
+ *front = *back
+ n++
+ w := runewidth.RuneWidth(back.Ch)
+ if w == 0 || w == 2 && runewidth.IsAmbiguousWidth(back.Ch) {
+ w = 1
+ }
+ x += w
+ // If not CJK, fill trailing space with whitespace
+ if !is_cjk && w == 2 {
+ charbuf = append(charbuf, char_info{attr: attr, char: ' '})
+ }
+ }
+ return n
+}
+
+// compares 'back_buffer' with 'front_buffer' and prepares all changes in the form of
+// 'diff_msg's in the 'diff_buf'
+func prepare_diff_messages() {
+ // clear buffers
+ diffbuf = diffbuf[:0]
+ charbuf = charbuf[:0]
+
+ var diff diff_msg
+ gbeg := 0
+ for y := 0; y < front_buffer.height; y++ {
+ same := true
+ line_offset := y * front_buffer.width
+ for x := 0; x < front_buffer.width; x++ {
+ cell_offset := line_offset + x
+ back := &back_buffer.cells[cell_offset]
+ front := &front_buffer.cells[cell_offset]
+ if *back != *front {
+ same = false
+ break
+ }
+ }
+ if same && diff.lines > 0 {
+ diffbuf = append(diffbuf, diff)
+ diff = diff_msg{}
+ }
+ if !same {
+ beg := len(charbuf)
+ end := beg + append_diff_line(y)
+ if diff.lines == 0 {
+ diff.pos = short(y)
+ gbeg = beg
+ }
+ diff.lines++
+ diff.chars = charbuf[gbeg:end]
+ }
+ }
+ if diff.lines > 0 {
+ diffbuf = append(diffbuf, diff)
+ diff = diff_msg{}
+ }
+}
+
+func get_ct(table []word, idx int) word {
+ idx = idx & 0x0F
+ if idx >= len(table) {
+ idx = len(table) - 1
+ }
+ return table[idx]
+}
+
+func cell_to_char_info(c Cell) (attr word, wc [2]wchar) {
+ attr = get_ct(color_table_fg, int(c.Fg)) | get_ct(color_table_bg, int(c.Bg))
+ if c.Fg&AttrReverse|c.Bg&AttrReverse != 0 {
+ attr = (attr&0xF0)>>4 | (attr&0x0F)<<4
+ }
+ if c.Fg&AttrBold != 0 {
+ attr |= foreground_intensity
+ }
+ if c.Bg&AttrBold != 0 {
+ attr |= background_intensity
+ }
+
+ r0, r1 := utf16.EncodeRune(c.Ch)
+ if r0 == 0xFFFD {
+ wc[0] = wchar(c.Ch)
+ wc[1] = ' '
+ } else {
+ wc[0] = wchar(r0)
+ wc[1] = wchar(r1)
+ }
+ return
+}
+
+func move_cursor(x, y int) {
+ err := set_console_cursor_position(out, coord{short(x), short(y)})
+ if err != nil {
+ panic(err)
+ }
+}
+
+func show_cursor(visible bool) {
+ var v int32
+ if visible {
+ v = 1
+ }
+
+ var info console_cursor_info
+ info.size = 100
+ info.visible = v
+ err := set_console_cursor_info(out, &info)
+ if err != nil {
+ panic(err)
+ }
+}
+
+func clear() {
+ var err error
+ attr, char := cell_to_char_info(Cell{
+ ' ',
+ foreground,
+ background,
+ })
+
+ area := int(term_size.x) * int(term_size.y)
+ err = fill_console_output_attribute(out, attr, area)
+ if err != nil {
+ panic(err)
+ }
+ err = fill_console_output_character(out, char[0], area)
+ if err != nil {
+ panic(err)
+ }
+ if !is_cursor_hidden(cursor_x, cursor_y) {
+ move_cursor(cursor_x, cursor_y)
+ }
+}
+
+func key_event_record_to_event(r *key_event_record) (Event, bool) {
+ if r.key_down == 0 {
+ return Event{}, false
+ }
+
+ e := Event{Type: EventKey}
+ if input_mode&InputAlt != 0 {
+ if alt_mode_esc {
+ e.Mod = ModAlt
+ alt_mode_esc = false
+ }
+ if r.control_key_state&(left_alt_pressed|right_alt_pressed) != 0 {
+ e.Mod = ModAlt
+ }
+ }
+
+ ctrlpressed := r.control_key_state&(left_ctrl_pressed|right_ctrl_pressed) != 0
+
+ if r.virtual_key_code >= vk_f1 && r.virtual_key_code <= vk_f12 {
+ switch r.virtual_key_code {
+ case vk_f1:
+ e.Key = KeyF1
+ case vk_f2:
+ e.Key = KeyF2
+ case vk_f3:
+ e.Key = KeyF3
+ case vk_f4:
+ e.Key = KeyF4
+ case vk_f5:
+ e.Key = KeyF5
+ case vk_f6:
+ e.Key = KeyF6
+ case vk_f7:
+ e.Key = KeyF7
+ case vk_f8:
+ e.Key = KeyF8
+ case vk_f9:
+ e.Key = KeyF9
+ case vk_f10:
+ e.Key = KeyF10
+ case vk_f11:
+ e.Key = KeyF11
+ case vk_f12:
+ e.Key = KeyF12
+ default:
+ panic("unreachable")
+ }
+
+ return e, true
+ }
+
+ if r.virtual_key_code <= vk_delete {
+ switch r.virtual_key_code {
+ case vk_insert:
+ e.Key = KeyInsert
+ case vk_delete:
+ e.Key = KeyDelete
+ case vk_home:
+ e.Key = KeyHome
+ case vk_end:
+ e.Key = KeyEnd
+ case vk_pgup:
+ e.Key = KeyPgup
+ case vk_pgdn:
+ e.Key = KeyPgdn
+ case vk_arrow_up:
+ e.Key = KeyArrowUp
+ case vk_arrow_down:
+ e.Key = KeyArrowDown
+ case vk_arrow_left:
+ e.Key = KeyArrowLeft
+ case vk_arrow_right:
+ e.Key = KeyArrowRight
+ case vk_backspace:
+ if ctrlpressed {
+ e.Key = KeyBackspace2
+ } else {
+ e.Key = KeyBackspace
+ }
+ case vk_tab:
+ e.Key = KeyTab
+ case vk_enter:
+ e.Key = KeyEnter
+ case vk_esc:
+ switch {
+ case input_mode&InputEsc != 0:
+ e.Key = KeyEsc
+ case input_mode&InputAlt != 0:
+ alt_mode_esc = true
+ return Event{}, false
+ }
+ case vk_space:
+ if ctrlpressed {
+ // manual return here, because KeyCtrlSpace is zero
+ e.Key = KeyCtrlSpace
+ return e, true
+ } else {
+ e.Key = KeySpace
+ }
+ }
+
+ if e.Key != 0 {
+ return e, true
+ }
+ }
+
+ if ctrlpressed {
+ if Key(r.unicode_char) >= KeyCtrlA && Key(r.unicode_char) <= KeyCtrlRsqBracket {
+ e.Key = Key(r.unicode_char)
+ if input_mode&InputAlt != 0 && e.Key == KeyEsc {
+ alt_mode_esc = true
+ return Event{}, false
+ }
+ return e, true
+ }
+ switch r.virtual_key_code {
+ case 192, 50:
+ // manual return here, because KeyCtrl2 is zero
+ e.Key = KeyCtrl2
+ return e, true
+ case 51:
+ if input_mode&InputAlt != 0 {
+ alt_mode_esc = true
+ return Event{}, false
+ }
+ e.Key = KeyCtrl3
+ case 52:
+ e.Key = KeyCtrl4
+ case 53:
+ e.Key = KeyCtrl5
+ case 54:
+ e.Key = KeyCtrl6
+ case 189, 191, 55:
+ e.Key = KeyCtrl7
+ case 8, 56:
+ e.Key = KeyCtrl8
+ }
+
+ if e.Key != 0 {
+ return e, true
+ }
+ }
+
+ if r.unicode_char != 0 {
+ e.Ch = rune(r.unicode_char)
+ return e, true
+ }
+
+ return Event{}, false
+}
+
+func input_event_producer() {
+ var r input_record
+ var err error
+ var last_button Key
+ var last_button_pressed Key
+ var last_state = dword(0)
+ var last_x, last_y = -1, -1
+ handles := []syscall.Handle{in, interrupt}
+ for {
+ err = wait_for_multiple_objects(handles)
+ if err != nil {
+ input_comm <- Event{Type: EventError, Err: err}
+ }
+
+ select {
+ case <-cancel_comm:
+ cancel_done_comm <- true
+ return
+ default:
+ }
+
+ err = read_console_input(in, &r)
+ if err != nil {
+ input_comm <- Event{Type: EventError, Err: err}
+ }
+
+ switch r.event_type {
+ case key_event:
+ kr := (*key_event_record)(unsafe.Pointer(&r.event))
+ ev, ok := key_event_record_to_event(kr)
+ if ok {
+ for i := 0; i < int(kr.repeat_count); i++ {
+ input_comm <- ev
+ }
+ }
+ case window_buffer_size_event:
+ sr := *(*window_buffer_size_record)(unsafe.Pointer(&r.event))
+ input_comm <- Event{
+ Type: EventResize,
+ Width: int(sr.size.x),
+ Height: int(sr.size.y),
+ }
+ case mouse_event:
+ mr := *(*mouse_event_record)(unsafe.Pointer(&r.event))
+ ev := Event{Type: EventMouse}
+ switch mr.event_flags {
+ case 0, 2:
+ // single or double click
+ cur_state := mr.button_state
+ switch {
+ case last_state&mouse_lmb == 0 && cur_state&mouse_lmb != 0:
+ last_button = MouseLeft
+ last_button_pressed = last_button
+ case last_state&mouse_rmb == 0 && cur_state&mouse_rmb != 0:
+ last_button = MouseRight
+ last_button_pressed = last_button
+ case last_state&mouse_mmb == 0 && cur_state&mouse_mmb != 0:
+ last_button = MouseMiddle
+ last_button_pressed = last_button
+ case last_state&mouse_lmb != 0 && cur_state&mouse_lmb == 0:
+ last_button = MouseRelease
+ case last_state&mouse_rmb != 0 && cur_state&mouse_rmb == 0:
+ last_button = MouseRelease
+ case last_state&mouse_mmb != 0 && cur_state&mouse_mmb == 0:
+ last_button = MouseRelease
+ default:
+ last_state = cur_state
+ continue
+ }
+ last_state = cur_state
+ ev.Key = last_button
+ last_x, last_y = int(mr.mouse_pos.x), int(mr.mouse_pos.y)
+ ev.MouseX = last_x
+ ev.MouseY = last_y
+ case 1:
+ // mouse motion
+ x, y := int(mr.mouse_pos.x), int(mr.mouse_pos.y)
+ if last_state != 0 && (last_x != x || last_y != y) {
+ ev.Key = last_button_pressed
+ ev.Mod = ModMotion
+ ev.MouseX = x
+ ev.MouseY = y
+ last_x, last_y = x, y
+ } else {
+ ev.Type = EventNone
+ }
+ case 4:
+ // mouse wheel
+ n := int16(mr.button_state >> 16)
+ if n > 0 {
+ ev.Key = MouseWheelUp
+ } else {
+ ev.Key = MouseWheelDown
+ }
+ last_x, last_y = int(mr.mouse_pos.x), int(mr.mouse_pos.y)
+ ev.MouseX = last_x
+ ev.MouseY = last_y
+ default:
+ ev.Type = EventNone
+ }
+ if ev.Type != EventNone {
+ input_comm <- ev
+ }
+ }
+ }
+}
diff --git a/vendor/github.com/nsf/termbox-go/terminfo.go b/vendor/github.com/nsf/termbox-go/terminfo.go
new file mode 100644
index 0000000..5d38fce
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/terminfo.go
@@ -0,0 +1,226 @@
+// +build !windows
+// This file contains a simple and incomplete implementation of the terminfo
+// database. Information was taken from the ncurses manpages term(5) and
+// terminfo(5). Currently, only the string capabilities for special keys and for
+// functions without parameters are actually used. Colors are still done with
+// ANSI escape sequences. Other special features that are not (yet?) supported
+// are reading from ~/.terminfo, the TERMINFO_DIRS variable, Berkeley database
+// format and extended capabilities.
+
+package termbox
+
+import (
+ "bytes"
+ "encoding/binary"
+ "encoding/hex"
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "strings"
+)
+
+const (
+ ti_magic = 0432
+ ti_header_length = 12
+ ti_mouse_enter = "\x1b[?1000h\x1b[?1002h\x1b[?1015h\x1b[?1006h"
+ ti_mouse_leave = "\x1b[?1006l\x1b[?1015l\x1b[?1002l\x1b[?1000l"
+)
+
+func load_terminfo() ([]byte, error) {
+ var data []byte
+ var err error
+
+ term := os.Getenv("TERM")
+ if term == "" {
+ return nil, fmt.Errorf("termbox: TERM not set")
+ }
+
+ // The following behaviour follows the one described in terminfo(5) as
+ // distributed by ncurses.
+
+ terminfo := os.Getenv("TERMINFO")
+ if terminfo != "" {
+ // if TERMINFO is set, no other directory should be searched
+ return ti_try_path(terminfo)
+ }
+
+ // next, consider ~/.terminfo
+ home := os.Getenv("HOME")
+ if home != "" {
+ data, err = ti_try_path(home + "/.terminfo")
+ if err == nil {
+ return data, nil
+ }
+ }
+
+ // next, TERMINFO_DIRS
+ dirs := os.Getenv("TERMINFO_DIRS")
+ if dirs != "" {
+ for _, dir := range strings.Split(dirs, ":") {
+ if dir == "" {
+ // "" -> "/usr/share/terminfo"
+ dir = "/usr/share/terminfo"
+ }
+ data, err = ti_try_path(dir)
+ if err == nil {
+ return data, nil
+ }
+ }
+ }
+
+ // fall back to /usr/share/terminfo
+ return ti_try_path("/usr/share/terminfo")
+}
+
+func ti_try_path(path string) (data []byte, err error) {
+ // load_terminfo already made sure it is set
+ term := os.Getenv("TERM")
+
+ // first try, the typical *nix path
+ terminfo := path + "/" + term[0:1] + "/" + term
+ data, err = ioutil.ReadFile(terminfo)
+ if err == nil {
+ return
+ }
+
+ // fallback to darwin specific dirs structure
+ terminfo = path + "/" + hex.EncodeToString([]byte(term[:1])) + "/" + term
+ data, err = ioutil.ReadFile(terminfo)
+ return
+}
+
+func setup_term_builtin() error {
+ name := os.Getenv("TERM")
+ if name == "" {
+ return errors.New("termbox: TERM environment variable not set")
+ }
+
+ for _, t := range terms {
+ if t.name == name {
+ keys = t.keys
+ funcs = t.funcs
+ return nil
+ }
+ }
+
+ compat_table := []struct {
+ partial string
+ keys []string
+ funcs []string
+ }{
+ {"xterm", xterm_keys, xterm_funcs},
+ {"rxvt", rxvt_unicode_keys, rxvt_unicode_funcs},
+ {"linux", linux_keys, linux_funcs},
+ {"Eterm", eterm_keys, eterm_funcs},
+ {"screen", screen_keys, screen_funcs},
+ // let's assume that 'cygwin' is xterm compatible
+ {"cygwin", xterm_keys, xterm_funcs},
+ {"st", xterm_keys, xterm_funcs},
+ }
+
+ // try compatibility variants
+ for _, it := range compat_table {
+ if strings.Contains(name, it.partial) {
+ keys = it.keys
+ funcs = it.funcs
+ return nil
+ }
+ }
+
+ return errors.New("termbox: unsupported terminal")
+}
+
+func setup_term() (err error) {
+ var data []byte
+ var header [6]int16
+ var str_offset, table_offset int16
+
+ data, err = load_terminfo()
+ if err != nil {
+ return setup_term_builtin()
+ }
+
+ rd := bytes.NewReader(data)
+ // 0: magic number, 1: size of names section, 2: size of boolean section, 3:
+ // size of numbers section (in integers), 4: size of the strings section (in
+ // integers), 5: size of the string table
+
+ err = binary.Read(rd, binary.LittleEndian, header[:])
+ if err != nil {
+ return
+ }
+
+ number_sec_len := int16(2)
+ if header[0] == 542 { // doc says it should be octal 0542, but what I see it terminfo files is 542, learn to program please... thank you..
+ number_sec_len = 4
+ }
+
+ if (header[1]+header[2])%2 != 0 {
+ // old quirk to align everything on word boundaries
+ header[2] += 1
+ }
+ str_offset = ti_header_length + header[1] + header[2] + number_sec_len*header[3]
+ table_offset = str_offset + 2*header[4]
+
+ keys = make([]string, 0xFFFF-key_min)
+ for i, _ := range keys {
+ keys[i], err = ti_read_string(rd, str_offset+2*ti_keys[i], table_offset)
+ if err != nil {
+ return
+ }
+ }
+ funcs = make([]string, t_max_funcs)
+ // the last two entries are reserved for mouse. because the table offset is
+ // not there, the two entries have to fill in manually
+ for i, _ := range funcs[:len(funcs)-2] {
+ funcs[i], err = ti_read_string(rd, str_offset+2*ti_funcs[i], table_offset)
+ if err != nil {
+ return
+ }
+ }
+ funcs[t_max_funcs-2] = ti_mouse_enter
+ funcs[t_max_funcs-1] = ti_mouse_leave
+ return nil
+}
+
+func ti_read_string(rd *bytes.Reader, str_off, table int16) (string, error) {
+ var off int16
+
+ _, err := rd.Seek(int64(str_off), 0)
+ if err != nil {
+ return "", err
+ }
+ err = binary.Read(rd, binary.LittleEndian, &off)
+ if err != nil {
+ return "", err
+ }
+ _, err = rd.Seek(int64(table+off), 0)
+ if err != nil {
+ return "", err
+ }
+ var bs []byte
+ for {
+ b, err := rd.ReadByte()
+ if err != nil {
+ return "", err
+ }
+ if b == byte(0x00) {
+ break
+ }
+ bs = append(bs, b)
+ }
+ return string(bs), nil
+}
+
+// "Maps" the function constants from termbox.go to the number of the respective
+// string capability in the terminfo file. Taken from (ncurses) term.h.
+var ti_funcs = []int16{
+ 28, 40, 16, 13, 5, 39, 36, 27, 26, 34, 89, 88,
+}
+
+// Same as above for the special keys.
+var ti_keys = []int16{
+ 66, 68 /* apparently not a typo; 67 is F10 for whatever reason */, 69, 70,
+ 71, 72, 73, 74, 75, 67, 216, 217, 77, 59, 76, 164, 82, 81, 87, 61, 79, 83,
+}
diff --git a/vendor/github.com/nsf/termbox-go/terminfo_builtin.go b/vendor/github.com/nsf/termbox-go/terminfo_builtin.go
new file mode 100644
index 0000000..a948660
--- /dev/null
+++ b/vendor/github.com/nsf/termbox-go/terminfo_builtin.go
@@ -0,0 +1,64 @@
+// +build !windows
+
+package termbox
+
+// Eterm
+var eterm_keys = []string{
+ "\x1b[11~", "\x1b[12~", "\x1b[13~", "\x1b[14~", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[7~", "\x1b[8~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C",
+}
+var eterm_funcs = []string{
+ "\x1b7\x1b[?47h", "\x1b[2J\x1b[?47l\x1b8", "\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b[m\x0f", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "", "", "", "",
+}
+
+// screen
+var screen_keys = []string{
+ "\x1bOP", "\x1bOQ", "\x1bOR", "\x1bOS", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[1~", "\x1b[4~", "\x1b[5~", "\x1b[6~", "\x1bOA", "\x1bOB", "\x1bOD", "\x1bOC",
+}
+var screen_funcs = []string{
+ "\x1b[?1049h", "\x1b[?1049l", "\x1b[34h\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[J", "\x1b[m\x0f", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b[?1h\x1b=", "\x1b[?1l\x1b>", ti_mouse_enter, ti_mouse_leave,
+}
+
+// xterm
+var xterm_keys = []string{
+ "\x1bOP", "\x1bOQ", "\x1bOR", "\x1bOS", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1bOH", "\x1bOF", "\x1b[5~", "\x1b[6~", "\x1bOA", "\x1bOB", "\x1bOD", "\x1bOC",
+}
+var xterm_funcs = []string{
+ "\x1b[?1049h", "\x1b[?1049l", "\x1b[?12l\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b(B\x1b[m", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b[?1h\x1b=", "\x1b[?1l\x1b>", ti_mouse_enter, ti_mouse_leave,
+}
+
+// rxvt-unicode
+var rxvt_unicode_keys = []string{
+ "\x1b[11~", "\x1b[12~", "\x1b[13~", "\x1b[14~", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[7~", "\x1b[8~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C",
+}
+var rxvt_unicode_funcs = []string{
+ "\x1b[?1049h", "\x1b[r\x1b[?1049l", "\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b[m\x1b(B", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b=", "\x1b>", ti_mouse_enter, ti_mouse_leave,
+}
+
+// linux
+var linux_keys = []string{
+ "\x1b[[A", "\x1b[[B", "\x1b[[C", "\x1b[[D", "\x1b[[E", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[1~", "\x1b[4~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C",
+}
+var linux_funcs = []string{
+ "", "", "\x1b[?25h\x1b[?0c", "\x1b[?25l\x1b[?1c", "\x1b[H\x1b[J", "\x1b[0;10m", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "", "", "", "",
+}
+
+// rxvt-256color
+var rxvt_256color_keys = []string{
+ "\x1b[11~", "\x1b[12~", "\x1b[13~", "\x1b[14~", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[7~", "\x1b[8~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C",
+}
+var rxvt_256color_funcs = []string{
+ "\x1b7\x1b[?47h", "\x1b[2J\x1b[?47l\x1b8", "\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b[m\x0f", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b=", "\x1b>", ti_mouse_enter, ti_mouse_leave,
+}
+
+var terms = []struct {
+ name string
+ keys []string
+ funcs []string
+}{
+ {"Eterm", eterm_keys, eterm_funcs},
+ {"screen", screen_keys, screen_funcs},
+ {"xterm", xterm_keys, xterm_funcs},
+ {"rxvt-unicode", rxvt_unicode_keys, rxvt_unicode_funcs},
+ {"linux", linux_keys, linux_funcs},
+ {"rxvt-256color", rxvt_256color_keys, rxvt_256color_funcs},
+}
diff --git a/vendor/go4.org/.gitignore b/vendor/go4.org/.gitignore
new file mode 100644
index 0000000..daf913b
--- /dev/null
+++ b/vendor/go4.org/.gitignore
@@ -0,0 +1,24 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
diff --git a/vendor/go4.org/.travis.yml b/vendor/go4.org/.travis.yml
new file mode 100644
index 0000000..d9e211d
--- /dev/null
+++ b/vendor/go4.org/.travis.yml
@@ -0,0 +1,10 @@
+go_import_path: go4.org
+language: go
+go:
+ - "1.10.x"
+ - tip
+before_install:
+ - go get -u cloud.google.com/go/storage
+ - cd $HOME/gopath/src/cloud.google.com/go
+ - git reset --hard 4d445121f7d55f37b70187e796b16e64f6eea7a0
+ - cd $HOME/gopath/src/go4.org
diff --git a/vendor/go4.org/AUTHORS b/vendor/go4.org/AUTHORS
new file mode 100644
index 0000000..d1ad485
--- /dev/null
+++ b/vendor/go4.org/AUTHORS
@@ -0,0 +1,8 @@
+# This is the official list of go4 authors for copyright purposes.
+# This is distinct from the CONTRIBUTORS file, which is the list of
+# people who have contributed, even if they don't own the copyright on
+# their work.
+
+Mathieu Lonjaret
+Daniel Theophanes
+Google
diff --git a/vendor/go4.org/LICENSE b/vendor/go4.org/LICENSE
new file mode 100644
index 0000000..8f71f43
--- /dev/null
+++ b/vendor/go4.org/LICENSE
@@ -0,0 +1,202 @@
+ Apache License
+ Version 2.0, January 2004
+ http://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
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ 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.
+
diff --git a/vendor/go4.org/README.md b/vendor/go4.org/README.md
new file mode 100644
index 0000000..677ec17
--- /dev/null
+++ b/vendor/go4.org/README.md
@@ -0,0 +1,57 @@
+# go4
+
+[![travis badge](https://travis-ci.org/camlistore/go4.svg?branch=master)](https://travis-ci.org/camlistore/go4 "Travis CI")
+
+[go4.org](http://go4.org) is a collection of packages for
+Go programmers.
+
+They started out living in [Perkeep](https://perkeep.org)'s repo
+and elsewhere but they have nothing to do with Perkeep, so we're
+moving them here.
+
+## Details
+
+* **single repo**. go4 is a single repo. That means things can be
+ changed and rearranged globally atomically with ease and
+ confidence.
+
+* **no backwards compatibility**. go4 makes no backwards compatibility
+ promises. If you want to use go4, vendor it. And next time you
+ update your vendor tree, update to the latest API if things in go4
+ changed. The plan is to eventually provide tools to make this
+ easier.
+
+* **forward progress** because we have no backwards compatibility,
+ it's always okay to change things to make things better. That also
+ means the bar for contributions is lower. We don't have to get the
+ API 100% correct in the first commit.
+
+* **no Go version policy** go4 packages are usually built and tested
+ with the latest Go stable version. However, go4 has no overarching
+ version policy; each package can declare its own set of supported
+ Go versions.
+
+* **code review** contributions must be code-reviewed. We're trying
+ out Gerrithub, to see if we can find a mix of Github Pull Requests
+ and Gerrit that works well for many people. We'll see.
+
+* **CLA compliant** contributors must agree to the Google CLA (the
+ same as Go itself). This ensures we can move things into Go as
+ necessary in the future. It also makes lawyers at various
+ companies happy. The CLA is **not** a copyright *assignment*; you
+ retain the copyright on your work. The CLA just says that your
+ work is open source and you have permission to open source it. See
+ https://golang.org/doc/contribute.html#cla
+
+* **docs, tests, portability** all code should be documented in the
+ normal Go style, have tests, and be portable to different
+ operating systems and architectures. We'll try to get builders in
+ place to help run the tests on different OS/arches. For now we
+ have Travis at least.
+
+## Contact
+
+For any question, or communication when a Github issue is not appropriate,
+please contact the [Perkeep mailing
+list](https://groups.google.com/forum/#!forum/perkeep).
+
diff --git a/vendor/go4.org/bytereplacer/bytereplacer.go b/vendor/go4.org/bytereplacer/bytereplacer.go
new file mode 100644
index 0000000..5daa379
--- /dev/null
+++ b/vendor/go4.org/bytereplacer/bytereplacer.go
@@ -0,0 +1,286 @@
+/*
+Copyright 2015 The Perkeep 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 bytereplacer provides a utility for replacing parts of byte slices.
+package bytereplacer // import "go4.org/bytereplacer"
+
+import "bytes"
+
+// Replacer replaces a list of strings with replacements.
+// It is safe for concurrent use by multiple goroutines.
+type Replacer struct {
+ r replacer
+}
+
+// replacer is the interface that a replacement algorithm needs to implement.
+type replacer interface {
+ // Replace performs all replacements, in-place if possible.
+ Replace(s []byte) []byte
+}
+
+// New returns a new Replacer from a list of old, new string pairs.
+// Replacements are performed in order, without overlapping matches.
+func New(oldnew ...string) *Replacer {
+ if len(oldnew)%2 == 1 {
+ panic("bytes.NewReplacer: odd argument count")
+ }
+
+ allNewBytes := true
+ for i := 0; i < len(oldnew); i += 2 {
+ if len(oldnew[i]) != 1 {
+ return &Replacer{r: makeGenericReplacer(oldnew)}
+ }
+ if len(oldnew[i+1]) != 1 {
+ allNewBytes = false
+ }
+ }
+
+ if allNewBytes {
+ r := byteReplacer{}
+ for i := range r {
+ r[i] = byte(i)
+ }
+ // The first occurrence of old->new map takes precedence
+ // over the others with the same old string.
+ for i := len(oldnew) - 2; i >= 0; i -= 2 {
+ o := oldnew[i][0]
+ n := oldnew[i+1][0]
+ r[o] = n
+ }
+ return &Replacer{r: &r}
+ }
+
+ return &Replacer{r: makeGenericReplacer(oldnew)}
+}
+
+// Replace performs all replacements in-place on s. If the capacity
+// of s is not sufficient, a new slice is allocated, otherwise Replace
+// returns s.
+func (r *Replacer) Replace(s []byte) []byte {
+ return r.r.Replace(s)
+}
+
+type trieNode struct {
+ value []byte
+ priority int
+ prefix []byte
+ next *trieNode
+ table []*trieNode
+}
+
+func (t *trieNode) add(key, val []byte, priority int, r *genericReplacer) {
+ if len(key) == 0 {
+ if t.priority == 0 {
+ t.value = val
+ t.priority = priority
+ }
+ return
+ }
+
+ if len(t.prefix) > 0 {
+ // Need to split the prefix among multiple nodes.
+ var n int // length of the longest common prefix
+ for ; n < len(t.prefix) && n < len(key); n++ {
+ if t.prefix[n] != key[n] {
+ break
+ }
+ }
+ if n == len(t.prefix) {
+ t.next.add(key[n:], val, priority, r)
+ } else if n == 0 {
+ // First byte differs, start a new lookup table here. Looking up
+ // what is currently t.prefix[0] will lead to prefixNode, and
+ // looking up key[0] will lead to keyNode.
+ var prefixNode *trieNode
+ if len(t.prefix) == 1 {
+ prefixNode = t.next
+ } else {
+ prefixNode = &trieNode{
+ prefix: t.prefix[1:],
+ next: t.next,
+ }
+ }
+ keyNode := new(trieNode)
+ t.table = make([]*trieNode, r.tableSize)
+ t.table[r.mapping[t.prefix[0]]] = prefixNode
+ t.table[r.mapping[key[0]]] = keyNode
+ t.prefix = nil
+ t.next = nil
+ keyNode.add(key[1:], val, priority, r)
+ } else {
+ // Insert new node after the common section of the prefix.
+ next := &trieNode{
+ prefix: t.prefix[n:],
+ next: t.next,
+ }
+ t.prefix = t.prefix[:n]
+ t.next = next
+ next.add(key[n:], val, priority, r)
+ }
+ } else if t.table != nil {
+ // Insert into existing table.
+ m := r.mapping[key[0]]
+ if t.table[m] == nil {
+ t.table[m] = new(trieNode)
+ }
+ t.table[m].add(key[1:], val, priority, r)
+ } else {
+ t.prefix = key
+ t.next = new(trieNode)
+ t.next.add(nil, val, priority, r)
+ }
+}
+
+func (r *genericReplacer) lookup(s []byte, ignoreRoot bool) (val []byte, keylen int, found bool) {
+ // Iterate down the trie to the end, and grab the value and keylen with
+ // the highest priority.
+ bestPriority := 0
+ node := &r.root
+ n := 0
+ for node != nil {
+ if node.priority > bestPriority && !(ignoreRoot && node == &r.root) {
+ bestPriority = node.priority
+ val = node.value
+ keylen = n
+ found = true
+ }
+
+ if len(s) == 0 {
+ break
+ }
+ if node.table != nil {
+ index := r.mapping[s[0]]
+ if int(index) == r.tableSize {
+ break
+ }
+ node = node.table[index]
+ s = s[1:]
+ n++
+ } else if len(node.prefix) > 0 && bytes.HasPrefix(s, node.prefix) {
+ n += len(node.prefix)
+ s = s[len(node.prefix):]
+ node = node.next
+ } else {
+ break
+ }
+ }
+ return
+}
+
+// genericReplacer is the fully generic algorithm.
+// It's used as a fallback when nothing faster can be used.
+type genericReplacer struct {
+ root trieNode
+ // tableSize is the size of a trie node's lookup table. It is the number
+ // of unique key bytes.
+ tableSize int
+ // mapping maps from key bytes to a dense index for trieNode.table.
+ mapping [256]byte
+}
+
+func makeGenericReplacer(oldnew []string) *genericReplacer {
+ r := new(genericReplacer)
+ // Find each byte used, then assign them each an index.
+ for i := 0; i < len(oldnew); i += 2 {
+ key := oldnew[i]
+ for j := 0; j < len(key); j++ {
+ r.mapping[key[j]] = 1
+ }
+ }
+
+ for _, b := range r.mapping {
+ r.tableSize += int(b)
+ }
+
+ var index byte
+ for i, b := range r.mapping {
+ if b == 0 {
+ r.mapping[i] = byte(r.tableSize)
+ } else {
+ r.mapping[i] = index
+ index++
+ }
+ }
+ // Ensure root node uses a lookup table (for performance).
+ r.root.table = make([]*trieNode, r.tableSize)
+
+ for i := 0; i < len(oldnew); i += 2 {
+ r.root.add([]byte(oldnew[i]), []byte(oldnew[i+1]), len(oldnew)-i, r)
+ }
+ return r
+}
+
+func (r *genericReplacer) Replace(s []byte) []byte {
+ var last int
+ var prevMatchEmpty bool
+ dst := s[:0]
+ grown := false
+ for i := 0; i <= len(s); {
+ // Fast path: s[i] is not a prefix of any pattern.
+ if i != len(s) && r.root.priority == 0 {
+ index := int(r.mapping[s[i]])
+ if index == r.tableSize || r.root.table[index] == nil {
+ i++
+ continue
+ }
+ }
+
+ // Ignore the empty match iff the previous loop found the empty match.
+ val, keylen, match := r.lookup(s[i:], prevMatchEmpty)
+ prevMatchEmpty = match && keylen == 0
+ if match {
+ dst = append(dst, s[last:i]...)
+ if diff := len(val) - keylen; grown || diff < 0 {
+ dst = append(dst, val...)
+ i += keylen
+ } else if diff <= cap(s)-len(s) {
+ // The replacement is larger than the original, but can still fit in the original buffer.
+ copy(s[i+len(val):cap(dst)], s[i+keylen:])
+ dst = append(dst, val...)
+ s = s[:len(s)+diff]
+ i += len(val)
+ } else {
+ // The output will grow larger than the original buffer. Allocate a new one.
+ grown = true
+ newDst := make([]byte, len(dst), cap(dst)+diff)
+ copy(newDst, dst)
+ dst = newDst
+
+ dst = append(dst, val...)
+ i += keylen
+ }
+ last = i
+ continue
+ }
+ i++
+ }
+ if last != len(s) {
+ dst = append(dst, s[last:]...)
+ }
+ return dst
+}
+
+// byteReplacer is the implementation that's used when all the "old"
+// and "new" values are single ASCII bytes.
+// The array contains replacement bytes indexed by old byte.
+type byteReplacer [256]byte
+
+func (r *byteReplacer) Replace(s []byte) []byte {
+ for i, b := range s {
+ s[i] = r[b]
+ }
+ return s
+}
diff --git a/vendor/go4.org/bytereplacer/bytereplacer_test.go b/vendor/go4.org/bytereplacer/bytereplacer_test.go
new file mode 100644
index 0000000..81e8c6f
--- /dev/null
+++ b/vendor/go4.org/bytereplacer/bytereplacer_test.go
@@ -0,0 +1,423 @@
+/*
+Copyright 2015 The Perkeep 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 bytereplacer
+
+import (
+ "bytes"
+ "strings"
+ "testing"
+)
+
+var htmlEscaper = New(
+ "&", "&",
+ "<", "<",
+ ">", ">",
+ `"`, """,
+ "'", "'",
+)
+
+var htmlUnescaper = New(
+ "&", "&",
+ "<", "<",
+ ">", ">",
+ """, `"`,
+ "'", "'",
+)
+
+var capitalLetters = New("a", "A", "b", "B")
+
+func TestReplacer(t *testing.T) {
+ type testCase struct {
+ r *Replacer
+ in, out string
+ }
+ var testCases []testCase
+
+ // str converts 0xff to "\xff". This isn't just string(b) since that converts to UTF-8.
+ str := func(b byte) string {
+ return string([]byte{b})
+ }
+ var s []string
+
+ // inc maps "\x00"->"\x01", ..., "a"->"b", "b"->"c", ..., "\xff"->"\x00".
+ s = nil
+ for i := 0; i < 256; i++ {
+ s = append(s, str(byte(i)), str(byte(i+1)))
+ }
+ inc := New(s...)
+
+ // Test cases with 1-byte old strings, 1-byte new strings.
+ testCases = append(testCases,
+ testCase{capitalLetters, "brad", "BrAd"},
+ testCase{capitalLetters, strings.Repeat("a", (32<<10)+123), strings.Repeat("A", (32<<10)+123)},
+ testCase{capitalLetters, "", ""},
+
+ testCase{inc, "brad", "csbe"},
+ testCase{inc, "\x00\xff", "\x01\x00"},
+ testCase{inc, "", ""},
+
+ testCase{New("a", "1", "a", "2"), "brad", "br1d"},
+ )
+
+ // repeat maps "a"->"a", "b"->"bb", "c"->"ccc", ...
+ s = nil
+ for i := 0; i < 256; i++ {
+ n := i + 1 - 'a'
+ if n < 1 {
+ n = 1
+ }
+ s = append(s, str(byte(i)), strings.Repeat(str(byte(i)), n))
+ }
+ repeat := New(s...)
+
+ // Test cases with 1-byte old strings, variable length new strings.
+ testCases = append(testCases,
+ testCase{htmlEscaper, "No changes", "No changes"},
+ testCase{htmlEscaper, "I <3 escaping & stuff", "I <3 escaping & stuff"},
+ testCase{htmlEscaper, "&&&", "&&&"},
+ testCase{htmlEscaper, "", ""},
+
+ testCase{repeat, "brad", "bbrrrrrrrrrrrrrrrrrradddd"},
+ testCase{repeat, "abba", "abbbba"},
+ testCase{repeat, "", ""},
+
+ testCase{New("a", "11", "a", "22"), "brad", "br11d"},
+ )
+
+ // The remaining test cases have variable length old strings.
+
+ testCases = append(testCases,
+ testCase{htmlUnescaper, "&", "&"},
+ testCase{htmlUnescaper, "<b>HTML's neat</b>", "HTML's neat"},
+ testCase{htmlUnescaper, "", ""},
+
+ testCase{New("a", "1", "a", "2", "xxx", "xxx"), "brad", "br1d"},
+
+ testCase{New("a", "1", "aa", "2", "aaa", "3"), "aaaa", "1111"},
+
+ testCase{New("aaa", "3", "aa", "2", "a", "1"), "aaaa", "31"},
+ )
+
+ // gen1 has multiple old strings of variable length. There is no
+ // overall non-empty common prefix, but some pairwise common prefixes.
+ gen1 := New(
+ "aaa", "3[aaa]",
+ "aa", "2[aa]",
+ "a", "1[a]",
+ "i", "i",
+ "longerst", "most long",
+ "longer", "medium",
+ "long", "short",
+ "xx", "xx",
+ "x", "X",
+ "X", "Y",
+ "Y", "Z",
+ )
+ testCases = append(testCases,
+ testCase{gen1, "fooaaabar", "foo3[aaa]b1[a]r"},
+ testCase{gen1, "long, longerst, longer", "short, most long, medium"},
+ testCase{gen1, "xxxxx", "xxxxX"},
+ testCase{gen1, "XiX", "YiY"},
+ testCase{gen1, "", ""},
+ )
+
+ // gen2 has multiple old strings with no pairwise common prefix.
+ gen2 := New(
+ "roses", "red",
+ "violets", "blue",
+ "sugar", "sweet",
+ )
+ testCases = append(testCases,
+ testCase{gen2, "roses are red, violets are blue...", "red are red, blue are blue..."},
+ testCase{gen2, "", ""},
+ )
+
+ // gen3 has multiple old strings with an overall common prefix.
+ gen3 := New(
+ "abracadabra", "poof",
+ "abracadabrakazam", "splat",
+ "abraham", "lincoln",
+ "abrasion", "scrape",
+ "abraham", "isaac",
+ )
+ testCases = append(testCases,
+ testCase{gen3, "abracadabrakazam abraham", "poofkazam lincoln"},
+ testCase{gen3, "abrasion abracad", "scrape abracad"},
+ testCase{gen3, "abba abram abrasive", "abba abram abrasive"},
+ testCase{gen3, "", ""},
+ )
+
+ // foo{1,2,3,4} have multiple old strings with an overall common prefix
+ // and 1- or 2- byte extensions from the common prefix.
+ foo1 := New(
+ "foo1", "A",
+ "foo2", "B",
+ "foo3", "C",
+ )
+ foo2 := New(
+ "foo1", "A",
+ "foo2", "B",
+ "foo31", "C",
+ "foo32", "D",
+ )
+ foo3 := New(
+ "foo11", "A",
+ "foo12", "B",
+ "foo31", "C",
+ "foo32", "D",
+ )
+ foo4 := New(
+ "foo12", "B",
+ "foo32", "D",
+ )
+ testCases = append(testCases,
+ testCase{foo1, "fofoofoo12foo32oo", "fofooA2C2oo"},
+ testCase{foo1, "", ""},
+
+ testCase{foo2, "fofoofoo12foo32oo", "fofooA2Doo"},
+ testCase{foo2, "", ""},
+
+ testCase{foo3, "fofoofoo12foo32oo", "fofooBDoo"},
+ testCase{foo3, "", ""},
+
+ testCase{foo4, "fofoofoo12foo32oo", "fofooBDoo"},
+ testCase{foo4, "", ""},
+ )
+
+ // genAll maps "\x00\x01\x02...\xfe\xff" to "[all]", amongst other things.
+ allBytes := make([]byte, 256)
+ for i := range allBytes {
+ allBytes[i] = byte(i)
+ }
+ allString := string(allBytes)
+ genAll := New(
+ allString, "[all]",
+ "\xff", "[ff]",
+ "\x00", "[00]",
+ )
+ testCases = append(testCases,
+ testCase{genAll, allString, "[all]"},
+ testCase{genAll, "a\xff" + allString + "\x00", "a[ff][all][00]"},
+ testCase{genAll, "", ""},
+ )
+
+ // Test cases with empty old strings.
+
+ blankToX1 := New("", "X")
+ blankToX2 := New("", "X", "", "")
+ blankHighPriority := New("", "X", "o", "O")
+ blankLowPriority := New("o", "O", "", "X")
+ blankNoOp1 := New("", "")
+ blankNoOp2 := New("", "", "", "A")
+ blankFoo := New("", "X", "foobar", "R", "foobaz", "Z")
+ testCases = append(testCases,
+ testCase{blankToX1, "foo", "XfXoXoX"},
+ testCase{blankToX1, "", "X"},
+
+ testCase{blankToX2, "foo", "XfXoXoX"},
+ testCase{blankToX2, "", "X"},
+
+ testCase{blankHighPriority, "oo", "XOXOX"},
+ testCase{blankHighPriority, "ii", "XiXiX"},
+ testCase{blankHighPriority, "oiio", "XOXiXiXOX"},
+ testCase{blankHighPriority, "iooi", "XiXOXOXiX"},
+ testCase{blankHighPriority, "", "X"},
+
+ testCase{blankLowPriority, "oo", "OOX"},
+ testCase{blankLowPriority, "ii", "XiXiX"},
+ testCase{blankLowPriority, "oiio", "OXiXiOX"},
+ testCase{blankLowPriority, "iooi", "XiOOXiX"},
+ testCase{blankLowPriority, "", "X"},
+
+ testCase{blankNoOp1, "foo", "foo"},
+ testCase{blankNoOp1, "", ""},
+
+ testCase{blankNoOp2, "foo", "foo"},
+ testCase{blankNoOp2, "", ""},
+
+ testCase{blankFoo, "foobarfoobaz", "XRXZX"},
+ testCase{blankFoo, "foobar-foobaz", "XRX-XZX"},
+ testCase{blankFoo, "", "X"},
+ )
+
+ // single string replacer
+
+ abcMatcher := New("abc", "[match]")
+
+ testCases = append(testCases,
+ testCase{abcMatcher, "", ""},
+ testCase{abcMatcher, "ab", "ab"},
+ testCase{abcMatcher, "abc", "[match]"},
+ testCase{abcMatcher, "abcd", "[match]d"},
+ testCase{abcMatcher, "cabcabcdabca", "c[match][match]d[match]a"},
+ )
+
+ // Issue 6659 cases (more single string replacer)
+
+ noHello := New("Hello", "")
+ testCases = append(testCases,
+ testCase{noHello, "Hello", ""},
+ testCase{noHello, "Hellox", "x"},
+ testCase{noHello, "xHello", "x"},
+ testCase{noHello, "xHellox", "xx"},
+ )
+
+ // No-arg test cases.
+
+ nop := New()
+ testCases = append(testCases,
+ testCase{nop, "abc", "abc"},
+ testCase{nop, "", ""},
+ )
+
+ // Run the test cases.
+
+ for i, tc := range testCases {
+ {
+ // Replace with len(in) == cap(in)
+ in := make([]byte, len(tc.in))
+ copy(in, tc.in)
+ if s := string(tc.r.Replace(in)); s != tc.out {
+ t.Errorf("%d. Replace(%q /* len == cap */) = %q, want %q", i, tc.in, s, tc.out)
+ }
+ }
+
+ {
+ // Replace with len(in) < cap(in)
+ in := make([]byte, len(tc.in), len(tc.in)*2)
+ copy(in, tc.in)
+ if s := string(tc.r.Replace(in)); s != tc.out {
+ t.Errorf("%d. Replace(%q /* len < cap */) = %q, want %q", i, tc.in, s, tc.out)
+ }
+ }
+ }
+}
+
+func BenchmarkGenericNoMatch(b *testing.B) {
+ str := []byte(strings.Repeat("A", 100) + strings.Repeat("B", 100))
+ generic := New("a", "A", "b", "B", "12", "123") // varying lengths forces generic
+ for i := 0; i < b.N; i++ {
+ generic.Replace(str)
+ }
+}
+
+func BenchmarkGenericMatch1(b *testing.B) {
+ str := []byte(strings.Repeat("a", 100) + strings.Repeat("b", 100))
+ generic := New("a", "A", "b", "B", "12", "123")
+ for i := 0; i < b.N; i++ {
+ generic.Replace(str)
+ }
+}
+
+func BenchmarkGenericMatch2(b *testing.B) {
+ str := bytes.Repeat([]byte("It's <b>HTML</b>!"), 100)
+ for i := 0; i < b.N; i++ {
+ htmlUnescaper.Replace(str)
+ }
+}
+
+func benchmarkSingleString(b *testing.B, pattern, text string) {
+ r := New(pattern, "[match]")
+ buf := make([]byte, len(text), len(text)*7)
+ b.SetBytes(int64(len(text)))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ copy(buf, text)
+ r.Replace(buf)
+ }
+}
+
+func BenchmarkSingleMaxSkipping(b *testing.B) {
+ benchmarkSingleString(b, strings.Repeat("b", 25), strings.Repeat("a", 10000))
+}
+
+func BenchmarkSingleLongSuffixFail(b *testing.B) {
+ benchmarkSingleString(b, "b"+strings.Repeat("a", 500), strings.Repeat("a", 1002))
+}
+
+func BenchmarkSingleMatch(b *testing.B) {
+ benchmarkSingleString(b, "abcdef", strings.Repeat("abcdefghijklmno", 1000))
+}
+
+func benchmarkReplacer(b *testing.B, r *Replacer, str string) {
+ buf := make([]byte, len(str))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ copy(buf, str)
+ r.Replace(buf)
+ }
+}
+
+func BenchmarkByteByteNoMatch(b *testing.B) {
+ benchmarkReplacer(b, capitalLetters, strings.Repeat("A", 100)+strings.Repeat("B", 100))
+}
+
+func BenchmarkByteByteMatch(b *testing.B) {
+ benchmarkReplacer(b, capitalLetters, strings.Repeat("a", 100)+strings.Repeat("b", 100))
+}
+
+func BenchmarkByteStringMatch(b *testing.B) {
+ benchmarkReplacer(b, htmlEscaper, "<"+strings.Repeat("a", 99)+strings.Repeat("b", 99)+">")
+}
+
+func BenchmarkHTMLEscapeNew(b *testing.B) {
+ benchmarkReplacer(b, htmlEscaper, "I <3 to escape HTML & other text too.")
+}
+
+func BenchmarkHTMLEscapeOld(b *testing.B) {
+ str := "I <3 to escape HTML & other text too."
+ buf := make([]byte, len(str))
+ for i := 0; i < b.N; i++ {
+ copy(buf, str)
+ oldHTMLEscape(buf)
+ }
+}
+
+// The http package's old HTML escaping function in bytes form.
+func oldHTMLEscape(s []byte) []byte {
+ s = bytes.Replace(s, []byte("&"), []byte("&"), -1)
+ s = bytes.Replace(s, []byte("<"), []byte("<"), -1)
+ s = bytes.Replace(s, []byte(">"), []byte(">"), -1)
+ s = bytes.Replace(s, []byte(`"`), []byte("""), -1)
+ s = bytes.Replace(s, []byte("'"), []byte("'"), -1)
+ return s
+}
+
+// BenchmarkByteByteReplaces compares byteByteImpl against multiple Replaces.
+func BenchmarkByteByteReplaces(b *testing.B) {
+ str := strings.Repeat("a", 100) + strings.Repeat("b", 100)
+ for i := 0; i < b.N; i++ {
+ bytes.Replace(bytes.Replace([]byte(str), []byte{'a'}, []byte{'A'}, -1), []byte{'b'}, []byte{'B'}, -1)
+ }
+}
+
+// BenchmarkByteByteMap compares byteByteImpl against Map.
+func BenchmarkByteByteMap(b *testing.B) {
+ str := strings.Repeat("a", 100) + strings.Repeat("b", 100)
+ fn := func(r rune) rune {
+ switch r {
+ case 'a':
+ return 'A'
+ case 'b':
+ return 'B'
+ }
+ return r
+ }
+ for i := 0; i < b.N; i++ {
+ bytes.Map(fn, []byte(str))
+ }
+}
diff --git a/vendor/go4.org/cloud/cloudlaunch/cloudlaunch.go b/vendor/go4.org/cloud/cloudlaunch/cloudlaunch.go
new file mode 100644
index 0000000..b87cf81
--- /dev/null
+++ b/vendor/go4.org/cloud/cloudlaunch/cloudlaunch.go
@@ -0,0 +1,457 @@
+/*
+Copyright 2015 The Perkeep 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 cloudlaunch helps binaries run themselves on The Cloud, copying
+// themselves to GCE.
+package cloudlaunch // import "go4.org/cloud/cloudlaunch"
+
+import (
+ "encoding/json"
+ "flag"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "os"
+ "path"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "time"
+
+ "go4.org/cloud/google/gceutil"
+
+ "cloud.google.com/go/compute/metadata"
+ "cloud.google.com/go/storage"
+ "golang.org/x/net/context"
+ "golang.org/x/oauth2"
+ "golang.org/x/oauth2/google"
+ compute "google.golang.org/api/compute/v1"
+ "google.golang.org/api/googleapi"
+ "google.golang.org/api/option"
+ storageapi "google.golang.org/api/storage/v1"
+)
+
+func readFile(v string) string {
+ slurp, err := ioutil.ReadFile(v)
+ if err != nil {
+ log.Fatalf("Error reading %s: %v", v, err)
+ }
+ return strings.TrimSpace(string(slurp))
+}
+
+const baseConfig = `#cloud-config
+coreos:
+ update:
+ group: stable
+ reboot-strategy: $REBOOT
+ units:
+ - name: $NAME.service
+ command: start
+ content: |
+ [Unit]
+ Description=$NAME service
+ After=network.target
+
+ [Service]
+ Type=simple
+ ExecStartPre=/bin/sh -c 'mkdir -p /opt/bin && /usr/bin/curl --silent -f -o /opt/bin/$NAME $URL?$(date +%s) && chmod +x /opt/bin/$NAME'
+ ExecStart=/opt/bin/$NAME
+ RestartSec=10
+ Restart=always
+ StartLimitInterval=0
+
+ [Install]
+ WantedBy=network-online.target
+`
+
+// RestartPolicy controls whether the binary automatically restarts.
+type RestartPolicy int
+
+const (
+ RestartOnUpdates RestartPolicy = iota
+ RestartNever
+ // TODO: more graceful restarts; make systemd own listening on network sockets,
+ // don't break connections.
+)
+
+type Config struct {
+ // Name is the name of a service to run.
+ // This is the name of the systemd service (without .service)
+ // and the name of the GCE instance.
+ Name string
+
+ // RestartPolicy controls whether the binary automatically restarts
+ // on updates. The zero value means automatic.
+ RestartPolicy RestartPolicy
+
+ // UpdateStrategy sets the CoreOS automatic update strategy, and the
+ // associated reboots. Possible values are "best-effort", "etcd-lock",
+ // "reboot", "off", with "best-effort" being the default. See
+ // https://coreos.com/os/docs/latest/update-strategies.html
+ UpdateStrategy string
+
+ // BinaryBucket and BinaryObject are the GCS bucket and object
+ // within that bucket containing the Linux binary to download
+ // on boot and occasionally run. This binary must be public
+ // (at least for now).
+ BinaryBucket string
+ BinaryObject string // defaults to Name
+
+ GCEProjectID string
+ Zone string // defaults to us-central1-f
+ SSD bool
+
+ Scopes []string // any additional scopes
+
+ MachineType string
+ InstanceName string
+}
+
+// cloudLaunch is a launch of a Config.
+type cloudLaunch struct {
+ *Config
+ oauthClient *http.Client
+ computeService *compute.Service
+}
+
+func (c *Config) binaryURL() string {
+ return "https://storage.googleapis.com/" + c.BinaryBucket + "/" + c.binaryObject()
+}
+
+func (c *Config) instName() string { return c.Name } // for now
+func (c *Config) zone() string { return strDefault(c.Zone, "us-central1-f") }
+func (c *Config) machineType() string { return strDefault(c.MachineType, "g1-small") }
+func (c *Config) binaryObject() string { return strDefault(c.BinaryObject, c.Name) }
+func (c *Config) updateStrategy() string { return strDefault(c.UpdateStrategy, "best-effort") }
+
+func (c *Config) projectAPIURL() string {
+ return "https://www.googleapis.com/compute/v1/projects/" + c.GCEProjectID
+}
+func (c *Config) machineTypeURL() string {
+ return c.projectAPIURL() + "/zones/" + c.zone() + "/machineTypes/" + c.machineType()
+}
+
+func strDefault(a, b string) string {
+ if a != "" {
+ return a
+ }
+ return b
+}
+
+var (
+ doLaunch = flag.Bool("cloudlaunch", false, "Deploy or update this binary to the cloud. Must be on Linux, for now.")
+)
+
+func (c *Config) MaybeDeploy() {
+ flag.Parse()
+ if !*doLaunch {
+ go c.restartLoop()
+ return
+ }
+ defer os.Exit(1) // backup, in case we return without Fatal or os.Exit later
+
+ if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
+ log.Fatal("Can only use --cloudlaunch on linux/amd64, for now.")
+ }
+
+ if c.GCEProjectID == "" {
+ log.Fatal("cloudconfig.GCEProjectID is empty")
+ }
+ filename := filepath.Join(os.Getenv("HOME"), "keys", c.GCEProjectID+".key.json")
+ log.Printf("Using OAuth config from JSON service file: %s", filename)
+ jwtConf, err := google.JWTConfigFromJSON([]byte(readFile(filename)), append([]string{
+ storageapi.DevstorageFullControlScope,
+ compute.ComputeScope,
+ "https://www.googleapis.com/auth/cloud-platform",
+ }, c.Scopes...)...)
+ if err != nil {
+ log.Fatalf("ConfigFromJSON: %v", err)
+ }
+
+ cl := &cloudLaunch{
+ Config: c,
+ oauthClient: jwtConf.Client(oauth2.NoContext),
+ }
+ cl.computeService, _ = compute.New(cl.oauthClient)
+
+ cl.uploadBinary()
+ cl.createInstance()
+ os.Exit(0)
+}
+
+func (c *Config) restartLoop() {
+ if !metadata.OnGCE() {
+ return
+ }
+ if c.RestartPolicy == RestartNever {
+ return
+ }
+ url := c.binaryURL()
+ var lastEtag string
+ for {
+ res, err := http.Head(url + "?" + fmt.Sprint(time.Now().Unix()))
+ if err != nil {
+ log.Printf("Warning: %v", err)
+ time.Sleep(15 * time.Second)
+ continue
+ }
+ etag := res.Header.Get("Etag")
+ if etag == "" {
+ log.Printf("Warning, no ETag in response: %v", res)
+ time.Sleep(15 * time.Second)
+ continue
+ }
+ if lastEtag != "" && etag != lastEtag {
+ log.Printf("Binary updated; restarting.")
+ // TODO: more graceful restart, letting systemd own the network connections.
+ // Then we can finish up requests here.
+ os.Exit(0)
+ }
+ lastEtag = etag
+ time.Sleep(15 * time.Second)
+ }
+}
+
+// uploadBinary uploads the currently-running Linux binary.
+// It crashes if it fails.
+func (cl *cloudLaunch) uploadBinary() {
+ ctx := context.Background()
+ if cl.BinaryBucket == "" {
+ log.Fatal("cloudlaunch: Config.BinaryBucket is empty")
+ }
+ stoClient, err := storage.NewClient(ctx, option.WithHTTPClient(cl.oauthClient))
+ if err != nil {
+ log.Fatal(err)
+ }
+ w := stoClient.Bucket(cl.BinaryBucket).Object(cl.binaryObject()).NewWriter(ctx)
+ if err != nil {
+ log.Fatal(err)
+ }
+ w.ACL = []storage.ACLRule{
+ // If you don't give the owners access, the web UI seems to
+ // have a bug and doesn't have access to see that it's public, so
+ // won't render the "Shared Publicly" link. So we do that, even
+ // though it's dumb and unnecessary otherwise:
+ {
+ Entity: storage.ACLEntity("project-owners-" + cl.GCEProjectID),
+ Role: storage.RoleOwner,
+ },
+ // Public, so our systemd unit can get it easily:
+ {
+ Entity: storage.AllUsers,
+ Role: storage.RoleReader,
+ },
+ }
+ w.CacheControl = "no-cache"
+ selfPath := getSelfPath()
+ log.Printf("Uploading %q to %v", selfPath, cl.binaryURL())
+ f, err := os.Open(selfPath)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+ n, err := io.Copy(w, f)
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := w.Close(); err != nil {
+ log.Fatal(err)
+ }
+ log.Printf("Uploaded %d bytes", n)
+}
+
+func getSelfPath() string {
+ if runtime.GOOS != "linux" {
+ panic("TODO")
+ }
+ v, err := os.Readlink("/proc/self/exe")
+ if err != nil {
+ log.Fatal(err)
+ }
+ return v
+}
+
+func zoneInRegion(zone, regionURL string) bool {
+ if zone == "" {
+ panic("empty zone")
+ }
+ if regionURL == "" {
+ panic("empty regionURL")
+ }
+ // zone is like "us-central1-f"
+ // regionURL is like "https://www.googleapis.com/compute/v1/projects/camlistore-website/regions/us-central1"
+ region := path.Base(regionURL) // "us-central1"
+ if region == "" {
+ panic("empty region")
+ }
+ return strings.HasPrefix(zone, region)
+}
+
+// findIP finds an IP address to use, or returns the empty string if none is found.
+// It tries to find a reserved one in the same region where the name of the reserved IP
+// is "NAME-ip" and the IP is not in use.
+func (cl *cloudLaunch) findIP() string {
+ // Try to find it by name.
+ aggAddrList, err := cl.computeService.Addresses.AggregatedList(cl.GCEProjectID).Do()
+ if err != nil {
+ log.Fatal(err)
+ }
+ // https://godoc.org/google.golang.org/api/compute/v1#AddressAggregatedList
+ var ip string
+IPLoop:
+ for _, asl := range aggAddrList.Items {
+ for _, addr := range asl.Addresses {
+ log.Printf(" addr: %#v", addr)
+ if addr.Name == cl.Name+"-ip" && addr.Status == "RESERVED" && zoneInRegion(cl.zone(), addr.Region) {
+ ip = addr.Address
+ break IPLoop
+ }
+ }
+ }
+ return ip
+}
+
+func (cl *cloudLaunch) createInstance() {
+ inst := cl.lookupInstance()
+ if inst != nil {
+ log.Printf("Instance exists; not re-creating.")
+ return
+ }
+
+ log.Printf("Instance doesn't exist; creating...")
+
+ ip := cl.findIP()
+ log.Printf("Found IP: %v", ip)
+
+ cloudConfig := strings.NewReplacer(
+ "$NAME", cl.Name,
+ "$URL", cl.binaryURL(),
+ "$REBOOT", cl.updateStrategy(),
+ ).Replace(baseConfig)
+
+ instance := &compute.Instance{
+ Name: cl.instName(),
+ Description: cl.Name,
+ MachineType: cl.machineTypeURL(),
+ Disks: []*compute.AttachedDisk{cl.instanceDisk()},
+ Tags: &compute.Tags{
+ Items: []string{"http-server", "https-server"},
+ },
+ Metadata: &compute.Metadata{
+ Items: []*compute.MetadataItems{
+ {
+ Key: "user-data",
+ Value: googleapi.String(cloudConfig),
+ },
+ },
+ },
+ NetworkInterfaces: []*compute.NetworkInterface{
+ &compute.NetworkInterface{
+ AccessConfigs: []*compute.AccessConfig{
+ &compute.AccessConfig{
+ Type: "ONE_TO_ONE_NAT",
+ Name: "External NAT",
+ NatIP: ip,
+ },
+ },
+ Network: cl.projectAPIURL() + "/global/networks/default",
+ },
+ },
+ ServiceAccounts: []*compute.ServiceAccount{
+ {
+ Email: "default",
+ Scopes: cl.Scopes,
+ },
+ },
+ }
+
+ log.Printf("Creating instance...")
+ op, err := cl.computeService.Instances.Insert(cl.GCEProjectID, cl.zone(), instance).Do()
+ if err != nil {
+ log.Fatalf("Failed to create instance: %v", err)
+ }
+ opName := op.Name
+ log.Printf("Created. Waiting on operation %v", opName)
+OpLoop:
+ for {
+ time.Sleep(2 * time.Second)
+ op, err := cl.computeService.ZoneOperations.Get(cl.GCEProjectID, cl.zone(), opName).Do()
+ if err != nil {
+ log.Fatalf("Failed to get op %s: %v", opName, err)
+ }
+ switch op.Status {
+ case "PENDING", "RUNNING":
+ log.Printf("Waiting on operation %v", opName)
+ continue
+ case "DONE":
+ if op.Error != nil {
+ for _, operr := range op.Error.Errors {
+ log.Printf("Error: %+v", operr)
+ }
+ log.Fatalf("Failed to start.")
+ }
+ log.Printf("Success. %+v", op)
+ break OpLoop
+ default:
+ log.Fatalf("Unknown status %q: %+v", op.Status, op)
+ }
+ }
+
+ inst, err = cl.computeService.Instances.Get(cl.GCEProjectID, cl.zone(), cl.instName()).Do()
+ if err != nil {
+ log.Fatalf("Error getting instance after creation: %v", err)
+ }
+ ij, _ := json.MarshalIndent(inst, "", " ")
+ log.Printf("%s", ij)
+ log.Printf("Instance created.")
+ os.Exit(0)
+}
+
+// returns nil if instance doesn't exist.
+func (cl *cloudLaunch) lookupInstance() *compute.Instance {
+ inst, err := cl.computeService.Instances.Get(cl.GCEProjectID, cl.zone(), cl.instName()).Do()
+ if ae, ok := err.(*googleapi.Error); ok && ae.Code == 404 {
+ return nil
+ } else if err != nil {
+ log.Fatalf("Instances.Get: %v", err)
+ }
+ return inst
+}
+
+func (cl *cloudLaunch) instanceDisk() *compute.AttachedDisk {
+ imageURL, err := gceutil.CoreOSImageURL(cl.oauthClient)
+ if err != nil {
+ log.Fatalf("error looking up latest CoreOS stable image: %v", err)
+ }
+ diskName := cl.instName() + "-coreos-stateless-pd"
+ var diskType string
+ if cl.SSD {
+ diskType = cl.projectAPIURL() + "/zones/" + cl.zone() + "/diskTypes/pd-ssd"
+ }
+ return &compute.AttachedDisk{
+ AutoDelete: true,
+ Boot: true,
+ Type: "PERSISTENT",
+ InitializeParams: &compute.AttachedDiskInitializeParams{
+ DiskName: diskName,
+ SourceImage: imageURL,
+ DiskSizeGb: 50,
+ DiskType: diskType,
+ },
+ }
+}
diff --git a/vendor/go4.org/cloud/google/gceutil/gceutil.go b/vendor/go4.org/cloud/google/gceutil/gceutil.go
new file mode 100644
index 0000000..3ceaa98
--- /dev/null
+++ b/vendor/go4.org/cloud/google/gceutil/gceutil.go
@@ -0,0 +1,110 @@
+/*
+Copyright 2015 The Perkeep 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 gceutil provides utility functions to help with instances on
+// Google Compute Engine.
+package gceutil // import "go4.org/cloud/google/gceutil"
+
+import (
+ "encoding/json"
+ "errors"
+ "net/http"
+ "strings"
+ "time"
+
+ "google.golang.org/api/compute/v1"
+)
+
+// CoreOSImageURL returns the URL of the latest stable CoreOS image for running on Google Compute Engine.
+func CoreOSImageURL(cl *http.Client) (string, error) {
+ resp, err := cl.Get("https://www.googleapis.com/compute/v1/projects/coreos-cloud/global/images")
+ if err != nil {
+ return "", err
+ }
+ defer resp.Body.Close()
+
+ type coreOSImage struct {
+ SelfLink string
+ CreationTimestamp time.Time
+ Name string
+ }
+
+ type coreOSImageList struct {
+ Items []coreOSImage
+ }
+
+ imageList := &coreOSImageList{}
+ if err := json.NewDecoder(resp.Body).Decode(imageList); err != nil {
+ return "", err
+ }
+ if imageList == nil || len(imageList.Items) == 0 {
+ return "", errors.New("no images list in response")
+ }
+
+ imageURL := ""
+ var max time.Time // latest stable image creation time
+ for _, v := range imageList.Items {
+ if !strings.HasPrefix(v.Name, "coreos-stable") {
+ continue
+ }
+ if v.CreationTimestamp.After(max) {
+ max = v.CreationTimestamp
+ imageURL = v.SelfLink
+ }
+ }
+ if imageURL == "" {
+ return "", errors.New("no stable coreOS image found")
+ }
+ return imageURL, nil
+}
+
+// InstanceGroupAndManager contains both an InstanceGroup and
+// its InstanceGroupManager, if any.
+type InstanceGroupAndManager struct {
+ Group *compute.InstanceGroup
+
+ // Manager is the manager of the Group. It may be nil.
+ Manager *compute.InstanceGroupManager
+}
+
+// InstanceGroups returns all the instance groups in a project's zone, along
+// with their associated InstanceGroupManagers.
+// The returned map is keyed by the instance group identifier URL.
+func InstanceGroups(svc *compute.Service, proj, zone string) (map[string]InstanceGroupAndManager, error) {
+ managerList, err := svc.InstanceGroupManagers.List(proj, zone).Do()
+ if err != nil {
+ return nil, err
+ }
+ if managerList.NextPageToken != "" {
+ return nil, errors.New("too many managers; pagination not supported")
+ }
+ managedBy := make(map[string]*compute.InstanceGroupManager) // instance group URL -> its manager
+ for _, it := range managerList.Items {
+ managedBy[it.InstanceGroup] = it
+ }
+ groupList, err := svc.InstanceGroups.List(proj, zone).Do()
+ if err != nil {
+ return nil, err
+ }
+ if groupList.NextPageToken != "" {
+ return nil, errors.New("too many instance groups; pagination not supported")
+ }
+ ret := make(map[string]InstanceGroupAndManager)
+ for _, it := range groupList.Items {
+ ret[it.SelfLink] = InstanceGroupAndManager{it, managedBy[it.SelfLink]}
+ }
+ return ret, nil
+}
diff --git a/vendor/go4.org/cloud/google/gcsutil/storage.go b/vendor/go4.org/cloud/google/gcsutil/storage.go
new file mode 100644
index 0000000..c6e153a
--- /dev/null
+++ b/vendor/go4.org/cloud/google/gcsutil/storage.go
@@ -0,0 +1,180 @@
+/*
+Copyright 2015 The Go4 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 gcsutil provides tools for accessing Google Cloud Storage until they can be
+// completely replaced by cloud.google.com/go/storage.
+package gcsutil // import "go4.org/cloud/google/gcsutil"
+
+import (
+ "encoding/xml"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "os"
+ "strings"
+
+ "cloud.google.com/go/storage"
+ "go4.org/ctxutil"
+ "golang.org/x/net/context"
+)
+
+const gsAccessURL = "https://storage.googleapis.com"
+
+// An Object holds the name of an object (its bucket and key) within
+// Google Cloud Storage.
+type Object struct {
+ Bucket string
+ Key string
+}
+
+func (o *Object) valid() error {
+ if o == nil {
+ return errors.New("invalid nil Object")
+ }
+ if o.Bucket == "" {
+ return errors.New("missing required Bucket field in Object")
+ }
+ if o.Key == "" {
+ return errors.New("missing required Key field in Object")
+ }
+ return nil
+}
+
+// A SizedObject holds the bucket, key, and size of an object.
+type SizedObject struct {
+ Object
+ Size int64
+}
+
+func (o *Object) String() string {
+ if o == nil {
+ return ""
+ }
+ return fmt.Sprintf("%v/%v", o.Bucket, o.Key)
+}
+
+func (so SizedObject) String() string {
+ return fmt.Sprintf("%v/%v (%vB)", so.Bucket, so.Key, so.Size)
+}
+
+// Makes a simple body-less google storage request
+func simpleRequest(method, url_ string) (*http.Request, error) {
+ req, err := http.NewRequest(method, url_, nil)
+ if err != nil {
+ return nil, err
+ }
+ req.Header.Set("x-goog-api-version", "2")
+ return req, err
+}
+
+// ErrInvalidRange is used when the server has returned http.StatusRequestedRangeNotSatisfiable.
+var ErrInvalidRange = errors.New("gcsutil: requested range not satisfiable")
+
+// GetPartialObject fetches part of a Google Cloud Storage object.
+// This function relies on the ctx ctxutil.HTTPClient value being set to an OAuth2
+// authorized and authenticated HTTP client.
+// If length is negative, the rest of the object is returned.
+// It returns ErrInvalidRange if the server replies with http.StatusRequestedRangeNotSatisfiable.
+// The caller must call Close on the returned value.
+func GetPartialObject(ctx context.Context, obj Object, offset, length int64) (io.ReadCloser, error) {
+ if offset < 0 {
+ return nil, errors.New("invalid negative offset")
+ }
+ if err := obj.valid(); err != nil {
+ return nil, err
+ }
+
+ req, err := simpleRequest("GET", gsAccessURL+"/"+obj.Bucket+"/"+obj.Key)
+ if err != nil {
+ return nil, err
+ }
+ if length >= 0 {
+ req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", offset, offset+length-1))
+ } else {
+ req.Header.Set("Range", fmt.Sprintf("bytes=%d-", offset))
+ }
+ req.Cancel = ctx.Done()
+ res, err := ctxutil.Client(ctx).Do(req)
+ if err != nil {
+ return nil, fmt.Errorf("GET (offset=%d, length=%d) failed: %v\n", offset, length, err)
+ }
+ if res.StatusCode == http.StatusNotFound {
+ res.Body.Close()
+ return nil, os.ErrNotExist
+ }
+ if !(res.StatusCode == http.StatusPartialContent || (offset == 0 && res.StatusCode == http.StatusOK)) {
+ res.Body.Close()
+ if res.StatusCode == http.StatusRequestedRangeNotSatisfiable {
+ return nil, ErrInvalidRange
+ }
+ return nil, fmt.Errorf("GET (offset=%d, length=%d) got failed status: %v\n", offset, length, res.Status)
+ }
+
+ return res.Body, nil
+}
+
+// EnumerateObjects lists the objects in a bucket.
+// This function relies on the ctx oauth2.HTTPClient value being set to an OAuth2
+// authorized and authenticated HTTP client.
+// If after is non-empty, listing will begin with lexically greater object names.
+// If limit is non-zero, the length of the list will be limited to that number.
+func EnumerateObjects(ctx context.Context, bucket, after string, limit int) ([]*storage.ObjectAttrs, error) {
+ // Build url, with query params
+ var params []string
+ if after != "" {
+ params = append(params, "marker="+url.QueryEscape(after))
+ }
+ if limit > 0 {
+ params = append(params, fmt.Sprintf("max-keys=%v", limit))
+ }
+ query := ""
+ if len(params) > 0 {
+ query = "?" + strings.Join(params, "&")
+ }
+
+ req, err := simpleRequest("GET", gsAccessURL+"/"+bucket+"/"+query)
+ if err != nil {
+ return nil, err
+ }
+ req.Cancel = ctx.Done()
+ res, err := ctxutil.Client(ctx).Do(req)
+ if err != nil {
+ return nil, err
+ }
+ defer res.Body.Close()
+ if res.StatusCode != http.StatusOK {
+ return nil, fmt.Errorf("gcsutil: bad enumerate response code: %v", res.Status)
+ }
+
+ var xres struct {
+ Contents []SizedObject
+ }
+ if err = xml.NewDecoder(res.Body).Decode(&xres); err != nil {
+ return nil, err
+ }
+
+ objAttrs := make([]*storage.ObjectAttrs, len(xres.Contents))
+ for k, o := range xres.Contents {
+ objAttrs[k] = &storage.ObjectAttrs{
+ Name: o.Key,
+ Size: o.Size,
+ }
+ }
+
+ return objAttrs, nil
+}
diff --git a/vendor/go4.org/ctxutil/ctxutil.go b/vendor/go4.org/ctxutil/ctxutil.go
new file mode 100644
index 0000000..f5842a6
--- /dev/null
+++ b/vendor/go4.org/ctxutil/ctxutil.go
@@ -0,0 +1,44 @@
+/*
+Copyright 2015 The Go4 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 ctxutil contains golang.org/x/net/context related utilities.
+package ctxutil // import "go4.org/ctxutil"
+
+import (
+ "net/http"
+
+ "golang.org/x/net/context"
+ "golang.org/x/oauth2"
+)
+
+// HTTPClient is the context key to use with golang.org/x/net/context's WithValue function
+// to associate an *http.Client value with a context.
+//
+// We use the same value as the oauth2 package (which first introduced this key) rather
+// than creating a new one and forcing users to possibly set two.
+var HTTPClient = oauth2.HTTPClient
+
+// Client returns the HTTP client to use for the provided context.
+// If ctx is non-nil and has an associated HTTP client, that client is returned.
+// Otherwise, http.DefaultClient is returned.
+func Client(ctx context.Context) *http.Client {
+ if ctx != nil {
+ if hc, ok := ctx.Value(HTTPClient).(*http.Client); ok {
+ return hc
+ }
+ }
+ return http.DefaultClient
+}
diff --git a/vendor/go4.org/errorutil/highlight.go b/vendor/go4.org/errorutil/highlight.go
new file mode 100644
index 0000000..1b1efb0
--- /dev/null
+++ b/vendor/go4.org/errorutil/highlight.go
@@ -0,0 +1,58 @@
+/*
+Copyright 2011 Google Inc.
+
+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 errorutil helps make better error messages.
+package errorutil // import "go4.org/errorutil"
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "strings"
+)
+
+// HighlightBytePosition takes a reader and the location in bytes of a parse
+// error (for instance, from json.SyntaxError.Offset) and returns the line, column,
+// and pretty-printed context around the error with an arrow indicating the exact
+// position of the syntax error.
+func HighlightBytePosition(f io.Reader, pos int64) (line, col int, highlight string) {
+ line = 1
+ br := bufio.NewReader(f)
+ lastLine := ""
+ thisLine := new(bytes.Buffer)
+ for n := int64(0); n < pos; n++ {
+ b, err := br.ReadByte()
+ if err != nil {
+ break
+ }
+ if b == '\n' {
+ lastLine = thisLine.String()
+ thisLine.Reset()
+ line++
+ col = 1
+ } else {
+ col++
+ thisLine.WriteByte(b)
+ }
+ }
+ if line > 1 {
+ highlight += fmt.Sprintf("%5d: %s\n", line-1, lastLine)
+ }
+ highlight += fmt.Sprintf("%5d: %s\n", line, thisLine.String())
+ highlight += fmt.Sprintf("%s^\n", strings.Repeat(" ", col+5))
+ return
+}
diff --git a/vendor/go4.org/fault/fault.go b/vendor/go4.org/fault/fault.go
new file mode 100644
index 0000000..25cbdc7
--- /dev/null
+++ b/vendor/go4.org/fault/fault.go
@@ -0,0 +1,59 @@
+/*
+Copyright 2014 The Go4 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 fault handles fault injection for testing.
+package fault // import "go4.org/fault"
+
+import (
+ "errors"
+ "math/rand"
+ "os"
+ "strconv"
+ "strings"
+)
+
+var fakeErr = errors.New("fake injected error for testing")
+
+// An Injector reports whether fake errors should be returned.
+type Injector struct {
+ failPercent int
+}
+
+// NewInjector returns a new fault injector with the given name. The
+// environment variable "FAULT_" + capital(name) + "_FAIL_PERCENT"
+// controls the percentage of requests that fail. If undefined or
+// zero, no requests fail.
+func NewInjector(name string) *Injector {
+ var failPercent, _ = strconv.Atoi(os.Getenv("FAULT_" + strings.ToUpper(name) + "_FAIL_PERCENT"))
+ return &Injector{
+ failPercent: failPercent,
+ }
+}
+
+// ShouldFail reports whether a fake error should be returned.
+func (in *Injector) ShouldFail() bool {
+ return in.failPercent > 0 && in.failPercent > rand.Intn(100)
+}
+
+// FailErr checks ShouldFail and, if true, assigns a fake error to err
+// and returns true.
+func (in *Injector) FailErr(err *error) bool {
+ if !in.ShouldFail() {
+ return false
+ }
+ *err = fakeErr
+ return true
+}
diff --git a/vendor/go4.org/go4test/cloudlaunch/serve_on_cloud.go b/vendor/go4.org/go4test/cloudlaunch/serve_on_cloud.go
new file mode 100644
index 0000000..78d1420
--- /dev/null
+++ b/vendor/go4.org/go4test/cloudlaunch/serve_on_cloud.go
@@ -0,0 +1,95 @@
+// +build ignore
+
+/*
+Copyright 2016 The Go4 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.
+*/
+
+// The serve_on_cloud program deploys an HTTP server on Google Compute Engine,
+// serving from Google Cloud Storage. Its purpose is to help testing
+// go4.org/cloud/cloudlaunch and go4.org/wkfs/gcs.
+package main
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "net/http"
+ "os"
+ "path"
+ "regexp"
+ "time"
+
+ "go4.org/cloud/cloudlaunch"
+ "go4.org/wkfs"
+ _ "go4.org/wkfs/gcs"
+
+ "cloud.google.com/go/compute/metadata"
+ storageapi "google.golang.org/api/storage/v1"
+ compute "google.golang.org/api/compute/v1"
+)
+
+var httpAddr = flag.String("http", ":80", "HTTP address")
+
+var gcsBucket string
+
+func serveHTTP(w http.ResponseWriter, r *http.Request) {
+ rc, err := wkfs.Open(path.Join("/gcs", gcsBucket, r.URL.Path))
+ if err != nil {
+ http.Error(w, fmt.Sprintf("could not open %v: %v", r.URL.Path, err), 500)
+ return
+ }
+ defer rc.Close()
+ http.ServeContent(w, r, r.URL.Path, time.Now(), rc)
+}
+
+func main() {
+ if !metadata.OnGCE() {
+ bucket := os.Getenv("GCSBUCKET")
+ if bucket == "" {
+ log.Fatal("You need to set the GCSBUCKET env var to specify the Google Cloud Storage bucket to serve from.")
+ }
+ projectID := os.Getenv("GCEPROJECTID")
+ if projectID == "" {
+ log.Fatal("You need to set the GCEPROJECTID env var to specify the Google Cloud project where the instance will run.")
+ }
+ (&cloudlaunch.Config{
+ Name: "serveoncloud",
+ BinaryBucket: bucket,
+ GCEProjectID: projectID,
+ Scopes: []string{
+ storageapi.DevstorageFullControlScope,
+ compute.ComputeScope,
+ },
+ }).MaybeDeploy()
+ return
+ }
+
+ flag.Parse()
+
+ storageURLRxp := regexp.MustCompile(`https://storage.googleapis.com/(.+?)/serveoncloud.*`)
+ cloudConfig, err := metadata.InstanceAttributeValue("user-data")
+ if err != nil || cloudConfig == "" {
+ log.Fatalf("could not get cloud config from metadata: %v", err)
+ }
+ m := storageURLRxp.FindStringSubmatch(cloudConfig)
+ if len(m) < 2 {
+ log.Fatal("storage URL not found in cloud config")
+ }
+ gcsBucket = m[1]
+
+ http.HandleFunc("/", serveHTTP)
+
+ log.Fatal(http.ListenAndServe(*httpAddr, nil))
+}
diff --git a/vendor/go4.org/jsonconfig/eval.go b/vendor/go4.org/jsonconfig/eval.go
new file mode 100644
index 0000000..988597d
--- /dev/null
+++ b/vendor/go4.org/jsonconfig/eval.go
@@ -0,0 +1,321 @@
+/*
+Copyright 2011 The go4 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 jsonconfig
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strconv"
+ "strings"
+
+ "go4.org/errorutil"
+ "go4.org/wkfs"
+)
+
+type stringVector struct {
+ v []string
+}
+
+func (v *stringVector) Push(s string) {
+ v.v = append(v.v, s)
+}
+
+func (v *stringVector) Pop() {
+ v.v = v.v[:len(v.v)-1]
+}
+
+func (v *stringVector) Last() string {
+ return v.v[len(v.v)-1]
+}
+
+// A File is the type returned by ConfigParser.Open.
+type File interface {
+ io.ReadSeeker
+ io.Closer
+ Name() string
+}
+
+// ConfigParser specifies the environment for parsing a config file
+// and evaluating expressions.
+type ConfigParser struct {
+ rootJSON Obj
+
+ touchedFiles map[string]bool
+ includeStack stringVector
+
+ // Open optionally specifies an opener function.
+ Open func(filename string) (File, error)
+
+ // IncludeDirs optionally specifies where to find the other config files which are child
+ // objects of this config, if any. Even if nil, the working directory is always searched
+ // first.
+ IncludeDirs []string
+}
+
+func (c *ConfigParser) open(filename string) (File, error) {
+ if c.Open == nil {
+ return wkfs.Open(filename)
+ }
+ return c.Open(filename)
+}
+
+// Validates variable names for config _env expresssions
+var envPattern = regexp.MustCompile(`\$\{[A-Za-z0-9_]+\}`)
+
+// ReadFile parses the provided path and returns the config file.
+// If path is empty, the c.Open function must be defined.
+func (c *ConfigParser) ReadFile(path string) (Obj, error) {
+ if path == "" && c.Open == nil {
+ return nil, errors.New("ReadFile of empty string but Open hook not defined")
+ }
+ c.touchedFiles = make(map[string]bool)
+ var err error
+ c.rootJSON, err = c.recursiveReadJSON(path)
+ return c.rootJSON, err
+}
+
+// Decodes and evaluates a json config file, watching for include cycles.
+func (c *ConfigParser) recursiveReadJSON(configPath string) (decodedObject map[string]interface{}, err error) {
+ if configPath != "" {
+ absConfigPath, err := filepath.Abs(configPath)
+ if err != nil {
+ return nil, fmt.Errorf("Failed to expand absolute path for %s", configPath)
+ }
+ if c.touchedFiles[absConfigPath] {
+ return nil, fmt.Errorf("ConfigParser include cycle detected reading config: %v",
+ absConfigPath)
+ }
+ c.touchedFiles[absConfigPath] = true
+
+ c.includeStack.Push(absConfigPath)
+ defer c.includeStack.Pop()
+ }
+
+ var f File
+ if f, err = c.open(configPath); err != nil {
+ return nil, fmt.Errorf("Failed to open config: %v", err)
+ }
+ defer f.Close()
+
+ decodedObject = make(map[string]interface{})
+ dj := json.NewDecoder(f)
+ if err = dj.Decode(&decodedObject); err != nil {
+ extra := ""
+ if serr, ok := err.(*json.SyntaxError); ok {
+ if _, serr := f.Seek(0, os.SEEK_SET); serr != nil {
+ log.Fatalf("seek error: %v", serr)
+ }
+ line, col, highlight := errorutil.HighlightBytePosition(f, serr.Offset)
+ extra = fmt.Sprintf(":\nError at line %d, column %d (file offset %d):\n%s",
+ line, col, serr.Offset, highlight)
+ }
+ return nil, fmt.Errorf("error parsing JSON object in config file %s%s\n%v",
+ f.Name(), extra, err)
+ }
+
+ if err = c.evaluateExpressions(decodedObject, nil, false); err != nil {
+ return nil, fmt.Errorf("error expanding JSON config expressions in %s:\n%v",
+ f.Name(), err)
+ }
+
+ return decodedObject, nil
+}
+
+var regFunc = map[string]expanderFunc{}
+
+// RegisterFunc registers a new function that may be called from JSON
+// configs using an array of the form ["_name", arg0, argN...].
+// The provided name must begin with an underscore.
+func RegisterFunc(name string, fn func(c *ConfigParser, v []interface{}) (interface{}, error)) {
+ if len(name) < 2 || !strings.HasPrefix(name, "_") {
+ panic("illegal name")
+ }
+ if _, dup := regFunc[name]; dup {
+ panic("duplicate registration of " + name)
+ }
+ regFunc[name] = fn
+}
+
+type expanderFunc func(c *ConfigParser, v []interface{}) (interface{}, error)
+
+func namedExpander(name string) (fn expanderFunc, ok bool) {
+ switch name {
+ case "_env":
+ return (*ConfigParser).expandEnv, true
+ case "_fileobj":
+ return (*ConfigParser).expandFile, true
+ }
+ fn, ok = regFunc[name]
+ return
+}
+
+func (c *ConfigParser) evalValue(v interface{}) (interface{}, error) {
+ sl, ok := v.([]interface{})
+ if !ok {
+ return v, nil
+ }
+ if name, ok := sl[0].(string); ok {
+ if expander, ok := namedExpander(name); ok {
+ newval, err := expander(c, sl[1:])
+ if err != nil {
+ return nil, err
+ }
+ return newval, nil
+ }
+ }
+ for i, oldval := range sl {
+ newval, err := c.evalValue(oldval)
+ if err != nil {
+ return nil, err
+ }
+ sl[i] = newval
+ }
+ return v, nil
+}
+
+// CheckTypes parses m and returns an error if it encounters a type or value
+// that is not supported by this package.
+func (c *ConfigParser) CheckTypes(m map[string]interface{}) error {
+ return c.evaluateExpressions(m, nil, true)
+}
+
+// evaluateExpressions parses recursively m, populating it with the values
+// that are found, unless testOnly is true.
+func (c *ConfigParser) evaluateExpressions(m map[string]interface{}, seenKeys []string, testOnly bool) error {
+ for k, ei := range m {
+ thisPath := append(seenKeys, k)
+ switch subval := ei.(type) {
+ case string, bool, float64, nil:
+ continue
+ case []interface{}:
+ if len(subval) == 0 {
+ continue
+ }
+ evaled, err := c.evalValue(subval)
+ if err != nil {
+ return fmt.Errorf("%s: value error %v", strings.Join(thisPath, "."), err)
+ }
+ if !testOnly {
+ m[k] = evaled
+ }
+ case map[string]interface{}:
+ if err := c.evaluateExpressions(subval, thisPath, testOnly); err != nil {
+ return err
+ }
+ default:
+ return fmt.Errorf("%s: unhandled type %T", strings.Join(thisPath, "."), ei)
+ }
+ }
+ return nil
+}
+
+// Permit either:
+// ["_env", "VARIABLE"] (required to be set)
+// or ["_env", "VARIABLE", "default_value"]
+func (c *ConfigParser) expandEnv(v []interface{}) (interface{}, error) {
+ hasDefault := false
+ def := ""
+ if len(v) < 1 || len(v) > 2 {
+ return "", fmt.Errorf("_env expansion expected 1 or 2 args, got %d", len(v))
+ }
+ s, ok := v[0].(string)
+ if !ok {
+ return "", fmt.Errorf("Expected a string after _env expansion; got %#v", v[0])
+ }
+ boolDefault, wantsBool := false, false
+ if len(v) == 2 {
+ hasDefault = true
+ switch vdef := v[1].(type) {
+ case string:
+ def = vdef
+ case bool:
+ wantsBool = true
+ boolDefault = vdef
+ default:
+ return "", fmt.Errorf("Expected default value in %q _env expansion; got %#v", s, v[1])
+ }
+ }
+ var err error
+ expanded := envPattern.ReplaceAllStringFunc(s, func(match string) string {
+ envVar := match[2 : len(match)-1]
+ val := os.Getenv(envVar)
+ // Special case:
+ if val == "" && envVar == "USER" && runtime.GOOS == "windows" {
+ val = os.Getenv("USERNAME")
+ }
+ if val == "" {
+ if hasDefault {
+ return def
+ }
+ err = fmt.Errorf("couldn't expand environment variable %q", envVar)
+ }
+ return val
+ })
+ if wantsBool {
+ if expanded == "" {
+ return boolDefault, nil
+ }
+ return strconv.ParseBool(expanded)
+ }
+ return expanded, err
+}
+
+func (c *ConfigParser) expandFile(v []interface{}) (exp interface{}, err error) {
+ if len(v) != 1 {
+ return "", fmt.Errorf("_file expansion expected 1 arg, got %d", len(v))
+ }
+ var incPath string
+ if incPath, err = c.ConfigFilePath(v[0].(string)); err != nil {
+ return "", fmt.Errorf("Included config does not exist: %v", v[0])
+ }
+ if exp, err = c.recursiveReadJSON(incPath); err != nil {
+ return "", fmt.Errorf("In file included from %s:\n%v",
+ c.includeStack.Last(), err)
+ }
+ return exp, nil
+}
+
+// ConfigFilePath checks if configFile is found and returns a usable path to it.
+// It first checks if configFile is an absolute path, or if it's found in the
+// current working directory. If not, it then checks if configFile is in one of
+// c.IncludeDirs. It returns an error if configFile is absolute and could not be
+// statted, or os.ErrNotExist if configFile was not found.
+func (c *ConfigParser) ConfigFilePath(configFile string) (path string, err error) {
+ // Try to open as absolute / relative to CWD
+ _, err = os.Stat(configFile)
+ if err != nil && filepath.IsAbs(configFile) {
+ return "", err
+ }
+ if err == nil {
+ return configFile, nil
+ }
+
+ for _, d := range c.IncludeDirs {
+ if _, err := os.Stat(filepath.Join(d, configFile)); err == nil {
+ return filepath.Join(d, configFile), nil
+ }
+ }
+
+ return "", os.ErrNotExist
+}
diff --git a/vendor/go4.org/jsonconfig/jsonconfig.go b/vendor/go4.org/jsonconfig/jsonconfig.go
new file mode 100644
index 0000000..386dda8
--- /dev/null
+++ b/vendor/go4.org/jsonconfig/jsonconfig.go
@@ -0,0 +1,297 @@
+/*
+Copyright 2011 The go4 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 jsonconfig defines a helper type for JSON objects to be
+// used for configuration.
+package jsonconfig // import "go4.org/jsonconfig"
+
+import (
+ "fmt"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+// Obj is a JSON configuration map.
+type Obj map[string]interface{}
+
+// ReadFile reads JSON config data from the specified open file, expanding
+// all expressions. Use *ConfigParser.ReadFile instead if you
+// need to set c.IncludeDirs.
+func ReadFile(configPath string) (Obj, error) {
+ var c ConfigParser
+ return c.ReadFile(configPath)
+}
+
+func (jc Obj) RequiredObject(key string) Obj {
+ return jc.obj(key, false)
+}
+
+func (jc Obj) OptionalObject(key string) Obj {
+ return jc.obj(key, true)
+}
+
+func (jc Obj) obj(key string, optional bool) Obj {
+ jc.noteKnownKey(key)
+ ei, ok := jc[key]
+ if !ok {
+ if optional {
+ return make(Obj)
+ }
+ jc.appendError(fmt.Errorf("Missing required config key %q (object)", key))
+ return make(Obj)
+ }
+ m, ok := ei.(map[string]interface{})
+ if !ok {
+ jc.appendError(fmt.Errorf("Expected config key %q to be an object, not %T", key, ei))
+ return make(Obj)
+ }
+ return m
+}
+
+func (jc Obj) RequiredString(key string) string {
+ return jc.string(key, nil)
+}
+
+func (jc Obj) OptionalString(key, def string) string {
+ return jc.string(key, &def)
+}
+
+func (jc Obj) string(key string, def *string) string {
+ jc.noteKnownKey(key)
+ ei, ok := jc[key]
+ if !ok {
+ if def != nil {
+ return *def
+ }
+ jc.appendError(fmt.Errorf("Missing required config key %q (string)", key))
+ return ""
+ }
+ s, ok := ei.(string)
+ if !ok {
+ jc.appendError(fmt.Errorf("Expected config key %q to be a string", key))
+ return ""
+ }
+ return s
+}
+
+func (jc Obj) RequiredStringOrObject(key string) interface{} {
+ return jc.stringOrObject(key, true)
+}
+
+func (jc Obj) OptionalStringOrObject(key string) interface{} {
+ return jc.stringOrObject(key, false)
+}
+
+func (jc Obj) stringOrObject(key string, required bool) interface{} {
+ jc.noteKnownKey(key)
+ ei, ok := jc[key]
+ if !ok {
+ if !required {
+ return nil
+ }
+ jc.appendError(fmt.Errorf("Missing required config key %q (string or object)", key))
+ return ""
+ }
+ if _, ok := ei.(map[string]interface{}); ok {
+ return ei
+ }
+ if _, ok := ei.(string); ok {
+ return ei
+ }
+ jc.appendError(fmt.Errorf("Expected config key %q to be a string or object", key))
+ return ""
+}
+
+func (jc Obj) RequiredBool(key string) bool {
+ return jc.bool(key, nil)
+}
+
+func (jc Obj) OptionalBool(key string, def bool) bool {
+ return jc.bool(key, &def)
+}
+
+func (jc Obj) bool(key string, def *bool) bool {
+ jc.noteKnownKey(key)
+ ei, ok := jc[key]
+ if !ok {
+ if def != nil {
+ return *def
+ }
+ jc.appendError(fmt.Errorf("Missing required config key %q (boolean)", key))
+ return false
+ }
+ switch v := ei.(type) {
+ case bool:
+ return v
+ case string:
+ b, err := strconv.ParseBool(v)
+ if err != nil {
+ jc.appendError(fmt.Errorf("Config key %q has bad boolean format %q", key, v))
+ }
+ return b
+ default:
+ jc.appendError(fmt.Errorf("Expected config key %q to be a boolean", key))
+ return false
+ }
+}
+
+func (jc Obj) RequiredInt(key string) int {
+ return jc.int(key, nil)
+}
+
+func (jc Obj) OptionalInt(key string, def int) int {
+ return jc.int(key, &def)
+}
+
+func (jc Obj) int(key string, def *int) int {
+ jc.noteKnownKey(key)
+ ei, ok := jc[key]
+ if !ok {
+ if def != nil {
+ return *def
+ }
+ jc.appendError(fmt.Errorf("Missing required config key %q (integer)", key))
+ return 0
+ }
+ b, ok := ei.(float64)
+ if !ok {
+ jc.appendError(fmt.Errorf("Expected config key %q to be a number", key))
+ return 0
+ }
+ return int(b)
+}
+
+func (jc Obj) RequiredInt64(key string) int64 {
+ return jc.int64(key, nil)
+}
+
+func (jc Obj) OptionalInt64(key string, def int64) int64 {
+ return jc.int64(key, &def)
+}
+
+func (jc Obj) int64(key string, def *int64) int64 {
+ jc.noteKnownKey(key)
+ ei, ok := jc[key]
+ if !ok {
+ if def != nil {
+ return *def
+ }
+ jc.appendError(fmt.Errorf("Missing required config key %q (integer)", key))
+ return 0
+ }
+ b, ok := ei.(float64)
+ if !ok {
+ jc.appendError(fmt.Errorf("Expected config key %q to be a number", key))
+ return 0
+ }
+ return int64(b)
+}
+
+func (jc Obj) RequiredList(key string) []string {
+ return jc.requiredList(key, true)
+}
+
+func (jc Obj) OptionalList(key string) []string {
+ return jc.requiredList(key, false)
+}
+
+func (jc Obj) requiredList(key string, required bool) []string {
+ jc.noteKnownKey(key)
+ ei, ok := jc[key]
+ if !ok {
+ if required {
+ jc.appendError(fmt.Errorf("Missing required config key %q (list of strings)", key))
+ }
+ return nil
+ }
+ eil, ok := ei.([]interface{})
+ if !ok {
+ jc.appendError(fmt.Errorf("Expected config key %q to be a list, not %T", key, ei))
+ return nil
+ }
+ sl := make([]string, len(eil))
+ for i, ei := range eil {
+ s, ok := ei.(string)
+ if !ok {
+ jc.appendError(fmt.Errorf("Expected config key %q index %d to be a string, not %T", key, i, ei))
+ return nil
+ }
+ sl[i] = s
+ }
+ return sl
+}
+
+func (jc Obj) noteKnownKey(key string) {
+ _, ok := jc["_knownkeys"]
+ if !ok {
+ jc["_knownkeys"] = make(map[string]bool)
+ }
+ jc["_knownkeys"].(map[string]bool)[key] = true
+}
+
+func (jc Obj) appendError(err error) {
+ ei, ok := jc["_errors"]
+ if ok {
+ jc["_errors"] = append(ei.([]error), err)
+ } else {
+ jc["_errors"] = []error{err}
+ }
+}
+
+// UnknownKeys returns the keys from the config that have not yet been discovered by one of the RequiredT or OptionalT calls.
+func (jc Obj) UnknownKeys() []string {
+ ei, ok := jc["_knownkeys"]
+ var known map[string]bool
+ if ok {
+ known = ei.(map[string]bool)
+ }
+ var unknown []string
+ for k, _ := range jc {
+ if ok && known[k] {
+ continue
+ }
+ if strings.HasPrefix(k, "_") {
+ // Permit keys with a leading underscore as a
+ // form of comments.
+ continue
+ }
+ unknown = append(unknown, k)
+ }
+ sort.Strings(unknown)
+ return unknown
+}
+
+func (jc Obj) Validate() error {
+ unknown := jc.UnknownKeys()
+ for _, k := range unknown {
+ jc.appendError(fmt.Errorf("Unknown key %q", k))
+ }
+
+ ei, ok := jc["_errors"]
+ if !ok {
+ return nil
+ }
+ errList := ei.([]error)
+ if len(errList) == 1 {
+ return errList[0]
+ }
+ strs := make([]string, 0)
+ for _, v := range errList {
+ strs = append(strs, v.Error())
+ }
+ return fmt.Errorf("Multiple errors: " + strings.Join(strs, ", "))
+}
diff --git a/vendor/go4.org/jsonconfig/jsonconfig_test.go b/vendor/go4.org/jsonconfig/jsonconfig_test.go
new file mode 100644
index 0000000..8d2a1bd
--- /dev/null
+++ b/vendor/go4.org/jsonconfig/jsonconfig_test.go
@@ -0,0 +1,114 @@
+/*
+Copyright 2011 The go4 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 jsonconfig
+
+import (
+ "os"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+func testIncludes(configFile string, t *testing.T) {
+ var c ConfigParser
+ c.IncludeDirs = []string{"testdata"}
+ obj, err := c.ReadFile(configFile)
+ if err != nil {
+ t.Fatal(err)
+ }
+ two := obj.RequiredObject("two")
+ if err := obj.Validate(); err != nil {
+ t.Error(err)
+ }
+ if g, e := two.RequiredString("key"), "value"; g != e {
+ t.Errorf("sub object key = %q; want %q", g, e)
+ }
+}
+
+func TestIncludesCWD(t *testing.T) {
+ testIncludes("testdata/include1.json", t)
+}
+
+func TestIncludesIncludeDirs(t *testing.T) {
+ testIncludes("testdata/include1bis.json", t)
+}
+
+func TestIncludeLoop(t *testing.T) {
+ _, err := ReadFile("testdata/loop1.json")
+ if err == nil {
+ t.Fatal("expected an error about import cycles.")
+ }
+ if !strings.Contains(err.Error(), "include cycle detected") {
+ t.Fatalf("expected an error about import cycles; got: %v", err)
+ }
+}
+
+func TestBoolEnvs(t *testing.T) {
+ os.Setenv("TEST_EMPTY", "")
+ os.Setenv("TEST_TRUE", "true")
+ os.Setenv("TEST_ONE", "1")
+ os.Setenv("TEST_ZERO", "0")
+ os.Setenv("TEST_FALSE", "false")
+ obj, err := ReadFile("testdata/boolenv.json")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if str := obj.RequiredString("emptystr"); str != "" {
+ t.Errorf("str = %q, want empty", str)
+ }
+ tests := []struct {
+ key string
+ want bool
+ }{
+ {"def_false", false},
+ {"def_true", true},
+ {"set_true_def_false", true},
+ {"set_false_def_true", false},
+ {"lit_true", true},
+ {"lit_false", false},
+ {"one", true},
+ {"zero", false},
+ }
+ for _, tt := range tests {
+ if v := obj.RequiredBool(tt.key); v != tt.want {
+ t.Errorf("key %q = %v; want %v", tt.key, v, tt.want)
+ }
+ }
+ if err := obj.Validate(); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestListExpansion(t *testing.T) {
+ os.Setenv("TEST_BAR", "bar")
+ obj, err := ReadFile("testdata/listexpand.json")
+ if err != nil {
+ t.Fatal(err)
+ }
+ s := obj.RequiredString("str")
+ l := obj.RequiredList("list")
+ if err := obj.Validate(); err != nil {
+ t.Error(err)
+ }
+ want := []string{"foo", "bar"}
+ if !reflect.DeepEqual(l, want) {
+ t.Errorf("got = %#v\nwant = %#v", l, want)
+ }
+ if s != "bar" {
+ t.Errorf("str = %q, want %q", s, "bar")
+ }
+}
diff --git a/vendor/go4.org/jsonconfig/testdata/boolenv.json b/vendor/go4.org/jsonconfig/testdata/boolenv.json
new file mode 100644
index 0000000..fe9431e
--- /dev/null
+++ b/vendor/go4.org/jsonconfig/testdata/boolenv.json
@@ -0,0 +1,11 @@
+{
+ "emptystr": ["_env", "${TEST_EMPTY}", ""],
+ "def_false": ["_env", "${TEST_EMPTY}", false],
+ "def_true": ["_env", "${TEST_EMPTY}", true],
+ "set_true_def_false": ["_env", "${TEST_TRUE}", false],
+ "set_false_def_true": ["_env", "${TEST_FALSE}", true],
+ "one": ["_env", "${TEST_ONE}"],
+ "zero": ["_env", "${TEST_ZERO}"],
+ "lit_true": true,
+ "lit_false": false
+}
diff --git a/vendor/go4.org/jsonconfig/testdata/include1.json b/vendor/go4.org/jsonconfig/testdata/include1.json
new file mode 100644
index 0000000..6d8b38e
--- /dev/null
+++ b/vendor/go4.org/jsonconfig/testdata/include1.json
@@ -0,0 +1,3 @@
+{
+ "two": ["_fileobj", "testdata/include2.json"]
+}
diff --git a/vendor/go4.org/jsonconfig/testdata/include1bis.json b/vendor/go4.org/jsonconfig/testdata/include1bis.json
new file mode 100644
index 0000000..8459f8e
--- /dev/null
+++ b/vendor/go4.org/jsonconfig/testdata/include1bis.json
@@ -0,0 +1,3 @@
+{
+ "two": ["_fileobj", "include2.json"]
+}
diff --git a/vendor/go4.org/jsonconfig/testdata/include2.json b/vendor/go4.org/jsonconfig/testdata/include2.json
new file mode 100644
index 0000000..7a9e864
--- /dev/null
+++ b/vendor/go4.org/jsonconfig/testdata/include2.json
@@ -0,0 +1,3 @@
+{
+ "key": "value"
+}
diff --git a/vendor/go4.org/jsonconfig/testdata/listexpand.json b/vendor/go4.org/jsonconfig/testdata/listexpand.json
new file mode 100644
index 0000000..ccabcef
--- /dev/null
+++ b/vendor/go4.org/jsonconfig/testdata/listexpand.json
@@ -0,0 +1,4 @@
+{
+ "list": ["foo", ["_env", "${TEST_BAR}"]],
+ "str": ["_env", "${TEST_BAR}"]
+}
diff --git a/vendor/go4.org/jsonconfig/testdata/loop1.json b/vendor/go4.org/jsonconfig/testdata/loop1.json
new file mode 100644
index 0000000..215146f
--- /dev/null
+++ b/vendor/go4.org/jsonconfig/testdata/loop1.json
@@ -0,0 +1,3 @@
+{
+ "obj": ["_fileobj", "testdata/loop2.json"]
+}
diff --git a/vendor/go4.org/jsonconfig/testdata/loop2.json b/vendor/go4.org/jsonconfig/testdata/loop2.json
new file mode 100644
index 0000000..1d270eb
--- /dev/null
+++ b/vendor/go4.org/jsonconfig/testdata/loop2.json
@@ -0,0 +1,3 @@
+{
+ "obj": ["_fileobj", "testdata/loop1.json"]
+}
diff --git a/vendor/go4.org/legal/legal.go b/vendor/go4.org/legal/legal.go
new file mode 100644
index 0000000..954b143
--- /dev/null
+++ b/vendor/go4.org/legal/legal.go
@@ -0,0 +1,32 @@
+/*
+Copyright 2014 The Go4 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 legal provides in-process storage for compiled-in licenses.
+package legal // import "go4.org/legal"
+
+var licenses []string
+
+// RegisterLicense stores the license text.
+// It doesn't check whether the text was already present.
+func RegisterLicense(text string) {
+ licenses = append(licenses, text)
+ return
+}
+
+// Licenses returns a slice of the licenses.
+func Licenses() []string {
+ return licenses
+}
diff --git a/vendor/go4.org/legal/legal_test.go b/vendor/go4.org/legal/legal_test.go
new file mode 100644
index 0000000..0c65e9a
--- /dev/null
+++ b/vendor/go4.org/legal/legal_test.go
@@ -0,0 +1,29 @@
+/*
+Copyright 2014 The Go4 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 legal
+
+import (
+ "testing"
+)
+
+func TestRegisterLicense(t *testing.T) {
+ initial := len(licenses)
+ RegisterLicense("dummy")
+ if initial+1 != len(licenses) {
+ t.Fatal("didn't add a license")
+ }
+}
diff --git a/vendor/go4.org/lock/.gitignore b/vendor/go4.org/lock/.gitignore
new file mode 100644
index 0000000..b25c15b
--- /dev/null
+++ b/vendor/go4.org/lock/.gitignore
@@ -0,0 +1 @@
+*~
diff --git a/vendor/go4.org/lock/lock.go b/vendor/go4.org/lock/lock.go
new file mode 100644
index 0000000..3e25362
--- /dev/null
+++ b/vendor/go4.org/lock/lock.go
@@ -0,0 +1,186 @@
+/*
+Copyright 2013 The Go 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 lock is a file locking library.
+package lock // import "go4.org/lock"
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "sync"
+)
+
+// Lock locks the given file, creating the file if necessary. If the
+// file already exists, it must have zero size or an error is returned.
+// The lock is an exclusive lock (a write lock), but locked files
+// should neither be read from nor written to. Such files should have
+// zero size and only exist to co-ordinate ownership across processes.
+//
+// A nil Closer is returned if an error occurred. Otherwise, close that
+// Closer to release the lock.
+//
+// On Linux, FreeBSD and OSX, a lock has the same semantics as fcntl(2)'s
+// advisory locks. In particular, closing any other file descriptor for the
+// same file will release the lock prematurely.
+//
+// Attempting to lock a file that is already locked by the current process
+// has undefined behavior.
+//
+// On other operating systems, lock will fallback to using the presence and
+// content of a file named name + '.lock' to implement locking behavior.
+func Lock(name string) (io.Closer, error) {
+ abs, err := filepath.Abs(name)
+ if err != nil {
+ return nil, err
+ }
+ lockmu.Lock()
+ defer lockmu.Unlock()
+ if locked[abs] {
+ return nil, fmt.Errorf("file %q already locked", abs)
+ }
+
+ c, err := lockFn(abs)
+ if err != nil {
+ return nil, fmt.Errorf("cannot acquire lock: %v", err)
+ }
+ locked[abs] = true
+ return c, nil
+}
+
+var lockFn = lockPortable
+
+// lockPortable is a portable version not using fcntl. Doesn't handle crashes as gracefully,
+// since it can leave stale lock files.
+func lockPortable(name string) (io.Closer, error) {
+ fi, err := os.Stat(name)
+ if err == nil && fi.Size() > 0 {
+ st := portableLockStatus(name)
+ switch st {
+ case statusLocked:
+ return nil, fmt.Errorf("file %q already locked", name)
+ case statusStale:
+ os.Remove(name)
+ case statusInvalid:
+ return nil, fmt.Errorf("can't Lock file %q: has invalid contents", name)
+ }
+ }
+ f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_EXCL, 0666)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create lock file %s %v", name, err)
+ }
+ if err := json.NewEncoder(f).Encode(&pidLockMeta{OwnerPID: os.Getpid()}); err != nil {
+ return nil, fmt.Errorf("cannot write owner pid: %v", err)
+ }
+ return &unlocker{
+ f: f,
+ abs: name,
+ portable: true,
+ }, nil
+}
+
+type lockStatus int
+
+const (
+ statusInvalid lockStatus = iota
+ statusLocked
+ statusUnlocked
+ statusStale
+)
+
+type pidLockMeta struct {
+ OwnerPID int
+}
+
+func portableLockStatus(path string) lockStatus {
+ f, err := os.Open(path)
+ if err != nil {
+ return statusUnlocked
+ }
+ defer f.Close()
+ var meta pidLockMeta
+ if json.NewDecoder(f).Decode(&meta) != nil {
+ return statusInvalid
+ }
+ if meta.OwnerPID == 0 {
+ return statusInvalid
+ }
+ p, err := os.FindProcess(meta.OwnerPID)
+ if err != nil {
+ // e.g. on Windows
+ return statusStale
+ }
+ // On unix, os.FindProcess always is true, so we have to send
+ // it a signal to see if it's alive.
+ if signalZero != nil {
+ if p.Signal(signalZero) != nil {
+ return statusStale
+ }
+ }
+ return statusLocked
+}
+
+var signalZero os.Signal // nil or set by lock_sigzero.go
+
+var (
+ lockmu sync.Mutex
+ locked = map[string]bool{} // abs path -> true
+)
+
+type unlocker struct {
+ portable bool
+ f *os.File
+ abs string
+ // once guards the close method call.
+ once sync.Once
+ // err holds the error returned by Close.
+ err error
+}
+
+func (u *unlocker) Close() error {
+ u.once.Do(u.close)
+ return u.err
+}
+
+func (u *unlocker) close() {
+ lockmu.Lock()
+ defer lockmu.Unlock()
+ delete(locked, u.abs)
+
+ if u.portable {
+ // In the portable lock implementation, it's
+ // important to close before removing because
+ // Windows won't allow us to remove an open
+ // file.
+ if err := u.f.Close(); err != nil {
+ u.err = err
+ }
+ if err := os.Remove(u.abs); err != nil {
+ // Note that if both Close and Remove fail,
+ // we care more about the latter than the former
+ // so we'll return that error.
+ u.err = err
+ }
+ return
+ }
+ // In other implementatioons, it's nice for us to clean up.
+ // If we do do this, though, it needs to be before the
+ // u.f.Close below.
+ os.Remove(u.abs)
+ u.err = u.f.Close()
+}
diff --git a/vendor/go4.org/lock/lock_appengine.go b/vendor/go4.org/lock/lock_appengine.go
new file mode 100644
index 0000000..ab4cad6
--- /dev/null
+++ b/vendor/go4.org/lock/lock_appengine.go
@@ -0,0 +1,32 @@
+// +build appengine
+
+/*
+Copyright 2013 The Go 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 lock
+
+import (
+ "errors"
+ "io"
+)
+
+func init() {
+ lockFn = lockAppEngine
+}
+
+func lockAppEngine(name string) (io.Closer, error) {
+ return nil, errors.New("Lock not available on App Engine")
+}
diff --git a/vendor/go4.org/lock/lock_plan9.go b/vendor/go4.org/lock/lock_plan9.go
new file mode 100644
index 0000000..d841c27
--- /dev/null
+++ b/vendor/go4.org/lock/lock_plan9.go
@@ -0,0 +1,41 @@
+/*
+Copyright 2013 The Go 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 lock
+
+import (
+ "fmt"
+ "io"
+ "os"
+)
+
+func init() {
+ lockFn = lockPlan9
+}
+
+func lockPlan9(name string) (io.Closer, error) {
+ fi, err := os.Stat(name)
+ if err == nil && fi.Size() > 0 {
+ return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name)
+ }
+
+ f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE, os.ModeExclusive|0644)
+ if err != nil {
+ return nil, fmt.Errorf("Lock Create of %s failed: %v", name, err)
+ }
+
+ return &unlocker{f: f, abs: name}, nil
+}
diff --git a/vendor/go4.org/lock/lock_sigzero.go b/vendor/go4.org/lock/lock_sigzero.go
new file mode 100644
index 0000000..fd3ba2d
--- /dev/null
+++ b/vendor/go4.org/lock/lock_sigzero.go
@@ -0,0 +1,26 @@
+// +build !appengine
+// +build linux darwin freebsd openbsd netbsd dragonfly
+
+/*
+Copyright 2013 The Go 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 lock
+
+import "syscall"
+
+func init() {
+ signalZero = syscall.Signal(0)
+}
diff --git a/vendor/go4.org/lock/lock_test.go b/vendor/go4.org/lock/lock_test.go
new file mode 100644
index 0000000..de9c8f8
--- /dev/null
+++ b/vendor/go4.org/lock/lock_test.go
@@ -0,0 +1,222 @@
+/*
+Copyright 2013 The Go 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 lock
+
+import (
+ "bufio"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strconv"
+ "testing"
+)
+
+func TestLock(t *testing.T) {
+ testLock(t, false)
+}
+
+func TestLockPortable(t *testing.T) {
+ testLock(t, true)
+}
+
+func TestLockInChild(t *testing.T) {
+ f := os.Getenv("TEST_LOCK_FILE")
+ if f == "" {
+ // not child
+ return
+ }
+ lock := Lock
+ if v, _ := strconv.ParseBool(os.Getenv("TEST_LOCK_PORTABLE")); v {
+ lock = lockPortable
+ }
+
+ var lk io.Closer
+ for scan := bufio.NewScanner(os.Stdin); scan.Scan(); {
+ var err error
+ switch scan.Text() {
+ case "lock":
+ lk, err = lock(f)
+ case "unlock":
+ err = lk.Close()
+ lk = nil
+ case "exit":
+ // Simulate a crash, or at least not unlocking the lock.
+ os.Exit(0)
+ default:
+ err = fmt.Errorf("unexpected child command %q", scan.Text())
+ }
+ if err != nil {
+ fmt.Println(err)
+ } else {
+ fmt.Println("")
+ }
+ }
+}
+
+func testLock(t *testing.T, portable bool) {
+ lock := Lock
+ if portable {
+ lock = lockPortable
+ }
+ t.Logf("test lock, portable %v", portable)
+
+ td, err := ioutil.TempDir("", "")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(td)
+
+ path := filepath.Join(td, "foo.lock")
+
+ proc := newChildProc(t, path, portable)
+ defer proc.kill()
+
+ t.Logf("First lock in child")
+ if err := proc.do("lock"); err != nil {
+ t.Fatalf("first lock in child process: %v", err)
+ }
+
+ t.Logf("Crash child")
+ if err := proc.do("exit"); err != nil {
+ t.Fatalf("crash in child process: %v", err)
+ }
+
+ proc = newChildProc(t, path, portable)
+ defer proc.kill()
+
+ t.Logf("Locking+unlocking in child...")
+ if err := proc.do("lock"); err != nil {
+ t.Fatalf("lock in child process after crashing child: %v", err)
+ }
+ if err := proc.do("unlock"); err != nil {
+ t.Fatalf("lock in child process after crashing child: %v", err)
+ }
+
+ t.Logf("Locking in parent...")
+ lk1, err := lock(path)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ t.Logf("Again in parent...")
+ _, err = lock(path)
+ if err == nil {
+ t.Fatal("expected second lock to fail")
+ }
+
+ t.Logf("Locking in child...")
+ if err := proc.do("lock"); err == nil {
+ t.Fatalf("expected lock in child process to fail")
+ }
+
+ t.Logf("Unlocking lock in parent")
+ if err := lk1.Close(); err != nil {
+ t.Fatal(err)
+ }
+
+ t.Logf("Trying lock again in child...")
+ if err := proc.do("lock"); err != nil {
+ t.Fatal(err)
+ }
+ if err := proc.do("unlock"); err != nil {
+ t.Fatal(err)
+ }
+
+ lk3, err := lock(path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ lk3.Close()
+}
+
+type childLockCmd struct {
+ op string
+ reply chan<- error
+}
+
+type childProc struct {
+ proc *os.Process
+ c chan childLockCmd
+}
+
+func (c *childProc) kill() {
+ c.proc.Kill()
+}
+
+func (c *childProc) do(op string) error {
+ reply := make(chan error)
+ c.c <- childLockCmd{
+ op: op,
+ reply: reply,
+ }
+ return <-reply
+}
+
+func newChildProc(t *testing.T, path string, portable bool) *childProc {
+ cmd := exec.Command(os.Args[0], "-test.run=LockInChild$")
+ cmd.Env = []string{"TEST_LOCK_FILE=" + path}
+ toChild, err := cmd.StdinPipe()
+ if err != nil {
+ t.Fatalf("cannot make pipe: %v", err)
+ }
+ fromChild, err := cmd.StdoutPipe()
+ if err != nil {
+ t.Fatalf("cannot make pipe: %v", err)
+ }
+ cmd.Stderr = os.Stderr
+ if portable {
+ cmd.Env = append(cmd.Env, "TEST_LOCK_PORTABLE=1")
+ }
+ if err := cmd.Start(); err != nil {
+ t.Fatalf("cannot start child: %v", err)
+ }
+ cmdChan := make(chan childLockCmd)
+ go func() {
+ defer fromChild.Close()
+ defer toChild.Close()
+ inScan := bufio.NewScanner(fromChild)
+ for c := range cmdChan {
+ fmt.Fprintln(toChild, c.op)
+ ok := inScan.Scan()
+ if c.op == "exit" {
+ if ok {
+ c.reply <- errors.New("child did not exit")
+ } else {
+ cmd.Wait()
+ c.reply <- nil
+ }
+ break
+ }
+ if !ok {
+ panic("child exited early")
+ }
+ if errText := inScan.Text(); errText != "" {
+ c.reply <- errors.New(errText)
+ } else {
+ c.reply <- nil
+ }
+ }
+ }()
+ return &childProc{
+ c: cmdChan,
+ proc: cmd.Process,
+ }
+}
diff --git a/vendor/go4.org/lock/lock_unix.go b/vendor/go4.org/lock/lock_unix.go
new file mode 100644
index 0000000..d26056b
--- /dev/null
+++ b/vendor/go4.org/lock/lock_unix.go
@@ -0,0 +1,58 @@
+// +build linux darwin freebsd openbsd netbsd dragonfly solaris
+// +build !appengine
+
+/*
+Copyright 2013 The Go 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 lock
+
+import (
+ "fmt"
+ "io"
+ "os"
+
+ "golang.org/x/sys/unix"
+)
+
+func init() {
+ lockFn = lockFcntl
+}
+
+func lockFcntl(name string) (io.Closer, error) {
+ fi, err := os.Stat(name)
+ if err == nil && fi.Size() > 0 {
+ return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name)
+ }
+
+ f, err := os.Create(name)
+ if err != nil {
+ return nil, fmt.Errorf("Lock Create of %s failed: %v", name, err)
+ }
+
+ err = unix.FcntlFlock(f.Fd(), unix.F_SETLK, &unix.Flock_t{
+ Type: unix.F_WRLCK,
+ Whence: int16(os.SEEK_SET),
+ Start: 0,
+ Len: 0, // 0 means to lock the entire file.
+ Pid: 0, // only used by F_GETLK
+ })
+
+ if err != nil {
+ f.Close()
+ return nil, fmt.Errorf("Lock FcntlFlock of %s failed: %v", name, err)
+ }
+ return &unlocker{f: f, abs: name}, nil
+}
diff --git a/vendor/go4.org/lock/lock_windows.go b/vendor/go4.org/lock/lock_windows.go
new file mode 100644
index 0000000..4257487
--- /dev/null
+++ b/vendor/go4.org/lock/lock_windows.go
@@ -0,0 +1,78 @@
+/*
+Copyright 2013 The Go 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 lock
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "sync"
+
+ "golang.org/x/sys/windows"
+)
+
+func init() {
+ lockFn = lockWindows
+}
+
+type winUnlocker struct {
+ h windows.Handle
+ abs string
+ // err holds the error returned by Close.
+ err error
+ // once guards the close method call.
+ once sync.Once
+}
+
+func (u *winUnlocker) Close() error {
+ u.once.Do(u.close)
+ return u.err
+}
+
+func (u *winUnlocker) close() {
+ lockmu.Lock()
+ defer lockmu.Unlock()
+ delete(locked, u.abs)
+
+ u.err = windows.CloseHandle(u.h)
+}
+
+func lockWindows(name string) (io.Closer, error) {
+ fi, err := os.Stat(name)
+ if err == nil && fi.Size() > 0 {
+ return nil, fmt.Errorf("can't lock file %q: %s", name, "has non-zero size")
+ }
+
+ handle, err := winCreateEphemeral(name)
+ if err != nil {
+ return nil, fmt.Errorf("creation of lock %s failed: %v", name, err)
+ }
+
+ return &winUnlocker{h: handle, abs: name}, nil
+}
+
+func winCreateEphemeral(name string) (windows.Handle, error) {
+ const (
+ FILE_ATTRIBUTE_TEMPORARY = 0x100
+ FILE_FLAG_DELETE_ON_CLOSE = 0x04000000
+ )
+ handle, err := windows.CreateFile(windows.StringToUTF16Ptr(name), 0, 0, nil, windows.OPEN_ALWAYS, FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE, 0)
+ if err != nil {
+ return 0, err
+ }
+ return handle, nil
+}
diff --git a/vendor/go4.org/media/heif/bmff/bmff.go b/vendor/go4.org/media/heif/bmff/bmff.go
new file mode 100644
index 0000000..126a9da
--- /dev/null
+++ b/vendor/go4.org/media/heif/bmff/bmff.go
@@ -0,0 +1,833 @@
+/*
+Copyright 2018 The go4 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 bmff reads ISO BMFF boxes, as used by HEIF, etc.
+//
+// This is not so much as a generic BMFF reader as it is a BMFF reader
+// as needed by HEIF, though that may change in time. For now, only
+// boxes necessary for the go4.org/media/heif package have explicit
+// parsers.
+//
+// This package makes no API compatibility promises; it exists
+// primarily for use by the go4.org/media/heif package.
+package bmff
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "strings"
+)
+
+func NewReader(r io.Reader) *Reader {
+ br, ok := r.(*bufio.Reader)
+ if !ok {
+ br = bufio.NewReader(r)
+ }
+ return &Reader{br: bufReader{Reader: br}}
+}
+
+type Reader struct {
+ br bufReader
+ lastBox Box // or nil
+ noMoreBoxes bool // a box with size 0 (the final box) was seen
+}
+
+type BoxType [4]byte
+
+// Common box types.
+var (
+ TypeFtyp = BoxType{'f', 't', 'y', 'p'}
+ TypeMeta = BoxType{'m', 'e', 't', 'a'}
+)
+
+func (t BoxType) String() string { return string(t[:]) }
+
+func (t BoxType) EqualString(s string) bool {
+ // Could be cleaner, but see ohttps://github.com/golang/go/issues/24765
+ return len(s) == 4 && s[0] == t[0] && s[1] == t[1] && s[2] == t[2] && s[3] == t[3]
+}
+
+type parseFunc func(b box, br *bufio.Reader) (Box, error)
+
+// Box represents a BMFF box.
+type Box interface {
+ Size() int64 // 0 means unknown (will read to end of file)
+ Type() BoxType
+
+ // Parses parses the box, populating the fields
+ // in the returned concrete type.
+ //
+ // If Parse has already been called, Parse returns nil.
+ // If the box type is unknown, the returned error is ErrUnknownBox
+ // and it's guaranteed that no bytes have been read from the box.
+ Parse() (Box, error)
+
+ // Body returns the inner bytes of the box, ignoring the header.
+ // The body may start with the 4 byte header of a "Full Box" if the
+ // box's type derives from a full box. Most users will use Parse
+ // instead.
+ // Body will return a new reader at the beginning of the box if the
+ // outer box has already been parsed.
+ Body() io.Reader
+}
+
+// ErrUnknownBox is returned by Box.Parse for unrecognized box types.
+var ErrUnknownBox = errors.New("heif: unknown box")
+
+type parserFunc func(b *box, br *bufReader) (Box, error)
+
+func boxType(s string) BoxType {
+ if len(s) != 4 {
+ panic("bogus boxType length")
+ }
+ return BoxType{s[0], s[1], s[2], s[3]}
+}
+
+var parsers = map[BoxType]parserFunc{
+ boxType("dinf"): parseDataInformationBox,
+ boxType("dref"): parseDataReferenceBox,
+ boxType("ftyp"): parseFileTypeBox,
+ boxType("hdlr"): parseHandlerBox,
+ boxType("iinf"): parseItemInfoBox,
+ boxType("infe"): parseItemInfoEntry,
+ boxType("iloc"): parseItemLocationBox,
+ boxType("ipco"): parseItemPropertyContainerBox,
+ boxType("ipma"): parseItemPropertyAssociation,
+ boxType("iprp"): parseItemPropertiesBox,
+ boxType("irot"): parseImageRotation,
+ boxType("ispe"): parseImageSpatialExtentsProperty,
+ boxType("meta"): parseMetaBox,
+ boxType("pitm"): parsePrimaryItemBox,
+}
+
+type box struct {
+ size int64 // 0 means unknown, will read to end of file (box container)
+ boxType BoxType
+ body io.Reader
+ parsed Box // if non-nil, the Parsed result
+ slurp []byte // if non-nil, the contents slurped to memory
+}
+
+func (b *box) Size() int64 { return b.size }
+func (b *box) Type() BoxType { return b.boxType }
+
+func (b *box) Body() io.Reader {
+ if b.slurp != nil {
+ return bytes.NewReader(b.slurp)
+ }
+ return b.body
+}
+
+func (b *box) Parse() (Box, error) {
+ if b.parsed != nil {
+ return b.parsed, nil
+ }
+ parser, ok := parsers[b.Type()]
+ if !ok {
+ return nil, ErrUnknownBox
+ }
+ v, err := parser(b, &bufReader{Reader: bufio.NewReader(b.Body())})
+ if err != nil {
+ return nil, err
+ }
+ b.parsed = v
+ return v, nil
+}
+
+type FullBox struct {
+ *box
+ Version uint8
+ Flags uint32 // 24 bits
+}
+
+// ReadBox reads the next box.
+//
+// If the previously read box was not read to completion, ReadBox consumes
+// the rest of its data.
+//
+// At the end, the error is io.EOF.
+func (r *Reader) ReadBox() (Box, error) {
+ if r.noMoreBoxes {
+ return nil, io.EOF
+ }
+ if r.lastBox != nil {
+ if _, err := io.Copy(ioutil.Discard, r.lastBox.Body()); err != nil {
+ return nil, err
+ }
+ }
+ var buf [8]byte
+
+ _, err := io.ReadFull(r.br, buf[:4])
+ if err != nil {
+ return nil, err
+ }
+ box := &box{
+ size: int64(binary.BigEndian.Uint32(buf[:4])),
+ }
+
+ _, err = io.ReadFull(r.br, box.boxType[:]) // 4 more bytes
+ if err != nil {
+ return nil, err
+ }
+
+ // Special cases for size:
+ var remain int64
+ switch box.size {
+ case 1:
+ // 1 means it's actually a 64-bit size, after the type.
+ _, err = io.ReadFull(r.br, buf[:8])
+ if err != nil {
+ return nil, err
+ }
+ box.size = int64(binary.BigEndian.Uint64(buf[:8]))
+ if box.size < 0 {
+ // Go uses int64 for sizes typically, but BMFF uses uint64.
+ // We assume for now that nobody actually uses boxes larger
+ // than int64.
+ return nil, fmt.Errorf("unexpectedly large box %q", box.boxType)
+ }
+ remain = box.size - 2*4 - 8
+ case 0:
+ // 0 means unknown & to read to end of file. No more boxes.
+ r.noMoreBoxes = true
+ default:
+ remain = box.size - 2*4
+ }
+ if remain < 0 {
+ return nil, fmt.Errorf("Box header for %q has size %d, suggesting %d (negative) bytes remain", box.boxType, box.size, remain)
+ }
+ if box.size > 0 {
+ box.body = io.LimitReader(r.br, remain)
+ } else {
+ box.body = r.br
+ }
+ r.lastBox = box
+ return box, nil
+}
+
+// ReadAndParseBox wraps the ReadBox method, ensuring that the read box is of type typ
+// and parses successfully. It returns the parsed box.
+func (r *Reader) ReadAndParseBox(typ BoxType) (Box, error) {
+ box, err := r.ReadBox()
+ if err != nil {
+ return nil, fmt.Errorf("error reading %q box: %v", typ, err)
+ }
+ if box.Type() != typ {
+ return nil, fmt.Errorf("error reading %q box: got box type %q instead", typ, box.Type())
+ }
+ pbox, err := box.Parse()
+ if err != nil {
+ return nil, fmt.Errorf("error parsing read %q box: %v", typ, err)
+ }
+ return pbox, nil
+}
+
+func readFullBox(outer *box, br *bufReader) (fb FullBox, err error) {
+ fb.box = outer
+ // Parse FullBox header.
+ buf, err := br.Peek(4)
+ if err != nil {
+ return FullBox{}, fmt.Errorf("failed to read 4 bytes of FullBox: %v", err)
+ }
+ fb.Version = buf[0]
+ buf[0] = 0
+ fb.Flags = binary.BigEndian.Uint32(buf[:4])
+ br.Discard(4)
+ return fb, nil
+}
+
+type FileTypeBox struct {
+ *box
+ MajorBrand string // 4 bytes
+ MinorVersion string // 4 bytes
+ Compatible []string // all 4 bytes
+}
+
+func parseFileTypeBox(outer *box, br *bufReader) (Box, error) {
+ buf, err := br.Peek(8)
+ if err != nil {
+ return nil, err
+ }
+ ft := &FileTypeBox{
+ box: outer,
+ MajorBrand: string(buf[:4]),
+ MinorVersion: string(buf[4:8]),
+ }
+ br.Discard(8)
+ for {
+ buf, err := br.Peek(4)
+ if err == io.EOF {
+ return ft, nil
+ }
+ if err != nil {
+ return nil, err
+ }
+ ft.Compatible = append(ft.Compatible, string(buf[:4]))
+ br.Discard(4)
+ }
+}
+
+type MetaBox struct {
+ FullBox
+ Children []Box
+}
+
+func parseMetaBox(outer *box, br *bufReader) (Box, error) {
+ fb, err := readFullBox(outer, br)
+ if err != nil {
+ return nil, err
+ }
+ mb := &MetaBox{FullBox: fb}
+ return mb, br.parseAppendBoxes(&mb.Children)
+}
+
+func (br *bufReader) parseAppendBoxes(dst *[]Box) error {
+ if br.err != nil {
+ return br.err
+ }
+ boxr := NewReader(br.Reader)
+ for {
+ inner, err := boxr.ReadBox()
+ if err == io.EOF {
+ return nil
+ }
+ if err != nil {
+ br.err = err
+ return err
+ }
+ slurp, err := ioutil.ReadAll(inner.Body())
+ if err != nil {
+ br.err = err
+ return err
+ }
+ inner.(*box).slurp = slurp
+ *dst = append(*dst, inner)
+ }
+}
+
+// ItemInfoEntry represents an "infe" box.
+//
+// TODO: currently only parses Version 2 boxes.
+type ItemInfoEntry struct {
+ FullBox
+
+ ItemID uint16
+ ProtectionIndex uint16
+ ItemType string // always 4 bytes
+
+ Name string
+
+ // If Type == "mime":
+ ContentType string
+ ContentEncoding string
+
+ // If Type == "uri ":
+ ItemURIType string
+}
+
+func parseItemInfoEntry(outer *box, br *bufReader) (Box, error) {
+ fb, err := readFullBox(outer, br)
+ if err != nil {
+ return nil, err
+ }
+ ie := &ItemInfoEntry{FullBox: fb}
+ if fb.Version != 2 {
+ return nil, fmt.Errorf("TODO: found version %d infe box. Only 2 is supported now.", fb.Version)
+ }
+
+ ie.ItemID, _ = br.readUint16()
+ ie.ProtectionIndex, _ = br.readUint16()
+ if !br.ok() {
+ return nil, br.err
+ }
+ buf, err := br.Peek(4)
+ if err != nil {
+ return nil, err
+ }
+ ie.ItemType = string(buf[:4])
+ ie.Name, _ = br.readString()
+
+ switch ie.ItemType {
+ case "mime":
+ ie.ContentType, _ = br.readString()
+ if br.anyRemain() {
+ ie.ContentEncoding, _ = br.readString()
+ }
+ case "uri ":
+ ie.ItemURIType, _ = br.readString()
+ }
+ if !br.ok() {
+ return nil, br.err
+ }
+ return ie, nil
+}
+
+// ItemInfoBox represents an "iinf" box.
+type ItemInfoBox struct {
+ FullBox
+ Count uint16
+ ItemInfos []*ItemInfoEntry
+}
+
+func parseItemInfoBox(outer *box, br *bufReader) (Box, error) {
+ fb, err := readFullBox(outer, br)
+ if err != nil {
+ return nil, err
+ }
+ ib := &ItemInfoBox{FullBox: fb}
+
+ ib.Count, _ = br.readUint16()
+
+ var itemInfos []Box
+ br.parseAppendBoxes(&itemInfos)
+ if br.ok() {
+ for _, box := range itemInfos {
+ pb, err := box.Parse()
+ if err != nil {
+ return nil, fmt.Errorf("error parsing ItemInfoEntry in ItemInfoBox: %v", err)
+ }
+ if iie, ok := pb.(*ItemInfoEntry); ok {
+ ib.ItemInfos = append(ib.ItemInfos, iie)
+ }
+ }
+ }
+ if !br.ok() {
+ return FullBox{}, br.err
+ }
+ return ib, nil
+}
+
+// bufReader adds some HEIF/BMFF-specific methods around a *bufio.Reader.
+type bufReader struct {
+ *bufio.Reader
+ err error // sticky error
+}
+
+// ok reports whether all previous reads have been error-free.
+func (br *bufReader) ok() bool { return br.err == nil }
+
+func (br *bufReader) anyRemain() bool {
+ if br.err != nil {
+ return false
+ }
+ _, err := br.Peek(1)
+ return err == nil
+}
+
+func (br *bufReader) readUintN(bits uint8) (uint64, error) {
+ if br.err != nil {
+ return 0, br.err
+ }
+ if bits == 0 {
+ return 0, nil
+ }
+ nbyte := bits / 8
+ buf, err := br.Peek(int(nbyte))
+ if err != nil {
+ br.err = err
+ return 0, err
+ }
+ defer br.Discard(int(nbyte))
+ switch bits {
+ case 8:
+ return uint64(buf[0]), nil
+ case 16:
+ return uint64(binary.BigEndian.Uint16(buf[:2])), nil
+ case 32:
+ return uint64(binary.BigEndian.Uint32(buf[:4])), nil
+ case 64:
+ return binary.BigEndian.Uint64(buf[:8]), nil
+ default:
+ br.err = fmt.Errorf("invalid uintn read size")
+ return 0, br.err
+ }
+}
+
+func (br *bufReader) readUint8() (uint8, error) {
+ if br.err != nil {
+ return 0, br.err
+ }
+ v, err := br.ReadByte()
+ if err != nil {
+ br.err = err
+ return 0, err
+ }
+ return v, nil
+}
+
+func (br *bufReader) readUint16() (uint16, error) {
+ if br.err != nil {
+ return 0, br.err
+ }
+ buf, err := br.Peek(2)
+ if err != nil {
+ br.err = err
+ return 0, err
+ }
+ v := binary.BigEndian.Uint16(buf[:2])
+ br.Discard(2)
+ return v, nil
+}
+
+func (br *bufReader) readUint32() (uint32, error) {
+ if br.err != nil {
+ return 0, br.err
+ }
+ buf, err := br.Peek(4)
+ if err != nil {
+ br.err = err
+ return 0, err
+ }
+ v := binary.BigEndian.Uint32(buf[:4])
+ br.Discard(4)
+ return v, nil
+}
+
+func (br *bufReader) readString() (string, error) {
+ if br.err != nil {
+ return "", br.err
+ }
+ s0, err := br.ReadString(0)
+ if err != nil {
+ br.err = err
+ return "", err
+ }
+ s := strings.TrimSuffix(s0, "\x00")
+ if len(s) == len(s0) {
+ err = fmt.Errorf("unexpected non-null terminated string")
+ br.err = err
+ return "", err
+ }
+ return s, nil
+}
+
+// HEIF: ipco
+type ItemPropertyContainerBox struct {
+ *box
+ Properties []Box // of ItemProperty or ItemFullProperty
+}
+
+func parseItemPropertyContainerBox(outer *box, br *bufReader) (Box, error) {
+ ipc := &ItemPropertyContainerBox{box: outer}
+ return ipc, br.parseAppendBoxes(&ipc.Properties)
+}
+
+// HEIF: iprp
+type ItemPropertiesBox struct {
+ *box
+ PropertyContainer *ItemPropertyContainerBox
+ Associations []*ItemPropertyAssociation // at least 1
+}
+
+func parseItemPropertiesBox(outer *box, br *bufReader) (Box, error) {
+ ip := &ItemPropertiesBox{
+ box: outer,
+ }
+
+ var boxes []Box
+ err := br.parseAppendBoxes(&boxes)
+ if err != nil {
+ return nil, err
+ }
+ if len(boxes) < 2 {
+ return nil, fmt.Errorf("expect at least 2 boxes in children; got 0")
+ }
+
+ cb, err := boxes[0].Parse()
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse first box, %q: %v", boxes[0].Type(), err)
+ }
+
+ var ok bool
+ ip.PropertyContainer, ok = cb.(*ItemPropertyContainerBox)
+ if !ok {
+ return nil, fmt.Errorf("unexpected type %T for ItemPropertieBox.PropertyContainer", cb)
+ }
+
+ // Association boxes
+ ip.Associations = make([]*ItemPropertyAssociation, 0, len(boxes)-1)
+ for _, box := range boxes[1:] {
+ boxp, err := box.Parse()
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse association box: %v", err)
+ }
+ ipa, ok := boxp.(*ItemPropertyAssociation)
+ if !ok {
+ return nil, fmt.Errorf("unexpected box %q instead of ItemPropertyAssociation", boxp.Type())
+ }
+ ip.Associations = append(ip.Associations, ipa)
+ }
+ return ip, nil
+}
+
+type ItemPropertyAssociation struct {
+ FullBox
+ EntryCount uint32
+ Entries []ItemPropertyAssociationItem
+}
+
+// not a box
+type ItemProperty struct {
+ Essential bool
+ Index uint16
+}
+
+// not a box
+type ItemPropertyAssociationItem struct {
+ ItemID uint32
+ AssociationsCount int // as declared
+ Associations []ItemProperty // as parsed
+}
+
+func parseItemPropertyAssociation(outer *box, br *bufReader) (Box, error) {
+ fb, err := readFullBox(outer, br)
+ if err != nil {
+ return nil, err
+ }
+ ipa := &ItemPropertyAssociation{FullBox: fb}
+ count, _ := br.readUint32()
+ ipa.EntryCount = count
+
+ for i := uint64(0); i < uint64(count) && br.ok(); i++ {
+ var itemID uint32
+ if fb.Version < 1 {
+ itemID16, _ := br.readUint16()
+ itemID = uint32(itemID16)
+ } else {
+ itemID, _ = br.readUint32()
+ }
+ assocCount, _ := br.readUint8()
+ ipai := ItemPropertyAssociationItem{
+ ItemID: itemID,
+ AssociationsCount: int(assocCount),
+ }
+ for j := 0; j < int(assocCount) && br.ok(); j++ {
+ first, _ := br.readUint8()
+ essential := first&(1<<7) != 0
+ first &^= byte(1 << 7)
+
+ var index uint16
+ if fb.Flags&1 != 0 {
+ second, _ := br.readUint8()
+ index = uint16(first)<<8 | uint16(second)
+ } else {
+ index = uint16(first)
+ }
+ ipai.Associations = append(ipai.Associations, ItemProperty{
+ Essential: essential,
+ Index: index,
+ })
+ }
+ ipa.Entries = append(ipa.Entries, ipai)
+ }
+ if !br.ok() {
+ return nil, br.err
+ }
+ return ipa, nil
+}
+
+type ImageSpatialExtentsProperty struct {
+ FullBox
+ ImageWidth uint32
+ ImageHeight uint32
+}
+
+func parseImageSpatialExtentsProperty(outer *box, br *bufReader) (Box, error) {
+ fb, err := readFullBox(outer, br)
+ if err != nil {
+ return nil, err
+ }
+ w, err := br.readUint32()
+ if err != nil {
+ return nil, err
+ }
+ h, err := br.readUint32()
+ if err != nil {
+ return nil, err
+ }
+ return &ImageSpatialExtentsProperty{
+ FullBox: fb,
+ ImageWidth: w,
+ ImageHeight: h,
+ }, nil
+}
+
+type OffsetLength struct {
+ Offset, Length uint64
+}
+
+// not a box
+type ItemLocationBoxEntry struct {
+ ItemID uint16
+ ConstructionMethod uint8 // actually uint4
+ DataReferenceIndex uint16
+ BaseOffset uint64 // uint32 or uint64, depending on encoding
+ ExtentCount uint16
+ Extents []OffsetLength
+}
+
+// box "iloc"
+type ItemLocationBox struct {
+ FullBox
+
+ offsetSize, lengthSize, baseOffsetSize, indexSize uint8 // actually uint4
+
+ ItemCount uint16
+ Items []ItemLocationBoxEntry
+}
+
+func parseItemLocationBox(outer *box, br *bufReader) (Box, error) {
+ fb, err := readFullBox(outer, br)
+ if err != nil {
+ return nil, err
+ }
+ ilb := &ItemLocationBox{
+ FullBox: fb,
+ }
+ buf, err := br.Peek(4)
+ if err != nil {
+ return nil, err
+ }
+ ilb.offsetSize = buf[0] >> 4
+ ilb.lengthSize = buf[0] & 15
+ ilb.baseOffsetSize = buf[1] >> 4
+ if fb.Version > 0 { // version 1
+ ilb.indexSize = buf[1] & 15
+ }
+
+ ilb.ItemCount = binary.BigEndian.Uint16(buf[2:4])
+ br.Discard(4)
+
+ for i := 0; br.ok() && i < int(ilb.ItemCount); i++ {
+ var ent ItemLocationBoxEntry
+ ent.ItemID, _ = br.readUint16()
+ if fb.Version > 0 { // version 1
+ cmeth, _ := br.readUint16()
+ ent.ConstructionMethod = byte(cmeth & 15)
+ }
+ ent.DataReferenceIndex, _ = br.readUint16()
+ if br.ok() && ilb.baseOffsetSize > 0 {
+ br.Discard(int(ilb.baseOffsetSize) / 8)
+ }
+ ent.ExtentCount, _ = br.readUint16()
+ for j := 0; br.ok() && j < int(ent.ExtentCount); j++ {
+ var ol OffsetLength
+ ol.Offset, _ = br.readUintN(ilb.offsetSize * 8)
+ ol.Length, _ = br.readUintN(ilb.lengthSize * 8)
+ if br.err != nil {
+ return nil, br.err
+ }
+ ent.Extents = append(ent.Extents, ol)
+ }
+ ilb.Items = append(ilb.Items, ent)
+ }
+ if !br.ok() {
+ return nil, br.err
+ }
+ return ilb, nil
+}
+
+// a "hdlr" box.
+type HandlerBox struct {
+ FullBox
+ HandlerType string // always 4 bytes; usually "pict" for iOS Camera images
+ Name string
+}
+
+func parseHandlerBox(gen *box, br *bufReader) (Box, error) {
+ fb, err := readFullBox(gen, br)
+ if err != nil {
+ return nil, err
+ }
+ hb := &HandlerBox{
+ FullBox: fb,
+ }
+ buf, err := br.Peek(20)
+ if err != nil {
+ return nil, err
+ }
+ hb.HandlerType = string(buf[4:8])
+ br.Discard(20)
+
+ hb.Name, _ = br.readString()
+ return hb, br.err
+}
+
+// a "dinf" box
+type DataInformationBox struct {
+ *box
+ Children []Box
+}
+
+func parseDataInformationBox(gen *box, br *bufReader) (Box, error) {
+ dib := &DataInformationBox{box: gen}
+ return dib, br.parseAppendBoxes(&dib.Children)
+}
+
+// a "dref" box.
+type DataReferenceBox struct {
+ FullBox
+ EntryCount uint32
+ Children []Box
+}
+
+func parseDataReferenceBox(gen *box, br *bufReader) (Box, error) {
+ fb, err := readFullBox(gen, br)
+ if err != nil {
+ return nil, err
+ }
+ drb := &DataReferenceBox{FullBox: fb}
+ drb.EntryCount, _ = br.readUint32()
+ return drb, br.parseAppendBoxes(&drb.Children)
+}
+
+// "pitm" box
+type PrimaryItemBox struct {
+ FullBox
+ ItemID uint16
+}
+
+func parsePrimaryItemBox(gen *box, br *bufReader) (Box, error) {
+ fb, err := readFullBox(gen, br)
+ if err != nil {
+ return nil, err
+ }
+ pib := &PrimaryItemBox{FullBox: fb}
+ pib.ItemID, _ = br.readUint16()
+ if !br.ok() {
+ return nil, br.err
+ }
+ return pib, nil
+}
+
+// ImageRotation is a HEIF "irot" rotation property.
+type ImageRotation struct {
+ *box
+ Angle uint8 // 1 means 90 degrees counter-clockwise, 2 means 180 counter-clockwise
+}
+
+func parseImageRotation(gen *box, br *bufReader) (Box, error) {
+ v, err := br.readUint8()
+ if err != nil {
+ return nil, err
+ }
+ return &ImageRotation{box: gen, Angle: v & 3}, nil
+}
diff --git a/vendor/go4.org/media/heif/dumpheif/dumpheif.go b/vendor/go4.org/media/heif/dumpheif/dumpheif.go
new file mode 100644
index 0000000..44c6b8c
--- /dev/null
+++ b/vendor/go4.org/media/heif/dumpheif/dumpheif.go
@@ -0,0 +1,200 @@
+/*
+Copyright 2018 The go4 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.
+*/
+
+// The dumpheif program dumps the structure and metadata of a HEIF file.
+//
+// It exists purely for debugging the go4.org/media/heif and
+// go4.org/media/heif/bmff packages; it makes no backwards
+// compatibility promises.
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "strings"
+
+ "github.com/rwcarlsen/goexif/exif"
+ "github.com/rwcarlsen/goexif/tiff"
+
+ "go4.org/media/heif"
+ "go4.org/media/heif/bmff"
+)
+
+var (
+ exifItemID uint16
+ exifLoc bmff.ItemLocationBoxEntry
+)
+
+func main() {
+ flag.Parse()
+ if flag.NArg() != 1 {
+ fmt.Fprintf(os.Stderr, "usage: dumpheif \n")
+ os.Exit(1)
+ }
+ f, err := os.Open(flag.Arg(0))
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+
+ hf := heif.Open(f)
+
+ it, err := hf.PrimaryItem()
+ if err != nil {
+ log.Fatalf("PrimaryItem: %v", err)
+ }
+ fmt.Printf("primary item: %v\n", it.ID)
+
+ width, height, ok := it.SpatialExtents()
+ if ok {
+ fmt.Printf("spatial extents: %d x %d\n", width, height)
+ }
+ fmt.Printf("properties:\n")
+ for _, prop := range it.Properties {
+ fmt.Printf("\t%q: %#v\n", prop.Type(), prop)
+ }
+ if len(it.Properties) == 0 {
+ fmt.Printf("\t(no properties)\n")
+ }
+
+ if ex, err := hf.EXIF(); err == nil {
+ fmt.Printf("EXIF dump:\n")
+ ex, err := exif.Decode(bytes.NewReader(ex))
+ if err != nil {
+ log.Fatalf("EXIF decode: %v", err)
+ }
+ ex.Walk(exifWalkFunc(func(name exif.FieldName, tag *tiff.Tag) error {
+ fmt.Printf("\t%v = %v\n", name, tag)
+ return nil
+ }))
+ fmt.Printf("\n")
+ }
+
+ fmt.Printf("BMFF boxes:\n")
+ r := bmff.NewReader(f)
+ for {
+ box, err := r.ReadBox()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ log.Fatalf("ReadBox: %v", err)
+ }
+ dumpBox(box, 0)
+ }
+
+}
+
+type exifWalkFunc func(exif.FieldName, *tiff.Tag) error
+
+func (f exifWalkFunc) Walk(name exif.FieldName, tag *tiff.Tag) error {
+ return f(name, tag)
+}
+
+func dumpBox(box bmff.Box, depth int) {
+ indent := strings.Repeat(" ", depth)
+ fmt.Printf("%sBox: type %q, size %v\n", indent, box.Type(), box.Size())
+
+ box2, err := box.Parse()
+ if err == bmff.ErrUnknownBox {
+ slurp, err := ioutil.ReadAll(box.Body())
+ if err != nil {
+ log.Fatalf("%sreading body: %v", indent, err)
+ }
+ if len(slurp) < 5000 {
+ fmt.Printf("%s- contents: %q\n", indent, slurp)
+ } else {
+ fmt.Printf("%s- contents: (... %d bytes, starting with %q ...)\n", indent, len(slurp), slurp[:100])
+ }
+ return
+ }
+ if err != nil {
+ slurp, _ := ioutil.ReadAll(box.Body())
+ log.Fatalf("Parse box type %q: %v; slurp: %q", box.Type(), err, slurp)
+ }
+
+ switch v := box2.(type) {
+ case *bmff.FileTypeBox, *bmff.HandlerBox, *bmff.PrimaryItemBox:
+ fmt.Printf("%s- %T: %+v\n", indent, v, v)
+ case *bmff.MetaBox:
+ fmt.Printf("%s- %T, %d children:\n", indent, v, len(v.Children))
+ for _, child := range v.Children {
+ dumpBox(child, depth+1)
+ }
+ case *bmff.ItemInfoBox:
+ //slurp, _ := ioutil.ReadAll(box.Body())
+ //fmt.Printf("%s- %T raw: %q\n", indent, v, slurp)
+ fmt.Printf("%s- %T, %d children (%d in slice):\n", indent, v, v.Count, len(v.ItemInfos))
+ for _, child := range v.ItemInfos {
+ dumpBox(child, depth+1)
+ }
+ case *bmff.ItemInfoEntry:
+ fmt.Printf("%s- %T, %+v\n", indent, v, v)
+ if v.ItemType == "Exif" {
+ exifItemID = v.ItemID
+ }
+ case *bmff.ItemPropertiesBox:
+ fmt.Printf("%s- %T\n", indent, v)
+ if v.PropertyContainer != nil {
+ dumpBox(v.PropertyContainer, depth+1)
+ }
+ for _, child := range v.Associations {
+ dumpBox(child, depth+1)
+ }
+ case *bmff.ItemPropertyAssociation:
+ fmt.Printf("%s- %T: %d declared entries, %d parsed:\n", indent, v, v.EntryCount, len(v.Entries))
+ for _, ai := range v.Entries {
+ fmt.Printf("%s for Item ID %d, %d associations declared, %d parsed:\n", indent, ai.ItemID, ai.AssociationsCount, len(ai.Associations))
+ for _, ass := range ai.Associations {
+ fmt.Printf("%s index: %d, essential: %v\n", indent, ass.Index, ass.Essential)
+ }
+ }
+ case *bmff.DataInformationBox:
+ fmt.Printf("%s- %T\n", indent, v)
+ for _, child := range v.Children {
+ dumpBox(child, depth+1)
+ }
+ case *bmff.DataReferenceBox:
+ fmt.Printf("%s- %T\n", indent, v)
+ for _, child := range v.Children {
+ dumpBox(child, depth+1)
+ }
+ case *bmff.ItemPropertyContainerBox:
+ fmt.Printf("%s- %T\n", indent, v)
+ for _, child := range v.Properties {
+ dumpBox(child, depth+1)
+ }
+ case *bmff.ItemLocationBox:
+ fmt.Printf("%s- %T: %d items declared, %d parsed:\n", indent, v, v.ItemCount, len(v.Items))
+ for _, lbe := range v.Items {
+ fmt.Printf("%s %+v\n", indent, lbe)
+ if exifItemID != 0 && lbe.ItemID == exifItemID {
+ exifLoc = lbe
+ }
+ }
+
+ case *bmff.ImageSpatialExtentsProperty:
+ fmt.Printf("%s- %T dimensions: %d x %d\n", indent, v, v.ImageWidth, v.ImageHeight)
+ default:
+ fmt.Printf("%s- gotype: %T\n", indent, box2)
+ }
+
+}
diff --git a/vendor/go4.org/media/heif/heif.go b/vendor/go4.org/media/heif/heif.go
new file mode 100644
index 0000000..cb6da04
--- /dev/null
+++ b/vendor/go4.org/media/heif/heif.go
@@ -0,0 +1,292 @@
+/*
+Copyright 2018 The go4 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 heif reads HEIF containers, as found in Apple HEIC/HEVC images.
+// This package does not decode images; it only reads the metadata.
+//
+// This package is a work in progress and makes no API compatibility
+// promises.
+package heif
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "log"
+
+ "go4.org/media/heif/bmff"
+)
+
+// File represents a HEIF file.
+//
+// Methods on File should not be called concurrently.
+type File struct {
+ ra io.ReaderAt
+ primary *Item
+
+ // Populated lazily, by getMeta:
+ metaErr error
+ meta *BoxMeta
+}
+
+// BoxMeta contains the low-level BMFF metadata boxes.
+type BoxMeta struct {
+ FileType *bmff.FileTypeBox
+ Handler *bmff.HandlerBox
+ PrimaryItem *bmff.PrimaryItemBox
+ ItemInfo *bmff.ItemInfoBox
+ Properties *bmff.ItemPropertiesBox
+ ItemLocation *bmff.ItemLocationBox
+}
+
+// EXIFItemID returns the item ID of the EXIF part, or 0 if not found.
+func (m *BoxMeta) EXIFItemID() uint32 {
+ if m.ItemInfo == nil {
+ return 0
+ }
+ for _, ife := range m.ItemInfo.ItemInfos {
+ if ife.ItemType == "Exif" {
+ return uint32(ife.ItemID)
+ }
+ }
+ return 0
+}
+
+// Item represents an item in a HEIF file.
+type Item struct {
+ f *File
+
+ ID uint32
+ Info *bmff.ItemInfoEntry
+ Location *bmff.ItemLocationBoxEntry // location in file
+ Properties []bmff.Box
+}
+
+// SpatialExtents returns the item's spatial extents property values, if present,
+// not correcting from any camera rotation metadata.
+func (it *Item) SpatialExtents() (width, height int, ok bool) {
+ for _, p := range it.Properties {
+ if p, ok := p.(*bmff.ImageSpatialExtentsProperty); ok {
+ return int(p.ImageWidth), int(p.ImageHeight), true
+ }
+ }
+ return
+}
+
+// Rotations returns the number of 90 degree rotations counter-clockwise that this
+// image should be rendered at, in the range [0,3].
+func (it *Item) Rotations() int {
+ for _, p := range it.Properties {
+ if p, ok := p.(*bmff.ImageRotation); ok {
+ return int(p.Angle)
+ }
+ }
+ return 0
+}
+
+// VisualDimensions returns the item's width and height after correcting
+// for any rotations.
+func (it *Item) VisualDimensions() (width, height int, ok bool) {
+ width, height, ok = it.SpatialExtents()
+ for i := 0; i < it.Rotations(); i++ {
+ width, height = height, width
+ }
+ return
+}
+
+// TODO: add HEIF imir (mirroring) accessor, like Image.SpatialExtents.
+
+// Open returns a handle to access a HEIF file.
+func Open(f io.ReaderAt) *File {
+ return &File{ra: f}
+}
+
+// ErrNoEXIF is returned by File.EXIF when a file does not contain an EXIF item.
+var ErrNoEXIF = errors.New("heif: no EXIF found")
+
+// ErrUnknownItem is returned by File.ItemByID for unknown items.
+var ErrUnknownItem = errors.New("heif: unknown item")
+
+// EXIF returns the raw EXIF data from the file.
+// The error is ErrNoEXIF if the file did not contain EXIF.
+//
+// The raw EXIF data can be parsed by the
+// github.com/rwcarlsen/goexif/exif package's Decode function.
+func (f *File) EXIF() ([]byte, error) {
+ meta, err := f.getMeta()
+ if err != nil {
+ return nil, err
+ }
+ exifID := meta.EXIFItemID()
+ if exifID == 0 {
+ return nil, ErrNoEXIF
+ }
+ it, err := f.ItemByID(exifID)
+ if err != nil {
+ return nil, err
+ }
+ if it.Location == nil {
+ return nil, errors.New("heif: file said it contained EXIF, but didn't say where")
+ }
+ if n := len(it.Location.Extents); n != 1 {
+ return nil, fmt.Errorf("heif: expected 1 EXIF section, saw %d", n)
+ }
+ offLen := it.Location.Extents[0]
+ const maxSize = 20 << 10 // 20MB of EXIF seems excessive; cap it for sanity
+ if offLen.Length > maxSize {
+ return nil, fmt.Errorf("heif: declared EXIF size %d exceeds threshold of %d bytes", offLen.Length, maxSize)
+ }
+ buf := make([]byte, offLen.Length-4)
+ n, err := f.ra.ReadAt(buf, int64(offLen.Offset)+4) // TODO: why 4? did I miss something?
+ if err != nil {
+ log.Printf("Read %d bytes + %v: %q", n, err, buf)
+ return nil, err
+ }
+ return buf, nil
+}
+
+func (f *File) setMetaErr(err error) error {
+ if f.metaErr != nil {
+ f.metaErr = err
+ }
+ return err
+}
+
+func (f *File) getMeta() (*BoxMeta, error) {
+ if f.metaErr != nil {
+ return nil, f.metaErr
+ }
+ if f.meta != nil {
+ return f.meta, nil
+ }
+ const assumedMaxSize = 5 << 40 // arbitrary
+ sr := io.NewSectionReader(f.ra, 0, assumedMaxSize)
+ bmr := bmff.NewReader(sr)
+
+ meta := &BoxMeta{}
+
+ pbox, err := bmr.ReadAndParseBox(bmff.TypeFtyp)
+ if err != nil {
+ return nil, f.setMetaErr(err)
+ }
+ meta.FileType = pbox.(*bmff.FileTypeBox)
+
+ pbox, err = bmr.ReadAndParseBox(bmff.TypeMeta)
+ if err != nil {
+ return nil, f.setMetaErr(err)
+ }
+ metabox := pbox.(*bmff.MetaBox)
+
+ for _, box := range metabox.Children {
+ boxp, err := box.Parse()
+ if err == bmff.ErrUnknownBox {
+ continue
+ }
+ if err != nil {
+ return nil, f.setMetaErr(err)
+ }
+ switch v := boxp.(type) {
+ case *bmff.HandlerBox:
+ meta.Handler = v
+ case *bmff.PrimaryItemBox:
+ meta.PrimaryItem = v
+ case *bmff.ItemInfoBox:
+ meta.ItemInfo = v
+ case *bmff.ItemPropertiesBox:
+ meta.Properties = v
+ case *bmff.ItemLocationBox:
+ meta.ItemLocation = v
+ }
+ }
+
+ f.meta = meta
+ return f.meta, nil
+}
+
+// PrimaryItem returns the HEIF file's primary item.
+func (f *File) PrimaryItem() (*Item, error) {
+ meta, err := f.getMeta()
+ if err != nil {
+ return nil, err
+ }
+ if meta.PrimaryItem == nil {
+ return nil, errors.New("heif: HEIF file lacks primary item box")
+ }
+ return f.ItemByID(uint32(meta.PrimaryItem.ItemID))
+}
+
+// ItemByID by returns the file's Item of a given ID.
+// If the ID is known, the returned error is ErrUnknownItem.
+func (f *File) ItemByID(id uint32) (*Item, error) {
+ meta, err := f.getMeta()
+ if err != nil {
+ return nil, err
+ }
+ it := &Item{
+ f: f,
+ ID: id,
+ }
+ if meta.ItemLocation != nil {
+ for _, ilbe := range meta.ItemLocation.Items {
+ if uint32(ilbe.ItemID) == id {
+ shallowCopy := ilbe
+ it.Location = &shallowCopy
+ }
+ }
+ }
+ if meta.ItemInfo != nil {
+ for _, iie := range meta.ItemInfo.ItemInfos {
+ if uint32(iie.ItemID) == id {
+ it.Info = iie
+ }
+ }
+ }
+ if it.Info == nil {
+ return nil, ErrUnknownItem
+ }
+ if meta.Properties != nil {
+ allProps := meta.Properties.PropertyContainer.Properties
+ for _, ipa := range meta.Properties.Associations {
+ // TODO: I've never seen a file with more than
+ // top-level ItemPropertyAssociation box, but
+ // apparently they can exist with different
+ // versions/flags. For now we just merge them
+ // all together, but that's not really right.
+ // So for now, just bail once a previous loop
+ // found anything.
+ if len(it.Properties) > 0 {
+ break
+ }
+
+ for _, ipai := range ipa.Entries {
+ if ipai.ItemID != id {
+ continue
+ }
+ for _, ass := range ipai.Associations {
+ if ass.Index != 0 && int(ass.Index) <= len(allProps) {
+ box := allProps[ass.Index-1]
+ boxp, err := box.Parse()
+ if err == nil {
+ box = boxp
+ }
+ it.Properties = append(it.Properties, box)
+ }
+ }
+ }
+ }
+ }
+ return it, nil
+}
diff --git a/vendor/go4.org/media/heif/heif_test.go b/vendor/go4.org/media/heif/heif_test.go
new file mode 100644
index 0000000..61ba7fc
--- /dev/null
+++ b/vendor/go4.org/media/heif/heif_test.go
@@ -0,0 +1,113 @@
+package heif
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "testing"
+
+ "github.com/rwcarlsen/goexif/exif"
+ "github.com/rwcarlsen/goexif/tiff"
+)
+
+func TestAll(t *testing.T) {
+ f, err := os.Open("testdata/park.heic")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer f.Close()
+ h := Open(f)
+
+ // meta
+ _, err = h.getMeta()
+ if err != nil {
+ t.Fatalf("getMeta: %v", err)
+ }
+
+ it, err := h.PrimaryItem()
+ if err != nil {
+ t.Fatalf("PrimaryItem: %v", err)
+ }
+ if want := uint32(49); it.ID != want {
+ t.Errorf("PrimaryIem ID = %v; want %v", it.ID, want)
+ }
+ if it.Location == nil {
+ t.Errorf("Item.Location is nil")
+ }
+ if it.Info == nil {
+ t.Errorf("Item.Info is nil")
+ }
+ if len(it.Properties) == 0 {
+ t.Errorf("Item.Properties is empty")
+ }
+ for _, prop := range it.Properties {
+ t.Logf(" property: %q, %#v", prop.Type(), prop)
+ }
+ if w, h, ok := it.SpatialExtents(); !ok || w == 0 || h == 0 {
+ t.Errorf("no spatial extents found")
+ } else {
+ t.Logf("dimensions: %v x %v", w, h)
+ }
+
+ // exif
+ exbuf, err := h.EXIF()
+ if err != nil {
+ t.Errorf("EXIF: %v", err)
+ } else {
+ const magic = "Exif\x00\x00"
+ if !bytes.HasPrefix(exbuf, []byte(magic)) {
+ t.Errorf("Exif buffer doesn't start with %q: got %q", magic, exbuf)
+ }
+ x, err := exif.Decode(bytes.NewReader(exbuf))
+ if err != nil {
+ t.Fatalf("EXIF decode: %v", err)
+ }
+ got := map[string]string{}
+ if err := x.Walk(walkFunc(func(name exif.FieldName, tag *tiff.Tag) error {
+ got[fmt.Sprint(name)] = fmt.Sprint(tag)
+ return nil
+ })); err != nil {
+ t.Fatalf("EXIF walk: %v", err)
+ }
+ if g, w := len(got), 56; g < w {
+ t.Errorf("saw %v EXIF tags; want at least %v", g, w)
+ }
+ if g, w := got["GPSLongitude"], `["122/1","21/1","3776/100"]`; g != w {
+ t.Errorf("GPSLongitude = %#q; want %#q", g, w)
+ }
+
+ }
+}
+
+func TestRotations(t *testing.T) {
+ f, err := os.Open("testdata/rotate.heic")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer f.Close()
+ h := Open(f)
+ it, err := h.PrimaryItem()
+ if err != nil {
+ t.Fatalf("PrimaryItem: %v", err)
+ }
+ if r := it.Rotations(); r != 3 {
+ t.Errorf("Rotations = %v; want %v", r, 3)
+ }
+ sw, sh, ok := it.SpatialExtents()
+ if !ok {
+ t.Fatalf("expected spatial extents")
+ }
+ vw, vh, ok := it.VisualDimensions()
+ if !ok {
+ t.Fatalf("expected visual dimensions")
+ }
+ if vw != sh || vh != sw {
+ t.Errorf("visual dimensions = %v, %v; want %v, %v", vw, vh, sh, sw)
+ }
+}
+
+type walkFunc func(exif.FieldName, *tiff.Tag) error
+
+func (f walkFunc) Walk(name exif.FieldName, tag *tiff.Tag) error {
+ return f(name, tag)
+}
diff --git a/vendor/go4.org/media/heif/testdata/park.heic b/vendor/go4.org/media/heif/testdata/park.heic
new file mode 100644
index 0000000000000000000000000000000000000000..7e182de593e50a8b6e5f1c36b89e122ea06af282
GIT binary patch
literal 50000
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
Y^6Yampw9x~w7{FHKsGydNhbn!4eFpl2><{9
literal 0
HcmV?d00001
diff --git a/vendor/go4.org/media/heif/testdata/rotate.heic b/vendor/go4.org/media/heif/testdata/rotate.heic
new file mode 100644
index 0000000000000000000000000000000000000000..b65c5704b3e942e333a0de7430ece1cb7cd7ae25
GIT binary patch
literal 4096
zcmeHKYitx%7(KJwcDsFT-z}xU_62>vc$!o!