From 0075ef607f498da0de559843298f11ee5c8c6a56 Mon Sep 17 00:00:00 2001 From: Will Date: Sun, 22 May 2016 22:16:37 +0900 Subject: [PATCH] initial import --- FORMAT.md | 90 + LICENSE | 621 ++ NOTICE | 268 + README.md | 144 + archive.go | 379 + archive/archive.go | 76 + archive/archive_test.go | 170 + archive/reader.go | 47 + archive/verify.go | 22 + archive/writer.go | 63 + archive_test.go | 398 + args.go | 296 + binary/binary.go | 140 + binary/binary_test.go | 168 + bytesize.go | 43 + create.go | 123 + extract.go | 90 + filter.go | 42 + key.go | 170 + key_test.go | 152 + keygen.go | 20 + list.go | 72 + main.go | 73 + vendor/github.com/codahale/sss/LICENSE | 21 + vendor/github.com/codahale/sss/README.md | 11 + vendor/github.com/codahale/sss/gf256.go | 81 + vendor/github.com/codahale/sss/gf256_test.go | 35 + vendor/github.com/codahale/sss/polynomial.go | 67 + .../codahale/sss/polynomial_test.go | 89 + vendor/github.com/codahale/sss/sss.go | 102 + vendor/github.com/codahale/sss/sss_test.go | 32 + vendor/github.com/dchest/blake2b/README | 23 + vendor/github.com/dchest/blake2b/blake2b.go | 299 + .../github.com/dchest/blake2b/blake2b_test.go | 625 ++ vendor/github.com/dchest/blake2b/block.go | 1420 +++ vendor/github.com/jessevdk/go-flags/LICENSE | 26 + vendor/github.com/jessevdk/go-flags/README.md | 135 + vendor/github.com/jessevdk/go-flags/arg.go | 24 + .../github.com/jessevdk/go-flags/arg_test.go | 133 + .../jessevdk/go-flags/assert_test.go | 177 + .../jessevdk/go-flags/check_crosscompile.sh | 16 + .../github.com/jessevdk/go-flags/closest.go | 59 + .../github.com/jessevdk/go-flags/command.go | 441 + .../jessevdk/go-flags/command_test.go | 544 ++ .../jessevdk/go-flags/completion.go | 300 + .../jessevdk/go-flags/completion_test.go | 294 + .../github.com/jessevdk/go-flags/convert.go | 341 + .../jessevdk/go-flags/convert_test.go | 159 + vendor/github.com/jessevdk/go-flags/error.go | 134 + .../jessevdk/go-flags/example_test.go | 110 + vendor/github.com/jessevdk/go-flags/flags.go | 256 + vendor/github.com/jessevdk/go-flags/group.go | 385 + .../jessevdk/go-flags/group_test.go | 255 + vendor/github.com/jessevdk/go-flags/help.go | 473 + .../github.com/jessevdk/go-flags/help_test.go | 462 + vendor/github.com/jessevdk/go-flags/ini.go | 593 ++ .../github.com/jessevdk/go-flags/ini_test.go | 950 ++ .../github.com/jessevdk/go-flags/long_test.go | 85 + vendor/github.com/jessevdk/go-flags/man.go | 194 + .../jessevdk/go-flags/marshal_test.go | 97 + .../github.com/jessevdk/go-flags/multitag.go | 140 + vendor/github.com/jessevdk/go-flags/option.go | 434 + .../jessevdk/go-flags/options_test.go | 45 + .../jessevdk/go-flags/optstyle_other.go | 67 + .../jessevdk/go-flags/optstyle_windows.go | 106 + vendor/github.com/jessevdk/go-flags/parser.go | 652 ++ .../jessevdk/go-flags/parser_test.go | 500 + .../jessevdk/go-flags/pointer_test.go | 81 + .../jessevdk/go-flags/short_test.go | 194 + .../github.com/jessevdk/go-flags/tag_test.go | 38 + .../github.com/jessevdk/go-flags/termsize.go | 28 + .../jessevdk/go-flags/termsize_linux.go | 7 + .../jessevdk/go-flags/termsize_nosysioctl.go | 7 + .../jessevdk/go-flags/termsize_other.go | 7 + .../jessevdk/go-flags/termsize_unix.go | 7 + .../jessevdk/go-flags/unknown_test.go | 66 + vendor/github.com/klauspost/compress/LICENSE | 27 + .../github.com/klauspost/compress/README.md | 330 + .../klauspost/compress/flate/asm_test.go | 193 + .../klauspost/compress/flate/copy.go | 32 + .../klauspost/compress/flate/copy_test.go | 54 + .../klauspost/compress/flate/crc32_amd64.go | 39 + .../klauspost/compress/flate/crc32_amd64.s | 219 + .../klauspost/compress/flate/crc32_noasm.go | 34 + .../klauspost/compress/flate/deflate.go | 1357 +++ .../klauspost/compress/flate/deflate_test.go | 632 ++ .../klauspost/compress/flate/fixedhuff.go | 78 + .../klauspost/compress/flate/flate_test.go | 260 + .../klauspost/compress/flate/gen.go | 265 + .../compress/flate/huffman_bit_writer.go | 717 ++ .../compress/flate/huffman_bit_writer_test.go | 368 + .../klauspost/compress/flate/huffman_code.go | 363 + .../klauspost/compress/flate/inflate.go | 846 ++ .../klauspost/compress/flate/inflate_test.go | 225 + .../klauspost/compress/flate/reader_test.go | 97 + .../klauspost/compress/flate/reverse_bits.go | 48 + .../klauspost/compress/flate/snappy.go | 558 ++ .../testdata/huffman-null-max.dyn.expect | Bin 0 -> 78 bytes .../huffman-null-max.dyn.expect-noinput | Bin 0 -> 78 bytes .../flate/testdata/huffman-null-max.golden | Bin 0 -> 8204 bytes .../flate/testdata/huffman-null-max.in | Bin 0 -> 65535 bytes .../flate/testdata/huffman-null-max.wb.expect | Bin 0 -> 78 bytes .../huffman-null-max.wb.expect-noinput | Bin 0 -> 78 bytes .../flate/testdata/huffman-pi.dyn.expect | Bin 0 -> 1696 bytes .../testdata/huffman-pi.dyn.expect-noinput | Bin 0 -> 1696 bytes .../compress/flate/testdata/huffman-pi.golden | Bin 0 -> 1606 bytes .../compress/flate/testdata/huffman-pi.in | 1 + .../flate/testdata/huffman-pi.wb.expect | Bin 0 -> 1696 bytes .../testdata/huffman-pi.wb.expect-noinput | Bin 0 -> 1696 bytes .../flate/testdata/huffman-rand-1k.dyn.expect | Bin 0 -> 1054 bytes .../huffman-rand-1k.dyn.expect-noinput | Bin 0 -> 1054 bytes .../flate/testdata/huffman-rand-1k.golden | Bin 0 -> 1005 bytes .../flate/testdata/huffman-rand-1k.in | Bin 0 -> 1000 bytes .../flate/testdata/huffman-rand-1k.wb.expect | Bin 0 -> 1005 bytes .../huffman-rand-1k.wb.expect-noinput | Bin 0 -> 1054 bytes .../testdata/huffman-rand-limit.dyn.expect | Bin 0 -> 229 bytes .../huffman-rand-limit.dyn.expect-noinput | Bin 0 -> 229 bytes .../flate/testdata/huffman-rand-limit.golden | Bin 0 -> 252 bytes .../flate/testdata/huffman-rand-limit.in | 4 + .../testdata/huffman-rand-limit.wb.expect | Bin 0 -> 186 bytes .../huffman-rand-limit.wb.expect-noinput | Bin 0 -> 186 bytes .../flate/testdata/huffman-rand-max.golden | Bin 0 -> 65540 bytes .../flate/testdata/huffman-rand-max.in | Bin 0 -> 65535 bytes .../flate/testdata/huffman-shifts.dyn.expect | Bin 0 -> 32 bytes .../huffman-shifts.dyn.expect-noinput | Bin 0 -> 32 bytes .../flate/testdata/huffman-shifts.golden | Bin 0 -> 1812 bytes .../compress/flate/testdata/huffman-shifts.in | 2 + .../flate/testdata/huffman-shifts.wb.expect | Bin 0 -> 32 bytes .../testdata/huffman-shifts.wb.expect-noinput | Bin 0 -> 32 bytes .../testdata/huffman-text-shift.dyn.expect | Bin 0 -> 231 bytes .../huffman-text-shift.dyn.expect-noinput | Bin 0 -> 231 bytes .../flate/testdata/huffman-text-shift.golden | Bin 0 -> 231 bytes .../flate/testdata/huffman-text-shift.in | 14 + .../testdata/huffman-text-shift.wb.expect | Bin 0 -> 231 bytes .../huffman-text-shift.wb.expect-noinput | Bin 0 -> 231 bytes .../flate/testdata/huffman-text.dyn.expect | 1 + .../testdata/huffman-text.dyn.expect-noinput | 1 + .../flate/testdata/huffman-text.golden | 3 + .../compress/flate/testdata/huffman-text.in | 13 + .../flate/testdata/huffman-text.wb.expect | 1 + .../testdata/huffman-text.wb.expect-noinput | 1 + .../flate/testdata/huffman-zero.dyn.expect | Bin 0 -> 17 bytes .../testdata/huffman-zero.dyn.expect-noinput | Bin 0 -> 17 bytes .../flate/testdata/huffman-zero.golden | Bin 0 -> 51 bytes .../compress/flate/testdata/huffman-zero.in | 1 + .../flate/testdata/huffman-zero.wb.expect | Bin 0 -> 6 bytes .../testdata/huffman-zero.wb.expect-noinput | Bin 0 -> 6 bytes .../null-long-match.dyn.expect-noinput | Bin 0 -> 206 bytes .../null-long-match.wb.expect-noinput | Bin 0 -> 206 bytes .../klauspost/compress/flate/token.go | 105 + .../klauspost/compress/flate/writer_test.go | 70 + .../klauspost/compress/gzip/gunzip.go | 342 + .../klauspost/compress/gzip/gunzip_test.go | 571 ++ .../klauspost/compress/gzip/gzip.go | 274 + .../klauspost/compress/gzip/gzip_test.go | 519 + .../compress/gzip/testdata/issue6550.gz | Bin 0 -> 65536 bytes .../compress/gzip/testdata/test.json | 5902 ++++++++++++ .../testdata/Mark.Twain-Tom.Sawyer.txt | 8472 +++++++++++++++++ .../klauspost/compress/testdata/e.txt | 1 + .../klauspost/compress/testdata/pi.txt | 1 + vendor/github.com/klauspost/cpuid/LICENSE | 22 + vendor/github.com/klauspost/cpuid/README.md | 145 + vendor/github.com/klauspost/cpuid/cpuid.go | 1022 ++ vendor/github.com/klauspost/cpuid/cpuid_386.s | 42 + .../github.com/klauspost/cpuid/cpuid_amd64.s | 42 + .../github.com/klauspost/cpuid/cpuid_test.go | 727 ++ .../klauspost/cpuid/detect_intel.go | 17 + .../github.com/klauspost/cpuid/detect_ref.go | 23 + vendor/github.com/klauspost/cpuid/generate.go | 3 + .../klauspost/cpuid/mockcpu_test.go | 209 + .../github.com/klauspost/cpuid/private-gen.go | 476 + .../klauspost/cpuid/private/README.md | 6 + .../klauspost/cpuid/private/cpuid.go | 987 ++ .../klauspost/cpuid/private/cpuid_386.s | 42 + .../klauspost/cpuid/private/cpuid_amd64.s | 42 + .../cpuid/private/cpuid_detect_intel.go | 17 + .../cpuid/private/cpuid_detect_ref.go | 23 + .../klauspost/cpuid/private/cpuid_test.go | 719 ++ .../klauspost/cpuid/testdata/cpuid_data.zip | Bin 0 -> 201312 bytes .../klauspost/cpuid/testdata/getall.go | 77 + vendor/github.com/klauspost/crc32/LICENSE | 28 + vendor/github.com/klauspost/crc32/README.md | 84 + vendor/github.com/klauspost/crc32/crc32.go | 186 + .../github.com/klauspost/crc32/crc32_amd64.go | 62 + .../github.com/klauspost/crc32/crc32_amd64.s | 237 + .../klauspost/crc32/crc32_amd64p32.go | 40 + .../klauspost/crc32/crc32_amd64p32.s | 67 + .../klauspost/crc32/crc32_generic.go | 29 + .../github.com/klauspost/crc32/crc32_test.go | 170 + .../klauspost/crc32/example_test.go | 28 + vendor/github.com/magical/argon2/README.md | 21 + vendor/github.com/magical/argon2/api.go | 67 + vendor/github.com/magical/argon2/api_test.go | 50 + vendor/github.com/magical/argon2/argon2.go | 302 + .../github.com/magical/argon2/argon2_test.go | 137 + vendor/github.com/magical/argon2/round.go | 443 + vendor/github.com/magical/argon2/round.py | 54 + vendor/github.com/wg/ecies/aead.go | 106 + vendor/github.com/wg/ecies/aead_test.go | 69 + vendor/github.com/wg/ecies/box.go | 90 + vendor/github.com/wg/ecies/box_test.go | 124 + .../chacha20poly1305/chacha20poly1305.go | 90 + .../chacha20poly1305/chacha20poly1305_test.go | 114 + vendor/github.com/wg/ecies/cipher.go | 13 + vendor/github.com/wg/ecies/doc.go | 14 + vendor/github.com/wg/ecies/ecdh.go | 43 + vendor/github.com/wg/ecies/ecdh_test.go | 157 + .../vendor/github.com/dchest/blake2b/README | 23 + .../github.com/dchest/blake2b/blake2b.go | 299 + .../github.com/dchest/blake2b/blake2b_test.go | 625 ++ .../vendor/github.com/dchest/blake2b/block.go | 1420 +++ .../ecies/vendor/golang.org/x/crypto/AUTHORS | 3 + .../vendor/golang.org/x/crypto/CONTRIBUTORS | 3 + .../ecies/vendor/golang.org/x/crypto/LICENSE | 27 + .../ecies/vendor/golang.org/x/crypto/PATENTS | 22 + .../ecies/vendor/golang.org/x/crypto/README | 3 + .../x/crypto/curve25519/const_amd64.s | 20 + .../x/crypto/curve25519/cswap_amd64.s | 88 + .../x/crypto/curve25519/curve25519.go | 841 ++ .../x/crypto/curve25519/curve25519_test.go | 29 + .../golang.org/x/crypto/curve25519/doc.go | 23 + .../x/crypto/curve25519/freeze_amd64.s | 94 + .../x/crypto/curve25519/ladderstep_amd64.s | 1398 +++ .../x/crypto/curve25519/mont25519_amd64.go | 240 + .../x/crypto/curve25519/mul_amd64.s | 191 + .../x/crypto/curve25519/square_amd64.s | 153 + .../schwanenlied.me/yawning/chacha20/LICENSE | 122 + .../yawning/chacha20/README.md | 14 + .../yawning/chacha20/chacha20.go | 273 + .../yawning/chacha20/chacha20_amd64.go | 95 + .../yawning/chacha20/chacha20_amd64.py | 1303 +++ .../yawning/chacha20/chacha20_amd64.s | 1187 +++ .../yawning/chacha20/chacha20_ref.go | 392 + .../yawning/chacha20/chacha20_test.go | 523 + .../yawning/poly1305/README.md | 17 + .../yawning/poly1305/poly1305.go | 207 + .../yawning/poly1305/poly1305_32.go | 236 + .../yawning/poly1305/poly1305_test.go | 585 ++ .../schwanenlied.me/yawning/x448/LICENSE.txt | 23 + .../schwanenlied.me/yawning/x448/README.md | 13 + .../schwanenlied.me/yawning/x448/x448.go | 115 + .../schwanenlied.me/yawning/x448/x448_ref.go | 779 ++ .../schwanenlied.me/yawning/x448/x448_test.go | 265 + .../xchacha20poly1305/xchacha20poly1305.go | 75 + .../xchacha20poly1305_test.go | 65 + vendor/golang.org/x/crypto/AUTHORS | 3 + vendor/golang.org/x/crypto/CONTRIBUTORS | 3 + vendor/golang.org/x/crypto/LICENSE | 27 + vendor/golang.org/x/crypto/PATENTS | 22 + vendor/golang.org/x/crypto/README | 3 + .../golang.org/x/crypto/ssh/terminal/util.go | 128 + .../x/crypto/ssh/terminal/util_bsd.go | 12 + .../x/crypto/ssh/terminal/util_linux.go | 11 + .../x/crypto/ssh/terminal/util_plan9.go | 58 + .../x/crypto/ssh/terminal/util_test.go | 1 + .../x/crypto/ssh/terminal/util_windows.go | 174 + 256 files changed, 58234 insertions(+) create mode 100644 FORMAT.md create mode 100644 LICENSE create mode 100644 NOTICE create mode 100644 README.md create mode 100644 archive.go create mode 100644 archive/archive.go create mode 100644 archive/archive_test.go create mode 100644 archive/reader.go create mode 100644 archive/verify.go create mode 100644 archive/writer.go create mode 100644 archive_test.go create mode 100644 args.go create mode 100644 binary/binary.go create mode 100644 binary/binary_test.go create mode 100644 bytesize.go create mode 100644 create.go create mode 100644 extract.go create mode 100644 filter.go create mode 100644 key.go create mode 100644 key_test.go create mode 100644 keygen.go create mode 100644 list.go create mode 100644 main.go create mode 100644 vendor/github.com/codahale/sss/LICENSE create mode 100644 vendor/github.com/codahale/sss/README.md create mode 100644 vendor/github.com/codahale/sss/gf256.go create mode 100644 vendor/github.com/codahale/sss/gf256_test.go create mode 100644 vendor/github.com/codahale/sss/polynomial.go create mode 100644 vendor/github.com/codahale/sss/polynomial_test.go create mode 100644 vendor/github.com/codahale/sss/sss.go create mode 100644 vendor/github.com/codahale/sss/sss_test.go create mode 100644 vendor/github.com/dchest/blake2b/README create mode 100644 vendor/github.com/dchest/blake2b/blake2b.go create mode 100644 vendor/github.com/dchest/blake2b/blake2b_test.go create mode 100644 vendor/github.com/dchest/blake2b/block.go create mode 100644 vendor/github.com/jessevdk/go-flags/LICENSE create mode 100644 vendor/github.com/jessevdk/go-flags/README.md create mode 100644 vendor/github.com/jessevdk/go-flags/arg.go create mode 100644 vendor/github.com/jessevdk/go-flags/arg_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/assert_test.go create mode 100755 vendor/github.com/jessevdk/go-flags/check_crosscompile.sh create mode 100644 vendor/github.com/jessevdk/go-flags/closest.go create mode 100644 vendor/github.com/jessevdk/go-flags/command.go create mode 100644 vendor/github.com/jessevdk/go-flags/command_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/completion.go create mode 100644 vendor/github.com/jessevdk/go-flags/completion_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/convert.go create mode 100644 vendor/github.com/jessevdk/go-flags/convert_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/error.go create mode 100644 vendor/github.com/jessevdk/go-flags/example_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/flags.go create mode 100644 vendor/github.com/jessevdk/go-flags/group.go create mode 100644 vendor/github.com/jessevdk/go-flags/group_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/help.go create mode 100644 vendor/github.com/jessevdk/go-flags/help_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/ini.go create mode 100644 vendor/github.com/jessevdk/go-flags/ini_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/long_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/man.go create mode 100644 vendor/github.com/jessevdk/go-flags/marshal_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/multitag.go create mode 100644 vendor/github.com/jessevdk/go-flags/option.go create mode 100644 vendor/github.com/jessevdk/go-flags/options_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/optstyle_other.go create mode 100644 vendor/github.com/jessevdk/go-flags/optstyle_windows.go create mode 100644 vendor/github.com/jessevdk/go-flags/parser.go create mode 100644 vendor/github.com/jessevdk/go-flags/parser_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/pointer_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/short_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/tag_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/termsize.go create mode 100644 vendor/github.com/jessevdk/go-flags/termsize_linux.go create mode 100644 vendor/github.com/jessevdk/go-flags/termsize_nosysioctl.go create mode 100644 vendor/github.com/jessevdk/go-flags/termsize_other.go create mode 100644 vendor/github.com/jessevdk/go-flags/termsize_unix.go create mode 100644 vendor/github.com/jessevdk/go-flags/unknown_test.go create mode 100644 vendor/github.com/klauspost/compress/LICENSE create mode 100644 vendor/github.com/klauspost/compress/README.md create mode 100644 vendor/github.com/klauspost/compress/flate/asm_test.go create mode 100644 vendor/github.com/klauspost/compress/flate/copy.go create mode 100644 vendor/github.com/klauspost/compress/flate/copy_test.go create mode 100644 vendor/github.com/klauspost/compress/flate/crc32_amd64.go create mode 100644 vendor/github.com/klauspost/compress/flate/crc32_amd64.s create mode 100644 vendor/github.com/klauspost/compress/flate/crc32_noasm.go create mode 100644 vendor/github.com/klauspost/compress/flate/deflate.go create mode 100644 vendor/github.com/klauspost/compress/flate/deflate_test.go create mode 100644 vendor/github.com/klauspost/compress/flate/fixedhuff.go create mode 100644 vendor/github.com/klauspost/compress/flate/flate_test.go create mode 100644 vendor/github.com/klauspost/compress/flate/gen.go create mode 100644 vendor/github.com/klauspost/compress/flate/huffman_bit_writer.go create mode 100644 vendor/github.com/klauspost/compress/flate/huffman_bit_writer_test.go create mode 100644 vendor/github.com/klauspost/compress/flate/huffman_code.go create mode 100644 vendor/github.com/klauspost/compress/flate/inflate.go create mode 100644 vendor/github.com/klauspost/compress/flate/inflate_test.go create mode 100644 vendor/github.com/klauspost/compress/flate/reader_test.go create mode 100644 vendor/github.com/klauspost/compress/flate/reverse_bits.go create mode 100644 vendor/github.com/klauspost/compress/flate/snappy.go create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-null-max.dyn.expect create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-null-max.dyn.expect-noinput create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-null-max.golden create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-null-max.in create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-null-max.wb.expect create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-null-max.wb.expect-noinput create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-pi.dyn.expect create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-pi.dyn.expect-noinput create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-pi.golden create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-pi.in create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-pi.wb.expect create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-pi.wb.expect-noinput create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.dyn.expect create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.dyn.expect-noinput create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.golden create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.in create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.wb.expect create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.wb.expect-noinput create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.dyn.expect create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.dyn.expect-noinput create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.golden create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.in create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.wb.expect create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.wb.expect-noinput create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-max.golden create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-max.in create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-shifts.dyn.expect create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-shifts.dyn.expect-noinput create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-shifts.golden create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-shifts.in create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-shifts.wb.expect create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-shifts.wb.expect-noinput create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-text-shift.dyn.expect create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-text-shift.dyn.expect-noinput create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-text-shift.golden create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-text-shift.in create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-text-shift.wb.expect create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-text-shift.wb.expect-noinput create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-text.dyn.expect create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-text.dyn.expect-noinput create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-text.golden create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-text.in create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-text.wb.expect create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-text.wb.expect-noinput create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-zero.dyn.expect create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-zero.dyn.expect-noinput create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-zero.golden create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-zero.in create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-zero.wb.expect create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/huffman-zero.wb.expect-noinput create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/null-long-match.dyn.expect-noinput create mode 100644 vendor/github.com/klauspost/compress/flate/testdata/null-long-match.wb.expect-noinput create mode 100644 vendor/github.com/klauspost/compress/flate/token.go create mode 100644 vendor/github.com/klauspost/compress/flate/writer_test.go create mode 100644 vendor/github.com/klauspost/compress/gzip/gunzip.go create mode 100644 vendor/github.com/klauspost/compress/gzip/gunzip_test.go create mode 100644 vendor/github.com/klauspost/compress/gzip/gzip.go create mode 100644 vendor/github.com/klauspost/compress/gzip/gzip_test.go create mode 100644 vendor/github.com/klauspost/compress/gzip/testdata/issue6550.gz create mode 100644 vendor/github.com/klauspost/compress/gzip/testdata/test.json create mode 100644 vendor/github.com/klauspost/compress/testdata/Mark.Twain-Tom.Sawyer.txt create mode 100644 vendor/github.com/klauspost/compress/testdata/e.txt create mode 100644 vendor/github.com/klauspost/compress/testdata/pi.txt create mode 100644 vendor/github.com/klauspost/cpuid/LICENSE create mode 100644 vendor/github.com/klauspost/cpuid/README.md create mode 100644 vendor/github.com/klauspost/cpuid/cpuid.go create mode 100644 vendor/github.com/klauspost/cpuid/cpuid_386.s create mode 100644 vendor/github.com/klauspost/cpuid/cpuid_amd64.s create mode 100644 vendor/github.com/klauspost/cpuid/cpuid_test.go create mode 100644 vendor/github.com/klauspost/cpuid/detect_intel.go create mode 100644 vendor/github.com/klauspost/cpuid/detect_ref.go create mode 100644 vendor/github.com/klauspost/cpuid/generate.go create mode 100644 vendor/github.com/klauspost/cpuid/mockcpu_test.go create mode 100644 vendor/github.com/klauspost/cpuid/private-gen.go create mode 100644 vendor/github.com/klauspost/cpuid/private/README.md create mode 100644 vendor/github.com/klauspost/cpuid/private/cpuid.go create mode 100644 vendor/github.com/klauspost/cpuid/private/cpuid_386.s create mode 100644 vendor/github.com/klauspost/cpuid/private/cpuid_amd64.s create mode 100644 vendor/github.com/klauspost/cpuid/private/cpuid_detect_intel.go create mode 100644 vendor/github.com/klauspost/cpuid/private/cpuid_detect_ref.go create mode 100644 vendor/github.com/klauspost/cpuid/private/cpuid_test.go create mode 100644 vendor/github.com/klauspost/cpuid/testdata/cpuid_data.zip create mode 100644 vendor/github.com/klauspost/cpuid/testdata/getall.go create mode 100644 vendor/github.com/klauspost/crc32/LICENSE create mode 100644 vendor/github.com/klauspost/crc32/README.md create mode 100644 vendor/github.com/klauspost/crc32/crc32.go create mode 100644 vendor/github.com/klauspost/crc32/crc32_amd64.go create mode 100644 vendor/github.com/klauspost/crc32/crc32_amd64.s create mode 100644 vendor/github.com/klauspost/crc32/crc32_amd64p32.go create mode 100644 vendor/github.com/klauspost/crc32/crc32_amd64p32.s create mode 100644 vendor/github.com/klauspost/crc32/crc32_generic.go create mode 100644 vendor/github.com/klauspost/crc32/crc32_test.go create mode 100644 vendor/github.com/klauspost/crc32/example_test.go create mode 100644 vendor/github.com/magical/argon2/README.md create mode 100644 vendor/github.com/magical/argon2/api.go create mode 100644 vendor/github.com/magical/argon2/api_test.go create mode 100644 vendor/github.com/magical/argon2/argon2.go create mode 100644 vendor/github.com/magical/argon2/argon2_test.go create mode 100644 vendor/github.com/magical/argon2/round.go create mode 100644 vendor/github.com/magical/argon2/round.py create mode 100644 vendor/github.com/wg/ecies/aead.go create mode 100644 vendor/github.com/wg/ecies/aead_test.go create mode 100644 vendor/github.com/wg/ecies/box.go create mode 100644 vendor/github.com/wg/ecies/box_test.go create mode 100644 vendor/github.com/wg/ecies/chacha20poly1305/chacha20poly1305.go create mode 100644 vendor/github.com/wg/ecies/chacha20poly1305/chacha20poly1305_test.go create mode 100644 vendor/github.com/wg/ecies/cipher.go create mode 100644 vendor/github.com/wg/ecies/doc.go create mode 100644 vendor/github.com/wg/ecies/ecdh.go create mode 100644 vendor/github.com/wg/ecies/ecdh_test.go create mode 100644 vendor/github.com/wg/ecies/vendor/github.com/dchest/blake2b/README create mode 100644 vendor/github.com/wg/ecies/vendor/github.com/dchest/blake2b/blake2b.go create mode 100644 vendor/github.com/wg/ecies/vendor/github.com/dchest/blake2b/blake2b_test.go create mode 100644 vendor/github.com/wg/ecies/vendor/github.com/dchest/blake2b/block.go create mode 100644 vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/AUTHORS create mode 100644 vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/CONTRIBUTORS create mode 100644 vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/LICENSE create mode 100644 vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/PATENTS create mode 100644 vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/README create mode 100644 vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/const_amd64.s create mode 100644 vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s create mode 100644 vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/curve25519.go create mode 100644 vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/curve25519_test.go create mode 100644 vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/doc.go create mode 100644 vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/freeze_amd64.s create mode 100644 vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s create mode 100644 vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go create mode 100644 vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/mul_amd64.s create mode 100644 vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/square_amd64.s create mode 100644 vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/LICENSE create mode 100644 vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/README.md create mode 100644 vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20.go create mode 100644 vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20_amd64.go create mode 100644 vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20_amd64.py create mode 100644 vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20_amd64.s create mode 100644 vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20_ref.go create mode 100644 vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20_test.go create mode 100644 vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/poly1305/README.md create mode 100644 vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/poly1305/poly1305.go create mode 100644 vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/poly1305/poly1305_32.go create mode 100644 vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/poly1305/poly1305_test.go create mode 100644 vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/x448/LICENSE.txt create mode 100644 vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/x448/README.md create mode 100644 vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/x448/x448.go create mode 100644 vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/x448/x448_ref.go create mode 100644 vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/x448/x448_test.go create mode 100644 vendor/github.com/wg/ecies/xchacha20poly1305/xchacha20poly1305.go create mode 100644 vendor/github.com/wg/ecies/xchacha20poly1305/xchacha20poly1305_test.go create mode 100644 vendor/golang.org/x/crypto/AUTHORS create mode 100644 vendor/golang.org/x/crypto/CONTRIBUTORS create mode 100644 vendor/golang.org/x/crypto/LICENSE create mode 100644 vendor/golang.org/x/crypto/PATENTS create mode 100644 vendor/golang.org/x/crypto/README create mode 100644 vendor/golang.org/x/crypto/ssh/terminal/util.go create mode 100644 vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go create mode 100644 vendor/golang.org/x/crypto/ssh/terminal/util_linux.go create mode 100644 vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go create mode 100644 vendor/golang.org/x/crypto/ssh/terminal/util_test.go create mode 100644 vendor/golang.org/x/crypto/ssh/terminal/util_windows.go diff --git a/FORMAT.md b/FORMAT.md new file mode 100644 index 0000000..aa4af72 --- /dev/null +++ b/FORMAT.md @@ -0,0 +1,90 @@ +# arc - disk format + +arc archives are tar archives compressed with gzip and then encrypted +with the XChaCha20 + Poly1305 authenticated encryption mode using a +key derived in one of three ways: + + 1. from a password using the Argon2 KDF + 2. from a static-ephemeral ECDH key exchange + 3. from a random key split into n shards + +The on-disk format begins with a 1-byte disk format version V followed +by a 1-byte archive type T, then a type-specific number of bytes, a +16-byte Poly1305 authentication tag, a 24-byte cryptographically secure +random nonce, and finally the encrypted data. + +All numbers are stored in little-endian format. + +## Password Archive Format + +The 32-byte XChaCha20Poly1305 key is generated by applying the Argon2 +KDF to a user-supplied password and 32 bytes of cryptographically +secure random salt. + + T = 1 + I = uint32 number of iterations + M = uint32 memory usage + + ┌─┬─┬────┬────┬───────────────────────────────┐ + │V│T│I │M │Salt │ + ├─┴─┴────┴────┴─┬───────────────────────┬─────┴─────────────┐ + │Tag │Nonce │Data···············│ + ├───────────────┴───────────────────────┴───────────────────┤ + │···························································│ + └───────────────────────────────────────────────────────────┘ + +## Curve448 Archive Format + +The 32-byte XChaCha20Poly1305 key results from applying BLAKE2b to the +shared secret derived from a X448 ECDH key exchange with an ephemeral +private key and static public key. The corresponding ephemeral public +key is embedded in the archive. + + T = 2 + + ┌─┬─┬───────────────────────────────────────────────────────┐ + │V│T│Ephemeral Public Key │ + ├─┴─┴───────────┬───────────────────────┬───────────────────┤ + │Tag │Nonce │Data···············│ + ├───────────────┴───────────────────────┴───────────────────┤ + │···························································│ + └───────────────────────────────────────────────────────────┘ + +## Shard Archive Format + +The 32-byte XChaCha20Poly1305 key is cryptographically secure random +bytes split into n shards using Shamir's Secret Sharing algorithm. +One archive is generated for each n and k archives must be present to +recreate the key and decrypt the archive. + + T = 3 + n = shard number + + ┌─┬─┬─┬───────────────────────────────┐ + │V│T│n│Shard │ + ├─┴─┴─┴─────────┬─────────────────────┴─┬───────────────────┐ + │Tag │Nonce │Data···············│ + ├───────────────┴───────────────────────┴───────────────────┤ + │···························································│ + └───────────────────────────────────────────────────────────┘ + +## Curve448 Key Format + +arc curve448 public and private keys are encrypted with XChaCha20+ +Poly1305 using a key derived from applying the Argon2 KDF to a +password and 32 bytes of cryptographically secure random salt. + + T = public = 1, private = 2 + I = uint32 number of iterations + M = uint32 memory usage + + ┌─┬─┬────┬────┬───────────────────────────────┐ + │V│T│I │M │Salt │ + ├─┴─┴────┴────┴─┬───────────────────────┬─────┴─────────────┐ + │Tag │Nonce │Key················│ + ├───────────────┴───────────────────────┴───────────────────┤ + │···························································│ + └───────────────────────────────────────────────────────────┘ + +Private keys use a user-supplied password while public keys use an +empty string. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..94a0453 --- /dev/null +++ b/LICENSE @@ -0,0 +1,621 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..31abdaf --- /dev/null +++ b/NOTICE @@ -0,0 +1,268 @@ +arc - Copyright (C) 2016 - Will Glozer + +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ NOTICE: chacha20, poly1305 ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + +To the extent possible under law, Yawning Angel has waived all copyright +and related or neighboring rights to chacha20, using the Creative +Commons "CC0" public domain dedication. See LICENSE or + for full details. + +To the extent possible under law, Yawning Angel waived all copyright +and related or neighboring rights to poly1305, using the creative +commons "CC0" public domain dedication. See LICENSE or + for full details. + +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ NOTICE: x448 ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + +The MIT License (MIT) + +Copyright (c) 2011 Stanford University. +Copyright (c) 2014-2015 Cryptography Research, Inc. +Copyright (c) 2015 Yawning Angel. + +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. + +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ NOTICE: blake2b ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + +Written in 2012 by Dmitry Chestnykh. + +To the extent possible under law, the author have dedicated all copyright +and related and neighboring rights to this software to the public domain +worldwide. This software is distributed without any warranty. +http://creativecommons.org/publicdomain/zero/1.0/ + +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ NOTICE: sss ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + +The MIT License (MIT) + +Copyright (c) 2014 Coda Hale + +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. + +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ NOTICE: argon2 ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + +Copyright © 2015 Andrew Ekstedt +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ NOTICE: compress ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ NOTICE: cpuid ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + +The MIT License (MIT) + +Copyright (c) 2015 Klaus Post + +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. + +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ NOTICE: crc32 ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + +Copyright (c) 2012 The Go Authors. All rights reserved. +Copyright (c) 2015 Klaus Post + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ NOTICE: go-flags ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + +Copyright (c) 2012 Jesse van den Kieboom. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ NOTICE: golang.org/x/crypto/ssh/terminal ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ END OF NOTICE ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ diff --git a/README.md b/README.md new file mode 100644 index 0000000..d0afa8f --- /dev/null +++ b/README.md @@ -0,0 +1,144 @@ +# arc - secure file archiver + +arc is a file archiver designed to manage secure and stable archives +suitable for storage and transmission. arc archives are standard tar +archives compressed with gzip and then encrypted with the XChaCha20+ +Poly1305 authenticated encryption mode. + +arc is distributed as open source code and static executables with +no external dependencies. + +## Security + +arc archives are designed for secure storage and transmission and +must not allow decryption or tampering by an attacker without the +appropriate encryption key. + +However, arc has not been subject to peer review and the specific +algorithm combinations used have not been standardized. + +arc archives are encrypted with XChaCha20 + Poly1305 using the +same algorithm as NaCl's secretbox but substituting XChaCha20 for +XSalsa20. This algorithm is similar to the ChaCha20 + Poly1305 +AEAD mode defined in RFC 7539 but uses a longer random nonce and +does not include lengths in the authentication tag computation. + +The XChaCha20 + Poly1305 key is derived in one of three ways: + + 1. from a password using the Argon2 KDF + 2. from a static-ephemeral ECDH key exchange + 3. from a random key split into n shards + +See the Archive sections below for details of each. + +## Stability + +arc archives are designed for long-term storage and their content +should be extractable using hardware and software that does not +exist at the time the archive was created. + +A decrypted archive is a standard gzip-compressed tar archive for +which there exist a wide variety of open source tools & libraries +capable of reading and extracting their contents. Should that fail +the tar and gzip formats are well documented and reasonably simple +to implement. + +Decryption is more difficult due to rapid advances in the state of +the art and arc's desire for strong security. However portable open +source C implementations of each algorithm are available, and the +implementations arc uses are written in Go, a language designed for +long-term backwards compatibility. + +See the Compatibility section which follows for important caveats +and read FORMAT for the specific disk format arc uses as a header +for the encrypted tar+gzip stream. + +## Compatibility + +arc releases follow the semantic versioning scheme and the major +version will be incremented when the on-disk format changes. + +Each release of arc will support a single version of the on-disk +format and any security flaws will cause a new release with the +version incremented and support for the flawed method dropped. + +This means future versions of arc may not be capable of extracting +old archives so copies of arc in binary and/or source form should +be kept alongside the archives themselves. + +## Password Archives + +A password, cost parameters, and cryptographically secure random salt +are used as input to the Argon2 password hashing function to derive +the encryption key used to encrypt & decrypt the archive. + +## Curve448 Archives + +A Curve448 key pair is generated via arc's --keygen option. + +Encryption uses the public key and an ephemeral private key as input +to the X448 ECDH key exchange function and the resulting shared secret +is hashed with BLAKE2b to derive the encryption key. The corresponding +ephemeral public key is embedded in the archive and used with the +static private key to decrypt the archive. + +This method is suitable for transmitting archives to another party or +for use on a system that may become compromised after the archive is +created. + +## Shard Archives + +The encryption key is cryptographically secure random bytes that are +split into n shards using Shamir's Secret Sharing algorithm. One +archive is generated for each shard and k must be present to recreate +the key and decrypt the archive. + +This method is most suitable for small archives that will be stored +or transmitted via multiple channels where k - 1 can be compromised +with no loss in archive security. + +## License + +Copyright (C) 2016 Will Glozer. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +## Acknowledgments + +arc contains code from a number of open source projects including +Yawning Angel's chacha20, poly1305, and x448 libraries, Dmitry +Chestnykh's blake2b, Coda Hale's sss, Andrw Ekstedt's argon2, Klaus +Post's optimized compression packages and Jesse van den Kieboom's +go-flags. See NOTICE for license details. + +## Cryptography Notice + +This distribution includes cryptographic software. The country in +which you currently reside may have restrictions on the import, +possession, use, and/or re-export to another country, of encryption +software. BEFORE using any encryption software, please check your +country's laws, regulations and policies concerning the import, +possession, or use, and re-export of encryption software, to see if +this is permitted. See for more +information. + +The U.S. Government Department of Commerce, Bureau of Industry and +Security (BIS), has classified this software as Export Commodity +Control Number (ECCN) 5D002.C.1, which includes information security +software using or performing cryptographic functions with asymmetric +algorithms. The form and manner of this distribution makes it +eligible for export under the License Exception ENC Technology +Software Unrestricted (TSU) exception (see the BIS Export +Administration Regulations, Section 740.13) for both object code and +source code. diff --git a/archive.go b/archive.go new file mode 100644 index 0000000..a251ddf --- /dev/null +++ b/archive.go @@ -0,0 +1,379 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package main + +import ( + "bufio" + "crypto/rand" + "errors" + "io" + + "github.com/codahale/sss" + "github.com/magical/argon2" + "github.com/wg/arc/archive" + "github.com/wg/arc/binary" +) + +const ( + Version = 0x01 + Password = 0x01 + Curve448 = 0x02 + Shard = 0x03 + KeySize = archive.KeySize +) + +type Archiver interface { + Reader() (*Reader, error) + Writer() (*Writer, error) +} + +type Reader struct { + buffer *bufio.Reader + files []File + *archive.Reader +} + +type Writer struct { + buffer *bufio.Writer + files []File + tagAt int64 + *archive.Writer +} + +var ( + ErrInvalidArchive = errors.New("archive: verify failed") + ErrInvalidVersion = errors.New("archive: unsupported version") + ErrPasswordArchive = errors.New("archive: password archive") + ErrCurve448Archive = errors.New("archive: curve448 archive") + ErrShardArchive = errors.New("archive: shard archive") +) + +// A PasswordArchive is encrypted with a key derived from a password, +// cost parameters, and cryptographically secure random salt using the +// Argon2 password hashing function. +type PasswordArchive struct { + Version byte + Type byte + Iterations uint32 + Memory uint32 + Salt [32]byte + Password []byte + File File +} + +func NewPasswordArchive(password []byte, iterations, memory uint32, file File) *PasswordArchive { + return &PasswordArchive{ + Version: Version, + Type: Password, + Iterations: iterations, + Memory: memory, + Password: password, + File: file, + } +} + +func (a *PasswordArchive) Reader() (*Reader, error) { + err := binary.Read(a.File, binary.LE, a) + if err != nil { + return nil, err + } + + switch { + case a.Version != Version: + return nil, ErrInvalidVersion + case a.Type == Curve448: + return nil, ErrCurve448Archive + case a.Type == Shard: + return nil, ErrShardArchive + } + + key, err := a.Key() + if err != nil { + return nil, err + } + + return newArchiveReader(key, a.File, a.File) +} + +func (a *PasswordArchive) Writer() (*Writer, error) { + _, err := rand.Read(a.Salt[:]) + if err != nil { + return nil, err + } + + err = binary.Write(a.File, binary.LE, a) + if err != nil { + return nil, err + } + + key, err := a.Key() + if err != nil { + return nil, err + } + + return newArchiveWriter(key, a.File, a.File) +} + +func (a *PasswordArchive) Key() ([]byte, error) { + var ( + password = a.Password + salt = a.Salt[:] + iterations = int(a.Iterations) + memory = int64(a.Memory) + ) + return argon2.Key(password, salt, iterations, 1, memory, KeySize) +} + +// A Curve448Archive is encrypted with a key derived from applying +// BLAKE2b to the shared secret derived from an X448 ECDH key exchange +// with an ephemeral private key and static public key. +type Curve448Archive struct { + Version byte + Type byte + Ephemeral PublicKey + PublicKey *PublicKey + PrivateKey *PrivateKey + File File +} + +func NewCurve448Archive(public *PublicKey, private *PrivateKey, file File) *Curve448Archive { + return &Curve448Archive{ + Version: Version, + Type: Curve448, + PublicKey: public, + PrivateKey: private, + File: file, + } +} + +func (a *Curve448Archive) Reader() (*Reader, error) { + err := binary.Read(a.File, binary.LE, a) + if err != nil { + return nil, err + } + + switch { + case a.Version != Version: + return nil, ErrInvalidVersion + case a.Type == Password: + return nil, ErrPasswordArchive + case a.Type == Shard: + return nil, ErrShardArchive + } + + key, err := ComputeSharedKey(&a.Ephemeral, a.PrivateKey, KeySize) + if err != nil { + return nil, err + } + + return newArchiveReader(key, a.File, a.File) +} + +func (a *Curve448Archive) Writer() (*Writer, error) { + ephemeralPublicKey, ephemeralPrivateKey, err := GenerateKeypair() + if err != nil { + return nil, err + } + defer ephemeralPrivateKey.Zero() + + key, err := ComputeSharedKey(a.PublicKey, ephemeralPrivateKey, KeySize) + if err != nil { + return nil, err + } + + a.Ephemeral = *ephemeralPublicKey + err = binary.Write(a.File, binary.LE, a) + if err != nil { + return nil, err + } + + return newArchiveWriter(key, a.File, a.File) +} + +// A ShardArchive is encrypted with a key consisting of cryptographically +// secure random bytes. That key is split into n shards using Shamir's +// Secret Sharing algorithm and one archive is generate for each shard. +// k shards must be present to recreate the key. +type ShardArchive struct { + Version byte + Type byte + ID byte + Share [KeySize]byte + Threshold int + File File + Shards []*ShardArchive +} + +func NewShardArchive(threshold int, files []File) *ShardArchive { + shards := make([]*ShardArchive, len(files)) + + for i, file := range files { + shards[i] = &ShardArchive{ + Version: Version, + Type: Shard, + Threshold: threshold, + File: file, + Shards: shards, + } + } + + return shards[0] +} + +func (a *ShardArchive) Reader() (*Reader, error) { + shares := make(map[byte][]byte, len(a.Shards)) + + for _, shard := range a.Shards { + err := binary.Read(shard.File, binary.LE, shard) + if err != nil { + return nil, err + } + + switch { + case shard.Version != Version: + return nil, ErrInvalidVersion + case shard.Type == Password: + return nil, ErrPasswordArchive + case shard.Type == Curve448: + return nil, ErrCurve448Archive + } + + shares[shard.ID] = shard.Share[:] + } + + key := sss.Combine(shares) + + return newArchiveReader(key, a.File, a.Files()...) +} + +func (a *ShardArchive) Writer() (*Writer, error) { + var key [32]byte + + _, err := rand.Read(key[:]) + if err != nil { + return nil, err + } + + n := byte(len(a.Shards)) + k := byte(a.Threshold) + + shares, err := sss.Split(n, k, key[:]) + if err != nil { + return nil, err + } + + writers := make([]io.Writer, len(a.Shards)) + for id, share := range shares { + index := id - 1 + shard := a.Shards[index] + + shard.ID = id + copy(shard.Share[:], share) + + err = binary.Write(shard.File, binary.LE, shard) + if err != nil { + return nil, err + } + writers[index] = shard.File + } + w := io.MultiWriter(writers...) + + return newArchiveWriter(key[:], w, a.Files()...) +} + +func (a *ShardArchive) Files() []File { + files := make([]File, len(a.Shards)) + for i, shard := range a.Shards { + files[i] = shard.File + } + return files +} + +func newArchiveReader(key []byte, raw io.Reader, files ...File) (*Reader, error) { + switch valid, err := verify(key, files[0]); { + case err != nil: + return nil, err + case !valid: + return nil, ErrInvalidArchive + } + + buffer := bufio.NewReader(raw) + r, err := archive.NewReader(buffer, key) + + return &Reader{ + Reader: r, + buffer: buffer, + files: files, + }, err +} + +func newArchiveWriter(key []byte, raw io.Writer, files ...File) (*Writer, error) { + tagAt, err := files[0].Seek(0, 1) + if err != nil { + return nil, err + } + + buffer := bufio.NewWriter(raw) + w, err := archive.NewWriter(buffer, key) + + return &Writer{ + Writer: w, + buffer: buffer, + files: files, + tagAt: tagAt, + }, err +} + +func verify(key []byte, file File) (bool, error) { + p, err := file.Seek(0, 1) + if err != nil { + return false, err + } + defer file.Seek(p, 0) + buffer := bufio.NewReader(file) + return archive.Verify(buffer, key) +} + +func (r *Reader) Close() error { + for _, f := range r.files { + err := f.Close() + if err != nil { + return err + } + } + return nil +} + +func (w *Writer) Close() error { + tag, err := w.Finish() + if err != nil { + return err + } + + err = w.buffer.Flush() + if err != nil { + return err + } + + for _, f := range w.files { + _, err := f.WriteAt(tag, w.tagAt) + if err != nil { + return err + } + + err = f.Close() + if err != nil { + return err + } + } + + return nil +} + +type File interface { + io.Reader + io.Writer + io.WriterAt + io.Seeker + io.Closer +} diff --git a/archive/archive.go b/archive/archive.go new file mode 100644 index 0000000..3199371 --- /dev/null +++ b/archive/archive.go @@ -0,0 +1,76 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package archive + +import ( + "crypto/rand" + "crypto/subtle" + "io" + + "github.com/wg/ecies/xchacha20poly1305" +) + +const KeySize = xchacha20poly1305.KeySize + +type Archive struct { + xchacha20poly1305.XChaCha20Poly1305 + tag [xchacha20poly1305.TagSize]byte + io.Reader + io.Writer +} + +func NewArchiveFromReader(r io.Reader, key []byte) (*Archive, error) { + var nonce [xchacha20poly1305.NonceSize]byte + a := &Archive{Reader: r} + + if _, err := io.ReadFull(r, a.tag[:]); err != nil { + return nil, err + } + + if _, err := io.ReadFull(r, nonce[:]); err != nil { + return nil, err + } + + err := a.Init(key, nonce[:]) + return a, err +} + +func NewArchiveForWriter(w io.Writer, key []byte) (*Archive, error) { + var nonce [xchacha20poly1305.NonceSize]byte + a := &Archive{Writer: w} + + if _, err := rand.Read(nonce[:]); err != nil { + return nil, err + } + + if err := a.Init(key, nonce[:]); err != nil { + return nil, err + } + + if _, err := w.Write(a.tag[:]); err != nil { + return nil, err + } + + if _, err := w.Write(nonce[:]); err != nil { + return nil, err + } + + return a, nil +} + +func (a *Archive) Read(b []byte) (int, error) { + n, err := a.Reader.Read(b) + a.Decrypt(b[:n], b[:n]) + return n, err +} + +func (a *Archive) Write(b []byte) (int, error) { + a.Encrypt(b, b) + return a.Writer.Write(b) +} + +func (a *Archive) Verify() bool { + var tag [xchacha20poly1305.TagSize]byte + a.Tag(tag[:0]) + return subtle.ConstantTimeCompare(a.tag[:], tag[:]) == 1 +} diff --git a/archive/archive_test.go b/archive/archive_test.go new file mode 100644 index 0000000..3234ecb --- /dev/null +++ b/archive/archive_test.go @@ -0,0 +1,170 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package archive + +import ( + "archive/tar" + "bytes" + "crypto/rand" + "io" + "io/ioutil" + "testing" +) + +func TestCreateArchive(t *testing.T) { + entries := []*tar.Header{ + {Name: "foo", Size: 0}, + {Name: "bar", Size: 1<<16 - 1}, + {Name: "baz", Size: 64}, + } + key := randomKey() + + buf, dat, err := createArchive(key, entries) + if err != nil { + t.Fatal(err) + } + + r, err := NewReader(buf, key) + if err != nil { + t.Fatal(err) + } + + for i, e := range entries { + switch next, err := r.Next(); { + case err != nil: + t.Fatal(err) + case e.Name != next.Name: + t.Fatalf("expected entry name %s got %s", e.Name, next.Name) + case e.Size != next.Size: + t.Fatalf("expected entry size %d got %d", e.Size, next.Size) + } + + switch b, err := ioutil.ReadAll(r); { + case err != nil: + t.Fatal(err) + case int(e.Size) != len(b): + t.Fatalf("expected to read %d bytes got %d", e.Size, len(b)) + case !bytes.Equal(b, dat[i]): + t.Fatalf("expected content '%v' got '%v'", b, dat[i]) + } + } + + if !r.Verify() { + t.Fatal("archive verify failed") + } +} + +func TestVerifyArchive(t *testing.T) { + entries := []*tar.Header{ + {Name: "foo", Size: 32}, + {Name: "bar", Size: 64}, + } + key := randomKey() + + buf, _, err := createArchive(key, entries) + if err != nil { + t.Fatal(err) + } + + if valid, _ := Verify(buf, key); !valid { + t.Fatal("archive verify failed") + } +} + +func TestVerifyFailWrongKey(t *testing.T) { + entries := []*tar.Header{ + {Name: "foo", Size: 32}, + {Name: "bar", Size: 64}, + } + key := randomKey() + + buf, _, err := createArchive(key, entries) + if err != nil { + t.Fatal(err) + } + + key[0] = ^key[0] + + if valid, _ := Verify(buf, key); valid { + t.Fatal("verified invalid archive") + } +} + +func TestVerifyFailByteFlip(t *testing.T) { + entries := []*tar.Header{ + {Name: "foo", Size: 32}, + {Name: "bar", Size: 64}, + } + key := randomKey() + + buf, _, err := createArchive(key, entries) + if err != nil { + t.Fatal(err) + } + + archive := buf.Bytes() + for i, b := range archive { + archive[i] = ^archive[i] + + r := bytes.NewReader(archive) + if valid, _ := Verify(r, key); valid { + t.Fatal("verified invalid archive at", i) + } + + archive[i] = b + } +} + +func TestWriterInvariants(t *testing.T) { + _, _, err := createArchive(make([]byte, 31), nil) + if err == nil { + t.Fatalf("created archive with 31 byte key") + } +} + +func createArchive(key []byte, entries []*tar.Header) (*Buffer, [][]byte, error) { + buf := &Buffer{} + + arc, err := NewWriter(buf, key) + if err != nil { + return nil, nil, err + } + + dat := make([][]byte, len(entries)) + + for i, e := range entries { + err := arc.Add(e) + if err != nil { + return nil, nil, err + } + + dat[i] = make([]byte, e.Size) + _, err = rand.Read(dat[i]) + if err != nil { + return nil, nil, err + } + + err = arc.Copy(bytes.NewReader(dat[i]), e.Size) + if err != nil { + return nil, nil, err + } + } + + tag, _ := arc.Finish() + copy(buf.Bytes()[0:16], tag) + + return buf, dat, nil +} + +type Buffer struct { + bytes.Buffer +} + +func randomKey() []byte { + key := make([]byte, 32) + _, err := io.ReadFull(rand.Reader, key) + if err != nil { + panic(err) + } + return key +} diff --git a/archive/reader.go b/archive/reader.go new file mode 100644 index 0000000..a2e3207 --- /dev/null +++ b/archive/reader.go @@ -0,0 +1,47 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package archive + +import ( + "archive/tar" + "compress/gzip" + "io" +) + +type Reader struct { + archiver *tar.Reader + compressor *gzip.Reader + archive *Archive +} + +func NewReader(r io.Reader, key []byte) (*Reader, error) { + archive, err := NewArchiveFromReader(r, key) + if err != nil { + return nil, err + } + + compressor, err := gzip.NewReader(archive) + if err != nil { + return nil, err + } + + archiver := tar.NewReader(compressor) + + return &Reader{ + archiver: archiver, + compressor: compressor, + archive: archive, + }, nil +} + +func (r *Reader) Next() (*tar.Header, error) { + return r.archiver.Next() +} + +func (r *Reader) Read(b []byte) (int, error) { + return r.archiver.Read(b) +} + +func (r *Reader) Verify() bool { + return r.archive.Verify() +} diff --git a/archive/verify.go b/archive/verify.go new file mode 100644 index 0000000..8c826b3 --- /dev/null +++ b/archive/verify.go @@ -0,0 +1,22 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package archive + +import ( + "io" + "io/ioutil" +) + +func Verify(r io.Reader, key []byte) (bool, error) { + archive, err := NewArchiveFromReader(r, key) + if err != nil { + return false, err + } + + _, err = io.Copy(ioutil.Discard, archive) + if err != nil { + return false, err + } + + return archive.Verify(), nil +} diff --git a/archive/writer.go b/archive/writer.go new file mode 100644 index 0000000..332c3c6 --- /dev/null +++ b/archive/writer.go @@ -0,0 +1,63 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package archive + +import ( + "archive/tar" + "errors" + "io" + + "github.com/klauspost/compress/gzip" +) + +var ( + ErrShortCopy = errors.New("archive: short copy") +) + +type Writer struct { + archiver *tar.Writer + compressor *gzip.Writer + archive *Archive +} + +func NewWriter(w io.Writer, key []byte) (*Writer, error) { + archive, err := NewArchiveForWriter(w, key) + if err != nil { + return nil, err + } + + compressor := gzip.NewWriter(archive) + archiver := tar.NewWriter(compressor) + + return &Writer{ + archiver: archiver, + compressor: compressor, + archive: archive, + }, nil +} + +func (w *Writer) Add(header *tar.Header) error { + return w.archiver.WriteHeader(header) +} + +func (w *Writer) Copy(r io.Reader, size int64) error { + switch n, err := io.Copy(w.archiver, r); { + case err != nil: + return err + case n < size: + return ErrShortCopy + } + return w.archiver.Flush() +} + +func (w *Writer) Finish() ([]byte, error) { + if err := w.archiver.Close(); err != nil { + return nil, err + } + + if err := w.compressor.Close(); err != nil { + return nil, err + } + + return w.archive.Tag(nil), nil +} diff --git a/archive_test.go b/archive_test.go new file mode 100644 index 0000000..14d7e9c --- /dev/null +++ b/archive_test.go @@ -0,0 +1,398 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package main + +import ( + "archive/tar" + "bytes" + "crypto/rand" + "encoding/binary" + "io" + "io/ioutil" + "testing" + + "github.com/codahale/sss" + "github.com/magical/argon2" + "github.com/wg/arc/archive" +) + +var entries = []*tar.Header{ + {Name: "foo", Size: 0}, + {Name: "bar", Size: 1<<16 - 1}, + {Name: "baz", Size: 64}, +} + +func TestPasswordArchive(t *testing.T) { + arc := NewPasswordArchive([]byte("secret"), 1, 8, &Buffer{}) + dat := createArchive(t, arc) + verifyArchive(t, arc, dat) +} + +func TestPasswordArchiveKey(t *testing.T) { + var ( + password = []byte("secret") + iterations = 1 + memory = 8 + ) + + buf := &Buffer{} + arc := NewPasswordArchive(password, uint32(iterations), uint32(memory), buf) + createArchive(t, arc) + + buf.Rewind() + buf.Seek(2+4+4+32, 0) + + key, err := argon2.Key(password, arc.Salt[:], int(iterations), 1, int64(memory), KeySize) + if err != nil { + t.Fatal("password key derivation failed", err) + } + + if valid, err := archive.Verify(buf, key); !valid || err != nil { + t.Fatal("password archive key incorrect") + } +} + +func TestPasswordArchiveFormat(t *testing.T) { + buf := &Buffer{} + arc := NewPasswordArchive([]byte("secret"), 2, 16, buf) + createArchive(t, arc) + + if binary.LittleEndian.Uint32(buf.buffer[2:6]) != arc.Iterations { + t.Fatal("serialized iterations incorrect") + } + + if binary.LittleEndian.Uint32(buf.buffer[6:10]) != arc.Memory { + t.Fatal("serialized memory incorrect") + } + + if !bytes.Equal(buf.buffer[10:42], arc.Salt[:]) { + t.Fatal("serialized salt incorrect") + } +} + +func TestWrongPassword(t *testing.T) { + arc := NewPasswordArchive([]byte("secret"), 1, 8, &Buffer{}) + createArchive(t, arc) + arc.Password = []byte("terces") + ensureInvalid(t, arc) +} + +func TestCurve448Archive(t *testing.T) { + public, private := keypair(t) + arc := NewCurve448Archive(public, private, &Buffer{}) + dat := createArchive(t, arc) + verifyArchive(t, arc, dat) +} + +func TestCurve448ArchiveKey(t *testing.T) { + public, private := keypair(t) + buf := &Buffer{} + arc := NewCurve448Archive(public, nil, buf) + createArchive(t, arc) + + buf.Rewind() + buf.Seek(2+56, 0) + + key, err := ComputeSharedKey(&arc.Ephemeral, private, KeySize) + if err != nil { + t.Fatal("curve448 key derivation failed", err) + } + + if valid, err := archive.Verify(buf, key); !valid || err != nil { + t.Fatal("curve448 archive key incorrect") + } +} + +func TestCurve448ArchiveFormat(t *testing.T) { + public, private := keypair(t) + buf := &Buffer{} + arc := NewCurve448Archive(public, private, buf) + createArchive(t, arc) + + if !bytes.Equal(buf.buffer[2:58], arc.Ephemeral[:]) { + t.Fatal("serialized ephemeral public key incorrect") + } +} + +func TestWrongPrivateKey(t *testing.T) { + public, _ := keypair(t) + _, private := keypair(t) + arc := NewCurve448Archive(public, private, &Buffer{}) + createArchive(t, arc) + ensureInvalid(t, arc) +} + +func TestShardArchive(t *testing.T) { + arc := NewShardArchive(2, buffers(3)) + dat := createArchive(t, arc) + verifyArchive(t, arc, dat) +} + +func TestShardArchiveKey(t *testing.T) { + arc := NewShardArchive(2, buffers(3)) + createArchive(t, arc) + + shares := map[byte][]byte{} + for _, shard := range arc.Shards { + shares[shard.ID] = shard.Share[:] + } + key := sss.Combine(shares) + + for _, shard := range arc.Shards { + buf := shard.File.(*Buffer) + buf.Rewind() + buf.Seek(2+1+KeySize, 0) + + if valid, err := archive.Verify(buf, key); !valid || err != nil { + t.Fatal("shard archive key incorrect") + } + } +} + +func TestShardArchiveFormat(t *testing.T) { + arc := NewShardArchive(2, buffers(3)) + createArchive(t, arc) + + for _, shard := range arc.Shards { + buf := shard.File.(*Buffer) + + if buf.buffer[2] != shard.ID { + t.Fatal("serialized shard ID incorrect") + } + + if !bytes.Equal(buf.buffer[3:3+KeySize], shard.Share[:]) { + t.Fatal("serialized shard share incorrect") + } + } +} + +func TestMissingShard(t *testing.T) { + arc := NewShardArchive(2, buffers(2)) + createArchive(t, arc) + arc.Shards = arc.Shards[:1] + ensureInvalid(t, arc) +} + +func TestArchiveHeader(t *testing.T) { + public, private := keypair(t) + var ( + password = NewPasswordArchive([]byte("secret"), 1, 8, &Buffer{}) + curve448 = NewCurve448Archive(public, private, &Buffer{}) + shard = NewShardArchive(2, buffers(2)) + ) + + createArchive(t, password) + createArchive(t, curve448) + createArchive(t, shard) + + switch { + case password.File.(*Buffer).buffer[0] != Version: + t.Fatal("wrong version in password archive") + case password.File.(*Buffer).buffer[1] != Password: + t.Fatal("wrong type in password archive") + case curve448.File.(*Buffer).buffer[0] != Version: + t.Fatal("wrong version in curve448 archive") + case curve448.File.(*Buffer).buffer[1] != Curve448: + t.Fatal("wrong type in curve448 archive") + } + + for _, s := range shard.Shards { + switch { + case s.File.(*Buffer).buffer[0] != Version: + t.Fatal("wrong version in shard archive") + case s.File.(*Buffer).buffer[1] != Shard: + t.Fatal("wrong type in shard archive") + + } + } +} + +func TestWrongArchiveType(t *testing.T) { + public, private := keypair(t) + var ( + password = NewPasswordArchive([]byte("secret"), 1, 8, &Buffer{}) + curve448 = NewCurve448Archive(public, private, &Buffer{}) + shard = NewShardArchive(2, buffers(2)) + ) + + createArchive(t, password) + createArchive(t, curve448) + createArchive(t, shard) + + ensureInvalidType(t, NewPasswordArchive([]byte("secret"), 1, 8, curve448.File)) + ensureInvalidType(t, NewPasswordArchive([]byte("secret"), 1, 8, shard.Shards[0].File)) + ensureInvalidType(t, NewCurve448Archive(public, private, password.File)) + ensureInvalidType(t, NewCurve448Archive(public, private, shard.Shards[0].File)) + ensureInvalidType(t, NewShardArchive(2, []File{password.File})) + ensureInvalidType(t, NewShardArchive(2, []File{curve448.File})) +} + +func createArchive(t *testing.T, a Archiver) [][]byte { + dat := make([][]byte, len(entries)) + + writer, err := a.Writer() + if err != nil { + t.Fatal(err) + } + + for i, e := range entries { + err := writer.Add(e) + if err != nil { + t.Fatal(err) + } + + dat[i] = make([]byte, e.Size) + _, err = rand.Read(dat[i]) + if err != nil { + t.Fatal(err) + } + + err = writer.Copy(bytes.NewReader(dat[i]), e.Size) + if err != nil { + t.Fatal(err) + } + } + + writer.Close() + + switch a := a.(type) { + case *PasswordArchive: + a.File.(*Buffer).Rewind() + case *Curve448Archive: + a.File.(*Buffer).Rewind() + case *ShardArchive: + for _, s := range a.Shards { + s.File.(*Buffer).Rewind() + } + } + + return dat +} + +func verifyArchive(t *testing.T, a Archiver, dat [][]byte) { + reader, err := a.Reader() + if err != nil { + t.Fatal(err) + } + + for i, e := range entries { + switch next, err := reader.Next(); { + case err != nil: + t.Fatal(err) + case e.Name != next.Name: + t.Fatalf("expected entry name %s got %s", e.Name, next.Name) + case e.Size != next.Size: + t.Fatalf("expected entry size %d got %d", e.Size, next.Size) + } + + switch b, err := ioutil.ReadAll(reader); { + case err != nil: + t.Fatal(err) + case int(e.Size) != len(b): + t.Fatalf("expected to read %d bytes got %d", e.Size, len(b)) + case !bytes.Equal(b, dat[i]): + t.Fatalf("expected content '%v' got '%v'", b, dat[i]) + } + } + + if !reader.Verify() { + t.Fatalf("archive verify failed") + } +} + +func ensureInvalid(t *testing.T, a Archiver) { + switch _, err := a.Reader(); { + case err != nil && err != ErrInvalidArchive: + t.Fatal("error validating archive", err) + case err == nil: + t.Fatal("invalid archive verified") + } +} + +func ensureInvalidType(t *testing.T, a Archiver) { + switch _, err := a.Reader(); { + case err == ErrPasswordArchive: + case err == ErrCurve448Archive: + case err == ErrShardArchive: + case err != nil: + t.Fatal("error checking archive type", err) + case err == nil: + t.Fatal("invalid archive type accepted") + } + + switch a := a.(type) { + case *PasswordArchive: + a.File.(*Buffer).Rewind() + case *Curve448Archive: + a.File.(*Buffer).Rewind() + case *ShardArchive: + for _, s := range a.Shards { + s.File.(*Buffer).Rewind() + } + } +} + +func keypair(t *testing.T) (*PublicKey, *PrivateKey) { + public, private, err := GenerateKeypair() + if err != nil { + t.Fatal(err) + } + return public, private +} + +func buffers(n int) []File { + files := make([]File, n) + for i := range files { + files[i] = &Buffer{} + } + return files +} + +type Buffer struct { + buffer []byte + offset int +} + +func (b *Buffer) Read(p []byte) (int, error) { + s := b.buffer[b.offset:] + if len(s) == 0 { + return 0, io.EOF + } + n := copy(p, s) + b.offset += n + return n, nil +} + +func (b *Buffer) Write(p []byte) (int, error) { + n := len(p) + b.buffer = append(b.buffer, p...) + b.offset += n + return n, nil +} + +func (b *Buffer) WriteAt(p []byte, off int64) (int, error) { + n := len(p) + m := int(off) + copy(b.buffer[m:m+n], p) + return n, nil +} + +func (b *Buffer) Seek(offset int64, whence int) (int64, error) { + switch whence { + case 0: + b.offset = int(offset) + case 1: + b.offset += int(offset) + case 2: + b.offset = len(b.buffer) - int(offset) + } + return int64(b.offset), nil +} + +func (b *Buffer) Close() error { + return nil +} + +func (b *Buffer) Rewind() { + b.offset = 0 +} diff --git a/args.go b/args.go new file mode 100644 index 0000000..19c7db5 --- /dev/null +++ b/args.go @@ -0,0 +1,296 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package main + +import ( + "bytes" + "errors" + "fmt" + "os" + + "github.com/jessevdk/go-flags" + + "golang.org/x/crypto/ssh/terminal" +) + +type Args struct { + OperationMode `group:"Archive Operation Mode"` + OperationModifier `group:"Archive Operation Modifiers"` + KeyManagementMode `group:"Key Management Mode"` + SecurityOptions `group:"Archive Security Options"` + PasswordOptions `group:"Password Options"` + KeyManagementOptions `group:"Key Generation Options"` + MiscOpts `group:"Misc Options"` + Positional `positional-args:"true" required:"0"` +} + +type OperationMode struct { + Create bool `short:"c" long:"create" description:"create new archive"` + List bool `short:"t" long:"list" description:"list archive contents"` + Extract bool `short:"x" long:"extract" description:"extract from archive"` +} + +type OperationModifier struct { + File string `short:"f" long:"file" description:"archive file"` + Shards []string ` long:"shard" description:"archive shard"` +} + +type SecurityOptions struct { + Password bool `long:"password" description:"derive key from password"` + Key string `long:"key" description:"derive key from ECDH exchange"` + Threshold int `long:"threshold" description:"random key with SSS threshold"` +} + +type KeyManagementMode struct { + Keygen bool `long:"keygen" description:"generate key pair"` +} + +type KeyManagementOptions struct { + Private string `long:"private" description:"private key file"` + Public string `long:"public" description:"public key file"` +} + +type PasswordOptions struct { + Iterations uint32 `long:"iterations" description:"argon2 iterations"` + Memory uint32 `long:"memory" description:"argon2 memory use"` +} + +type MiscOpts struct { + Help bool `short:"h" long:"help" description:"show this help message"` + Verbose []bool `short:"v" long:"verbose" description:"generate verbose output"` +} + +type Positional struct { + Names []string `positional-arg-name:"names"` +} + +func NewCommand() (*Cmd, error) { + args, err := ParseArgs(os.Args[1:]...) + if err != nil { + return nil, err + } + + c := &Cmd{ + Verbose: len(args.Verbose), + Names: args.Names, + } + + var mode int + switch { + case args.Create: + c.Op = c.Create + mode = os.O_EXCL | os.O_CREATE | os.O_WRONLY + case args.List: + c.Op = c.List + mode = os.O_RDONLY + case args.Extract: + c.Op = c.Extract + mode = os.O_RDONLY + case args.Keygen: + c.Op = c.Keygen + } + + switch { + case args.Password: + c.Archiver, err = args.PreparePasswordArchive(mode) + case args.Key != "": + c.Archiver, err = args.PrepareCurve448Archive(mode) + case len(args.Shards) > 0: + c.Archiver, err = args.PrepareShardArchive(mode) + case args.Keygen: + c.Public, c.Private, err = args.PrepareKeygen() + } + + return c, err +} + +func ParseArgs(arg ...string) (*Args, error) { + args := &Args{ + PasswordOptions: PasswordOptions{ + Iterations: 3, + Memory: 16, + }, + } + + parser := flags.NewParser(args, flags.PassDoubleDash) + parser.Usage = "[OPTIONS]" + + if _, err := parser.Parse(); err != nil { + return nil, err + } + + if args.Help { + b := bytes.Buffer{} + parser.WriteHelp(&b) + return nil, errors.New(b.String()) + } + + err := args.Validate() + return args, err +} + +func (a *Args) Validate() error { + switch { + case !a.Create && !a.List && !a.Extract && !a.Keygen: + return fmt.Errorf("must specify one of -c, -t, -x, --keygen") + + case a.Create && (a.List || a.Extract || a.Keygen): + return fmt.Errorf("can't combine -c, --create with other operations") + case a.List && (a.Create || a.Extract || a.Keygen): + return fmt.Errorf("can't combine -t, --list with other operations") + case a.Extract && (a.Create || a.List || a.Keygen): + return fmt.Errorf("can't combine -x, --extract with other operations") + case a.Keygen && (a.Create || a.Extract || a.List): + return fmt.Errorf("can't combine --keygen with other operations") + + case a.Create && !a.Password && a.Key == "" && len(a.Shards) == 0: + return fmt.Errorf("create requires --password, --key, or --shard") + case a.List && !a.Password && a.Key == "" && len(a.Shards) == 0: + return fmt.Errorf("list requires --password, --key, or --shard") + case a.Extract && !a.Password && a.Key == "" && len(a.Shards) == 0: + return fmt.Errorf("extract requires --password, --key, or --shard") + + case a.Password && a.Key != "": + return fmt.Errorf("can't combine --password with --key") + case a.Password && len(a.Shards) > 0: + return fmt.Errorf("can't combine --password with --shard") + case a.Key != "" && len(a.Shards) > 0: + return fmt.Errorf("can't combine --key with --shard") + + case len(a.Shards) > 255: + return fmt.Errorf("can't use more than 255 shards") + case a.Create && len(a.Shards) > 0 && len(a.Shards) < 2: + return fmt.Errorf("can't use less than 2 shards") + case a.Create && len(a.Shards) > 0 && a.Threshold <= 1: + return fmt.Errorf("--threshold must be > 1") + case a.Create && len(a.Shards) > 0 && a.Threshold > len(a.Shards): + return fmt.Errorf("--threshold must be <= %d", len(a.Shards)) + + case !a.Keygen && (a.Password || a.Key != "") && a.File == "": + return fmt.Errorf("must provide -f, --file") + case !a.Keygen && !a.Password && a.Key == "" && a.File == "" && len(a.Shards) == 0: + return fmt.Errorf("must provide -f, --file or --shard") + case !a.Keygen && a.File != "" && len(a.Shards) > 0: + return fmt.Errorf("can't combine -f, --file and --shard") + + case a.Keygen && (a.Public == "" || a.Private == ""): + return fmt.Errorf("keygen requires --public and --private") + + case a.Create && len(a.Names) == 0: + return fmt.Errorf("no files or directories specified") + } + + return nil +} + +func (a *Args) PreparePasswordArchive(mode int) (Archiver, error) { + file, err := os.OpenFile(a.File, mode, 0600) + if err != nil { + return nil, err + } + + password, err := ReadPassword() + if err != nil { + return nil, err + } + + return NewPasswordArchive(password, a.Iterations, a.Memory, file), nil +} + +func (a *Args) PrepareCurve448Archive(mode int) (Archiver, error) { + var publicKey PublicKey + var privateKey PrivateKey + var err error + + if mode&os.O_CREATE == os.O_CREATE { + err = a.LoadPublicKey(&publicKey) + } else { + err = a.LoadPrivateKey(&privateKey) + } + + if err != nil { + return nil, fmt.Errorf("file %s: %s", a.Key, err) + } + + file, err := os.OpenFile(a.File, mode, 0600) + if err != nil { + return nil, err + } + + return NewCurve448Archive(&publicKey, &privateKey, file), nil +} + +func (a *Args) PrepareShardArchive(mode int) (Archiver, error) { + files := make([]File, len(a.Shards)) + for i, path := range a.Shards { + file, err := os.OpenFile(path, mode, 0600) + if err != nil { + return nil, err + } + files[i] = file + } + return NewShardArchive(a.Threshold, files), nil +} + +func (a *Args) PrepareKeygen() (public *KeyContainer, private *KeyContainer, err error) { + mode := os.O_EXCL | os.O_CREATE | os.O_WRONLY + + public, err = a.OpenPublicKeyContainer(a.Public, mode) + if err != nil { + return nil, nil, fmt.Errorf("can't create public key: %s", err) + } + + private, err = a.OpenPrivateKeyContainer(a.Private, mode) + if err != nil { + return nil, nil, fmt.Errorf("can't create private key: %s", err) + } + + return public, private, err +} + +func (a *Args) LoadPublicKey(key *PublicKey) error { + c, err := a.OpenPublicKeyContainer(a.Key, os.O_RDONLY) + if err != nil { + return err + } + defer c.Close() + return c.ReadPublicKey(key) +} + +func (a *Args) LoadPrivateKey(key *PrivateKey) error { + c, err := a.OpenPrivateKeyContainer(a.Key, os.O_RDONLY) + if err != nil { + return err + } + defer c.Close() + return c.ReadPrivateKey(key) +} + +func (a *Args) OpenPublicKeyContainer(path string, mode int) (*KeyContainer, error) { + file, err := os.OpenFile(path, mode, 0600) + if err != nil { + return nil, err + } + return NewKeyContainer(file, []byte(""), 1, 8), nil +} + +func (a *Args) OpenPrivateKeyContainer(path string, mode int) (*KeyContainer, error) { + file, err := os.OpenFile(path, mode, 0600) + if err != nil { + return nil, err + } + + password, err := ReadPassword() + if err != nil { + return nil, err + } + + return NewKeyContainer(file, password, a.Iterations, a.Memory), nil +} + +func ReadPassword() ([]byte, error) { + fmt.Print("password: ") + b, err := terminal.ReadPassword(int(os.Stdin.Fd())) + fmt.Print("\n") + return b, err +} diff --git a/binary/binary.go b/binary/binary.go new file mode 100644 index 0000000..667f17f --- /dev/null +++ b/binary/binary.go @@ -0,0 +1,140 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package binary + +import ( + "encoding/binary" + "io" + "reflect" +) + +type ByteOrder binary.ByteOrder + +var ( + BE ByteOrder = binary.BigEndian + LE ByteOrder = binary.LittleEndian +) + +func Write(w io.Writer, order ByteOrder, data interface{}) error { + v := reflect.Indirect(reflect.ValueOf(data)) + t := v.Type() + + out := make([]byte, size(v, t)) + buf := out + + for i := 0; i < t.NumField(); i++ { + v := v.Field(i) + t := v.Type() + + if skip(v, t) { + continue + } + + switch t.Kind() { + case reflect.Int8: + buf[0] = byte(v.Int()) + case reflect.Uint8: + buf[0] = byte(v.Uint()) + case reflect.Int16: + order.PutUint16(buf, uint16(v.Int())) + case reflect.Uint16: + order.PutUint16(buf, uint16(v.Uint())) + case reflect.Int32: + order.PutUint32(buf, uint32(v.Int())) + case reflect.Uint32: + order.PutUint32(buf, uint32(v.Uint())) + case reflect.Int64: + order.PutUint64(buf, uint64(v.Int())) + case reflect.Uint64: + order.PutUint64(buf, uint64(v.Uint())) + case reflect.Array: + copy(buf, v.Slice(0, v.Len()).Bytes()) + } + + buf = buf[t.Size():] + } + + _, err := w.Write(out) + return err +} + +func Read(r io.Reader, order ByteOrder, data interface{}) error { + v := reflect.Indirect(reflect.ValueOf(data)) + t := v.Type() + + buf := make([]byte, size(v, t)) + + _, err := io.ReadFull(r, buf) + if err != nil { + return err + } + + for i := 0; i < t.NumField(); i++ { + v := v.Field(i) + t := v.Type() + + if skip(v, t) { + continue + } + + switch t.Kind() { + case reflect.Int8: + v.SetInt(int64(buf[0])) + case reflect.Uint8: + v.SetUint(uint64(buf[0])) + case reflect.Int16: + v.SetInt(int64(order.Uint16(buf))) + case reflect.Uint16: + v.SetUint(uint64(order.Uint16(buf))) + case reflect.Int32: + v.SetInt(int64(order.Uint32(buf))) + case reflect.Uint32: + v.SetUint(uint64(order.Uint32(buf))) + case reflect.Int64: + v.SetInt(int64(order.Uint64(buf))) + case reflect.Uint64: + v.SetUint(uint64(order.Uint64(buf))) + case reflect.Array: + reflect.Copy(v, reflect.ValueOf(buf)) + } + + buf = buf[t.Size():] + } + + return nil +} + +func size(v reflect.Value, t reflect.Type) uintptr { + size := uintptr(0) + + for i := 0; i < t.NumField(); i++ { + v := v.Field(i) + t := v.Type() + if !skip(v, t) { + size += t.Size() + } + } + + return size +} + +func skip(v reflect.Value, t reflect.Type) bool { + if !v.CanSet() { + return true + } + + switch t.Kind() { + case reflect.Int8, reflect.Uint8: + return false + case reflect.Int16, reflect.Uint16: + return false + case reflect.Int32, reflect.Uint32: + return false + case reflect.Int64, reflect.Uint64: + return false + case reflect.Array: + return t.Elem().Size() != 1 + } + + return true +} diff --git a/binary/binary_test.go b/binary/binary_test.go new file mode 100644 index 0000000..1bfdfa3 --- /dev/null +++ b/binary/binary_test.go @@ -0,0 +1,168 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package binary + +import ( + "bytes" + "encoding/binary" + "math" + "reflect" + "testing" +) + +func TestBinaryArray(t *testing.T) { + type Values struct { + Byte byte + Array [3]byte + Int64 int64 + } + + in := &Values{1, [3]byte{2, 3, 4}, 0xAC00BD00} + + buf := &bytes.Buffer{} + out := &Values{} + + if err := Write(buf, binary.LittleEndian, in); err != nil { + t.Fatal(err) + } + + if err := Read(buf, binary.LittleEndian, out); err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(in, out) { + t.Fatalf("round trip serialization failed") + } +} + +func TestBinaryMinMax(t *testing.T) { + type Values struct { + MinInt8 int8 + MaxInt8 int8 + MaxUint8 uint8 + MinInt16 int16 + MaxInt16 int16 + MaxUint16 uint16 + MinInt32 int32 + MaxInt32 int32 + MaxUint32 uint32 + MinInt64 int64 + MaxInt64 int64 + MaxUint64 uint64 + } + + in := &Values{ + MinInt8: math.MinInt8, + MaxInt8: math.MaxInt8, + MaxUint8: 1<<8 - 1, + MinInt16: math.MinInt16, + MaxInt16: math.MaxInt16, + MaxUint16: 1<<16 - 1, + MinInt32: math.MinInt32, + MaxInt32: math.MaxInt32, + MaxUint32: 1<<32 - 1, + MinInt64: math.MinInt64, + MaxInt64: math.MaxInt64, + MaxUint64: 1<<64 - 1, + } + + out := &Values{} + buf := &bytes.Buffer{} + + if err := Write(buf, binary.LittleEndian, in); err != nil { + t.Fatal(err) + } + + if err := Read(buf, binary.LittleEndian, out); err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(in, out) { + t.Fatalf("round trip serialization failed") + } +} + +func TestBinaryByteOrder(t *testing.T) { + type Values struct { + Uint16 uint16 + Uint32 uint32 + Uint64 uint64 + } + + in := &Values{ + Uint16: 0x1234, + Uint32: 0x12345678, + Uint64: 0x1234567890ABCDEF, + } + + little := []byte{0xEF, 0xCD, 0xAB, 0x90, 0x78, 0x56, 0x34, 0x12} + + buf := &bytes.Buffer{} + + if err := Write(buf, binary.LittleEndian, in); err != nil { + t.Fatal(err) + } + + if !bytes.Equal(buf.Bytes()[0:2], little[6:8]) { + t.Fatalf("uint16 little endian incorrect") + } + + if !bytes.Equal(buf.Bytes()[2:6], little[4:8]) { + t.Fatalf("uint32 little endian incorrect") + } + + if !bytes.Equal(buf.Bytes()[6:14], little[0:8]) { + t.Fatalf("uint64 little endian incorrect") + } + buf.Reset() + + big := []byte{0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF} + + if err := Write(buf, binary.BigEndian, in); err != nil { + t.Fatal(err) + } + + if !bytes.Equal(buf.Bytes()[0:2], big[0:2]) { + t.Fatalf("uint16 big endian incorrect") + } + + if !bytes.Equal(buf.Bytes()[2:6], big[0:4]) { + t.Fatalf("uint32 big endian incorrect") + } + + if !bytes.Equal(buf.Bytes()[6:14], big[0:8]) { + t.Fatalf("uint64 big endian incorrect") + } + +} + +func TestBinarySkip(t *testing.T) { + type Values struct { + A byte + B string + C int32 + D []byte + e byte + } + + in := &Values{1, "foo", 0xABCDEF, []byte("bar"), 2} + + out := &Values{} + buf := &bytes.Buffer{} + + if err := Write(buf, binary.LittleEndian, in); err != nil { + t.Fatal(err) + } + + if err := Read(buf, binary.LittleEndian, out); err != nil { + t.Fatal(err) + } + + in.B = "" + in.D = nil + in.e = 0 + + if !reflect.DeepEqual(in, out) { + t.Fatal("round trip serialization failed") + } +} diff --git a/bytesize.go b/bytesize.go new file mode 100644 index 0000000..9791f64 --- /dev/null +++ b/bytesize.go @@ -0,0 +1,43 @@ +// Copyright 2009 The Go 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 main + +import "fmt" + +type ByteSize float64 + +const ( + _ = iota // ignore first value by assigning to blank identifier + KB ByteSize = 1 << (10 * iota) + MB + GB + TB + PB + EB + ZB + YB +) + +func (b ByteSize) String() string { + switch { + case b >= YB: + return fmt.Sprintf("%.2fY", b/YB) + case b >= ZB: + return fmt.Sprintf("%.2fZ", b/ZB) + case b >= EB: + return fmt.Sprintf("%.2fE", b/EB) + case b >= PB: + return fmt.Sprintf("%.2fP", b/PB) + case b >= TB: + return fmt.Sprintf("%.2fT", b/TB) + case b >= GB: + return fmt.Sprintf("%.2fG", b/GB) + case b >= MB: + return fmt.Sprintf("%.2fM", b/MB) + case b >= KB: + return fmt.Sprintf("%.2fK", b/KB) + } + return fmt.Sprintf("%.2fB", b) +} diff --git a/create.go b/create.go new file mode 100644 index 0000000..2444e1f --- /dev/null +++ b/create.go @@ -0,0 +1,123 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package main + +import ( + "archive/tar" + "fmt" + "io" + "os" + "path/filepath" + + "github.com/wg/arc/archive" +) + +func (c *Cmd) Create(arc *archive.Writer, names ...string) error { + headers, errors := Scan(names) + for header := range headers { + name := header.Name + size := header.Size + + err := arc.Add(header) + if err != nil { + return err + } + + if header.Typeflag == tar.TypeReg { + r, err := os.Open(name) + if err != nil { + return err + } + + err = arc.Copy(r, size) + r.Close() + + if err != nil { + return err + } + } + + if c.Verbose > 0 { + fmt.Println("a", name) + } + } + + select { + case err := <-errors: + return err + default: + return nil + } +} + +func Scan(names []string) (<-chan *tar.Header, <-chan error) { + headers := make(chan *tar.Header, 64) + errors := make(chan error) + + go func() { + err := scan(names, headers) + close(headers) + if err != nil { + errors <- err + } + }() + + return headers, errors +} + +func scan(names []string, headers chan<- *tar.Header) error { + for _, name := range names { + info, err := os.Lstat(name) + if err != nil { + return err + } + + mode := info.Mode() + link := "" + + if !mode.IsRegular() && mode&(os.ModeDir|os.ModeSymlink) == 0 { + continue + } + + if mode&os.ModeSymlink != 0 { + link, err = os.Readlink(name) + if err != nil { + return err + } + } + + header, err := tar.FileInfoHeader(info, link) + if err != nil { + return err + } + + header.Name = name + headers <- header + + if mode.IsDir() { + dir, err := os.Open(name) + if err != nil { + return err + } + + for err == nil { + names, err = dir.Readdirnames(64) + if err != nil { + break + } + + for i, n := range names { + names[i] = filepath.Join(name, n) + } + + err = scan(names, headers) + } + dir.Close() + + if err != nil && err != io.EOF { + return err + } + } + } + return nil +} diff --git a/extract.go b/extract.go new file mode 100644 index 0000000..4730421 --- /dev/null +++ b/extract.go @@ -0,0 +1,90 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package main + +import ( + "archive/tar" + "fmt" + "io" + "os" + "path/filepath" + "time" + + "github.com/wg/arc/archive" +) + +func (c *Cmd) Extract(arc *RegexFilter) error { + mtimes := map[string]time.Time{} + + for arc.Next() { + h := arc.Header + + name := h.Name + mode := os.FileMode(h.Mode) + + var err error + switch h.Typeflag { + case tar.TypeReg, tar.TypeRegA: + err = extract(name, mode, h.Size, arc) + case tar.TypeDir: + err = os.Mkdir(name, mode) + case tar.TypeSymlink: + err = os.Symlink(h.Linkname, name) + } + + var action string + switch { + case os.IsExist(err): + action = "-" + case err != nil: + return err + default: + action = "x" + } + + if c.Verbose > 0 { + fmt.Println(action, name) + } + + mtimes[name] = h.ModTime + } + + switch { + case arc.Error != nil: + return arc.Error + case !arc.Verify(): + return ErrVerifyFailed + } + + ctime := time.Now() + for name, mtime := range mtimes { + err := os.Chtimes(name, ctime, mtime) + if err != nil { + return err + } + } + + return nil +} + +func extract(path string, mode os.FileMode, size int64, r io.Reader) error { + err := os.MkdirAll(filepath.Dir(path), 0) + if err != nil { + return err + } + + f, err := os.OpenFile(path, os.O_EXCL|os.O_CREATE|os.O_WRONLY, mode) + if err != nil { + return err + } + defer f.Close() + + switch n, err := io.Copy(f, r); { + case err != nil: + return err + case n < size: + return archive.ErrShortCopy + } + + return nil +} diff --git a/filter.go b/filter.go new file mode 100644 index 0000000..3991946 --- /dev/null +++ b/filter.go @@ -0,0 +1,42 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package main + +import ( + "archive/tar" + "io" + "regexp" + "strings" + + "github.com/wg/arc/archive" +) + +type RegexFilter struct { + Header *tar.Header + Error error + regex *regexp.Regexp + *archive.Reader +} + +func NewRegexFilter(r *archive.Reader, paths ...string) (*RegexFilter, error) { + regex, err := regexp.Compile(strings.Join(paths, "|")) + return &RegexFilter{ + regex: regex, + Reader: r, + }, err +} + +func (f *RegexFilter) Next() bool { + for { + switch header, err := f.Reader.Next(); { + case err == io.EOF: + return false + case err != nil: + f.Error = err + return false + case f.regex.MatchString(header.Name): + f.Header = header + return true + } + } +} diff --git a/key.go b/key.go new file mode 100644 index 0000000..12ffb1b --- /dev/null +++ b/key.go @@ -0,0 +1,170 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package main + +import ( + "crypto/rand" + "crypto/subtle" + "errors" + "io" + + "github.com/dchest/blake2b" + "github.com/magical/argon2" + "github.com/wg/arc/binary" + "github.com/wg/ecies" + "github.com/wg/ecies/xchacha20poly1305" +) + +const ( + Public = 0x01 + Private = 0x02 + NonSize = xchacha20poly1305.NonceSize + TagSize = xchacha20poly1305.TagSize +) + +type ( + PublicKey [56]byte + PrivateKey [56]byte +) + +type KeyContainer struct { + Version byte + Type byte + Iterations uint32 + Memory uint32 + Salt [32]byte + Tag [TagSize]byte + Nonce [NonSize]byte + Key [56]byte + Password []byte + File io.ReadWriteCloser +} + +var ( + ErrInvalidPublicKey = errors.New("invalid public key") + ErrInvalidPrivateKey = errors.New("invalid private key") +) + +func GenerateKeypair() (*PublicKey, *PrivateKey, error) { + var public, private [56]byte + err := ecies.GenerateCurve448Key(rand.Reader, &public, &private) + return (*PublicKey)(&public), (*PrivateKey)(&private), err +} + +func ComputeSharedKey(public *PublicKey, private *PrivateKey, size uint8) ([]byte, error) { + hash, err := blake2b.New(&blake2b.Config{Size: size}) + if err != nil { + return nil, err + } + + var secret [56]byte + err = ecies.X448(&secret, (*[56]byte)(public), (*[56]byte)(private)) + hash.Write(secret[:]) + + for i := range secret { + secret[i] = 0 + } + + return hash.Sum(nil), err +} + +func (private *PrivateKey) Zero() { + for i := range private { + private[i] = 0 + } +} + +func NewKeyContainer(file io.ReadWriteCloser, password []byte, iterations, memory uint32) *KeyContainer { + return &KeyContainer{ + Version: 1, + Iterations: iterations, + Memory: memory, + Password: password, + File: file, + } +} + +func (c *KeyContainer) ReadPublicKey(key *PublicKey) error { + return c.read(Public, (*[56]byte)(key)) +} + +func (c *KeyContainer) WritePublicKey(key *PublicKey) error { + return c.write(Public, (*[56]byte)(key)) +} + +func (c *KeyContainer) ReadPrivateKey(key *PrivateKey) error { + return c.read(Private, (*[56]byte)(key)) +} + +func (c *KeyContainer) WritePrivateKey(key *PrivateKey) error { + return c.write(Private, (*[56]byte)(key)) +} + +func (c *KeyContainer) Close() error { + return c.File.Close() +} + +func (c *KeyContainer) read(t byte, key *[56]byte) error { + switch err := binary.Read(c.File, binary.LE, c); { + case err != nil: + return err + case c.Type != t && t == Public: + return ErrInvalidPublicKey + case c.Type != t && t == Private: + return ErrInvalidPrivateKey + } + + var tag [TagSize]byte + x, err := c.cipher() + if err != nil { + return err + } + + x.Decrypt(key[:], c.Key[:]) + x.Tag(tag[:0]) + + if subtle.ConstantTimeCompare(c.Tag[:], tag[:]) != 1 { + return ErrInvalidPrivateKey + } + + return nil +} + +func (c *KeyContainer) write(t byte, key *[56]byte) error { + c.Type = t + + if _, err := rand.Read(c.Salt[:]); err != nil { + return err + } + + if _, err := rand.Read(c.Nonce[:]); err != nil { + return err + } + + x, err := c.cipher() + if err != nil { + return err + } + + x.Encrypt(c.Key[:], key[:]) + x.Tag(c.Tag[:0]) + + return binary.Write(c.File, binary.LE, c) +} + +func (c *KeyContainer) cipher() (*xchacha20poly1305.XChaCha20Poly1305, error) { + var ( + salt = c.Salt[:] + iterations = int(c.Iterations) + memory = int64(c.Memory) + keySize = xchacha20poly1305.KeySize + ) + + key, err := argon2.Key(c.Password, salt, iterations, 1, memory, keySize) + if err != nil { + return nil, err + } + + x := &xchacha20poly1305.XChaCha20Poly1305{} + return x, x.Init(key[:], c.Nonce[:]) +} diff --git a/key_test.go b/key_test.go new file mode 100644 index 0000000..9ddd328 --- /dev/null +++ b/key_test.go @@ -0,0 +1,152 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package main + +import ( + "bytes" + "testing" + + "github.com/magical/argon2" + "github.com/wg/arc/binary" + "github.com/wg/ecies/xchacha20poly1305" +) + +func TestPublicKeyFormat(t *testing.T) { + p, _ := keypair(t) + b, c := StorePublicKey(t, p) + + if b.buffer[1] != Public { + t.Fatal("serialized type incorrect") + } + + CheckKeyFormat(t, (*[56]byte)(p), b, c) +} + +func TestPrivateKeyFormat(t *testing.T) { + _, p := keypair(t) + b, c := StorePrivateKey(t, p) + + if b.buffer[1] != Private { + t.Fatal("serialized type incorrect") + } + + CheckKeyFormat(t, (*[56]byte)(p), b, c) +} + +func CheckKeyFormat(t *testing.T, k *[56]byte, b *Buffer, c *KeyContainer) { + key, err := argon2.Key(c.Password, c.Salt[:], int(c.Iterations), 1, int64(c.Memory), KeySize) + if err != nil { + t.Fatal("password key derivation failed", err) + } + + x := xchacha20poly1305.XChaCha20Poly1305{} + if err := x.Init(key, c.Nonce[:]); err != nil { + t.Fatal(err) + } + + dst := [56]byte{} + tag := [TagSize]byte{} + + x.Decrypt(dst[:], c.Key[:]) + x.Tag(tag[:0]) + + if !bytes.Equal(k[:], dst[:]) { + t.Fatal("decrypted key incorrect") + } + + if !bytes.Equal(tag[:], c.Tag[:]) { + t.Fatal("authentication tag incorrect") + } + + if binary.LE.Uint32(b.buffer[2:6]) != c.Iterations { + t.Fatal("serialized iterations incorrect") + } + + if binary.LE.Uint32(b.buffer[6:10]) != c.Memory { + t.Fatal("serialized memory incorrect") + } + + if !bytes.Equal(b.buffer[10:42], c.Salt[:]) { + t.Fatal("serialized salt incorrect") + } + + if !bytes.Equal(b.buffer[42:58], tag[:]) { + t.Fatal("serialized tag incorrect") + } + + if !bytes.Equal(b.buffer[58:82], c.Nonce[:]) { + t.Fatal("serialized nonce incorrect") + } +} + +func TestPublicPrivateKeypair(t *testing.T) { + pub, priv := keypair(t) + + shared0, err := ComputeSharedKey(pub, priv, KeySize) + if err != nil { + t.Fatal(err) + } + + _, puc := StorePublicKey(t, pub) + _, prc := StorePrivateKey(t, priv) + + priv.Zero() + + if err := puc.ReadPublicKey(pub); err != nil { + t.Fatal("failed to load public key", err) + } + + if err := prc.ReadPrivateKey(priv); err != nil { + t.Fatal("failed to load private key", err) + } + + shared1, err := ComputeSharedKey(pub, priv, KeySize) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(shared0, shared1) { + t.Fatal("serialized keys incorrect") + } +} + +func TestWrongKeyType(t *testing.T) { + pub, priv := keypair(t) + + _, pubc := StorePublicKey(t, pub) + _, privc := StorePrivateKey(t, priv) + + if err := pubc.ReadPrivateKey(priv); err != ErrInvalidPrivateKey { + t.Fatal("loaded public key as private key") + } + + if err := privc.ReadPublicKey(pub); err != ErrInvalidPublicKey { + t.Fatal("loaded private key as public key") + } +} + +func StorePublicKey(t *testing.T, key *PublicKey) (*Buffer, *KeyContainer) { + b := &Buffer{} + c := NewKeyContainer(b, []byte(""), 1, 8) + + if err := c.WritePublicKey(key); err != nil { + t.Fatal("failed to store public key", err) + } + + b.Rewind() + + return b, c +} + +func StorePrivateKey(t *testing.T, key *PrivateKey) (*Buffer, *KeyContainer) { + b := &Buffer{} + c := NewKeyContainer(b, []byte("secret"), 1, 8) + + if err := c.WritePrivateKey(key); err != nil { + t.Fatal("failed to store private key", err) + } + + b.Rewind() + + return b, c +} diff --git a/keygen.go b/keygen.go new file mode 100644 index 0000000..7a78595 --- /dev/null +++ b/keygen.go @@ -0,0 +1,20 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package main + +func (c *Cmd) Keygen(puc *KeyContainer, prc *KeyContainer) error { + public, private, err := GenerateKeypair() + if err != nil { + return err + } + + if err = puc.WritePublicKey(public); err != nil { + return err + } + + if err = prc.WritePrivateKey(private); err != nil { + return err + } + + return nil +} diff --git a/list.go b/list.go new file mode 100644 index 0000000..82bc64c --- /dev/null +++ b/list.go @@ -0,0 +1,72 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package main + +import ( + "archive/tar" + "errors" + "fmt" + "os" +) + +var ( + ErrVerifyFailed = errors.New("archive: verify failed") + ErrNoEntryFound = errors.New("archive: no entry found") +) + +func (c *Cmd) List(arc *RegexFilter) error { + matches := 0 + + for arc.Next() { + h := arc.Header + switch { + case c.Verbose > 0: + const layout = "%s %-6d %-6d %8s %s %s\n" + mode := mode(h) + size := size(h) + date := h.ModTime.Format("2006-01-02 15:04") + name := name(h) + fmt.Printf(layout, mode, h.Uid, h.Gid, size, date, name) + default: + fmt.Println(h.Name) + } + matches++ + } + + switch { + case arc.Error != nil: + return arc.Error + case !arc.Verify(): + return ErrVerifyFailed + case matches == 0: + return ErrNoEntryFound + } + + return nil +} + +func mode(h *tar.Header) string { + mode := os.FileMode(h.Mode) + switch h.Typeflag { + case tar.TypeDir: + mode |= os.ModeDir + case tar.TypeSymlink: + mode |= os.ModeSymlink + } + return mode.String() +} + +func size(h *tar.Header) string { + if h.Size == 0 { + return "0" + } + return ByteSize(h.Size).String() +} + +func name(h *tar.Header) string { + name := h.Name + if h.Typeflag == tar.TypeSymlink { + name += " -> " + h.Linkname + } + return name +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..1972cad --- /dev/null +++ b/main.go @@ -0,0 +1,73 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package main + +import ( + "fmt" + "os" + + "github.com/wg/arc/archive" +) + +type Cmd struct { + Op interface{} + Archiver Archiver + Verbose int + Names []string + Private *KeyContainer + Public *KeyContainer +} + +func main() { + c, err := NewCommand() + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + switch op := c.Op.(type) { + case func(*archive.Writer, ...string) error: + arc := c.createArchive() + err = op(arc.Writer, c.Names...) + defer arc.Close() + case func(*RegexFilter) error: + arc, filter := c.filterArchive() + err = op(filter) + defer arc.Close() + case func(*KeyContainer, *KeyContainer) error: + err = op(c.Public, c.Private) + defer c.Public.Close() + defer c.Private.Close() + } + + if err != nil { + c.Fatal(err) + } +} + +func (c *Cmd) createArchive() *Writer { + arc, err := c.Archiver.Writer() + if err != nil { + c.Fatal(err) + } + return arc +} + +func (c *Cmd) filterArchive() (*Reader, *RegexFilter) { + arc, err := c.Archiver.Reader() + if err != nil { + c.Fatal(err) + } + + f, err := NewRegexFilter(arc.Reader, c.Names...) + if err != nil { + c.Fatal(err) + } + + return arc, f +} + +func (c *Cmd) Fatal(v ...interface{}) { + fmt.Println(v...) + os.Exit(1) +} diff --git a/vendor/github.com/codahale/sss/LICENSE b/vendor/github.com/codahale/sss/LICENSE new file mode 100644 index 0000000..f9835c2 --- /dev/null +++ b/vendor/github.com/codahale/sss/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Coda Hale + +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/codahale/sss/README.md b/vendor/github.com/codahale/sss/README.md new file mode 100644 index 0000000..f659012 --- /dev/null +++ b/vendor/github.com/codahale/sss/README.md @@ -0,0 +1,11 @@ +# sss (Shamir's Secret Sharing) + +[![Build Status](https://travis-ci.org/codahale/sss.png?branch=master)](https://travis-ci.org/codahale/sss) + +A pure Go implementation of +[Shamir's Secret Sharing algorithm](http://en.wikipedia.org/wiki/Shamir's_Secret_Sharing) +over GF(2^8). + +Inspired by @hbs's [Python implementation](https://github.com/hbs/PySSSS). + +For documentation, check [godoc](http://godoc.org/github.com/codahale/sss). diff --git a/vendor/github.com/codahale/sss/gf256.go b/vendor/github.com/codahale/sss/gf256.go new file mode 100644 index 0000000..bff81ae --- /dev/null +++ b/vendor/github.com/codahale/sss/gf256.go @@ -0,0 +1,81 @@ +package sss + +func mul(e, a byte) byte { + if e == 0 || a == 0 { + return 0 + } + return exp[(int(log[e])+int(log[a]))%255] +} + +func div(e, a byte) byte { + if a == 0 { + panic("div by zero") + } + + if e == 0 { + return 0 + } + + p := (int(log[e]) - int(log[a])) % 255 + if p < 0 { + p += 255 + } + + return exp[p] +} + +const ( + fieldSize = 256 // 2^8 +) + +var ( + // 0x11b prime polynomial and 0x03 as generator + exp = [fieldSize]byte{ + 0x01, 0x03, 0x05, 0x0f, 0x11, 0x33, 0x55, 0xff, 0x1a, 0x2e, 0x72, 0x96, + 0xa1, 0xf8, 0x13, 0x35, 0x5f, 0xe1, 0x38, 0x48, 0xd8, 0x73, 0x95, 0xa4, + 0xf7, 0x02, 0x06, 0x0a, 0x1e, 0x22, 0x66, 0xaa, 0xe5, 0x34, 0x5c, 0xe4, + 0x37, 0x59, 0xeb, 0x26, 0x6a, 0xbe, 0xd9, 0x70, 0x90, 0xab, 0xe6, 0x31, + 0x53, 0xf5, 0x04, 0x0c, 0x14, 0x3c, 0x44, 0xcc, 0x4f, 0xd1, 0x68, 0xb8, + 0xd3, 0x6e, 0xb2, 0xcd, 0x4c, 0xd4, 0x67, 0xa9, 0xe0, 0x3b, 0x4d, 0xd7, + 0x62, 0xa6, 0xf1, 0x08, 0x18, 0x28, 0x78, 0x88, 0x83, 0x9e, 0xb9, 0xd0, + 0x6b, 0xbd, 0xdc, 0x7f, 0x81, 0x98, 0xb3, 0xce, 0x49, 0xdb, 0x76, 0x9a, + 0xb5, 0xc4, 0x57, 0xf9, 0x10, 0x30, 0x50, 0xf0, 0x0b, 0x1d, 0x27, 0x69, + 0xbb, 0xd6, 0x61, 0xa3, 0xfe, 0x19, 0x2b, 0x7d, 0x87, 0x92, 0xad, 0xec, + 0x2f, 0x71, 0x93, 0xae, 0xe9, 0x20, 0x60, 0xa0, 0xfb, 0x16, 0x3a, 0x4e, + 0xd2, 0x6d, 0xb7, 0xc2, 0x5d, 0xe7, 0x32, 0x56, 0xfa, 0x15, 0x3f, 0x41, + 0xc3, 0x5e, 0xe2, 0x3d, 0x47, 0xc9, 0x40, 0xc0, 0x5b, 0xed, 0x2c, 0x74, + 0x9c, 0xbf, 0xda, 0x75, 0x9f, 0xba, 0xd5, 0x64, 0xac, 0xef, 0x2a, 0x7e, + 0x82, 0x9d, 0xbc, 0xdf, 0x7a, 0x8e, 0x89, 0x80, 0x9b, 0xb6, 0xc1, 0x58, + 0xe8, 0x23, 0x65, 0xaf, 0xea, 0x25, 0x6f, 0xb1, 0xc8, 0x43, 0xc5, 0x54, + 0xfc, 0x1f, 0x21, 0x63, 0xa5, 0xf4, 0x07, 0x09, 0x1b, 0x2d, 0x77, 0x99, + 0xb0, 0xcb, 0x46, 0xca, 0x45, 0xcf, 0x4a, 0xde, 0x79, 0x8b, 0x86, 0x91, + 0xa8, 0xe3, 0x3e, 0x42, 0xc6, 0x51, 0xf3, 0x0e, 0x12, 0x36, 0x5a, 0xee, + 0x29, 0x7b, 0x8d, 0x8c, 0x8f, 0x8a, 0x85, 0x94, 0xa7, 0xf2, 0x0d, 0x17, + 0x39, 0x4b, 0xdd, 0x7c, 0x84, 0x97, 0xa2, 0xfd, 0x1c, 0x24, 0x6c, 0xb4, + 0xc7, 0x52, 0xf6, 0x01, + } + log = [fieldSize]byte{ + 0x00, 0x00, 0x19, 0x01, 0x32, 0x02, 0x1a, 0xc6, 0x4b, 0xc7, 0x1b, 0x68, + 0x33, 0xee, 0xdf, 0x03, 0x64, 0x04, 0xe0, 0x0e, 0x34, 0x8d, 0x81, 0xef, + 0x4c, 0x71, 0x08, 0xc8, 0xf8, 0x69, 0x1c, 0xc1, 0x7d, 0xc2, 0x1d, 0xb5, + 0xf9, 0xb9, 0x27, 0x6a, 0x4d, 0xe4, 0xa6, 0x72, 0x9a, 0xc9, 0x09, 0x78, + 0x65, 0x2f, 0x8a, 0x05, 0x21, 0x0f, 0xe1, 0x24, 0x12, 0xf0, 0x82, 0x45, + 0x35, 0x93, 0xda, 0x8e, 0x96, 0x8f, 0xdb, 0xbd, 0x36, 0xd0, 0xce, 0x94, + 0x13, 0x5c, 0xd2, 0xf1, 0x40, 0x46, 0x83, 0x38, 0x66, 0xdd, 0xfd, 0x30, + 0xbf, 0x06, 0x8b, 0x62, 0xb3, 0x25, 0xe2, 0x98, 0x22, 0x88, 0x91, 0x10, + 0x7e, 0x6e, 0x48, 0xc3, 0xa3, 0xb6, 0x1e, 0x42, 0x3a, 0x6b, 0x28, 0x54, + 0xfa, 0x85, 0x3d, 0xba, 0x2b, 0x79, 0x0a, 0x15, 0x9b, 0x9f, 0x5e, 0xca, + 0x4e, 0xd4, 0xac, 0xe5, 0xf3, 0x73, 0xa7, 0x57, 0xaf, 0x58, 0xa8, 0x50, + 0xf4, 0xea, 0xd6, 0x74, 0x4f, 0xae, 0xe9, 0xd5, 0xe7, 0xe6, 0xad, 0xe8, + 0x2c, 0xd7, 0x75, 0x7a, 0xeb, 0x16, 0x0b, 0xf5, 0x59, 0xcb, 0x5f, 0xb0, + 0x9c, 0xa9, 0x51, 0xa0, 0x7f, 0x0c, 0xf6, 0x6f, 0x17, 0xc4, 0x49, 0xec, + 0xd8, 0x43, 0x1f, 0x2d, 0xa4, 0x76, 0x7b, 0xb7, 0xcc, 0xbb, 0x3e, 0x5a, + 0xfb, 0x60, 0xb1, 0x86, 0x3b, 0x52, 0xa1, 0x6c, 0xaa, 0x55, 0x29, 0x9d, + 0x97, 0xb2, 0x87, 0x90, 0x61, 0xbe, 0xdc, 0xfc, 0xbc, 0x95, 0xcf, 0xcd, + 0x37, 0x3f, 0x5b, 0xd1, 0x53, 0x39, 0x84, 0x3c, 0x41, 0xa2, 0x6d, 0x47, + 0x14, 0x2a, 0x9e, 0x5d, 0x56, 0xf2, 0xd3, 0xab, 0x44, 0x11, 0x92, 0xd9, + 0x23, 0x20, 0x2e, 0x89, 0xb4, 0x7c, 0xb8, 0x26, 0x77, 0x99, 0xe3, 0xa5, + 0x67, 0x4a, 0xed, 0xde, 0xc5, 0x31, 0xfe, 0x18, 0x0d, 0x63, 0x8c, 0x80, + 0xc0, 0xf7, 0x70, 0x07, + } +) diff --git a/vendor/github.com/codahale/sss/gf256_test.go b/vendor/github.com/codahale/sss/gf256_test.go new file mode 100644 index 0000000..fe4f2ea --- /dev/null +++ b/vendor/github.com/codahale/sss/gf256_test.go @@ -0,0 +1,35 @@ +package sss + +import ( + "testing" +) + +func TestMul(t *testing.T) { + if v, want := mul(90, 21), byte(254); v != want { + t.Errorf("Was %v, but expected %v", v, want) + } +} + +func TestDiv(t *testing.T) { + if v, want := div(90, 21), byte(189); v != want { + t.Errorf("Was %v, but expected %v", v, want) + } +} + +func TestDivZero(t *testing.T) { + if v, want := div(0, 2), byte(0); v != want { + t.Errorf("Was %v, but expected %v", v, want) + } +} + +func TestDivByZero(t *testing.T) { + defer func() { + m := recover() + if m != "div by zero" { + t.Error(m) + } + }() + + div(2, 0) + t.Error("Shouldn't have been able to divide those") +} diff --git a/vendor/github.com/codahale/sss/polynomial.go b/vendor/github.com/codahale/sss/polynomial.go new file mode 100644 index 0000000..b8b183a --- /dev/null +++ b/vendor/github.com/codahale/sss/polynomial.go @@ -0,0 +1,67 @@ +package sss + +import "io" + +// the degree of the polynomial +func degree(p []byte) int { + return len(p) - 1 +} + +// evaluate the polynomial at the given point +func eval(p []byte, x byte) (result byte) { + // Horner's scheme + for i := 1; i <= len(p); i++ { + result = mul(result, x) ^ p[len(p)-i] + } + return +} + +// generates a random n-degree polynomial w/ a given x-intercept +func generate(degree byte, x byte, rand io.Reader) ([]byte, error) { + result := make([]byte, degree+1) + result[0] = x + + buf := make([]byte, degree-1) + if _, err := io.ReadFull(rand, buf); err != nil { + return nil, err + } + + for i := byte(1); i < degree; i++ { + result[i] = buf[i-1] + } + + // the Nth term can't be zero, or else it's a (N-1) degree polynomial + for { + buf = make([]byte, 1) + if _, err := io.ReadFull(rand, buf); err != nil { + return nil, err + } + + if buf[0] != 0 { + result[degree] = buf[0] + return result, nil + } + } +} + +// an input/output pair +type pair struct { + x, y byte +} + +// Lagrange interpolation +func interpolate(points []pair, x byte) (value byte) { + for i, a := range points { + weight := byte(1) + for j, b := range points { + if i != j { + top := x ^ b.x + bottom := a.x ^ b.x + factor := div(top, bottom) + weight = mul(weight, factor) + } + } + value = value ^ mul(weight, a.y) + } + return +} diff --git a/vendor/github.com/codahale/sss/polynomial_test.go b/vendor/github.com/codahale/sss/polynomial_test.go new file mode 100644 index 0000000..2783b6a --- /dev/null +++ b/vendor/github.com/codahale/sss/polynomial_test.go @@ -0,0 +1,89 @@ +package sss + +import ( + "bytes" + "testing" +) + +var ( + p = []byte{1, 0, 2, 3} + p2 = []byte{70, 32, 6} +) + +func TestDegree(t *testing.T) { + if v, want := degree(p), 3; v != want { + t.Errorf("Was %v, but expected %v", v, want) + } +} + +func TestEval(t *testing.T) { + if v, want := eval(p, 2), byte(17); v != want { + t.Errorf("Was %v, but expected %v", v, want) + } +} + +func TestGenerate(t *testing.T) { + b := []byte{1, 2, 3} + + expected := []byte{10, 1, 2, 3} + actual, err := generate(3, 10, bytes.NewReader(b)) + if err != nil { + t.Error(err) + } + + if !bytes.Equal(actual, expected) { + t.Errorf("Was %v, but expected %v", actual, expected) + } +} + +func TestGenerateEOF(t *testing.T) { + b := []byte{1} + + p, err := generate(3, 10, bytes.NewReader(b)) + if p != nil { + t.Errorf("Was %v, but expected an error", p) + } + + if err == nil { + t.Error("No error returned") + } +} + +func TestGeneratePolyEOFFullSize(t *testing.T) { + b := []byte{1, 2, 0, 0, 0, 0} + + p, err := generate(3, 10, bytes.NewReader(b)) + if p != nil { + t.Errorf("Was %v, but xpected an error", p) + } + + if err == nil { + t.Error("No error returned") + } +} + +func TestGenerateFullSize(t *testing.T) { + b := []byte{1, 2, 0, 4} + + expected := []byte{10, 1, 2, 4} + actual, err := generate(3, 10, bytes.NewReader(b)) + if err != nil { + t.Error(err) + } + + if !bytes.Equal(actual, expected) { + t.Errorf("Was %v but expected %v", actual, expected) + } +} + +func TestInterpolate(t *testing.T) { + in := []pair{ + pair{x: 1, y: 1}, + pair{x: 2, y: 2}, + pair{x: 3, y: 3}, + } + + if v, want := interpolate(in, 0), byte(0); v != want { + t.Errorf("Was %v, but expected %v", v, want) + } +} diff --git a/vendor/github.com/codahale/sss/sss.go b/vendor/github.com/codahale/sss/sss.go new file mode 100644 index 0000000..5c37a76 --- /dev/null +++ b/vendor/github.com/codahale/sss/sss.go @@ -0,0 +1,102 @@ +// Package sss implements Shamir's Secret Sharing algorithm over GF(2^8). +// +// Shamir's Secret Sharing algorithm allows you to securely share a secret with +// N people, allowing the recovery of that secret if K of those people combine +// their shares. +// +// It begins by encoding a secret as a number (e.g., 42), and generating N +// random polynomial equations of degree K-1 which have an X-intercept equal to +// the secret. Given K=3, the following equations might be generated: +// +// f1(x) = 78x^2 + 19x + 42 +// f2(x) = 128x^2 + 171x + 42 +// f3(x) = 121x^2 + 3x + 42 +// f4(x) = 91x^2 + 95x + 42 +// etc. +// +// These polynomials are then evaluated for values of X > 0: +// +// f1(1) = 139 +// f2(2) = 896 +// f3(3) = 1140 +// f4(4) = 1783 +// etc. +// +// These (x, y) pairs are the shares given to the parties. In order to combine +// shares to recover the secret, these (x, y) pairs are used as the input points +// for Lagrange interpolation, which produces a polynomial which matches the +// given points. This polynomial can be evaluated for f(0), producing the secret +// value--the common x-intercept for all the generated polynomials. +// +// If fewer than K shares are combined, the interpolated polynomial will be +// wrong, and the result of f(0) will not be the secret. +// +// This package constructs polynomials over the field GF(2^8) for each byte of +// the secret, allowing for fast splitting and combining of anything which can +// be encoded as bytes. +// +// This package has not been audited by cryptography or security professionals. +package sss + +import ( + "crypto/rand" + "errors" +) + +var ( + // ErrInvalidCount is returned when the count parameter is invalid. + ErrInvalidCount = errors.New("N must be > 1") + // ErrInvalidThreshold is returned when the threshold parameter is invalid. + ErrInvalidThreshold = errors.New("K must be > 1") +) + +// Split the given secret into N shares of which K are required to recover the +// secret. Returns a map of share IDs (1-255) to shares. +func Split(n, k byte, secret []byte) (map[byte][]byte, error) { + if n <= 1 { + return nil, ErrInvalidCount + } + + if k <= 1 { + return nil, ErrInvalidThreshold + } + + shares := make(map[byte][]byte, n) + + for _, b := range secret { + p, err := generate(k-1, b, rand.Reader) + if err != nil { + return nil, err + } + + for x := byte(1); x <= n; x++ { + shares[x] = append(shares[x], eval(p, x)) + } + } + + return shares, nil +} + +// Combine the given shares into the original secret. +// +// N.B.: There is no way to know whether the returned value is, in fact, the +// original secret. +func Combine(shares map[byte][]byte) []byte { + var secret []byte + for _, v := range shares { + secret = make([]byte, len(v)) + break + } + + points := make([]pair, len(shares)) + for i := range secret { + p := 0 + for k, v := range shares { + points[p] = pair{x: k, y: v[i]} + p++ + } + secret[i] = interpolate(points, 0) + } + + return secret +} diff --git a/vendor/github.com/codahale/sss/sss_test.go b/vendor/github.com/codahale/sss/sss_test.go new file mode 100644 index 0000000..57846ee --- /dev/null +++ b/vendor/github.com/codahale/sss/sss_test.go @@ -0,0 +1,32 @@ +package sss + +import ( + "fmt" +) + +func Example() { + secret := "well hello there!" // our secret + n := byte(30) // create 30 shares + k := byte(2) // require 2 of them to combine + + shares, err := Split(n, k, []byte(secret)) // split into 30 shares + if err != nil { + fmt.Println(err) + return + } + + // select a random subset of the total shares + subset := make(map[byte][]byte, k) + for x, y := range shares { // just iterate since maps are randomized + subset[x] = y + if len(subset) == int(k) { + break + } + } + + // combine two shares and recover the secret + recovered := string(Combine(subset)) + fmt.Println(recovered) + + // Output: well hello there! +} diff --git a/vendor/github.com/dchest/blake2b/README b/vendor/github.com/dchest/blake2b/README new file mode 100644 index 0000000..09f0143 --- /dev/null +++ b/vendor/github.com/dchest/blake2b/README @@ -0,0 +1,23 @@ +Go implementation of BLAKE2b collision-resistant cryptographic hash function +created by Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn, and +Christian Winnerlein (https://blake2.net). + +INSTALLATION + + $ go get github.com/dchest/blake2b + + +DOCUMENTATION + + See http://godoc.org/github.com/dchest/blake2b + + +PUBLIC DOMAIN DEDICATION + +Written in 2012 by Dmitry Chestnykh. + +To the extent possible under law, the author have dedicated all copyright +and related and neighboring rights to this software to the public domain +worldwide. This software is distributed without any warranty. +http://creativecommons.org/publicdomain/zero/1.0/ + diff --git a/vendor/github.com/dchest/blake2b/blake2b.go b/vendor/github.com/dchest/blake2b/blake2b.go new file mode 100644 index 0000000..f3eb388 --- /dev/null +++ b/vendor/github.com/dchest/blake2b/blake2b.go @@ -0,0 +1,299 @@ +// Written in 2012 by Dmitry Chestnykh. +// +// To the extent possible under law, the author have dedicated all copyright +// and related and neighboring rights to this software to the public domain +// worldwide. This software is distributed without any warranty. +// http://creativecommons.org/publicdomain/zero/1.0/ + +// Package blake2b implements BLAKE2b cryptographic hash function. +package blake2b + +import ( + "encoding/binary" + "errors" + "hash" +) + +const ( + BlockSize = 128 // block size of algorithm + Size = 64 // maximum digest size + SaltSize = 16 // maximum salt size + PersonSize = 16 // maximum personalization string size + KeySize = 64 // maximum size of key +) + +type digest struct { + h [8]uint64 // current chain value + t [2]uint64 // message bytes counter + f [2]uint64 // finalization flags + x [BlockSize]byte // buffer for data not yet compressed + nx int // number of bytes in buffer + + ih [8]uint64 // initial chain value (after config) + paddedKey [BlockSize]byte // copy of key, padded with zeros + isKeyed bool // indicates whether hash was keyed + size uint8 // digest size in bytes + isLastNode bool // indicates processing of the last node in tree hashing +} + +// Initialization values. +var iv = [8]uint64{ + 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, + 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, 0x9b05688c2b3e6c1f, + 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, +} + +// Config is used to configure hash function parameters and keying. +// All parameters are optional. +type Config struct { + Size uint8 // digest size (if zero, default size of 64 bytes is used) + Key []byte // key for prefix-MAC + Salt []byte // salt (if < 16 bytes, padded with zeros) + Person []byte // personalization (if < 16 bytes, padded with zeros) + Tree *Tree // parameters for tree hashing +} + +// Tree represents parameters for tree hashing. +type Tree struct { + Fanout uint8 // fanout + MaxDepth uint8 // maximal depth + LeafSize uint32 // leaf maximal byte length (0 for unlimited) + NodeOffset uint64 // node offset (0 for first, leftmost or leaf) + NodeDepth uint8 // node depth (0 for leaves) + InnerHashSize uint8 // inner hash byte length + IsLastNode bool // indicates processing of the last node of layer +} + +var ( + defaultConfig = &Config{Size: Size} + config256 = &Config{Size: 32} +) + +func verifyConfig(c *Config) error { + if c.Size > Size { + return errors.New("digest size is too large") + } + if len(c.Key) > KeySize { + return errors.New("key is too large") + } + if len(c.Salt) > SaltSize { + // Smaller salt is okay: it will be padded with zeros. + return errors.New("salt is too large") + } + if len(c.Person) > PersonSize { + // Smaller personalization is okay: it will be padded with zeros. + return errors.New("personalization is too large") + } + if c.Tree != nil { + if c.Tree.Fanout == 1 { + return errors.New("fanout of 1 is not allowed in tree mode") + } + if c.Tree.MaxDepth < 2 { + return errors.New("incorrect tree depth") + } + if c.Tree.InnerHashSize < 1 || c.Tree.InnerHashSize > Size { + return errors.New("incorrect tree inner hash size") + } + } + return nil +} + +// New returns a new hash.Hash configured with the given Config. +// Config can be nil, in which case the default one is used, calculating 64-byte digest. +// Returns non-nil error if Config contains invalid parameters. +func New(c *Config) (hash.Hash, error) { + if c == nil { + c = defaultConfig + } else { + if c.Size == 0 { + // Set default size if it's zero. + c.Size = Size + } + if err := verifyConfig(c); err != nil { + return nil, err + } + } + d := new(digest) + d.initialize(c) + return d, nil +} + +// initialize initializes digest with the given +// config, which must be non-nil and verified. +func (d *digest) initialize(c *Config) { + // Create parameter block. + var p [BlockSize]byte + p[0] = c.Size + p[1] = uint8(len(c.Key)) + if c.Salt != nil { + copy(p[32:], c.Salt) + } + if c.Person != nil { + copy(p[48:], c.Person) + } + if c.Tree != nil { + p[2] = c.Tree.Fanout + p[3] = c.Tree.MaxDepth + binary.LittleEndian.PutUint32(p[4:], c.Tree.LeafSize) + binary.LittleEndian.PutUint64(p[8:], c.Tree.NodeOffset) + p[16] = c.Tree.NodeDepth + p[17] = c.Tree.InnerHashSize + } else { + p[2] = 1 + p[3] = 1 + } + // Initialize. + d.size = c.Size + for i := 0; i < 8; i++ { + d.h[i] = iv[i] ^ binary.LittleEndian.Uint64(p[i*8:]) + } + if c.Tree != nil && c.Tree.IsLastNode { + d.isLastNode = true + } + // Process key. + if c.Key != nil { + copy(d.paddedKey[:], c.Key) + d.Write(d.paddedKey[:]) + d.isKeyed = true + } + // Save a copy of initialized state. + copy(d.ih[:], d.h[:]) +} + +// New512 returns a new hash.Hash computing the BLAKE2b 64-byte checksum. +func New512() hash.Hash { + d := new(digest) + d.initialize(defaultConfig) + return d +} + +// New256 returns a new hash.Hash computing the BLAKE2b 32-byte checksum. +func New256() hash.Hash { + d := new(digest) + d.initialize(config256) + return d +} + +// NewMAC returns a new hash.Hash computing BLAKE2b prefix- +// Message Authentication Code of the given size in bytes +// (up to 64) with the given key (up to 64 bytes in length). +func NewMAC(outBytes uint8, key []byte) hash.Hash { + d, err := New(&Config{Size: outBytes, Key: key}) + if err != nil { + panic(err.Error()) + } + return d +} + +// Reset resets the state of digest to the initial state +// after configuration and keying. +func (d *digest) Reset() { + copy(d.h[:], d.ih[:]) + d.t[0] = 0 + d.t[1] = 0 + d.f[0] = 0 + d.f[1] = 0 + d.nx = 0 + if d.isKeyed { + d.Write(d.paddedKey[:]) + } +} + +// Size returns the digest size in bytes. +func (d *digest) Size() int { return int(d.size) } + +// BlockSize returns the algorithm block size in bytes. +func (d *digest) BlockSize() int { return BlockSize } + +func (d *digest) Write(p []byte) (nn int, err error) { + nn = len(p) + left := BlockSize - d.nx + if len(p) > left { + // Process buffer. + copy(d.x[d.nx:], p[:left]) + p = p[left:] + blocks(d, d.x[:]) + d.nx = 0 + } + // Process full blocks except for the last one. + if len(p) > BlockSize { + n := len(p) &^ (BlockSize - 1) + if n == len(p) { + n -= BlockSize + } + blocks(d, p[:n]) + p = p[n:] + } + // Fill buffer. + d.nx += copy(d.x[d.nx:], p) + return +} + +// Sum returns the calculated checksum. +func (d0 *digest) Sum(in []byte) []byte { + // Make a copy of d0 so that caller can keep writing and summing. + d := *d0 + hash := d.checkSum() + return append(in, hash[:d.size]...) +} + +func (d *digest) checkSum() [Size]byte { + // Do not create unnecessary copies of the key. + if d.isKeyed { + for i := 0; i < len(d.paddedKey); i++ { + d.paddedKey[i] = 0 + } + } + + dec := BlockSize - uint64(d.nx) + if d.t[0] < dec { + d.t[1]-- + } + d.t[0] -= dec + + // Pad buffer with zeros. + for i := d.nx; i < len(d.x); i++ { + d.x[i] = 0 + } + // Set last block flag. + d.f[0] = 0xffffffffffffffff + if d.isLastNode { + d.f[1] = 0xffffffffffffffff + } + // Compress last block. + blocks(d, d.x[:]) + + var out [Size]byte + j := 0 + for _, s := range d.h[:(d.size-1)/8+1] { + out[j+0] = byte(s >> 0) + out[j+1] = byte(s >> 8) + out[j+2] = byte(s >> 16) + out[j+3] = byte(s >> 24) + out[j+4] = byte(s >> 32) + out[j+5] = byte(s >> 40) + out[j+6] = byte(s >> 48) + out[j+7] = byte(s >> 56) + j += 8 + } + return out +} + +// Sum512 returns a 64-byte BLAKE2b hash of data. +func Sum512(data []byte) [64]byte { + var d digest + d.initialize(defaultConfig) + d.Write(data) + return d.checkSum() +} + +// Sum256 returns a 32-byte BLAKE2b hash of data. +func Sum256(data []byte) (out [32]byte) { + var d digest + d.initialize(config256) + d.Write(data) + sum := d.checkSum() + copy(out[:], sum[:32]) + return +} diff --git a/vendor/github.com/dchest/blake2b/blake2b_test.go b/vendor/github.com/dchest/blake2b/blake2b_test.go new file mode 100644 index 0000000..38e4c28 --- /dev/null +++ b/vendor/github.com/dchest/blake2b/blake2b_test.go @@ -0,0 +1,625 @@ +// Written in 2012 by Dmitry Chestnykh. +// +// To the extent possible under law, the author have dedicated all copyright +// and related and neighboring rights to this software to the public domain +// worldwide. This software is distributed without any warranty. +// http://creativecommons.org/publicdomain/zero/1.0/ + +package blake2b + +import ( + "fmt" + "testing" +) + +func TestSum(t *testing.T) { + buf := make([]byte, len(golden)) + for i := range buf { + buf[i] = byte(i) + } + h := New512() + for i, v := range golden { + if v != fmt.Sprintf("%x", Sum512(buf[:i])) { + t.Errorf("%d: Sum512(): \nexpected %s\ngot %x", i, v, Sum512(buf[:i])) + } + h.Reset() + h.Write(buf[:i]) + sum := h.Sum(nil) + if fmt.Sprintf("%x", sum) != v { + t.Errorf("%d:\nexpected %s\ngot %x", i, v, sum) + } + + } +} + +func TestSum256(t *testing.T) { + // Simple one-hash test. + in := "The cryptographic hash function BLAKE2 is an improved version of the SHA-3 finalist BLAKE" + good := "e5866d0c42b4e27e89a316fa5c3ba8cacae754e53d8267da37ba1893c2fcd92c" + if good != fmt.Sprintf("%x", Sum256([]byte(in))) { + t.Errorf("Sum256(): \nexpected %s\ngot %x", good, Sum256([]byte(in))) + } + +} + +func TestSumLength(t *testing.T) { + h, _ := New(&Config{Size: 19}) + sum := h.Sum(nil) + if len(sum) != 19 { + t.Fatalf("Sum() returned a slice larger than the given hash size") + } +} + +func TestKeyedSum(t *testing.T) { + buf := make([]byte, len(goldenKeyed)) + for i := range buf { + buf[i] = byte(i) + } + h := NewMAC(64, buf[:64]) + for i, v := range goldenKeyed { + h.Reset() + h.Write(buf[:i]) + sum := h.Sum(nil) + if fmt.Sprintf("%x", sum) != v { + t.Errorf("%d:\nexpected %s\ngot %x", i, v, sum) + } + + } +} + +var bench = New512() +var buf = make([]byte, 8<<10) + +func BenchmarkWrite1K(b *testing.B) { + b.SetBytes(1024) + for i := 0; i < b.N; i++ { + bench.Write(buf[:1024]) + } +} + +func BenchmarkWrite8K(b *testing.B) { + b.SetBytes(int64(len(buf))) + for i := 0; i < b.N; i++ { + bench.Write(buf) + } +} + +func BenchmarkHash64(b *testing.B) { + b.SetBytes(64) + for i := 0; i < b.N; i++ { + Sum512(buf[:64]) + } +} + +func BenchmarkHash128(b *testing.B) { + b.SetBytes(128) + for i := 0; i < b.N; i++ { + Sum512(buf[:128]) + } +} + +func BenchmarkHash1K(b *testing.B) { + b.SetBytes(1024) + for i := 0; i < b.N; i++ { + Sum512(buf[:1024]) + } +} + +// Test vectors taken from reference implementation in C#. +var golden = []string{ + "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce", + "2fa3f686df876995167e7c2e5d74c4c7b6e48f8068fe0e44208344d480f7904c36963e44115fe3eb2a3ac8694c28bcb4f5a0f3276f2e79487d8219057a506e4b", + "1c08798dc641aba9dee435e22519a4729a09b2bfe0ff00ef2dcd8ed6f8a07d15eaf4aee52bbf18ab5608a6190f70b90486c8a7d4873710b1115d3debbb4327b5", + "40a374727302d9a4769c17b5f409ff32f58aa24ff122d7603e4fda1509e919d4107a52c57570a6d94e50967aea573b11f86f473f537565c66f7039830a85d186", + "77ddf4b14425eb3d053c1e84e3469d92c4cd910ed20f92035e0c99d8a7a86cecaf69f9663c20a7aa230bc82f60d22fb4a00b09d3eb8fc65ef547fe63c8d3ddce", + "cbaa0ba7d482b1f301109ae41051991a3289bc1198005af226c5e4f103b66579f461361044c8ba3439ff12c515fb29c52161b7eb9c2837b76a5dc33f7cb2e2e8", + "f95d45cf69af5c2023bdb505821e62e85d7caedf7beda12c0248775b0c88205eeb35af3a90816f6608ce7dd44ec28db1140614e1ddebf3aa9cd1843e0fad2c36", + "8f945ba700f2530e5c2a7df7d5dce0f83f9efc78c073fe71ae1f88204a4fd1cf70a073f5d1f942ed623aa16e90a871246c90c45b621b3401a5ddbd9df6264165", + "e998e0dc03ec30eb99bb6bfaaf6618acc620320d7220b3af2b23d112d8e9cb1262f3c0d60d183b1ee7f096d12dae42c958418600214d04f5ed6f5e718be35566", + "6a9a090c61b3410aede7ec9138146ceb2c69662f460c3da53c6515c1eb31f41ca3d280e567882f95cf664a94147d78f42cfc714a40d22ef19470e053493508a2", + "29102511d749db3cc9b4e335fa1f5e8faca8421d558f6a3f3321d50d044a248ba595cfc3efd3d2adc97334da732413f5cbf4751c362ba1d53862ac1e8dabeee8", + "c97a4779d47e6f77729b5917d0138abb35980ab641bd73a8859eb1ac98c05362ed7d608f2e9587d6ba9e271d343125d40d933a8ed04ec1fe75ec407c7a53c34e", + "10f0dc91b9f845fb95fad6860e6ce1adfa002c7fc327116d44d047cd7d5870d772bb12b5fac00e02b08ac2a0174d0446c36ab35f14ca31894cd61c78c849b48a", + "dea9101cac62b8f6a3c650f90eea5bfae2653a4eafd63a6d1f0f132db9e4f2b1b662432ec85b17bcac41e775637881f6aab38dd66dcbd080f0990a7a6e9854fe", + "441ffaa08cd79dff4afc9b9e5b5620eec086730c25f661b1d6fbfbd1cec3148dd72258c65641f2fca5eb155fadbcabb13c6e21dc11faf72c2a281b7d56145f19", + "444b240fe3ed86d0e2ef4ce7d851edde22155582aa0914797b726cd058b6f45932e0e129516876527b1dd88fc66d7119f4ab3bed93a61a0e2d2d2aeac336d958", + "bfbabbef45554ccfa0dc83752a19cc35d5920956b301d558d772282bc867009168e9e98606bb5ba73a385de5749228c925a85019b71f72fe29b3cd37ca52efe6", + "9c4d0c3e1cdbbf485bec86f41cec7c98373f0e09f392849aaa229ebfbf397b22085529cb7ef39f9c7c2222a514182b1effaa178cc3687b1b2b6cbcb6fdeb96f8", + "477176b3bfcbadd7657c23c24625e4d0d674d1868f006006398af97aa41877c8e70d3d14c3bbc9bbcdcea801bd0e1599af1f3eec67405170f4e26c964a57a8b7", + "a78c490eda3173bb3f10dee52f110fb1c08e0302230b85ddd7c11257d92de148785ef00c039c0bb8eb9808a35b2d8c080f572859714c9d4069c5bcaf090e898e", + "58d023397beb5b4145cb2255b07d74290b36d9fd1e594afbd8eea47c205b2efbfe6f46190faf95af504ab072e36f6c85d767a321bfd7f22687a4abbf494a689c", + "4001ec74d5a46fd29c2c3cdbe5d1b9f20e51a941be98d2a4e1e2fbf866a672121db6f81a514cfd10e7358d571bdba48e4ce708b9d124894bc0b5ed554935f73a", + "ccd1b22dab6511225d2401ea2d8625d206a12473cc732b615e5640cefff0a4adf971b0e827a619e0a80f5db9ccd0962329010d07e34a2064e731c520817b2183", + "b4a0a9e3574edb9e1e72aa31e39cc5f30dbf943f8cabc408449654a39131e66d718a18819143e3ea96b4a1895988a1c0056cf2b6e04f9ac19d657383c2910c44", + "447becab16630608d39f4f058b16f7af95b85a76aa0fa7cea2b80755fb76e9c804f2ca78f02643c915fbf2fce5e19de86000de03b18861815a83126071f8a37b", + "54e6dab9977380a5665822db93374eda528d9beb626f9b94027071cb26675e112b4a7fec941ee60a81e4d2ea3ff7bc52cfc45dfbfe735a1c646b2cf6d6a49b62", + "3ea62625949e3646704d7e3c906f82f6c028f540f5f72a794b0c57bf97b7649bfeb90b01d3ca3e829de21b3826e6f87014d3c77350cb5a15ff5d468a81bec160", + "213cfe145c54a33691569980e5938c8883a46d84d149c8ff1a67cd287b4d49c6da69d3a035443db085983d0efe63706bd5b6f15a7da459e8d50a19093db55e80", + "5716c4a38f38db104e494a0a27cbe89a26a6bb6f499ec01c8c01aa7cb88497e75148cd6eee12a7168b6f78ab74e4be749251a1a74c38c86d6129177e2889e0b6", + "030460a98bdf9ff17cd96404f28fc304f2b7c04eaade53677fd28f788ca22186b8bc80dd21d17f8549c711aff0e514e19d4e15f5990252a03e082f28dc2052f6", + "19e7f1ccee88a10672333e390cf22013a8c734c6cb9eab41f17c3c8032a2e4aca0569ea36f0860c7a1af28fa476840d66011168859334a9e4ef9cc2e61a0e29e", + "29f8b8c78c80f2fcb4bdf7825ed90a70d625ff785d262677e250c04f3720c888d03f8045e4edf3f5285bd39d928a10a7d0a5df00b8484ac2868142a1e8bea351", + "5c52920a7263e39d57920ca0cb752ac6d79a04fef8a7a216a1ecb7115ce06d89fd7d735bd6f4272555dba22c2d1c96e6352322c62c5630fde0f4777a76c3de2c", + "83b098f262251bf660064a9d3511ce7687a09e6dfbb878299c30e93dfb43a9314db9a600337db26ebeedaf2256a96dabe9b29e7573ad11c3523d874dde5be7ed", + "9447d98aa5c9331352f43d3e56d0a9a9f9581865998e2885cc56dd0a0bd5a7b50595bd10f7529bcd31f37dc16a1465d594079667da2a3fcb70401498837cedeb", + "867732f2feeb23893097561ac710a4bff453be9cfbedba8ba324f9d312a82d732e1b83b829fdcd177b882ca0c1bf544b223be529924a246a63cf059bfdc50a1b", + "f15ab26d4cdfcf56e196bb6ba170a8fccc414de9285afd98a3d3cf2fb88fcbc0f19832ac433a5b2cc2392a4ce34332987d8d2c2bef6c3466138db0c6e42fa47b", + "2813516d68ed4a08b39d648aa6aacd81e9d655ecd5f0c13556c60fdf0d333ea38464b36c02baccd746e9575e96c63014f074ae34a0a25b320f0fbedd6acf7665", + "d3259afca8a48962fa892e145acf547f26923ae8d4924c8a531581526b04b44c7af83c643ef5a0bc282d36f3fb04c84e28b351f40c74b69dc7840bc717b6f15f", + "f14b061ae359fa31b989e30332bfe8de8cc8cdb568e14be214a2223b84caab7419549ecfcc96ce2acec119485d87d157d3a8734fc426597d64f36570ceaf224d", + "55e70b01d1fbf8b23b57fb62e26c2ce54f13f8fa2464e6eb98d16a6117026d8b90819012496d4071ebe2e59557ece3519a7aa45802f9615374877332b73490b3", + "25261eb296971d6e4a71b2928e64839c67d422872bf9f3c31993615222de9f8f0b2c4be8548559b4b354e736416e3218d4e8a1e219a4a6d43e1a9a521d0e75fc", + "08307f347c41294e34bb54cb42b1522d22f824f7b6e5db50fda096798e181a8f026fa27b4ae45d52a62caf9d5198e24a4913c6671775b2d723c1239bfbf016d7", + "1e5c62e7e9bfa1b118747a2de08b3ca10112af96a46e4b22c3fc06f9bfee4eb5c49e057a4a4886234324572576bb9b5ecfde0d99b0de4f98ec16e4d1b85fa947", + "c74a77395fb8bc126447454838e561e962853dc7eb49a1e3cb67c3d0851f3e39517be8c350ac910903d49cd2bfdf545c99316d0346170b739f0add5d533c2cfc", + "0dd57b423cc01eb2861391eb886a0d17079b933fc76eb3fc08a19f8a74952cb68f6bcdc644f77370966e4d13e80560bcf082ef0479d48fbbab4df03b53a4e178", + "4d8dc3923edccdfce70072398b8a3da5c31fcb3ee3b645c85f717cbaeb4b673a19394425a585bfb464d92f1597d0b754d163f97ced343b25db5a70ef48ebb34f", + "f0a50553e4dfb0c4e3e3d3ba82034857e3b1e50918f5b8a7d698e10d242b0fb544af6c92d0c3aaf9932220416117b4e78ecb8a8f430e13b82a5915290a5819c5", + "b15543f3f736086627cc5365e7e8988c2ef155c0fd4f428961b00d1526f04d6d6a658b4b8ed32c5d8621e7f4f8e8a933d9ecc9dd1b8333cbe28cfc37d9719e1c", + "7b4fa158e415fef023247264cbbe15d16d91a44424a8db707eb1e2033c30e9e1e7c8c0864595d2cb8c580eb47e9d16abbd7e44e824f7cedb7def57130e52cfe9", + "60424ff23234c34dc9687ad502869372cc31a59380186bc2361c835d972f49666eb1ac69629de646f03f9b4db9e2ace093fbfdf8f20ab5f98541978be8ef549f", + "7406018ce704d84f5eb9c79fea97da345699468a350ee0b2d0f3a4bf2070304ea862d72a51c57d3064947286f531e0eaf7563702262e6c724abf5ed8c8398d17", + "14ef5c6d647b3bd1e6e32006c231199810de5c4dc88e70240273b0ea18e651a3eb4f5ca3114b8a56716969c7cda27e0c8db832ad5e89a2dc6cb0adbe7d93abd1", + "38cf6c24e3e08bcf1f6cf3d1b1f65b905239a3118033249e448113ec632ea6dc346feeb2571c38bd9a7398b2221280328002b23e1a45adaffe66d93f6564eaa2", + "6cd7208a4bc7e7e56201bbba02a0f489cd384abe40afd4222f158b3d986ee72a54c50fb64fd4ed2530eda2c8af2928a0da6d4f830ae1c9db469dfd970f12a56f", + "659858f0b5c9edab5b94fd732f6e6b17c51cc096104f09beb3afc3aa467c2ecf885c4c6541effa9023d3b5738ae5a14d867e15db06fe1f9d1127b77e1aabb516", + "26cca0126f5d1a813c62e5c71001c046f9c92095704550be5873a495a999ad010a4f79491f24f286500adce1a137bc2084e4949f5b7294cefe51ecaff8e95cba", + "4147c1f55172788c5567c561feef876f621fff1ce87786b8467637e70dfbcd0dbdb6415cb600954ab9c04c0e457e625b407222c0fe1ae21b2143688ada94dc58", + "5b1bf154c62a8af6e93d35f18f7f90abb16a6ef0e8d1aecd118bf70167bab2af08935c6fdc0663ce74482d17a8e54b546d1c296631c65f3b522a515839d43d71", + "9f600419a4e8f4fb834c24b0f7fc13bf4e279d98e8a3c765ee934917403e3a66097182ea21453cb63ebbe8b73a9c2167596446438c57627f330badd4f569f7d6", + "457ef6466a8924fd8011a34471a5a1ac8ccd9bd0d07a97414ac943021ce4b9e4b9c8db0a28f016ed43b1542481990022147b313e194671131e708dd43a3ed7dc", + "9997b2194d9af6dfcb9143f41c0ed83d3a3f4388361103d38c2a49b280a581212715fd908d41c651f5c715ca38c0ce2830a37e00e508ced1bcdc320e5e4d1e2e", + "5c6bbf16baa180f986bd40a1287ed4c549770e7284858fc47bc21ab95ebbf3374b4ee3fd9f2af60f3395221b2acc76f2d34c132954049f8a3a996f1e32ec84e5", + "d10bf9a15b1c9fc8d41f89bb140bf0be08d2f3666176d13baac4d381358ad074c9d4748c300520eb026daeaea7c5b158892fde4e8ec17dc998dcd507df26eb63", + "2fc6e69fa26a89a5ed269092cb9b2a449a4409a7a44011eecad13d7c4b0456602d402fa5844f1a7a758136ce3d5d8d0e8b86921ffff4f692dd95bdc8e5ff0052", + "fcbe8be7dcb49a32dbdf239459e26308b84dff1ea480df8d104eeff34b46fae98627b450c2267d48c0946a697c5b59531452ac0484f1c84e3a33d0c339bb2e28", + "a19093a6e3bcf5952f850f2030f69b9606f147f90b8baee3362da71d9f35b44ef9d8f0a7712ba1877fddcd2d8ea8f1e5a773d0b745d4725605983a2de901f803", + "3c2006423f73e268fa59d2920377eb29a4f9a8b462be15983ee3b85ae8a78e992633581a9099893b63db30241c34f643027dc878279af5850d7e2d4a2653073a", + "d0f2f2e3787653f77cce2fa24835785bbd0c433fc779465a115149905a9dd1cb827a628506d457fcf124a0c2aef9ce2d2a0a0f63545570d8667ff9e2eba07334", + "78a9fc048e25c6dcb5de45667de8ffdd3a93711141d594e9fa62a959475da6075ea8f0916e84e45ad911b75467077ee52d2c9aebf4d58f20ce4a3a00458b05d4", + "45813f441769ab6ed37d349ff6e72267d76ae6bb3e3c612ec05c6e02a12af5a37c918b52bf74267c3f6a3f183a8064ff84c07b193d08066789a01accdb6f9340", + "956da1c68d83a7b881e01b9a966c3c0bf27f68606a8b71d457bd016d4c41dd8a380c709a296cb4c6544792920fd788835771a07d4a16fb52ed48050331dc4c8b", + "df186c2dc09caa48e14e942f75de5ac1b7a21e4f9f072a5b371e09e07345b0740c76177b01278808fec025eded9822c122afd1c63e6f0ce2e32631041063145c", + "87475640966a9fdcd6d3a3b5a2cca5c08f0d882b10243c0ec1bf3c6b1c37f2cd3212f19a057864477d5eaf8faed73f2937c768a0af415e84bbce6bd7de23b660", + "c3b573bbe10949a0fbd4ff884c446f2229b76902f9dfdbb8a0353da5c83ca14e8151bbaac82fd1576a009adc6f1935cf26edd4f1fb8da483e6c5cd9d8923adc3", + "b09d8d0bba8a7286e43568f7907550e42036d674e3c8fc34d8ca46f771d6466b70fb605875f6a863c877d12f07063fdc2e90ccd459b1910dcd52d8f10b2b0a15", + "af3a22bf75b21abfb0acd54422ba1b7300a952eff02ebeb65b5c234471a98df32f4f9643ce1904108a168767924280bd76c83f8c82d9a79d9259b195362a2a04", + "bf4ff2221b7e6957a724cd964aa3d5d0d9941f540413752f4699d8101b3e537508bf09f8508b317736ffd265f2847aa7d84bd2d97569c49d632aed9945e5fa5e", + "9c6b6b78199b1bdacb4300e31479fa622a6b5bc80d4678a6078f88a8268cd7206a2799e8d4621a464ef6b43dd8adffe97caf221b22b6b8778b149a822aefbb09", + "890656f09c99d280b5ecb381f56427b813751bc652c7828078b23a4af83b4e3a61fdbac61f89bee84ea6bee760c047f25c6b0a201c69a38fd6fd971af18588bb", + "31a046f7882ffe6f83ce472e9a0701832ec7b3f76fbcfd1df60fe3ea48fde1651254247c3fd95e100f9172731e17fd5297c11f4bb328363ca361624a81af797c", + "27a60b2d00e7a671d47d0aec2a686a0ac04b52f40ab6629028eb7d13f4baa99ac0fe46ee6c814944f2f4b4d20e9378e4847ea44c13178091e277b87ea7a55711", + "8b5ccef194162c1f19d68f91e0b0928f289ec5283720840c2f73d253111238dcfe94af2b59c2c1ca2591901a7bc060e7459b6c47df0f71701a35cc0aa831b5b6", + "57ab6c4b2229aeb3b70476d803cd63812f107ce6da17fed9b17875e8f86c724f49e024cbf3a1b8b119c50357652b81879d2ade2d588b9e4f7cedba0e4644c9ee", + "0190a8dac320a739f322e15731aa140ddaf5bed294d5c82e54fef29f214e18aafaa84f8be99af62950266b8f901f15dd4c5d35516fc35b4cab2e96e4695bbe1c", + "d14d7c4c415eeb0e10b159224bea127ebd84f9591c702a330f5bb7bb7aa44ea39de6ed01f18da7adf40cfb97c5d152c27528824b21e239526af8f36b214e0cfb", + "be28c4be706970488fac7d29c3bd5c4e986085c4c3332f1f3fd30973db614164ba2f31a78875ffdc150325c88327a9443ed04fdfe5be93876d1628560c764a80", + "031da1069e3a2e9c3382e436ffd79df74b1ca6a8adb2deabe676ab45994cbc054f037d2f0eace858d32c14e2d1c8b46077308e3bdc2c1b53172ecf7a8c14e349", + "4665cef8ba4db4d0acb118f2987f0bb09f8f86aa445aa3d5fc9a8b346864787489e8fcecc125d17e9b56e12988eac5ecc7286883db0661b8ff05da2afff30fe4", + "63b7032e5f930cc9939517f9e986816cfbec2be59b9568b13f2ead05bae7777cab620c6659404f7409e4199a3be5f7865aa7cbdf8c4253f7e8219b1bd5f46fea", + "9f09bf093a2b0ff8c2634b49e37f1b2135b447aa9144c9787dbfd92129316c99e88aab8a21fdef2372d1189aec500f95775f1f92bfb45545e4259fb9b7b02d14", + "f9f8493c68088807df7f6a2693d64ea59f03e9e05a223e68524ca32195a4734b654fcea4d2734c866cf95c889fb10c49159be2f5043dc98bb55e02ef7bdcb082", + "3c9a7359ab4febce07b20ac447b06a240b7fe1dae5439c49b60b5819f7812e4c172406c1aac316713cf0dded1038077258e2eff5b33913d9d95caeb4e6c6b970", + "ad6aab8084510e822cfce8625d62cf4de655f4763884c71e80bab9ac9d5318dba4a6033ed29084e65216c031606ca17615dcfe3ba11d26851ae0999ca6e232cf", + "156e9e6261374c9dc884f36e70f0fe1ab9297997b836fa7d170a9c9ebf575b881e7bcea44d6c0248d35597907154828955be19135852f9228815eca024a8adfb", + "4215407633f4cca9b6788be93e6aa3d963c7d6ce4b147247099f46a3acb500a30038cb3e788c3d29f132ad844e80e9e99251f6db96acd8a091cfc770af53847b", + "1c077e279de6548523502b6df800ffdab5e2c3e9442eb838f58c295f3b147cef9d701c41c321283f00c71affa0619310399126295b78dd4d1a74572ef9ed5135", + "f07a555f49fe481cf4cd0a87b71b82e4a95064d06677fdd90a0eb598877ba1c83d4677b393c3a3b6661c421f5b12cb99d20376ba7275c2f3a8f5a9b7821720da", + "b5911b380d20c7b04323e4026b38e200f534259233b581e02c1e3e2d8438d6c66d5a4eb201d5a8b75072c4ec29106334da70bc79521b0ced2cfd533f5ff84f95", + "01f070a09bae911296361f91aa0e8e0d09a7725478536d9d48c5fe1e5e7c3c5b9b9d6eb07796f6da57ae562a7d70e882e37adfde83f0c433c2cd363536bb22c8", + "6f793eb4374a48b0775acaf9adcf8e45e54270c9475f004ad8d5973e2aca52747ff4ed04ae967275b9f9eb0e1ff75fb4f794fa8be9add7a41304868d103fab10", + "965f20f139765fcc4ce4ba3794675863cac24db472cd2b799d035bce3dbea502da7b524865f6b811d8c5828d3a889646fe64a380da1aa7c7044e9f245dced128", + "ec295b5783601244c30e4641e3b45be222c4dce77a58700f53bc8ec52a941690b4d0b087fb6fcb3f39832b9de8f75ec20bd43079811749cdc907edb94157d180", + "61c72f8ccc91dbb54ca6750bc489672de09faedb8fdd4f94ff2320909a303f5d5a98481c0bc1a625419fb4debfbf7f8a53bb07ec3d985e8ea11e72d559940780", + "afd8145b259eefc8d12620c3c5b03e1ed8fd2ccefe0365078c80fd42c1770e28b44948f27e65a1886690110db814397b68e43d80d1ba16dfa358e739c898cfa3", + "552fc7893cf1ce933ada35c0da98844e41545e244c3157a1428d7b4c21f9cd7e4071aed77b7ca9f1c38fba32237412ef21a342742ec8324378f21e507fafdd88", + "467a33fbadf5ebc52596ef86aaaefc6faba8ee651b1ce04de368a03a5a9040ef2835e00adb09abb3fbd2bce818a2413d0b0253b5bda4fc5b2f6f85f3fd5b55f2", + "22eff8e6dd5236f5f57d94ede874d6c9428e8f5d566f17cd6d1848cd752fe13c655cb10fbaaff76872f2bf2da99e15dc624075e1ec2f58a3f64072121838569e", + "9cec6bbf62c4bce4138abae1cbec8dad31950444e90321b1347196834c114b864af3f3cc3508f83751ffb4eda7c84d140734bb4263c3625c00f04f4c8068981b", + "a8b60fa4fc2442f6f1514ad7402626920cc7c2c9f72124b8cba8ee2cb7c4586f658a4410cffcc0ab88343955e094c6af0d20d0c714fb0a988f543f300f58d389", + "8271cc45dfa5e4170e847e8630b952cf9c2aa777d06f26a7585b8381f188dacc7337391cfcc94b053dc4ec29cc17f077870428f1ac23fddda165ef5a3f155f39", + "bf23c0c25c8060e4f6995f1623a3bebecaa96e308680000a8aa3cd56bb1a6da099e10d9231b37f4519b2efd2c24de72f31a5f19535241b4a59fa3c03ceb790e7", + "877fd652c05281009c0a5250e7a3a671f8b18c108817fe4a874de22da8e45db11958a600c5f62e67d36cbf84474cf244a9c2b03a9fb9dc711cd1a2cab6f3fae0", + "29df4d87ea444baf5bcdf5f4e41579e28a67de84149f06c03f110ea84f572a9f676addd04c4878f49c5c00accda441b1a387caceb2e993bb7a10cd8c2d6717e1", + "710dacb166844639cd7b637c274209424e2449dc35d790bbfa4f76177054a36b3b76fac0ca6e61df1e687000678ac0746df75d0a3954897681fd393a155a1bb4", + "c1d5f93b8dea1f2571babccbc01764541a0cda87e444d673c50966ca559c33354b3acb26e5d5781ffb28847a4b4754d77008c62a835835f500dea7c3b58bdae2", + "a41e41271cdab8af4d72b104bfb2ad041ac4df14677da671d85640c4b187f50c2b66513c4619fbd5d5dc4fe65dd37b9042e9848dda556a504caa2b1c6afe4730", + "e7bcbacdc379c43d81ebadcb37781552fc1d753e8cf310d968392d06c91f1d64cc9e90ce1d22c32d277fc6cda433a4d442c762e9eacf2c259f32d64cf9da3a22", + "51755b4ac5456b13218a19c5b9242f57c4a981e4d4ecdce09a3193362b808a579345d4881c2607a56534dd7f21956aff72c2f4173a6e7b6cc2212ba0e3daee1f", + "dcc2c4beb9c1f2607b786c20c631972347034c1cc02fcc7d02ff01099cfe1c6989840ac213923629113aa8bad713ccf0fe4ce13264fb32b8b0fe372da382544a", + "3d55176acea4a7e3a65ffa9fb10a7a1767199cf077cee9f71532d67cd7c73c9f93cfc37ccdcc1fdef50aad46a504a650d298d597a3a9fa95c6c40cb71fa5e725", + "d07713c005de96dd21d2eb8bbeca66746ea51a31ae922a3e74864889540a48db27d7e4c90311638b224bf0201b501891754848113c266108d0adb13db71909c7", + "58983c21433d950caa23e4bc18543b8e601c204318532152daf5e159a0cd1480183d29285c05f129cb0cc3164687928086ffe380158df1d394c6ac0d4288bca8", + "8100a8dc528d2b682ab4250801ba33f02a3e94c54dac0ae1482aa21f51ef3a82f3807e6facb0aeb05947bf7aa2adcb034356f90fa4560ede02201a37e411ec1a", + "07025f1bb6c784f3fe49de5c14b936a5acacacaab33f6ac4d0e00ab6a12483d6bec00b4fe67c7ca5cc508c2a53efb5bfa5398769d843ff0d9e8b14d36a01a77f", + "ba6aefd972b6186e027a76273a4a723321a3f580cfa894da5a9ce8e721c828552c64dacee3a7fd2d743b5c35ad0c8efa71f8ce99bf96334710e2c2346e8f3c52", + "e0721e02517aedfa4e7e9ba503e025fd46e714566dc889a84cbfe56a55dfbe2fc4938ac4120588335deac8ef3fa229adc9647f54ad2e3472234f9b34efc46543", + "b6292669ccd38d5f01caae96ba272c76a879a45743afa0725d83b9ebb26665b731f1848c52f11972b6644f554c064fa90780dbbbf3a89d4fc31f67df3e5857ef", + "2319e3789c47e2daa5fe807f61bec2a1a6537fa03f19ff32e87eecbfd64b7e0e8ccff439ac333b040f19b0c4ddd11a61e24ac1fe0f10a039806c5dcc0da3d115", + "f59711d44a031d5f97a9413c065d1e614c417ede998590325f49bad2fd444d3e4418be19aec4e11449ac1a57207898bc57d76a1bcf3566292c20c683a5c4648f", + "df0a9d0c212843a6a934e3902b2dd30d17fba5f969d2030b12a546d8a6a45e80cf5635f071f0452e9c919275da99bed51eb1173c1af0518726b75b0ec3bae2b5", + "a3eb6e6c7bf2fb8b28bfe8b15e15bb500f781ecc86f778c3a4e655fc5869bf2846a245d4e33b7b14436a17e63be79b36655c226a50ffbc7124207b0202342db5", + "56d4cbcd070563426a017069425c2cd2ae540668287a5fb9dac432eb8ab1a353a30f2fe1f40d83333afe696a267795408a92fe7da07a0c1814cf77f36e105ee8", + "e59b9987d428b3eda37d80abdb16cd2b0aef674c2b1dda4432ea91ee6c935c684b48b4428a8cc740e579a30deff35a803013820dd23f14ae1d8413b5c8672aec", + "cd9fcc99f99d4cc16d031900b2a736e1508db4b586814e6345857f354a70ccecb1df3b50a19adaf43c278efa423ff4bb6c523ec7fd7859b97b168a7ebff8467c", + "0602185d8c3a78738b99164b8bc6ffb21c7debebbf806372e0da44d121545597b9c662a255dc31542cf995ecbe6a50fb5e6e0ee4ef240fe557eded1188087e86", + "c08afa5b927bf08097afc5fff9ca4e7800125c1f52f2af3553fa2b89e1e3015c4f87d5e0a48956ad31450b083dad147ffb5ec03434a26830cf37d103ab50c5da", + "36f1e1c11d6ef6bc3b536d505d544a871522c5c2a253067ec9933b6ec25464daf985525f5b9560a16d890259ac1bb5cc67c0c469cde133def000ea1d686f4f5d", + "bf2ab2e2470f5438c3b689e66e7686fffa0cb1e1798ad3a86ff99075bf6138e33d9c0ce59afb24ac67a02af34428191a9a0a6041c07471b7c3b1a752d6fc0b8b", + "d400601f9728ccc4c92342d9787d8d28ab323af375ca5624b4bb91d17271fbae862e413be73f1f68e615b8c5c391be0dbd9144746eb339ad541547ba9c468a17", + "79fe2fe157eb85a038abb8ebbc647731d2c83f51b0ac6ee14aa284cb6a3549a4dcceb300740a825f52f5fb30b03b8c4d8b0f4aa67a63f4a94e3303c4eda4c02b", + "75351313b52a8529298d8c186b1768666dcca8595317d7a4816eb88c062020c0c8efc554bb341b64688db5ccafc35f3c3cd09d6564b36d7b04a248e146980d4b", + "e3128b1d311d02179d7f25f97a5a8bee2cc8c86303644fcd664e157d1fef00f23e46f9a5e8e5c890ce565bb6abd4302ce06469d52a5bd53e1c5a54d04649dc03", + "c2382a72d2d3ace9d5933d00b60827ed380cda08d0ba5f6dd41e29ee6dbe8ecb9235f06be95d83b6816a2fb7a5ad47035e8a4b69a4884b99e4bece58cab25d44", + "6b1c69460bbd50ac2ed6f32e6e887cfed407d47dcf0aaa60387fe320d780bd03eab6d7baeb2a07d10cd552a300341354ea9a5f03183a623f92a2d4d9f00926af", + "6cda206c80cdc9c44ba990e0328c314f819b142d00630404c48c05dc76d1b00ce4d72fc6a48e1469ddef609412c364820854214b4869af090f00d3c1ba443e1b", + "7ffc8c26fbd6a0f7a609e6e1939f6a9edf1b0b066641fb76c4f9602ed748d11602496b35355b1aa255850a509d2f8ee18c8f3e1d7dcbc37a136598f56a59ed17", + "70de1f08dd4e09d5fc151f17fc991a23abfc05104290d50468882efaf582b6ec2f14f577c0d68c3ad06626916e3c86e6daab6c53e5163e82b6bd0ce49fc0d8df", + "4f81935756ed35ee2058ee0c6a6110d6fac5cb6a4f46aa9411603f99965823b6da4838276c5c06bc7880e376d92758369ee7305bcec8d3cfd28ccabb7b4f0579", + "abcb61cb3683d18f27ad527908ed2d32a0426cb7bb4bf18061903a7dc42e7e76f982382304d18af8c80d91dd58dd47af76f8e2c36e28af2476b4bccf82e89fdf", + "02d261ad56a526331b643dd2186de9a82e72a58223cd1e723686c53d869b83b94632b7b647ab2afc0d522e29da3a5615b741d82852e0df41b66007dbcba90543", + "c5832741fa30c5436823015383d297ff4c4a5d7276c3f902122066e04be5431b1a85faf73b918434f9300963d1dea9e8ac3924ef490226edeea5f743e410669f", + "cfaeab268cd075a5a6aed515023a032d54f2f2ff733ce0cbc78db51db4504d675923f82746d6594606ad5d67734b11a67cc6a468c2032e43ca1a94c6273a985e", + "860850f92eb268272b67d133609bd64e34f61bf03f4c1738645c17fec818465d7ecd2be2907641130025fda79470ab731646e7f69440e8367ea76ac4cee8a1df", + "84b154ed29bbedefa648286839046f4b5aa34430e2d67f7496e4c39f2c7ea78995f69e1292200016f16ac3b37700e6c7e7861afc396b64a59a1dbf47a55c4bbc", + "aeeec260a5d8eff5ccab8b95da435a63ed7a21ea7fc7559413fd617e33609f8c290e64bbacc528f6c080262288b0f0a3219be223c991bee92e72349593e67638", + "8ad78a9f26601d127e8d2f2f976e63d19a054a17dcf59e0f013ab54a6887bbdffde7aaae117e0fbf3271016595b9d9c712c01b2c53e9655a382bc4522e616645", + "8934159dade1ac74147dfa282c75954fcef443ef25f80dfe9fb6ea633b8545111d08b34ef43fff17026c7964f5deac6d2b3c29dacf2747f022df5967dfdc1a0a", + "cd36dd0b240614cf2fa2b9e959679dcdd72ec0cd58a43da3790a92f6cdeb9e1e795e478a0a47d371100d340c5cedcdbbc9e68b3f460818e5bdff7b4cda4c2744", + "00df4e099b807137a85990f49d3a94315e5a5f7f7a6076b303e96b056fb93800111f479628e2f8db59aeb6ac70c3b61f51f9b46e80ffdeae25ebddb4af6cb4ee", + "2b9c955e6caed4b7c9e246b86f9a1726e810c59d126cee66ed71bf015b83558a4b6d84d18dc3ff4620c2ffb722359fdef85ba0d4e2d22ecbe0ed784f99afe587", + "181df0a261a2f7d29ea5a15772715105d450a4b6c236f699f462d60ca76487feedfc9f5eb92df838e8fb5dc3694e84c5e0f4a10b761f506762be052c745a6ee8", + "21fb203458bf3a7e9a80439f9a902899cd5de0139dfd56f7110c9dec8437b26bda63de2f565926d85edb1d6c6825669743dd9992653d13979544d5dc8228bfaa", + "ef021f29c5ffb830e64b9aa9058dd660fd2fcb81c497a7e698bcfbf59de5ad4a86ff93c10a4b9d1ae5774725f9072dcde9e1f199bab91f8bff921864aa502eee", + "b3cfda40526b7f1d37569bdfcdf911e5a6efe6b2ec90a0454c47b2c046bf130fc3b352b34df4813d48d33ab8e269b69b075676cb6d00a8dcf9e1f967ec191b2c", + "b4c6c3b267071eefb9c8c72e0e2b941293641f8673cb70c1cc26ad1e73cf141755860ad19b34c2f34ed35bb52ec4507cc1fe59047743a5f0c6febde625e26091", + "57a34f2bcca60d4b85103b830c9d7952a416be5263ae429c9e5e53fe8590a8f78ec65a51109ea85dcdf7b6223f9f2b340539fad81923dbf8edabf95129e4dff6", + "9cf46662fcd61a232277b685663b8b5da832dfd9a3b8ccfeec993ec6ac415ad07e048adfe414df272770dba867da5c1224c6fd0aa0c2187d426ac647e9887361", + "5ce1042ab4d542c2f9ee9d17262af8164098935bef173d0e18489b04841746cd2f2df866bd7da6e5ef9024c648023ec723ab9c62fd80285739d84f15d2ab515a", + "8488396bd4a8729b7a473178f232dadf3f0f8e22678ba5a43e041e72da1e2cf82194c307207a54cb8156293339eaec693ff66bfcd5efc65e95e4ecaf54530abd", + "f598da901c3835bca560779037dfde9f0c51dc61c0b760fc1522d7b470ee63f5bdc6498476e86049ad86e4e21af2854a984cc905427d2f17f66b1f41c3da6f61", + "5f93269798cf02132107337660a8d7a177354c0212eb93e555e7c37a08aef3d8dce01217011cd965c04dd2c105f2e2b6cae5e4e6bcaf09dfbee3e0a6a6357c37", + "0ecf581d47bac9230986faabd70c2f5b80e91066f0ec55a842937882286d2ca007bb4e973b0b091d52167ff7c4009c7ab4ad38fff1dceacdb7be81ef4a452952", + "5aeca8abe1528582b2a307b4009585498a3d467ca6101cb0c5126f9976056e9ffc123cc20c302b2a737f492c75d21f01512c90ca0541dfa56e950a321dcb28d8", + "732fbf8f1cb2b8329263ede27858fe46f8d3354d376bcda0548e7ce1fa9dd11f85eb661fe950b543aa635ca4d3f04ede5b32d6b656e5ce1c44d35c4a6c56cff8", + "d5e938735d63788c80100aefd18648d18cf272f69f20ff24cfe2895c088ad08b0104da1672a4eb26fc52545cc7d7a01b266cf546c403c45bd129eb41bdd9200b", + "65a245b49352ee297d91af8c8be00528ac6e046dd83ac7bd465a98816dd68f3e00e1ae8f895327a7e9a8c9326598379a29c9fc91ec0c6eef08f3e2b216c11008", + "c95654b63019130ab45dd0fb4941b98aeb3af2a123913eca2ce99b3e97410a7bf8661cc7fbaa2bc1cf2b13113b1ed40a0118b88e5fffc3542759ea007ed4c58d", + "1eb262f38fa494431f017dad44c0dfb69324ac032f04b657fc91a88647bb74760f24e7c956514f0cf002990b182c1642b9b2426e96a61187e4e012f00e217d84", + "3b955aeebfa5151ac1ab8e3f5cc1e3767084c842a575d36269836e97353d41622b731dddcd5f269550a3a5b87be1e90326340b6e0e62555815d9600597ac6ef9", + "68289f6605473ba0e4f241baf7477a9885426a858f19ef2a18b0d40ef8e41282ed5526b519799e270f13881327918278755711071d8511fe963e3b5606aa3716", + "80a33787542612c38f6bcd7cd86cab460227509b1cbad5ec408a91413d51155a0476dadbf3a2518e4a6e77cc346622e347a469bf8baa5f04eb2d98705355d063", + "34629bc6d831391c4cdf8af1b4b7b6b8e8ee17cf98c70e5dd586cd99f14b11df945166236a9571e6d591bb83ee4d164d46f6b9d8ef86ff865a81bfb91b00424b", + "8b7cc339163863bb4383e542b0ef0e7cf36b84ad932cdf5a80419ec9ad692e7a7e784d2c7cb3796a18b8f800035f3aa06c824100611120a7bdeb35618ccb81b7", + "4f084e4939dd5a7f5a658fad58a18a15c25c32ec1c7fd5c5c6c3e892b3971aeaac308304ef17b1c47239ea4bb398b3fd6d4528d8de8e768ae0f1a5a5c6b5c297", + "48f407a1af5b8009b2051742e8cf5cd5656669e7d722ee8e7bd202060849442168d8facc117c012bfb7bf449d99befff6a34aea203f1d8d352722be5014ec818", + "a6aa82cd1e426f9a73bfa39a29037876114655b8c22d6d3ff8b638ae7dea6b17843e09e52eb66fa1e475e4a8a3de429b7d0f4a776fcb8bdc9b9fede7d52e815f", + "5817027d6bdd00c5dd10ac593cd560372270775a18526d7e6f13872a2e20eab664625be7168ac4bd7c9e0ce7fc4099e0f48442e2c767191c6e1284e9b2ccea8c", + "08e41028340a45c74e4052b3a8d6389e22e043a1adab5e28d97619450d723469b620caa519b81c14523854f619fd3027e3847bd03276e60604a80ddb4de876d6", + "130b8420537eb07d72abda07c85acbd8b9a44f16321dd0422145f809673d30f2b5321326e2bff317ef3fef983c51c4f8ab24a325d298e34afce569a82555774c", + "ac49b844afaa012e31c474ca263648844fd2f6307992c2f752aca02c3828965175794deee2d2ee95c61cd284f6b5a2d75e2ef2b29ee8149e77fb81447b2fd04b", + "b9d7ca81cc60bb9578e44024e5a0a0be80f27336a6a9f4e53df3999cb191280b090e2ac2d29c5baad9d71415bdc129e69aa2667af6a7fd5e189fccdcee817340", + "a755e113386572c75ced61d719706070b9146048e42a9f8cd35667a088b42f08808abdf77e618abd959afc757379ca2c00bcc1a48390fa2bff618b1e0078a613", + "a73c7debed326f1c0db0795ee7d6e3946894b826b1f8101c56c823ba17168312e7f53fc7dbe52c3e11e69852c40485e2ef182477862ea6a34ec136e2dfeea6f4", + "6cb8f9d52c56d82cac28f39ea1593e8bb2506293ac0d68376a1709b62a46df14a4ae64b2d8fab76733a1ced2d548e3f3c6fcb49d40c3d5808e449cd83d1c2aa2", + "683fa2b2369a10162c1c1c7b24bc970ee67da220564f32203f625696c0352a0b9ad96624362d952d84463c1106a2dba7a092599884b35a0b89c8f1b6a9b5a61e", + "aad9ad44610118b77d508aeb1bbcd1c1b7d0171397fb510a401bbc0ec34623670d86a2dc3c8f3ab5a2044df730256727545f0860ce21a1eac717dfc48f5d228e", + "c42578de23b4c987d5e1ac4d689ed5de4b0417f9704bc6bce969fa13471585d62c2cb1212a944f397fc9ca2c3747c3beb694ec4c5be68828dda53ef43faec6c0", + "470f00841ee8244e63ed2c7ea30e2e419897c197462ecccecf713b42a5065fff5914bc9b79affe8f6b657875e789ae213bd914cd35bd174d46e9d18bd843773d", + "34fc4213730f47a5e9a3580f643e12945cfcb31bf206f6ad450ce528da3fa432e005d6b0ecce10dca7c5995f6aacc5150e1b009e19751e8309f8859531844374", + "fb3c1f0f56a56f8e316fdf5d853c8c872c39635d083634c3904fc3ac07d1b578e85ff0e480e92d44ade33b62e893ee32343e79ddf6ef292e89b582d312502314", + "c7c97fc65dd2b9e3d3d607d31598d3f84261e9919251e9c8e57bb5f829377d5f73eabbed55c6c381180f29ad02e5be797ffec7e57bdecbc50ad3d062f0993ab0", + "a57a49cdbe67ae7d9f797bb5cc7efc2df07f4e1b15955f85dae74b76e2ecb85afb6cd9eeed8888d5ca3ec5ab65d27a7b19e578475760a045ac3c92e13a938e77", + "c7143fce9614a17fd653aeb140726dc9c3dbb1de6cc581b2726897ec24b7a50359ad492243be66d9edd8c933b5b80e0b91bb61ea98056006516976fae8d99a35", + "65bb58d07f937e2d3c7e65385f9c54730b704105ccdb691f6e146d4ee8f6c086f49511035110a9ad6031fdceb943e0f9613bcb276dd40f0624ef0f924f809783", + "e540277f683b1186dd3b5b3f61433396581a35feb12002be8c6a6231fc40ffa70f08081bc58b2d94f7649543614a435faa2d62110e13dabc7b86629b63af9c24", + "418500878c5fbcb584c432f4285e05e49f2e3e075399a0dbfcf874ebf8c03d02bf16bc6989d161c77ca0786b05053c6c709433712319192128835cf0b660595b", + "889090dbb1944bdc9433ee5ef1010c7a4a24a8e71ecea8e12a31318ce49dcab0aca5c3802334aab2cc84b14c6b9321fe586bf3f876f19cd406eb1127fb944801", + "53b6a28910aa92e27e536fb549cf9b9918791060898e0b9fe183577ff43b5e9c7689c745b32e412269837c31b89e6cc12bf76e13cad366b74ece48bb85fd09e9", + "7c092080c6a80d672409d081d3d177106bcd63567785140719490950ae07ae8fcaabbaaab330cfbcf7374482c220af2eadeeb73dcbb35ed823344e144e7d4899", + "9ccde566d2400509181111f32dde4cd63209fe59a30c114546ad2776d889a41bad8fa1bb468cb2f9d42ca9928a7770fef8e8ba4d0c812d9a1e75c3d8d2ccd75a", + "6e293bf5d03fe43977cfe3f57ccdb3ae282a85455dca33f37f4b74f8398cc612433d755cbec412f8f82a3bd3bc4a278f7ecd0dfa9bbdc40be7a787c8f159b2df", + "c56546fb2178456f336164c18b90deffc83ae2b5a3aca77b6884d36d2c1db39501b3e65e36c758c66e3188451fdb3515ee162c001f06c3e8cb573adf30f7a101", + "6f82f89f299ebca2fe014b59bffe1aa84e88b1915fe256afb646fd8448af2b8891a7fab37a4ea6f9a50e6c317039d8cf878f4c8e1a0dd464f0b4d6ff1c7ea853", + "2b8599ff9c3d6198637ad51e57d1998b0d75313fe2dd61a533c964a6dd9607c6f723e9452ce46e014b1c1d6de77ba5b88c914d1c597bf1eae13474b4290e89b2", + "08bf346d38e1df06c8260edb1da75579275948d5c0a0aa9ed2886f8856de5417a156998758f5b17e52f101ca957a71137473dfd18d7d209c4c10d9233c93691d", + "6df2156d773114d310b63db9ee5350d77e6bcf25b05fcd910f9b31bc42bb13fe8225ebcb2a23a62280777b6bf74e2cd0917c7640b43defe468cd1e18c943c66a", + "7c7038bc13a91151828a5ba82b4a96040f258a4dfb1b1373f0d359168afb0517a20b28a12d3644046be66b8d08d8ae7f6a923ea1c00187c6d11dc502bac71305", + "bcd1b30d808fb739b987cbf154bea00da9d40380b861d4c1d6377122dadd61c0e59018b71941cfb62e00dcd70aeb9abf0473e80f0a7eca6b6dea246ab229dd2b", + "7ed4468d968530fe7ab2c33540b26d8c3bd3ed44b34fbe8c2a9d7f805b5ada0ea252eeade4fce97f89728ad85bc8bb2430b1bef2cddd32c8446e59b8e8ba3c67", + "6d30b7c6ce8a3236c0ca2f8d728b1088ca06983a8043e621d5dcf0c537d13b08791edeb01a3cf0943ec1c890ab6e29b146a236cd46bcb9d93bf516fb67c63fe5", + "97fe03cef31438508911bded975980a66029305dc5e3fa8ad1b4fb22fcdf5a19a733320327d8f71ccf496cb3a44a77af56e3dde73d3a5f176896cc57c9a5ad99", + "785a9d0fbd21136dbce8fa7eafd63c9dad220052978416b31d9753eaa149097847ed9b30a65c70507eff01879149ed5cf0471d37798edc05abd56ad4a2cccb1d", + "ad408d2abddfd37b3bf34794c1a3371d928ed7fc8d966225333584c5665817832a37c07f0dc7cb5aa874cd7d20fe8fab8eabcb9b33d2e0841f6e200960899d95", + "97668f745b6032fc815d9579322769dccd9501a5080029b8ae826befb6742331bd9f76efeb3e2b8e81a9786b282f5068a3a2424697a77c41876b7e753f4c7767", + "26bb985f47e7fee0cfd252d4ef96bed42b9c370c1c6a3e8c9eb04ef7f7818b833a0d1f043ebafb911dc779e02740a02a44d3a1ea45ed4ad55e686c927cafe97e", + "5bfe2b1dcf7fe9b95088acedb575c19016c743b2e763bf5851ac407c9eda43715edfa48b4825492c5179593fff21351b76e8b7e034e4c53c79f61f29c479bd08", + "c76509ef72f4a6f9c9c40618ed52b2084f83502232e0ac8bdaf3264368e4d0180f6854c4abf4f6509c79caafc44cf3194afc57bd077bd7b3c9bda3d4b8775816", + "d66f2beab990e354ccb910e4e9c7ac618c7b63ef292a96b552341de78dc46d3ec8cfabc699b50af41fda39cf1b0173660923510ad67faedef5207cffe8641d20", + "7d8f0672992b79be3a364d8e5904f4ab713bbc8ab01b4f309ad8ccf223ce1034a860dcb0b00550612cc2fa17f2969e18f22e1427d254b4a82b3a03a3eb394adf", + "a56d6725bfb3de47c1414adf25fc8f0fc9846f6987722bc06366d5ca4e89722925ebbc881418844075397a0ca89842c7b9e9e07e1d9d183ebeb39e120b483bf7", + "af5e03d7fe60c67e10313344434e79485a03a758d6dce985574745763c1c5c77d4fb3e6fb12230368370993bf90feed0c5d1607524562d7c09c0c210ed393d7c", + "7a20540cc07bf72b582421fc342e82f52134b69841ec28ed189e2ea6a29dd2f82a640352d222b52f2911dc72a7dab31caadd80c6118f13c56b2a1e4373be0ea3", + "486f02c63e5467ea1fdde7e82bfacc2c1ba5d636d9f3d08b210da3f372f706ec218cc17ff60aef703bbe0c15c38ae55d286a684f864c78211ccab4178c92adba", + "1c7a5c1dedcd04a921788f7eb23361ca1953b04b9c7aec35d65ea3e4996db26f281278ea4ae666ad81027d98af57262cdbfa4c085f4210568c7e15eec7805114", + "9ce3fa9a860bdbd5378fd6d7b8b671c6cb7692910ce8f9b6cb4122cbcbe6ac06ca0422cef1225935053b7d193a81b9e972eb85a1d3074f14cbb5ec9f0573892d", + "a91187be5c371c4265c174fd4653b8ab708551f83d1fee1cc1479581bc006d6fb78fcc9a5dee1db3666f508f9780a37593ebcccf5fbed39667dc6361e921f779", + "4625767d7b1d3d3ed2fbc674af14e0244152f2a4021fcf3311505d89bd81e2f9f9a500c3b199914db49500b3c98d03ea93286751a686a3b875daab0ccd63b44f", + "43dfdfe1b014fed3a2acabb7f3e9a182f2aa18019d27e3e6cdcf31a15b428e91e7b08cf5e5c376fce2d8a28ff85ab0a0a1656edb4a0a91532620096d9a5a652d", + "279e3202be3989ba3112772585177487e4fe3ee3eab49c2f7fa7fe87cfe7b80d3e0355edff6d031e6c96c795db1c6f041880ec3824defacf9263820a8e7327de", + "ea2d066ac229d4d4b616a8bedec734325224e4b4e58f1ae6dad7e40c2da29196c3b1ea9571dacc81e87328caa0211e09027b0524aa3f4a849917b3586747ebbb", + "49f014f5c61822c899ab5cae51be4044a4495e777deb7da9b6d8490efbb87530adf293daf079f94c33b7044ef62e2e5bb3eb11e17304f8453ee6ce24f033ddb0", + "9233490344e5b0dc5912671b7ae54cee7730dbe1f4c7d92a4d3e3aab50571708db51dcf9c2944591db651db32d22935b86944969be77d5b5feae6c3840a8db26", + "b6e75e6f4c7f453b7465d25b5ac8c7196902eaa953875228c8634e16e2ae1f38bc3275304335f5989eccc1e34167d4e68d7719968fba8e2fe67947c35c48e806", + "cc14ca665af1483efbc3af80080e650d5046a3932f4f51f3fe90a0705ec25104adf07839265dc51d43401411246e474f0d5e5637af94767283d53e0617e981f4", + "230a1c857cb2e7852e41b647e90e4585d2d881e1734dc38955356e8dd7bff39053092c6b38e236e1899525647073dddf6895d64206325e7647f275567b255909", + "cbb65321ac436e2ffdab2936359ce49023f7dee7614ef28d173c3d27c5d1bffa51553d433f8ee3c9e49c05a2b883cce954c9a8093b80612a0cdd4732e041f995", + "3e7e570074337275efb51315588034c3cf0dddca20b4612e0bd5b881e7e5476d319ce4fe9f19186e4c0826f44f131eb048e65be242b1172c63badb123ab0cbe8", + "d32e9ec02d38d4e1b8249df8dcb00c5b9c68eb8922672e3505393b6a210ba56f9496e5ee0490ef387c3cdec061f06bc0382d9304cafbb8e0cd33d57029e62df2", + "8c1512466089f05b3775c262b62d22b83854a83218130b4ec91b3ccbd293d2a54302cecaab9b100c68d1e6ddc8f07cddbdfe6fdaaaf099cc09d6b725879c6369", + "91a7f61c97c2911e4c812ef71d780ad8fa788794561d08303fd1c1cb608a46a12563086ec5b39d471aed94fb0f6c678a43b8792932f9028d772a22768ea23a9b", + "4f6bb222a395e8b18f6ba155477aed3f0729ac9e83e16d31a2a8bc655422b837c891c6199e6f0d75799e3b691525c581953517f252c4b9e3a27a28fbaf49644c", + "5d06c07e7a646c413a501c3f4bb2fc38127de7509b7077c4d9b5613201c1aa02fd5f79d2745915dd57fbcb4ce08695f6efc0cb3d2d330e19b4b0e6004ea6471e", + "b96756e57909968f14b796a5d30f4c9d671472cf82c8cfb2caca7ac7a44ca0a14c9842d00c82e337502c94d5960aca4c492ea7b0df919ddf1aada2a275bb10d4", + "ff0a015e98db9c99f03977710aac3e658c0d896f6d71d618ba79dc6cf72ac75b7c038eb6862dede4543e145413a6368d69f5722c827ba3ef25b6ae6440d39276", + "5b21c5fd8868367612474fa2e70e9cfa2201ffeee8fafab5797ad58fefa17c9b5b107da4a3db6320baaf2c8617d5a51df914ae88da3867c2d41f0cc14fa67928", +} + +var goldenKeyed = []string{ + "10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e996e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568", + "961f6dd1e4dd30f63901690c512e78e4b45e4742ed197c3c5e45c549fd25f2e4187b0bc9fe30492b16b0d0bc4ef9b0f34c7003fac09a5ef1532e69430234cebd", + "da2cfbe2d8409a0f38026113884f84b50156371ae304c4430173d08a99d9fb1b983164a3770706d537f49e0c916d9f32b95cc37a95b99d857436f0232c88a965", + "33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1", + "beaa5a3d08f3807143cf621d95cd690514d0b49efff9c91d24b59241ec0eefa5f60196d407048bba8d2146828ebcb0488d8842fd56bb4f6df8e19c4b4daab8ac", + "098084b51fd13deae5f4320de94a688ee07baea2800486689a8636117b46c1f4c1f6af7f74ae7c857600456a58a3af251dc4723a64cc7c0a5ab6d9cac91c20bb", + "6044540d560853eb1c57df0077dd381094781cdb9073e5b1b3d3f6c7829e12066bbaca96d989a690de72ca3133a83652ba284a6d62942b271ffa2620c9e75b1f", + "7a8cfe9b90f75f7ecb3acc053aaed6193112b6f6a4aeeb3f65d3de541942deb9e2228152a3c4bbbe72fc3b12629528cfbb09fe630f0474339f54abf453e2ed52", + "380beaf6ea7cc9365e270ef0e6f3a64fb902acae51dd5512f84259ad2c91f4bc4108db73192a5bbfb0cbcf71e46c3e21aee1c5e860dc96e8eb0b7b8426e6abe9", + "60fe3c4535e1b59d9a61ea8500bfac41a69dffb1ceadd9aca323e9a625b64da5763bad7226da02b9c8c4f1a5de140ac5a6c1124e4f718ce0b28ea47393aa6637", + "4fe181f54ad63a2983feaaf77d1e7235c2beb17fa328b6d9505bda327df19fc37f02c4b6f0368ce23147313a8e5738b5fa2a95b29de1c7f8264eb77b69f585cd", + "f228773ce3f3a42b5f144d63237a72d99693adb8837d0e112a8a0f8ffff2c362857ac49c11ec740d1500749dac9b1f4548108bf3155794dcc9e4082849e2b85b", + "962452a8455cc56c8511317e3b1f3b2c37df75f588e94325fdd77070359cf63a9ae6e930936fdf8e1e08ffca440cfb72c28f06d89a2151d1c46cd5b268ef8563", + "43d44bfa18768c59896bf7ed1765cb2d14af8c260266039099b25a603e4ddc5039d6ef3a91847d1088d401c0c7e847781a8a590d33a3c6cb4df0fab1c2f22355", + "dcffa9d58c2a4ca2cdbb0c7aa4c4c1d45165190089f4e983bb1c2cab4aaeff1fa2b5ee516fecd780540240bf37e56c8bcca7fab980e1e61c9400d8a9a5b14ac6", + "6fbf31b45ab0c0b8dad1c0f5f4061379912dde5aa922099a030b725c73346c524291adef89d2f6fd8dfcda6d07dad811a9314536c2915ed45da34947e83de34e", + "a0c65bddde8adef57282b04b11e7bc8aab105b99231b750c021f4a735cb1bcfab87553bba3abb0c3e64a0b6955285185a0bd35fb8cfde557329bebb1f629ee93", + "f99d815550558e81eca2f96718aed10d86f3f1cfb675cce06b0eff02f617c5a42c5aa760270f2679da2677c5aeb94f1142277f21c7f79f3c4f0cce4ed8ee62b1", + "95391da8fc7b917a2044b3d6f5374e1ca072b41454d572c7356c05fd4bc1e0f40b8bb8b4a9f6bce9be2c4623c399b0dca0dab05cb7281b71a21b0ebcd9e55670", + "04b9cd3d20d221c09ac86913d3dc63041989a9a1e694f1e639a3ba7e451840f750c2fc191d56ad61f2e7936bc0ac8e094b60caeed878c18799045402d61ceaf9", + "ec0e0ef707e4ed6c0c66f9e089e4954b058030d2dd86398fe84059631f9ee591d9d77375355149178c0cf8f8e7c49ed2a5e4f95488a2247067c208510fadc44c", + "9a37cce273b79c09913677510eaf7688e89b3314d3532fd2764c39de022a2945b5710d13517af8ddc0316624e73bec1ce67df15228302036f330ab0cb4d218dd", + "4cf9bb8fb3d4de8b38b2f262d3c40f46dfe747e8fc0a414c193d9fcf753106ce47a18f172f12e8a2f1c26726545358e5ee28c9e2213a8787aafbc516d2343152", + "64e0c63af9c808fd893137129867fd91939d53f2af04be4fa268006100069b2d69daa5c5d8ed7fddcb2a70eeecdf2b105dd46a1e3b7311728f639ab489326bc9", + "5e9c93158d659b2def06b0c3c7565045542662d6eee8a96a89b78ade09fe8b3dcc096d4fe48815d88d8f82620156602af541955e1f6ca30dce14e254c326b88f", + "7775dff889458dd11aef417276853e21335eb88e4dec9cfb4e9edb49820088551a2ca60339f12066101169f0dfe84b098fddb148d9da6b3d613df263889ad64b", + "f0d2805afbb91f743951351a6d024f9353a23c7ce1fc2b051b3a8b968c233f46f50f806ecb1568ffaa0b60661e334b21dde04f8fa155ac740eeb42e20b60d764", + "86a2af316e7d7754201b942e275364ac12ea8962ab5bd8d7fb276dc5fbffc8f9a28cae4e4867df6780d9b72524160927c855da5b6078e0b554aa91e31cb9ca1d", + "10bdf0caa0802705e706369baf8a3f79d72c0a03a80675a7bbb00be3a45e516424d1ee88efb56f6d5777545ae6e27765c3a8f5e493fc308915638933a1dfee55", + "b01781092b1748459e2e4ec178696627bf4ebafebba774ecf018b79a68aeb84917bf0b84bb79d17b743151144cd66b7b33a4b9e52c76c4e112050ff5385b7f0b", + "c6dbc61dec6eaeac81e3d5f755203c8e220551534a0b2fd105a91889945a638550204f44093dd998c076205dffad703a0e5cd3c7f438a7e634cd59fededb539e", + "eba51acffb4cea31db4b8d87e9bf7dd48fe97b0253ae67aa580f9ac4a9d941f2bea518ee286818cc9f633f2a3b9fb68e594b48cdd6d515bf1d52ba6c85a203a7", + "86221f3ada52037b72224f105d7999231c5e5534d03da9d9c0a12acb68460cd375daf8e24386286f9668f72326dbf99ba094392437d398e95bb8161d717f8991", + "5595e05c13a7ec4dc8f41fb70cb50a71bce17c024ff6de7af618d0cc4e9c32d9570d6d3ea45b86525491030c0d8f2b1836d5778c1ce735c17707df364d054347", + "ce0f4f6aca89590a37fe034dd74dd5fa65eb1cbd0a41508aaddc09351a3cea6d18cb2189c54b700c009f4cbf0521c7ea01be61c5ae09cb54f27bc1b44d658c82", + "7ee80b06a215a3bca970c77cda8761822bc103d44fa4b33f4d07dcb997e36d55298bceae12241b3fa07fa63be5576068da387b8d5859aeab701369848b176d42", + "940a84b6a84d109aab208c024c6ce9647676ba0aaa11f86dbb7018f9fd2220a6d901a9027f9abcf935372727cbf09ebd61a2a2eeb87653e8ecad1bab85dc8327", + "2020b78264a82d9f4151141adba8d44bf20c5ec062eee9b595a11f9e84901bf148f298e0c9f8777dcdbc7cc4670aac356cc2ad8ccb1629f16f6a76bcefbee760", + "d1b897b0e075ba68ab572adf9d9c436663e43eb3d8e62d92fc49c9be214e6f27873fe215a65170e6bea902408a25b49506f47babd07cecf7113ec10c5dd31252", + "b14d0c62abfa469a357177e594c10c194243ed2025ab8aa5ad2fa41ad318e0ff48cd5e60bec07b13634a711d2326e488a985f31e31153399e73088efc86a5c55", + "4169c5cc808d2697dc2a82430dc23e3cd356dc70a94566810502b8d655b39abf9e7f902fe717e0389219859e1945df1af6ada42e4ccda55a197b7100a30c30a1", + "258a4edb113d66c839c8b1c91f15f35ade609f11cd7f8681a4045b9fef7b0b24c82cda06a5f2067b368825e3914e53d6948ede92efd6e8387fa2e537239b5bee", + "79d2d8696d30f30fb34657761171a11e6c3f1e64cbe7bebee159cb95bfaf812b4f411e2f26d9c421dc2c284a3342d823ec293849e42d1e46b0a4ac1e3c86abaa", + "8b9436010dc5dee992ae38aea97f2cd63b946d94fedd2ec9671dcde3bd4ce9564d555c66c15bb2b900df72edb6b891ebcadfeff63c9ea4036a998be7973981e7", + "c8f68e696ed28242bf997f5b3b34959508e42d613810f1e2a435c96ed2ff560c7022f361a9234b9837feee90bf47922ee0fd5f8ddf823718d86d1e16c6090071", + "b02d3eee4860d5868b2c39ce39bfe81011290564dd678c85e8783f29302dfc1399ba95b6b53cd9ebbf400cca1db0ab67e19a325f2d115812d25d00978ad1bca4", + "7693ea73af3ac4dad21ca0d8da85b3118a7d1c6024cfaf557699868217bc0c2f44a199bc6c0edd519798ba05bd5b1b4484346a47c2cadf6bf30b785cc88b2baf", + "a0e5c1c0031c02e48b7f09a5e896ee9aef2f17fc9e18e997d7f6cac7ae316422c2b1e77984e5f3a73cb45deed5d3f84600105e6ee38f2d090c7d0442ea34c46d", + "41daa6adcfdb69f1440c37b596440165c15ada596813e2e22f060fcd551f24dee8e04ba6890387886ceec4a7a0d7fc6b44506392ec3822c0d8c1acfc7d5aebe8", + "14d4d40d5984d84c5cf7523b7798b254e275a3a8cc0a1bd06ebc0bee726856acc3cbf516ff667cda2058ad5c3412254460a82c92187041363cc77a4dc215e487", + "d0e7a1e2b9a447fee83e2277e9ff8010c2f375ae12fa7aaa8ca5a6317868a26a367a0b69fbc1cf32a55d34eb370663016f3d2110230eba754028a56f54acf57c", + "e771aa8db5a3e043e8178f39a0857ba04a3f18e4aa05743cf8d222b0b095825350ba422f63382a23d92e4149074e816a36c1cd28284d146267940b31f8818ea2", + "feb4fd6f9e87a56bef398b3284d2bda5b5b0e166583a66b61e538457ff0584872c21a32962b9928ffab58de4af2edd4e15d8b35570523207ff4e2a5aa7754caa", + "462f17bf005fb1c1b9e671779f665209ec2873e3e411f98dabf240a1d5ec3f95ce6796b6fc23fe171903b502023467dec7273ff74879b92967a2a43a5a183d33", + "d3338193b64553dbd38d144bea71c5915bb110e2d88180dbc5db364fd6171df317fc7268831b5aef75e4342b2fad8797ba39eddcef80e6ec08159350b1ad696d", + "e1590d585a3d39f7cb599abd479070966409a6846d4377acf4471d065d5db94129cc9be92573b05ed226be1e9b7cb0cabe87918589f80dadd4ef5ef25a93d28e", + "f8f3726ac5a26cc80132493a6fedcb0e60760c09cfc84cad178175986819665e76842d7b9fedf76dddebf5d3f56faaad4477587af21606d396ae570d8e719af2", + "30186055c07949948183c850e9a756cc09937e247d9d928e869e20bafc3cd9721719d34e04a0899b92c736084550186886efba2e790d8be6ebf040b209c439a4", + "f3c4276cb863637712c241c444c5cc1e3554e0fddb174d035819dd83eb700b4ce88df3ab3841ba02085e1a99b4e17310c5341075c0458ba376c95a6818fbb3e2", + "0aa007c4dd9d5832393040a1583c930bca7dc5e77ea53add7e2b3f7c8e231368043520d4a3ef53c969b6bbfd025946f632bd7f765d53c21003b8f983f75e2a6a", + "08e9464720533b23a04ec24f7ae8c103145f765387d738777d3d343477fd1c58db052142cab754ea674378e18766c53542f71970171cc4f81694246b717d7564", + "d37ff7ad297993e7ec21e0f1b4b5ae719cdc83c5db687527f27516cbffa822888a6810ee5c1ca7bfe3321119be1ab7bfa0a502671c8329494df7ad6f522d440f", + "dd9042f6e464dcf86b1262f6accfafbd8cfd902ed3ed89abf78ffa482dbdeeb6969842394c9a1168ae3d481a017842f660002d42447c6b22f7b72f21aae021c9", + "bd965bf31e87d70327536f2a341cebc4768eca275fa05ef98f7f1b71a0351298de006fba73fe6733ed01d75801b4a928e54231b38e38c562b2e33ea1284992fa", + "65676d800617972fbd87e4b9514e1c67402b7a331096d3bfac22f1abb95374abc942f16e9ab0ead33b87c91968a6e509e119ff07787b3ef483e1dcdccf6e3022", + "939fa189699c5d2c81ddd1ffc1fa207c970b6a3685bb29ce1d3e99d42f2f7442da53e95a72907314f4588399a3ff5b0a92beb3f6be2694f9f86ecf2952d5b41c", + "c516541701863f91005f314108ceece3c643e04fc8c42fd2ff556220e616aaa6a48aeb97a84bad74782e8dff96a1a2fa949339d722edcaa32b57067041df88cc", + "987fd6e0d6857c553eaebb3d34970a2c2f6e89a3548f492521722b80a1c21a153892346d2cba6444212d56da9a26e324dccbc0dcde85d4d2ee4399eec5a64e8f", + "ae56deb1c2328d9c4017706bce6e99d41349053ba9d336d677c4c27d9fd50ae6aee17e853154e1f4fe7672346da2eaa31eea53fcf24a22804f11d03da6abfc2b", + "49d6a608c9bde4491870498572ac31aac3fa40938b38a7818f72383eb040ad39532bc06571e13d767e6945ab77c0bdc3b0284253343f9f6c1244ebf2ff0df866", + "da582ad8c5370b4469af862aa6467a2293b2b28bd80ae0e91f425ad3d47249fdf98825cc86f14028c3308c9804c78bfeeeee461444ce243687e1a50522456a1d", + "d5266aa3331194aef852eed86d7b5b2633a0af1c735906f2e13279f14931a9fc3b0eac5ce9245273bd1aa92905abe16278ef7efd47694789a7283b77da3c70f8", + "2962734c28252186a9a1111c732ad4de4506d4b4480916303eb7991d659ccda07a9911914bc75c418ab7a4541757ad054796e26797feaf36e9f6ad43f14b35a4", + "e8b79ec5d06e111bdfafd71e9f5760f00ac8ac5d8bf768f9ff6f08b8f026096b1cc3a4c973333019f1e3553e77da3f98cb9f542e0a90e5f8a940cc58e59844b3", + "dfb320c44f9d41d1efdcc015f08dd5539e526e39c87d509ae6812a969e5431bf4fa7d91ffd03b981e0d544cf72d7b1c0374f8801482e6dea2ef903877eba675e", + "d88675118fdb55a5fb365ac2af1d217bf526ce1ee9c94b2f0090b2c58a06ca58187d7fe57c7bed9d26fca067b4110eefcd9a0a345de872abe20de368001b0745", + "b893f2fc41f7b0dd6e2f6aa2e0370c0cff7df09e3acfcc0e920b6e6fad0ef747c40668417d342b80d2351e8c175f20897a062e9765e6c67b539b6ba8b9170545", + "6c67ec5697accd235c59b486d7b70baeedcbd4aa64ebd4eef3c7eac189561a726250aec4d48cadcafbbe2ce3c16ce2d691a8cce06e8879556d4483ed7165c063", + "f1aa2b044f8f0c638a3f362e677b5d891d6fd2ab0765f6ee1e4987de057ead357883d9b405b9d609eea1b869d97fb16d9b51017c553f3b93c0a1e0f1296fedcd", + "cbaa259572d4aebfc1917acddc582b9f8dfaa928a198ca7acd0f2aa76a134a90252e6298a65b08186a350d5b7626699f8cb721a3ea5921b753ae3a2dce24ba3a", + "fa1549c9796cd4d303dcf452c1fbd5744fd9b9b47003d920b92de34839d07ef2a29ded68f6fc9e6c45e071a2e48bd50c5084e96b657dd0404045a1ddefe282ed", + "5cf2ac897ab444dcb5c8d87c495dbdb34e1838b6b629427caa51702ad0f9688525f13bec503a3c3a2c80a65e0b5715e8afab00ffa56ec455a49a1ad30aa24fcd", + "9aaf80207bace17bb7ab145757d5696bde32406ef22b44292ef65d4519c3bb2ad41a59b62cc3e94b6fa96d32a7faadae28af7d35097219aa3fd8cda31e40c275", + "af88b163402c86745cb650c2988fb95211b94b03ef290eed9662034241fd51cf398f8073e369354c43eae1052f9b63b08191caa138aa54fea889cc7024236897", + "48fa7d64e1ceee27b9864db5ada4b53d00c9bc7626555813d3cd6730ab3cc06ff342d727905e33171bde6e8476e77fb1720861e94b73a2c538d254746285f430", + "0e6fd97a85e904f87bfe85bbeb34f69e1f18105cf4ed4f87aec36c6e8b5f68bd2a6f3dc8a9ecb2b61db4eedb6b2ea10bf9cb0251fb0f8b344abf7f366b6de5ab", + "06622da5787176287fdc8fed440bad187d830099c94e6d04c8e9c954cda70c8bb9e1fc4a6d0baa831b9b78ef6648681a4867a11da93ee36e5e6a37d87fc63f6f", + "1da6772b58fabf9c61f68d412c82f182c0236d7d575ef0b58dd22458d643cd1dfc93b03871c316d8430d312995d4197f0874c99172ba004a01ee295abac24e46", + "3cd2d9320b7b1d5fb9aab951a76023fa667be14a9124e394513918a3f44096ae4904ba0ffc150b63bc7ab1eeb9a6e257e5c8f000a70394a5afd842715de15f29", + "04cdc14f7434e0b4be70cb41db4c779a88eaef6accebcb41f2d42fffe7f32a8e281b5c103a27021d0d08362250753cdf70292195a53a48728ceb5844c2d98bab", + "9071b7a8a075d0095b8fb3ae5113785735ab98e2b52faf91d5b89e44aac5b5d4ebbf91223b0ff4c71905da55342e64655d6ef8c89a4768c3f93a6dc0366b5bc8", + "ebb30240dd96c7bc8d0abe49aa4edcbb4afdc51ff9aaf720d3f9e7fbb0f9c6d6571350501769fc4ebd0b2141247ff400d4fd4be414edf37757bb90a32ac5c65a", + "8532c58bf3c8015d9d1cbe00eef1f5082f8f3632fbe9f1ed4f9dfb1fa79e8283066d77c44c4af943d76b300364aecbd0648c8a8939bd204123f4b56260422dec", + "fe9846d64f7c7708696f840e2d76cb4408b6595c2f81ec6a28a7f2f20cb88cfe6ac0b9e9b8244f08bd7095c350c1d0842f64fb01bb7f532dfcd47371b0aeeb79", + "28f17ea6fb6c42092dc264257e29746321fb5bdaea9873c2a7fa9d8f53818e899e161bc77dfe8090afd82bf2266c5c1bc930a8d1547624439e662ef695f26f24", + "ec6b7d7f030d4850acae3cb615c21dd25206d63e84d1db8d957370737ba0e98467ea0ce274c66199901eaec18a08525715f53bfdb0aacb613d342ebdceeddc3b", + "b403d3691c03b0d3418df327d5860d34bbfcc4519bfbce36bf33b208385fadb9186bc78a76c489d89fd57e7dc75412d23bcd1dae8470ce9274754bb8585b13c5", + "31fc79738b8772b3f55cd8178813b3b52d0db5a419d30ba9495c4b9da0219fac6df8e7c23a811551a62b827f256ecdb8124ac8a6792ccfecc3b3012722e94463", + "bb2039ec287091bcc9642fc90049e73732e02e577e2862b32216ae9bedcd730c4c284ef3968c368b7d37584f97bd4b4dc6ef6127acfe2e6ae2509124e66c8af4", + "f53d68d13f45edfcb9bd415e2831e938350d5380d3432278fc1c0c381fcb7c65c82dafe051d8c8b0d44e0974a0e59ec7bf7ed0459f86e96f329fc79752510fd3", + "8d568c7984f0ecdf7640fbc483b5d8c9f86634f6f43291841b309a350ab9c1137d24066b09da9944bac54d5bb6580d836047aac74ab724b887ebf93d4b32eca9", + "c0b65ce5a96ff774c456cac3b5f2c4cd359b4ff53ef93a3da0778be4900d1e8da1601e769e8f1b02d2a2f8c5b9fa10b44f1c186985468feeb008730283a6657d", + "4900bba6f5fb103ece8ec96ada13a5c3c85488e05551da6b6b33d988e611ec0fe2e3c2aa48ea6ae8986a3a231b223c5d27cec2eadde91ce07981ee652862d1e4", + "c7f5c37c7285f927f76443414d4357ff789647d7a005a5a787e03c346b57f49f21b64fa9cf4b7e45573e23049017567121a9c3d4b2b73ec5e9413577525db45a", + "ec7096330736fdb2d64b5653e7475da746c23a4613a82687a28062d3236364284ac01720ffb406cfe265c0df626a188c9e5963ace5d3d5bb363e32c38c2190a6", + "82e744c75f4649ec52b80771a77d475a3bc091989556960e276a5f9ead92a03f718742cdcfeaee5cb85c44af198adc43a4a428f5f0c2ddb0be36059f06d7df73", + "2834b7a7170f1f5b68559ab78c1050ec21c919740b784a9072f6e5d69f828d70c919c5039fb148e39e2c8a52118378b064ca8d5001cd10a5478387b966715ed6", + "16b4ada883f72f853bb7ef253efcab0c3e2161687ad61543a0d2824f91c1f81347d86be709b16996e17f2dd486927b0288ad38d13063c4a9672c39397d3789b6", + "78d048f3a69d8b54ae0ed63a573ae350d89f7c6cf1f3688930de899afa037697629b314e5cd303aa62feea72a25bf42b304b6c6bcb27fae21c16d925e1fbdac3", + "0f746a48749287ada77a82961f05a4da4abdb7d77b1220f836d09ec814359c0ec0239b8c7b9ff9e02f569d1b301ef67c4612d1de4f730f81c12c40cc063c5caa", + "f0fc859d3bd195fbdc2d591e4cdac15179ec0f1dc821c11df1f0c1d26e6260aaa65b79fafacafd7d3ad61e600f250905f5878c87452897647a35b995bcadc3a3", + "2620f687e8625f6a412460b42e2cef67634208ce10a0cbd4dff7044a41b7880077e9f8dc3b8d1216d3376a21e015b58fb279b521d83f9388c7382c8505590b9b", + "227e3aed8d2cb10b918fcb04f9de3e6d0a57e08476d93759cd7b2ed54a1cbf0239c528fb04bbf288253e601d3bc38b21794afef90b17094a182cac557745e75f", + "1a929901b09c25f27d6b35be7b2f1c4745131fdebca7f3e2451926720434e0db6e74fd693ad29b777dc3355c592a361c4873b01133a57c2e3b7075cbdb86f4fc", + "5fd7968bc2fe34f220b5e3dc5af9571742d73b7d60819f2888b629072b96a9d8ab2d91b82d0a9aaba61bbd39958132fcc4257023d1eca591b3054e2dc81c8200", + "dfcce8cf32870cc6a503eadafc87fd6f78918b9b4d0737db6810be996b5497e7e5cc80e312f61e71ff3e9624436073156403f735f56b0b01845c18f6caf772e6", + "02f7ef3a9ce0fff960f67032b296efca3061f4934d690749f2d01c35c81c14f39a67fa350bc8a0359bf1724bffc3bca6d7c7bba4791fd522a3ad353c02ec5aa8", + "64be5c6aba65d594844ae78bb022e5bebe127fd6b6ffa5a13703855ab63b624dcd1a363f99203f632ec386f3ea767fc992e8ed9686586aa27555a8599d5b808f", + "f78585505c4eaa54a8b5be70a61e735e0ff97af944ddb3001e35d86c4e2199d976104b6ae31750a36a726ed285064f5981b503889fef822fcdc2898dddb7889a", + "e4b5566033869572edfd87479a5bb73c80e8759b91232879d96b1dda36c012076ee5a2ed7ae2de63ef8406a06aea82c188031b560beafb583fb3de9e57952a7e", + "e1b3e7ed867f6c9484a2a97f7715f25e25294e992e41f6a7c161ffc2adc6daaeb7113102d5e6090287fe6ad94ce5d6b739c6ca240b05c76fb73f25dd024bf935", + "85fd085fdc12a080983df07bd7012b0d402a0f4043fcb2775adf0bad174f9b08d1676e476985785c0a5dcc41dbff6d95ef4d66a3fbdc4a74b82ba52da0512b74", + "aed8fa764b0fbff821e05233d2f7b0900ec44d826f95e93c343c1bc3ba5a24374b1d616e7e7aba453a0ada5e4fab5382409e0d42ce9c2bc7fb39a99c340c20f0", + "7ba3b2e297233522eeb343bd3ebcfd835a04007735e87f0ca300cbee6d416565162171581e4020ff4cf176450f1291ea2285cb9ebffe4c56660627685145051c", + "de748bcf89ec88084721e16b85f30adb1a6134d664b5843569babc5bbd1a15ca9b61803c901a4fef32965a1749c9f3a4e243e173939dc5a8dc495c671ab52145", + "aaf4d2bdf200a919706d9842dce16c98140d34bc433df320aba9bd429e549aa7a3397652a4d768277786cf993cde2338673ed2e6b66c961fefb82cd20c93338f", + "c408218968b788bf864f0997e6bc4c3dba68b276e2125a4843296052ff93bf5767b8cdce7131f0876430c1165fec6c4f47adaa4fd8bcfacef463b5d3d0fa61a0", + "76d2d819c92bce55fa8e092ab1bf9b9eab237a25267986cacf2b8ee14d214d730dc9a5aa2d7b596e86a1fd8fa0804c77402d2fcd45083688b218b1cdfa0dcbcb", + "72065ee4dd91c2d8509fa1fc28a37c7fc9fa7d5b3f8ad3d0d7a25626b57b1b44788d4caf806290425f9890a3a2a35a905ab4b37acfd0da6e4517b2525c9651e4", + "64475dfe7600d7171bea0b394e27c9b00d8e74dd1e416a79473682ad3dfdbb706631558055cfc8a40e07bd015a4540dcdea15883cbbf31412df1de1cd4152b91", + "12cd1674a4488a5d7c2b3160d2e2c4b58371bedad793418d6f19c6ee385d70b3e06739369d4df910edb0b0a54cbff43d54544cd37ab3a06cfa0a3ddac8b66c89", + "60756966479dedc6dd4bcff8ea7d1d4ce4d4af2e7b097e32e3763518441147cc12b3c0ee6d2ecabf1198cec92e86a3616fba4f4e872f5825330adbb4c1dee444", + "a7803bcb71bc1d0f4383dde1e0612e04f872b715ad30815c2249cf34abb8b024915cb2fc9f4e7cc4c8cfd45be2d5a91eab0941c7d270e2da4ca4a9f7ac68663a", + "b84ef6a7229a34a750d9a98ee2529871816b87fbe3bc45b45fa5ae82d5141540211165c3c5d7a7476ba5a4aa06d66476f0d9dc49a3f1ee72c3acabd498967414", + "fae4b6d8efc3f8c8e64d001dabec3a21f544e82714745251b2b4b393f2f43e0da3d403c64db95a2cb6e23ebb7b9e94cdd5ddac54f07c4a61bd3cb10aa6f93b49", + "34f7286605a122369540141ded79b8957255da2d4155abbf5a8dbb89c8eb7ede8eeef1daa46dc29d751d045dc3b1d658bb64b80ff8589eddb3824b13da235a6b", + "3b3b48434be27b9eababba43bf6b35f14b30f6a88dc2e750c358470d6b3aa3c18e47db4017fa55106d8252f016371a00f5f8b070b74ba5f23cffc5511c9f09f0", + "ba289ebd6562c48c3e10a8ad6ce02e73433d1e93d7c9279d4d60a7e879ee11f441a000f48ed9f7c4ed87a45136d7dccdca482109c78a51062b3ba4044ada2469", + "022939e2386c5a37049856c850a2bb10a13dfea4212b4c732a8840a9ffa5faf54875c5448816b2785a007da8a8d2bc7d71a54e4e6571f10b600cbdb25d13ede3", + "e6fec19d89ce8717b1a087024670fe026f6c7cbda11caef959bb2d351bf856f8055d1c0ebdaaa9d1b17886fc2c562b5e99642fc064710c0d3488a02b5ed7f6fd", + "94c96f02a8f576aca32ba61c2b206f907285d9299b83ac175c209a8d43d53bfe683dd1d83e7549cb906c28f59ab7c46f8751366a28c39dd5fe2693c9019666c8", + "31a0cd215ebd2cb61de5b9edc91e6195e31c59a5648d5c9f737e125b2605708f2e325ab3381c8dce1a3e958886f1ecdc60318f882cfe20a24191352e617b0f21", + "91ab504a522dce78779f4c6c6ba2e6b6db5565c76d3e7e7c920caf7f757ef9db7c8fcf10e57f03379ea9bf75eb59895d96e149800b6aae01db778bb90afbc989", + "d85cabc6bd5b1a01a5afd8c6734740da9fd1c1acc6db29bfc8a2e5b668b028b6b3154bfb8703fa3180251d589ad38040ceb707c4bad1b5343cb426b61eaa49c1", + "d62efbec2ca9c1f8bd66ce8b3f6a898cb3f7566ba6568c618ad1feb2b65b76c3ce1dd20f7395372faf28427f61c9278049cf0140df434f5633048c86b81e0399", + "7c8fdc6175439e2c3db15bafa7fb06143a6a23bc90f449e79deef73c3d492a671715c193b6fea9f036050b946069856b897e08c00768f5ee5ddcf70b7cd6d0e0", + "58602ee7468e6bc9df21bd51b23c005f72d6cb013f0a1b48cbec5eca299299f97f09f54a9a01483eaeb315a6478bad37ba47ca1347c7c8fc9e6695592c91d723", + "27f5b79ed256b050993d793496edf4807c1d85a7b0a67c9c4fa99860750b0ae66989670a8ffd7856d7ce411599e58c4d77b232a62bef64d15275be46a68235ff", + "3957a976b9f1887bf004a8dca942c92d2b37ea52600f25e0c9bc5707d0279c00c6e85a839b0d2d8eb59c51d94788ebe62474a791cadf52cccf20f5070b6573fc", + "eaa2376d55380bf772ecca9cb0aa4668c95c707162fa86d518c8ce0ca9bf7362b9f2a0adc3ff59922df921b94567e81e452f6c1a07fc817cebe99604b3505d38", + "c1e2c78b6b2734e2480ec550434cb5d613111adcc21d475545c3b1b7e6ff12444476e5c055132e2229dc0f807044bb919b1a5662dd38a9ee65e243a3911aed1a", + "8ab48713389dd0fcf9f965d3ce66b1e559a1f8c58741d67683cd971354f452e62d0207a65e436c5d5d8f8ee71c6abfe50e669004c302b31a7ea8311d4a916051", + "24ce0addaa4c65038bd1b1c0f1452a0b128777aabc94a29df2fd6c7e2f85f8ab9ac7eff516b0e0a825c84a24cfe492eaad0a6308e46dd42fe8333ab971bb30ca", + "5154f929ee03045b6b0c0004fa778edee1d139893267cc84825ad7b36c63de32798e4a166d24686561354f63b00709a1364b3c241de3febf0754045897467cd4", + "e74e907920fd87bd5ad636dd11085e50ee70459c443e1ce5809af2bc2eba39f9e6d7128e0e3712c316da06f4705d78a4838e28121d4344a2c79c5e0db307a677", + "bf91a22334bac20f3fd80663b3cd06c4e8802f30e6b59f90d3035cc9798a217ed5a31abbda7fa6842827bdf2a7a1c21f6fcfccbb54c6c52926f32da816269be1", + "d9d5c74be5121b0bd742f26bffb8c89f89171f3f934913492b0903c271bbe2b3395ef259669bef43b57f7fcc3027db01823f6baee66e4f9fead4d6726c741fce", + "50c8b8cf34cd879f80e2faab3230b0c0e1cc3e9dcadeb1b9d97ab923415dd9a1fe38addd5c11756c67990b256e95ad6d8f9fedce10bf1c90679cde0ecf1be347", + "0a386e7cd5dd9b77a035e09fe6fee2c8ce61b5383c87ea43205059c5e4cd4f4408319bb0a82360f6a58e6c9ce3f487c446063bf813bc6ba535e17fc1826cfc91", + "1f1459cb6b61cbac5f0efe8fc487538f42548987fcd56221cfa7beb22504769e792c45adfb1d6b3d60d7b749c8a75b0bdf14e8ea721b95dca538ca6e25711209", + "e58b3836b7d8fedbb50ca5725c6571e74c0785e97821dab8b6298c10e4c079d4a6cdf22f0fedb55032925c16748115f01a105e77e00cee3d07924dc0d8f90659", + "b929cc6505f020158672deda56d0db081a2ee34c00c1100029bdf8ea98034fa4bf3e8655ec697fe36f40553c5bb46801644a627d3342f4fc92b61f03290fb381", + "72d353994b49d3e03153929a1e4d4f188ee58ab9e72ee8e512f29bc773913819ce057ddd7002c0433ee0a16114e3d156dd2c4a7e80ee53378b8670f23e33ef56", + "c70ef9bfd775d408176737a0736d68517ce1aaad7e81a93c8c1ed967ea214f56c8a377b1763e676615b60f3988241eae6eab9685a5124929d28188f29eab06f7", + "c230f0802679cb33822ef8b3b21bf7a9a28942092901d7dac3760300831026cf354c9232df3e084d9903130c601f63c1f4a4a4b8106e468cd443bbe5a734f45f", + "6f43094cafb5ebf1f7a4937ec50f56a4c9da303cbb55ac1f27f1f1976cd96beda9464f0e7b9c54620b8a9fba983164b8be3578425a024f5fe199c36356b88972", + "3745273f4c38225db2337381871a0c6aafd3af9b018c88aa02025850a5dc3a42a1a3e03e56cbf1b0876d63a441f1d2856a39b8801eb5af325201c415d65e97fe", + "c50c44cca3ec3edaae779a7e179450ebdda2f97067c690aa6c5a4ac7c30139bb27c0df4db3220e63cb110d64f37ffe078db72653e2daacf93ae3f0a2d1a7eb2e", + "8aef263e385cbc61e19b28914243262af5afe8726af3ce39a79c27028cf3ecd3f8d2dfd9cfc9ad91b58f6f20778fd5f02894a3d91c7d57d1e4b866a7f364b6be", + "28696141de6e2d9bcb3235578a66166c1448d3e905a1b482d423be4bc5369bc8c74dae0acc9cc123e1d8ddce9f97917e8c019c552da32d39d2219b9abf0fa8c8", + "2fb9eb2085830181903a9dafe3db428ee15be7662224efd643371fb25646aee716e531eca69b2bdc8233f1a8081fa43da1500302975a77f42fa592136710e9dc", + "66f9a7143f7a3314a669bf2e24bbb35014261d639f495b6c9c1f104fe8e320aca60d4550d69d52edbd5a3cdeb4014ae65b1d87aa770b69ae5c15f4330b0b0ad8", + "f4c4dd1d594c3565e3e25ca43dad82f62abea4835ed4cd811bcd975e46279828d44d4c62c3679f1b7f7b9dd4571d7b49557347b8c5460cbdc1bef690fb2a08c0", + "8f1dc9649c3a84551f8f6e91cac68242a43b1f8f328ee92280257387fa7559aa6db12e4aeadc2d26099178749c6864b357f3f83b2fb3efa8d2a8db056bed6bcc", + "3139c1a7f97afd1675d460ebbc07f2728aa150df849624511ee04b743ba0a833092f18c12dc91b4dd243f333402f59fe28abdbbbae301e7b659c7a26d5c0f979", + "06f94a2996158a819fe34c40de3cf0379fd9fb85b3e363ba3926a0e7d960e3f4c2e0c70c7ce0ccb2a64fc29869f6e7ab12bd4d3f14fce943279027e785fb5c29", + "c29c399ef3eee8961e87565c1ce263925fc3d0ce267d13e48dd9e732ee67b0f69fad56401b0f10fcaac119201046cca28c5b14abdea3212ae65562f7f138db3d", + "4cec4c9df52eef05c3f6faaa9791bc7445937183224ecc37a1e58d0132d35617531d7e795f52af7b1eb9d147de1292d345fe341823f8e6bc1e5badca5c656108", + "898bfbae93b3e18d00697eab7d9704fa36ec339d076131cefdf30edbe8d9cc81c3a80b129659b163a323bab9793d4feed92d54dae966c77529764a09be88db45", + "ee9bd0469d3aaf4f14035be48a2c3b84d9b4b1fff1d945e1f1c1d38980a951be197b25fe22c731f20aeacc930ba9c4a1f4762227617ad350fdabb4e80273a0f4", + "3d4d3113300581cd96acbf091c3d0f3c310138cd6979e6026cde623e2dd1b24d4a8638bed1073344783ad0649cc6305ccec04beb49f31c633088a99b65130267", + "95c0591ad91f921ac7be6d9ce37e0663ed8011c1cfd6d0162a5572e94368bac02024485e6a39854aa46fe38e97d6c6b1947cd272d86b06bb5b2f78b9b68d559d", + "227b79ded368153bf46c0a3ca978bfdbef31f3024a5665842468490b0ff748ae04e7832ed4c9f49de9b1706709d623e5c8c15e3caecae8d5e433430ff72f20eb", + "5d34f3952f0105eef88ae8b64c6ce95ebfade0e02c69b08762a8712d2e4911ad3f941fc4034dc9b2e479fdbcd279b902faf5d838bb2e0c6495d372b5b7029813", + "7f939bf8353abce49e77f14f3750af20b7b03902e1a1e7fb6aaf76d0259cd401a83190f15640e74f3e6c5a90e839c7821f6474757f75c7bf9002084ddc7a62dc", + "062b61a2f9a33a71d7d0a06119644c70b0716a504de7e5e1be49bd7b86e7ed6817714f9f0fc313d06129597e9a2235ec8521de36f7290a90ccfc1ffa6d0aee29", + "f29e01eeae64311eb7f1c6422f946bf7bea36379523e7b2bbaba7d1d34a22d5ea5f1c5a09d5ce1fe682cced9a4798d1a05b46cd72dff5c1b355440b2a2d476bc", + "ec38cd3bbab3ef35d7cb6d5c914298351d8a9dc97fcee051a8a02f58e3ed6184d0b7810a5615411ab1b95209c3c810114fdeb22452084e77f3f847c6dbaafe16", + "c2aef5e0ca43e82641565b8cb943aa8ba53550caef793b6532fafad94b816082f0113a3ea2f63608ab40437ecc0f0229cb8fa224dcf1c478a67d9b64162b92d1", + "15f534efff7105cd1c254d074e27d5898b89313b7d366dc2d7d87113fa7d53aae13f6dba487ad8103d5e854c91fdb6e1e74b2ef6d1431769c30767dde067a35c", + "89acbca0b169897a0a2714c2df8c95b5b79cb69390142b7d6018bb3e3076b099b79a964152a9d912b1b86412b7e372e9cecad7f25d4cbab8a317be36492a67d7", + "e3c0739190ed849c9c962fd9dbb55e207e624fcac1eb417691515499eea8d8267b7e8f1287a63633af5011fde8c4ddf55bfdf722edf88831414f2cfaed59cb9a", + "8d6cf87c08380d2d1506eee46fd4222d21d8c04e585fbfd08269c98f702833a156326a0724656400ee09351d57b440175e2a5de93cc5f80db6daf83576cf75fa", + "da24bede383666d563eeed37f6319baf20d5c75d1635a6ba5ef4cfa1ac95487e96f8c08af600aab87c986ebad49fc70a58b4890b9c876e091016daf49e1d322e", + "f9d1d1b1e87ea7ae753a029750cc1cf3d0157d41805e245c5617bb934e732f0ae3180b78e05bfe76c7c3051e3e3ac78b9b50c05142657e1e03215d6ec7bfd0fc", + "11b7bc1668032048aa43343de476395e814bbbc223678db951a1b03a021efac948cfbe215f97fe9a72a2f6bc039e3956bfa417c1a9f10d6d7ba5d3d32ff323e5", + "b8d9000e4fc2b066edb91afee8e7eb0f24e3a201db8b6793c0608581e628ed0bcc4e5aa6787992a4bcc44e288093e63ee83abd0bc3ec6d0934a674a4da13838a", + "ce325e294f9b6719d6b61278276ae06a2564c03bb0b783fafe785bdf89c7d5acd83e78756d301b445699024eaeb77b54d477336ec2a4f332f2b3f88765ddb0c3", + "29acc30e9603ae2fccf90bf97e6cc463ebe28c1b2f9b4b765e70537c25c702a29dcbfbf14c99c54345ba2b51f17b77b5f15db92bbad8fa95c471f5d070a137cc", + "3379cbaae562a87b4c0425550ffdd6bfe1203f0d666cc7ea095be407a5dfe61ee91441cd5154b3e53b4f5fb31ad4c7a9ad5c7af4ae679aa51a54003a54ca6b2d", + "3095a349d245708c7cf550118703d7302c27b60af5d4e67fc978f8a4e60953c7a04f92fcf41aee64321ccb707a895851552b1e37b00bc5e6b72fa5bcef9e3fff", + "07262d738b09321f4dbccec4bb26f48cb0f0ed246ce0b31b9a6e7bc683049f1f3e5545f28ce932dd985c5ab0f43bd6de0770560af329065ed2e49d34624c2cbb", + "b6405eca8ee3316c87061cc6ec18dba53e6c250c63ba1f3bae9e55dd3498036af08cd272aa24d713c6020d77ab2f3919af1a32f307420618ab97e73953994fb4", + "7ee682f63148ee45f6e5315da81e5c6e557c2c34641fc509c7a5701088c38a74756168e2cd8d351e88fd1a451f360a01f5b2580f9b5a2e8cfc138f3dd59a3ffc", + "1d263c179d6b268f6fa016f3a4f29e943891125ed8593c81256059f5a7b44af2dcb2030d175c00e62ecaf7ee96682aa07ab20a611024a28532b1c25b86657902", + "106d132cbdb4cd2597812846e2bc1bf732fec5f0a5f65dbb39ec4e6dc64ab2ce6d24630d0f15a805c3540025d84afa98e36703c3dbee713e72dde8465bc1be7e", + "0e79968226650667a8d862ea8da4891af56a4e3a8b6d1750e394f0dea76d640d85077bcec2cc86886e506751b4f6a5838f7f0b5fef765d9dc90dcdcbaf079f08", + "521156a82ab0c4e566e5844d5e31ad9aaf144bbd5a464fdca34dbd5717e8ff711d3ffebbfa085d67fe996a34f6d3e4e60b1396bf4b1610c263bdbb834d560816", + "1aba88befc55bc25efbce02db8b9933e46f57661baeabeb21cc2574d2a518a3cba5dc5a38e49713440b25f9c744e75f6b85c9d8f4681f676160f6105357b8406", + "5a9949fcb2c473cda968ac1b5d08566dc2d816d960f57e63b898fa701cf8ebd3f59b124d95bfbbedc5f1cf0e17d5eaed0c02c50b69d8a402cabcca4433b51fd4", + "b0cead09807c672af2eb2b0f06dde46cf5370e15a4096b1a7d7cbb36ec31c205fbefca00b7a4162fa89fb4fb3eb78d79770c23f44e7206664ce3cd931c291e5d", + "bb6664931ec97044e45b2ae420ae1c551a8874bc937d08e969399c3964ebdba8346cdd5d09caafe4c28ba7ec788191ceca65ddd6f95f18583e040d0f30d0364d", + "65bc770a5faa3792369803683e844b0be7ee96f29f6d6a35568006bd5590f9a4ef639b7a8061c7b0424b66b60ac34af3119905f33a9d8c3ae18382ca9b689900", + "ea9b4dca333336aaf839a45c6eaa48b8cb4c7ddabffea4f643d6357ea6628a480a5b45f2b052c1b07d1fedca918b6f1139d80f74c24510dcbaa4be70eacc1b06", + "e6342fb4a780ad975d0e24bce149989b91d360557e87994f6b457b895575cc02d0c15bad3ce7577f4c63927ff13f3e381ff7e72bdbe745324844a9d27e3f1c01", + "3e209c9b33e8e461178ab46b1c64b49a07fb745f1c8bc95fbfb94c6b87c69516651b264ef980937fad41238b91ddc011a5dd777c7efd4494b4b6ecd3a9c22ac0", + "fd6a3d5b1875d80486d6e69694a56dbb04a99a4d051f15db2689776ba1c4882e6d462a603b7015dc9f4b7450f05394303b8652cfb404a266962c41bae6e18a94", + "951e27517e6bad9e4195fc8671dee3e7e9be69cee1422cb9fecfce0dba875f7b310b93ee3a3d558f941f635f668ff832d2c1d033c5e2f0997e4c66f147344e02", + "8eba2f874f1ae84041903c7c4253c82292530fc8509550bfdc34c95c7e2889d5650b0ad8cb988e5c4894cb87fbfbb19612ea93ccc4c5cad17158b9763464b492", + "16f712eaa1b7c6354719a8e7dbdfaf55e4063a4d277d947550019b38dfb564830911057d50506136e2394c3b28945cc964967d54e3000c2181626cfb9b73efd2", + "c39639e7d5c7fb8cdd0fd3e6a52096039437122f21c78f1679cea9d78a734c56ecbeb28654b4f18e342c331f6f7229ec4b4bc281b2d80a6eb50043f31796c88c", + "72d081af99f8a173dcc9a0ac4eb3557405639a29084b54a40172912a2f8a395129d5536f0918e902f9e8fa6000995f4168ddc5f893011be6a0dbc9b8a1a3f5bb", + "c11aa81e5efd24d5fc27ee586cfd8847fbb0e27601ccece5ecca0198e3c7765393bb74457c7e7a27eb9170350e1fb53857177506be3e762cc0f14d8c3afe9077", + "c28f2150b452e6c0c424bcde6f8d72007f9310fed7f2f87de0dbb64f4479d6c1441ba66f44b2accee61609177ed340128b407ecec7c64bbe50d63d22d8627727", + "f63d88122877ec30b8c8b00d22e89000a966426112bd44166e2f525b769ccbe9b286d437a0129130dde1a86c43e04bedb594e671d98283afe64ce331de9828fd", + "348b0532880b88a6614a8d7408c3f913357fbb60e995c60205be9139e74998aede7f4581e42f6b52698f7fa1219708c14498067fd1e09502de83a77dd281150c", + "5133dc8bef725359dff59792d85eaf75b7e1dcd1978b01c35b1b85fcebc63388ad99a17b6346a217dc1a9622ebd122ecf6913c4d31a6b52a695b86af00d741a0", + "2753c4c0e98ecad806e88780ec27fccd0f5c1ab547f9e4bf1659d192c23aa2cc971b58b6802580baef8adc3b776ef7086b2545c2987f348ee3719cdef258c403", + "b1663573ce4b9d8caefc865012f3e39714b9898a5da6ce17c25a6a47931a9ddb9bbe98adaa553beed436e89578455416c2a52a525cf2862b8d1d49a2531b7391", + "64f58bd6bfc856f5e873b2a2956ea0eda0d6db0da39c8c7fc67c9f9feefcff3072cdf9e6ea37f69a44f0c61aa0da3693c2db5b54960c0281a088151db42b11e8", + "0764c7be28125d9065c4b98a69d60aede703547c66a12e17e1c618994132f5ef82482c1e3fe3146cc65376cc109f0138ed9a80e49f1f3c7d610d2f2432f20605", + "f748784398a2ff03ebeb07e155e66116a839741a336e32da71ec696001f0ad1b25cd48c69cfca7265eca1dd71904a0ce748ac4124f3571076dfa7116a9cf00e9", + "3f0dbc0186bceb6b785ba78d2a2a013c910be157bdaffae81bb6663b1a73722f7f1228795f3ecada87cf6ef0078474af73f31eca0cc200ed975b6893f761cb6d", + "d4762cd4599876ca75b2b8fe249944dbd27ace741fdab93616cbc6e425460feb51d4e7adcc38180e7fc47c89024a7f56191adb878dfde4ead62223f5a2610efe", + "cd36b3d5b4c91b90fcbba79513cfee1907d8645a162afd0cd4cf4192d4a5f4c892183a8eacdb2b6b6a9d9aa8c11ac1b261b380dbee24ca468f1bfd043c58eefe", + "98593452281661a53c48a9d8cd790826c1a1ce567738053d0bee4a91a3d5bd92eefdbabebe3204f2031ca5f781bda99ef5d8ae56e5b04a9e1ecd21b0eb05d3e1", + "771f57dd2775ccdab55921d3e8e30ccf484d61fe1c1b9c2ae819d0fb2a12fab9be70c4a7a138da84e8280435daade5bbe66af0836a154f817fb17f3397e725a3", + "c60897c6f828e21f16fbb5f15b323f87b6c8955eabf1d38061f707f608abdd993fac3070633e286cf8339ce295dd352df4b4b40b2f29da1dd50b3a05d079e6bb", + "8210cd2c2d3b135c2cf07fa0d1433cd771f325d075c6469d9c7f1ba0943cd4ab09808cabf4acb9ce5bb88b498929b4b847f681ad2c490d042db2aec94214b06b", + "1d4edfffd8fd80f7e4107840fa3aa31e32598491e4af7013c197a65b7f36dd3ac4b478456111cd4309d9243510782fa31b7c4c95fa951520d020eb7e5c36e4ef", + "af8e6e91fab46ce4873e1a50a8ef448cc29121f7f74deef34a71ef89cc00d9274bc6c2454bbb3230d8b2ec94c62b1dec85f3593bfa30ea6f7a44d7c09465a253", + "29fd384ed4906f2d13aa9fe7af905990938bed807f1832454a372ab412eea1f5625a1fcc9ac8343b7c67c5aba6e0b1cc4644654913692c6b39eb9187ceacd3ec", + "a268c7885d9874a51c44dffed8ea53e94f78456e0b2ed99ff5a3924760813826d960a15edbedbb5de5226ba4b074e71b05c55b9756bb79e55c02754c2c7b6c8a", + "0cf8545488d56a86817cd7ecb10f7116b7ea530a45b6ea497b6c72c997e09e3d0da8698f46bb006fc977c2cd3d1177463ac9057fdd1662c85d0c126443c10473", + "b39614268fdd8781515e2cfebf89b4d5402bab10c226e6344e6b9ae000fb0d6c79cb2f3ec80e80eaeb1980d2f8698916bd2e9f747236655116649cd3ca23a837", + "74bef092fc6f1e5dba3663a3fb003b2a5ba257496536d99f62b9d73f8f9eb3ce9ff3eec709eb883655ec9eb896b9128f2afc89cf7d1ab58a72f4a3bf034d2b4a", + "3a988d38d75611f3ef38b8774980b33e573b6c57bee0469ba5eed9b44f29945e7347967fba2c162e1c3be7f310f2f75ee2381e7bfd6b3f0baea8d95dfb1dafb1", + "58aedfce6f67ddc85a28c992f1c0bd0969f041e66f1ee88020a125cbfcfebcd61709c9c4eba192c15e69f020d462486019fa8dea0cd7a42921a19d2fe546d43d", + "9347bd291473e6b4e368437b8e561e065f649a6d8ada479ad09b1999a8f26b91cf6120fd3bfe014e83f23acfa4c0ad7b3712b2c3c0733270663112ccd9285cd9", + "b32163e7c5dbb5f51fdc11d2eac875efbbcb7e7699090a7e7ff8a8d50795af5d74d9ff98543ef8cdf89ac13d0485278756e0ef00c817745661e1d59fe38e7537", + "1085d78307b1c4b008c57a2e7e5b234658a0a82e4ff1e4aaac72b312fda0fe27d233bc5b10e9cc17fdc7697b540c7d95eb215a19a1a0e20e1abfa126efd568c7", + "4e5c734c7dde011d83eac2b7347b373594f92d7091b9ca34cb9c6f39bdf5a8d2f134379e16d822f6522170ccf2ddd55c84b9e6c64fc927ac4cf8dfb2a17701f2", + "695d83bd990a1117b3d0ce06cc888027d12a054c2677fd82f0d4fbfc93575523e7991a5e35a3752e9b70ce62992e268a877744cdd435f5f130869c9a2074b338", + "a6213743568e3b3158b9184301f3690847554c68457cb40fc9a4b8cfd8d4a118c301a07737aeda0f929c68913c5f51c80394f53bff1c3e83b2e40ca97eba9e15", + "d444bfa2362a96df213d070e33fa841f51334e4e76866b8139e8af3bb3398be2dfaddcbc56b9146de9f68118dc5829e74b0c28d7711907b121f9161cb92b69a9", + "142709d62e28fcccd0af97fad0f8465b971e82201dc51070faa0372aa43e92484be1c1e73ba10906d5d1853db6a4106e0a7bf9800d373d6dee2d46d62ef2a461", +} diff --git a/vendor/github.com/dchest/blake2b/block.go b/vendor/github.com/dchest/blake2b/block.go new file mode 100644 index 0000000..2f04bb7 --- /dev/null +++ b/vendor/github.com/dchest/blake2b/block.go @@ -0,0 +1,1420 @@ +// Written in 2012 by Dmitry Chestnykh. +// +// To the extent possible under law, the author have dedicated all copyright +// and related and neighboring rights to this software to the public domain +// worldwide. This software is distributed without any warranty. +// http://creativecommons.org/publicdomain/zero/1.0/ + +// BLAKE2b compression of message blocks. + +package blake2b + +func blocks(d *digest, p []uint8) { + h0, h1, h2, h3, h4, h5, h6, h7 := d.h[0], d.h[1], d.h[2], d.h[3], d.h[4], d.h[5], d.h[6], d.h[7] + + for len(p) >= BlockSize { + // Increment counter. + d.t[0] += BlockSize + if d.t[0] < BlockSize { + d.t[1]++ + } + // Initialize compression function. + v0, v1, v2, v3, v4, v5, v6, v7 := h0, h1, h2, h3, h4, h5, h6, h7 + v8 := iv[0] + v9 := iv[1] + v10 := iv[2] + v11 := iv[3] + v12 := iv[4] ^ d.t[0] + v13 := iv[5] ^ d.t[1] + v14 := iv[6] ^ d.f[0] + v15 := iv[7] ^ d.f[1] + var m [16]uint64 + + j := 0 + for i := 0; i < 16; i++ { + m[i] = uint64(p[j]) | uint64(p[j+1])<<8 | uint64(p[j+2])<<16 | uint64(p[j+3])<<24 | + uint64(p[j+4])<<32 | uint64(p[j+5])<<40 | uint64(p[j+6])<<48 | uint64(p[j+7])<<56 + j += 8 + } + + // Round 1. + v0 += m[0] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[2] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[4] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[6] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[5] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[7] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[3] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[1] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[8] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[10] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[12] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[14] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[13] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[15] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[11] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[9] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 2. + v0 += m[14] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[4] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[9] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[13] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[15] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[6] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[8] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[10] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[1] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[0] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[11] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[5] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[7] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[3] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[2] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[12] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 3. + v0 += m[11] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[12] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[5] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[15] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[2] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[13] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[0] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[8] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[10] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[3] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[7] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[9] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[1] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[4] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[6] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[14] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 4. + v0 += m[7] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[3] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[13] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[11] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[12] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[14] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[1] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[9] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[2] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[5] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[4] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[15] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[0] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[8] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[10] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[6] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 5. + v0 += m[9] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[5] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[2] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[10] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[4] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[15] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[7] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[0] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[14] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[11] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[6] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[3] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[8] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[13] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[12] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[1] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 6. + v0 += m[2] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[6] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[0] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[8] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[11] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[3] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[10] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[12] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[4] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[7] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[15] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[1] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[14] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[9] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[5] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[13] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 7. + v0 += m[12] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[1] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[14] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[4] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[13] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[10] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[15] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[5] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[0] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[6] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[9] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[8] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[2] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[11] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[3] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[7] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 8. + v0 += m[13] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[7] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[12] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[3] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[1] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[9] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[14] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[11] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[5] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[15] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[8] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[2] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[6] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[10] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[4] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[0] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 9. + v0 += m[6] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[14] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[11] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[0] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[3] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[8] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[9] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[15] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[12] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[13] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[1] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[10] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[4] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[5] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[7] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[2] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 10. + v0 += m[10] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[8] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[7] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[1] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[6] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[5] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[4] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[2] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[15] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[9] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[3] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[13] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[12] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[0] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[14] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[11] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 11. + v0 += m[0] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[2] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[4] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[6] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[5] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[7] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[3] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[1] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[8] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[10] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[12] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[14] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[13] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[15] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[11] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[9] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 12. + v0 += m[14] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[4] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[9] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[13] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[15] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[6] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[8] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[10] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[1] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[0] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[11] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[5] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[7] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[3] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[2] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[12] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + h0 ^= v0 ^ v8 + h1 ^= v1 ^ v9 + h2 ^= v2 ^ v10 + h3 ^= v3 ^ v11 + h4 ^= v4 ^ v12 + h5 ^= v5 ^ v13 + h6 ^= v6 ^ v14 + h7 ^= v7 ^ v15 + + p = p[BlockSize:] + } + d.h[0], d.h[1], d.h[2], d.h[3], d.h[4], d.h[5], d.h[6], d.h[7] = h0, h1, h2, h3, h4, h5, h6, h7 +} diff --git a/vendor/github.com/jessevdk/go-flags/LICENSE b/vendor/github.com/jessevdk/go-flags/LICENSE new file mode 100644 index 0000000..bcca0d5 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) 2012 Jesse van den Kieboom. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/jessevdk/go-flags/README.md b/vendor/github.com/jessevdk/go-flags/README.md new file mode 100644 index 0000000..9378b76 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/README.md @@ -0,0 +1,135 @@ +go-flags: a go library for parsing command line arguments +========================================================= + +[![GoDoc](https://godoc.org/github.com/jessevdk/go-flags?status.png)](https://godoc.org/github.com/jessevdk/go-flags) [![Build Status](https://travis-ci.org/jessevdk/go-flags.svg?branch=master)](https://travis-ci.org/jessevdk/go-flags) [![Coverage Status](https://img.shields.io/coveralls/jessevdk/go-flags.svg)](https://coveralls.io/r/jessevdk/go-flags?branch=master) + +This library provides similar functionality to the builtin flag library of +go, but provides much more functionality and nicer formatting. From the +documentation: + +Package flags provides an extensive command line option parser. +The flags package is similar in functionality to the go builtin flag package +but provides more options and uses reflection to provide a convenient and +succinct way of specifying command line options. + +Supported features: +* Options with short names (-v) +* Options with long names (--verbose) +* Options with and without arguments (bool v.s. other type) +* Options with optional arguments and default values +* Multiple option groups each containing a set of options +* Generate and print well-formatted help message +* Passing remaining command line arguments after -- (optional) +* Ignoring unknown command line options (optional) +* Supports -I/usr/include -I=/usr/include -I /usr/include option argument specification +* Supports multiple short options -aux +* Supports all primitive go types (string, int{8..64}, uint{8..64}, float) +* Supports same option multiple times (can store in slice or last option counts) +* Supports maps +* Supports function callbacks +* Supports namespaces for (nested) option groups + +The flags package uses structs, reflection and struct field tags +to allow users to specify command line options. This results in very simple +and concise specification of your application options. For example: + +```go +type Options struct { + Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"` +} +``` + +This specifies one option with a short name -v and a long name --verbose. +When either -v or --verbose is found on the command line, a 'true' value +will be appended to the Verbose field. e.g. when specifying -vvv, the +resulting value of Verbose will be {[true, true, true]}. + +Example: +-------- +```go +var opts struct { + // Slice of bool will append 'true' each time the option + // is encountered (can be set multiple times, like -vvv) + Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"` + + // Example of automatic marshalling to desired type (uint) + Offset uint `long:"offset" description:"Offset"` + + // Example of a callback, called each time the option is found. + Call func(string) `short:"c" description:"Call phone number"` + + // Example of a required flag + Name string `short:"n" long:"name" description:"A name" required:"true"` + + // Example of a value name + File string `short:"f" long:"file" description:"A file" value-name:"FILE"` + + // Example of a pointer + Ptr *int `short:"p" description:"A pointer to an integer"` + + // Example of a slice of strings + StringSlice []string `short:"s" description:"A slice of strings"` + + // Example of a slice of pointers + PtrSlice []*string `long:"ptrslice" description:"A slice of pointers to string"` + + // Example of a map + IntMap map[string]int `long:"intmap" description:"A map from string to int"` +} + +// Callback which will invoke callto: to call a number. +// Note that this works just on OS X (and probably only with +// Skype) but it shows the idea. +opts.Call = func(num string) { + cmd := exec.Command("open", "callto:"+num) + cmd.Start() + cmd.Process.Release() +} + +// Make some fake arguments to parse. +args := []string{ + "-vv", + "--offset=5", + "-n", "Me", + "-p", "3", + "-s", "hello", + "-s", "world", + "--ptrslice", "hello", + "--ptrslice", "world", + "--intmap", "a:1", + "--intmap", "b:5", + "arg1", + "arg2", + "arg3", +} + +// Parse flags from `args'. Note that here we use flags.ParseArgs for +// the sake of making a working example. Normally, you would simply use +// flags.Parse(&opts) which uses os.Args +args, err := flags.ParseArgs(&opts, args) + +if err != nil { + panic(err) + os.Exit(1) +} + +fmt.Printf("Verbosity: %v\n", opts.Verbose) +fmt.Printf("Offset: %d\n", opts.Offset) +fmt.Printf("Name: %s\n", opts.Name) +fmt.Printf("Ptr: %d\n", *opts.Ptr) +fmt.Printf("StringSlice: %v\n", opts.StringSlice) +fmt.Printf("PtrSlice: [%v %v]\n", *opts.PtrSlice[0], *opts.PtrSlice[1]) +fmt.Printf("IntMap: [a:%v b:%v]\n", opts.IntMap["a"], opts.IntMap["b"]) +fmt.Printf("Remaining args: %s\n", strings.Join(args, " ")) + +// Output: Verbosity: [true true] +// Offset: 5 +// Name: Me +// Ptr: 3 +// StringSlice: [hello world] +// PtrSlice: [hello world] +// IntMap: [a:1 b:5] +// Remaining args: arg1 arg2 arg3 +``` + +More information can be found in the godocs: diff --git a/vendor/github.com/jessevdk/go-flags/arg.go b/vendor/github.com/jessevdk/go-flags/arg.go new file mode 100644 index 0000000..d160644 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/arg.go @@ -0,0 +1,24 @@ +package flags + +import ( + "reflect" +) + +// Arg represents a positional argument on the command line. +type Arg struct { + // The name of the positional argument (used in the help) + Name string + + // A description of the positional argument (used in the help) + Description string + + // Whether a positional argument is required + Required int + + value reflect.Value + tag multiTag +} + +func (a *Arg) isRemaining() bool { + return a.value.Type().Kind() == reflect.Slice +} diff --git a/vendor/github.com/jessevdk/go-flags/arg_test.go b/vendor/github.com/jessevdk/go-flags/arg_test.go new file mode 100644 index 0000000..117e90e --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/arg_test.go @@ -0,0 +1,133 @@ +package flags + +import ( + "testing" +) + +func TestPositional(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Positional struct { + Command int + Filename string + Rest []string + } `positional-args:"yes" required:"yes"` + }{} + + p := NewParser(&opts, Default) + ret, err := p.ParseArgs([]string{"10", "arg_test.go", "a", "b"}) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + if opts.Positional.Command != 10 { + t.Fatalf("Expected opts.Positional.Command to be 10, but got %v", opts.Positional.Command) + } + + if opts.Positional.Filename != "arg_test.go" { + t.Fatalf("Expected opts.Positional.Filename to be \"arg_test.go\", but got %v", opts.Positional.Filename) + } + + assertStringArray(t, opts.Positional.Rest, []string{"a", "b"}) + assertStringArray(t, ret, []string{}) +} + +func TestPositionalRequired(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Positional struct { + Command int + Filename string + Rest []string + } `positional-args:"yes" required:"yes"` + }{} + + p := NewParser(&opts, None) + _, err := p.ParseArgs([]string{"10"}) + + assertError(t, err, ErrRequired, "the required argument `Filename` was not provided") +} + +func TestPositionalRequiredRest1Fail(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Positional struct { + Rest []string `required:"yes"` + } `positional-args:"yes"` + }{} + + p := NewParser(&opts, None) + _, err := p.ParseArgs([]string{}) + + assertError(t, err, ErrRequired, "the required argument `Rest (at least 1 argument)` was not provided") +} + +func TestPositionalRequiredRest1Pass(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Positional struct { + Rest []string `required:"yes"` + } `positional-args:"yes"` + }{} + + p := NewParser(&opts, None) + _, err := p.ParseArgs([]string{"rest1"}) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + if len(opts.Positional.Rest) != 1 { + t.Fatalf("Expected 1 positional rest argument") + } + + assertString(t, opts.Positional.Rest[0], "rest1") +} + +func TestPositionalRequiredRest2Fail(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Positional struct { + Rest []string `required:"2"` + } `positional-args:"yes"` + }{} + + p := NewParser(&opts, None) + _, err := p.ParseArgs([]string{"rest1"}) + + assertError(t, err, ErrRequired, "the required argument `Rest (at least 2 arguments, but got only 1)` was not provided") +} + +func TestPositionalRequiredRest2Pass(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Positional struct { + Rest []string `required:"2"` + } `positional-args:"yes"` + }{} + + p := NewParser(&opts, None) + _, err := p.ParseArgs([]string{"rest1", "rest2", "rest3"}) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + if len(opts.Positional.Rest) != 3 { + t.Fatalf("Expected 3 positional rest argument") + } + + assertString(t, opts.Positional.Rest[0], "rest1") + assertString(t, opts.Positional.Rest[1], "rest2") + assertString(t, opts.Positional.Rest[2], "rest3") +} diff --git a/vendor/github.com/jessevdk/go-flags/assert_test.go b/vendor/github.com/jessevdk/go-flags/assert_test.go new file mode 100644 index 0000000..8e06636 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/assert_test.go @@ -0,0 +1,177 @@ +package flags + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "path" + "runtime" + "testing" +) + +func assertCallerInfo() (string, int) { + ptr := make([]uintptr, 15) + n := runtime.Callers(1, ptr) + + if n == 0 { + return "", 0 + } + + mef := runtime.FuncForPC(ptr[0]) + mefile, meline := mef.FileLine(ptr[0]) + + for i := 2; i < n; i++ { + f := runtime.FuncForPC(ptr[i]) + file, line := f.FileLine(ptr[i]) + + if file != mefile { + return file, line + } + } + + return mefile, meline +} + +func assertErrorf(t *testing.T, format string, args ...interface{}) { + msg := fmt.Sprintf(format, args...) + + file, line := assertCallerInfo() + + t.Errorf("%s:%d: %s", path.Base(file), line, msg) +} + +func assertFatalf(t *testing.T, format string, args ...interface{}) { + msg := fmt.Sprintf(format, args...) + + file, line := assertCallerInfo() + + t.Fatalf("%s:%d: %s", path.Base(file), line, msg) +} + +func assertString(t *testing.T, a string, b string) { + if a != b { + assertErrorf(t, "Expected %#v, but got %#v", b, a) + } +} + +func assertStringArray(t *testing.T, a []string, b []string) { + if len(a) != len(b) { + assertErrorf(t, "Expected %#v, but got %#v", b, a) + return + } + + for i, v := range a { + if b[i] != v { + assertErrorf(t, "Expected %#v, but got %#v", b, a) + return + } + } +} + +func assertBoolArray(t *testing.T, a []bool, b []bool) { + if len(a) != len(b) { + assertErrorf(t, "Expected %#v, but got %#v", b, a) + return + } + + for i, v := range a { + if b[i] != v { + assertErrorf(t, "Expected %#v, but got %#v", b, a) + return + } + } +} + +func assertParserSuccess(t *testing.T, data interface{}, args ...string) (*Parser, []string) { + parser := NewParser(data, Default&^PrintErrors) + ret, err := parser.ParseArgs(args) + + if err != nil { + t.Fatalf("Unexpected parse error: %s", err) + return nil, nil + } + + return parser, ret +} + +func assertParseSuccess(t *testing.T, data interface{}, args ...string) []string { + _, ret := assertParserSuccess(t, data, args...) + return ret +} + +func assertError(t *testing.T, err error, typ ErrorType, msg string) { + if err == nil { + assertFatalf(t, "Expected error: %s", msg) + return + } + + if e, ok := err.(*Error); !ok { + assertFatalf(t, "Expected Error type, but got %#v", err) + } else { + if e.Type != typ { + assertErrorf(t, "Expected error type {%s}, but got {%s}", typ, e.Type) + } + + if e.Message != msg { + assertErrorf(t, "Expected error message %#v, but got %#v", msg, e.Message) + } + } +} + +func assertParseFail(t *testing.T, typ ErrorType, msg string, data interface{}, args ...string) []string { + parser := NewParser(data, Default&^PrintErrors) + ret, err := parser.ParseArgs(args) + + assertError(t, err, typ, msg) + return ret +} + +func diff(a, b string) (string, error) { + atmp, err := ioutil.TempFile("", "help-diff") + + if err != nil { + return "", err + } + + btmp, err := ioutil.TempFile("", "help-diff") + + if err != nil { + return "", err + } + + if _, err := io.WriteString(atmp, a); err != nil { + return "", err + } + + if _, err := io.WriteString(btmp, b); err != nil { + return "", err + } + + ret, err := exec.Command("diff", "-u", "-d", "--label", "got", atmp.Name(), "--label", "expected", btmp.Name()).Output() + + os.Remove(atmp.Name()) + os.Remove(btmp.Name()) + + if err.Error() == "exit status 1" { + return string(ret), nil + } + + return string(ret), err +} + +func assertDiff(t *testing.T, actual, expected, msg string) { + if actual == expected { + return + } + + ret, err := diff(actual, expected) + + if err != nil { + assertErrorf(t, "Unexpected diff error: %s", err) + assertErrorf(t, "Unexpected %s, expected:\n\n%s\n\nbut got\n\n%s", msg, expected, actual) + } else { + assertErrorf(t, "Unexpected %s:\n\n%s", msg, ret) + } +} diff --git a/vendor/github.com/jessevdk/go-flags/check_crosscompile.sh b/vendor/github.com/jessevdk/go-flags/check_crosscompile.sh new file mode 100755 index 0000000..c494f61 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/check_crosscompile.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +set -e + +echo '# linux arm7' +GOARM=7 GOARCH=arm GOOS=linux go build +echo '# linux arm5' +GOARM=5 GOARCH=arm GOOS=linux go build +echo '# windows 386' +GOARCH=386 GOOS=windows go build +echo '# windows amd64' +GOARCH=amd64 GOOS=windows go build +echo '# darwin' +GOARCH=amd64 GOOS=darwin go build +echo '# freebsd' +GOARCH=amd64 GOOS=freebsd go build diff --git a/vendor/github.com/jessevdk/go-flags/closest.go b/vendor/github.com/jessevdk/go-flags/closest.go new file mode 100644 index 0000000..3b51875 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/closest.go @@ -0,0 +1,59 @@ +package flags + +func levenshtein(s string, t string) int { + if len(s) == 0 { + return len(t) + } + + if len(t) == 0 { + return len(s) + } + + dists := make([][]int, len(s)+1) + for i := range dists { + dists[i] = make([]int, len(t)+1) + dists[i][0] = i + } + + for j := range t { + dists[0][j] = j + } + + for i, sc := range s { + for j, tc := range t { + if sc == tc { + dists[i+1][j+1] = dists[i][j] + } else { + dists[i+1][j+1] = dists[i][j] + 1 + if dists[i+1][j] < dists[i+1][j+1] { + dists[i+1][j+1] = dists[i+1][j] + 1 + } + if dists[i][j+1] < dists[i+1][j+1] { + dists[i+1][j+1] = dists[i][j+1] + 1 + } + } + } + } + + return dists[len(s)][len(t)] +} + +func closestChoice(cmd string, choices []string) (string, int) { + if len(choices) == 0 { + return "", 0 + } + + mincmd := -1 + mindist := -1 + + for i, c := range choices { + l := levenshtein(cmd, c) + + if mincmd < 0 || l < mindist { + mindist = l + mincmd = i + } + } + + return choices[mincmd], mindist +} diff --git a/vendor/github.com/jessevdk/go-flags/command.go b/vendor/github.com/jessevdk/go-flags/command.go new file mode 100644 index 0000000..a30f560 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/command.go @@ -0,0 +1,441 @@ +package flags + +import ( + "reflect" + "sort" + "strconv" + "strings" + "unsafe" +) + +// Command represents an application command. Commands can be added to the +// parser (which itself is a command) and are selected/executed when its name +// is specified on the command line. The Command type embeds a Group and +// therefore also carries a set of command specific options. +type Command struct { + // Embedded, see Group for more information + *Group + + // The name by which the command can be invoked + Name string + + // The active sub command (set by parsing) or nil + Active *Command + + // Whether subcommands are optional + SubcommandsOptional bool + + // Aliases for the command + Aliases []string + + // Whether positional arguments are required + ArgsRequired bool + + commands []*Command + hasBuiltinHelpGroup bool + args []*Arg +} + +// Commander is an interface which can be implemented by any command added in +// the options. When implemented, the Execute method will be called for the last +// specified (sub)command providing the remaining command line arguments. +type Commander interface { + // Execute will be called for the last active (sub)command. The + // args argument contains the remaining command line arguments. The + // error that Execute returns will be eventually passed out of the + // Parse method of the Parser. + Execute(args []string) error +} + +// Usage is an interface which can be implemented to show a custom usage string +// in the help message shown for a command. +type Usage interface { + // Usage is called for commands to allow customized printing of command + // usage in the generated help message. + Usage() string +} + +type lookup struct { + shortNames map[string]*Option + longNames map[string]*Option + + commands map[string]*Command +} + +// AddCommand adds a new command to the parser with the given name and data. The +// data needs to be a pointer to a struct from which the fields indicate which +// options are in the command. The provided data can implement the Command and +// Usage interfaces. +func (c *Command) AddCommand(command string, shortDescription string, longDescription string, data interface{}) (*Command, error) { + cmd := newCommand(command, shortDescription, longDescription, data) + + cmd.parent = c + + if err := cmd.scan(); err != nil { + return nil, err + } + + c.commands = append(c.commands, cmd) + return cmd, nil +} + +// AddGroup adds a new group to the command with the given name and data. The +// data needs to be a pointer to a struct from which the fields indicate which +// options are in the group. +func (c *Command) AddGroup(shortDescription string, longDescription string, data interface{}) (*Group, error) { + group := newGroup(shortDescription, longDescription, data) + + group.parent = c + + if err := group.scanType(c.scanSubcommandHandler(group)); err != nil { + return nil, err + } + + c.groups = append(c.groups, group) + return group, nil +} + +// Commands returns a list of subcommands of this command. +func (c *Command) Commands() []*Command { + return c.commands +} + +// Find locates the subcommand with the given name and returns it. If no such +// command can be found Find will return nil. +func (c *Command) Find(name string) *Command { + for _, cc := range c.commands { + if cc.match(name) { + return cc + } + } + + return nil +} + +// Find an option that is part of the command, or any of its +// parent commands, by matching its long name +// (including the option namespace). +func (c *Command) FindOptionByLongName(longName string) (option *Option) { + for option == nil && c != nil { + option = c.Group.FindOptionByLongName(longName) + + c, _ = c.parent.(*Command) + } + + return option +} + +// Find an option that is part of the command, or any of its +// parent commands, by matching its long name +// (including the option namespace). +func (c *Command) FindOptionByShortName(shortName rune) (option *Option) { + for option == nil && c != nil { + option = c.Group.FindOptionByShortName(shortName) + + c, _ = c.parent.(*Command) + } + + return option +} + +// Args returns a list of positional arguments associated with this command. +func (c *Command) Args() []*Arg { + ret := make([]*Arg, len(c.args)) + copy(ret, c.args) + + return ret +} + +func newCommand(name string, shortDescription string, longDescription string, data interface{}) *Command { + return &Command{ + Group: newGroup(shortDescription, longDescription, data), + Name: name, + } +} + +func (c *Command) scanSubcommandHandler(parentg *Group) scanHandler { + f := func(realval reflect.Value, sfield *reflect.StructField) (bool, error) { + mtag := newMultiTag(string(sfield.Tag)) + + if err := mtag.Parse(); err != nil { + return true, err + } + + positional := mtag.Get("positional-args") + + if len(positional) != 0 { + stype := realval.Type() + + for i := 0; i < stype.NumField(); i++ { + field := stype.Field(i) + + m := newMultiTag((string(field.Tag))) + + if err := m.Parse(); err != nil { + return true, err + } + + name := m.Get("positional-arg-name") + + if len(name) == 0 { + name = field.Name + } + + var required int + + sreq := m.Get("required") + + if sreq != "" { + required = 1 + + if preq, err := strconv.ParseInt(sreq, 10, 32); err == nil { + required = int(preq) + } + } + + arg := &Arg{ + Name: name, + Description: m.Get("description"), + Required: required, + + value: realval.Field(i), + tag: m, + } + + c.args = append(c.args, arg) + + if len(mtag.Get("required")) != 0 { + c.ArgsRequired = true + } + } + + return true, nil + } + + subcommand := mtag.Get("command") + + if len(subcommand) != 0 { + ptrval := reflect.NewAt(realval.Type(), unsafe.Pointer(realval.UnsafeAddr())) + + shortDescription := mtag.Get("description") + longDescription := mtag.Get("long-description") + subcommandsOptional := mtag.Get("subcommands-optional") + aliases := mtag.GetMany("alias") + + subc, err := c.AddCommand(subcommand, shortDescription, longDescription, ptrval.Interface()) + if err != nil { + return true, err + } + + subc.Hidden = mtag.Get("hidden") != "" + + if len(subcommandsOptional) > 0 { + subc.SubcommandsOptional = true + } + + if len(aliases) > 0 { + subc.Aliases = aliases + } + + return true, nil + } + + return parentg.scanSubGroupHandler(realval, sfield) + } + + return f +} + +func (c *Command) scan() error { + return c.scanType(c.scanSubcommandHandler(c.Group)) +} + +func (c *Command) eachOption(f func(*Command, *Group, *Option)) { + c.eachCommand(func(c *Command) { + c.eachGroup(func(g *Group) { + for _, option := range g.options { + f(c, g, option) + } + }) + }, true) +} + +func (c *Command) eachCommand(f func(*Command), recurse bool) { + f(c) + + for _, cc := range c.commands { + if recurse { + cc.eachCommand(f, true) + } else { + f(cc) + } + } +} + +func (c *Command) eachActiveGroup(f func(cc *Command, g *Group)) { + c.eachGroup(func(g *Group) { + f(c, g) + }) + + if c.Active != nil { + c.Active.eachActiveGroup(f) + } +} + +func (c *Command) addHelpGroups(showHelp func() error) { + if !c.hasBuiltinHelpGroup { + c.addHelpGroup(showHelp) + c.hasBuiltinHelpGroup = true + } + + for _, cc := range c.commands { + cc.addHelpGroups(showHelp) + } +} + +func (c *Command) makeLookup() lookup { + ret := lookup{ + shortNames: make(map[string]*Option), + longNames: make(map[string]*Option), + commands: make(map[string]*Command), + } + + parent := c.parent + + var parents []*Command + + for parent != nil { + if cmd, ok := parent.(*Command); ok { + parents = append(parents, cmd) + parent = cmd.parent + } else { + parent = nil + } + } + + for i := len(parents) - 1; i >= 0; i-- { + parents[i].fillLookup(&ret, true) + } + + c.fillLookup(&ret, false) + return ret +} + +func (c *Command) fillLookup(ret *lookup, onlyOptions bool) { + c.eachGroup(func(g *Group) { + for _, option := range g.options { + if option.ShortName != 0 { + ret.shortNames[string(option.ShortName)] = option + } + + if len(option.LongName) > 0 { + ret.longNames[option.LongNameWithNamespace()] = option + } + } + }) + + if onlyOptions { + return + } + + for _, subcommand := range c.commands { + ret.commands[subcommand.Name] = subcommand + + for _, a := range subcommand.Aliases { + ret.commands[a] = subcommand + } + } +} + +func (c *Command) groupByName(name string) *Group { + if grp := c.Group.groupByName(name); grp != nil { + return grp + } + + for _, subc := range c.commands { + prefix := subc.Name + "." + + if strings.HasPrefix(name, prefix) { + if grp := subc.groupByName(name[len(prefix):]); grp != nil { + return grp + } + } else if name == subc.Name { + return subc.Group + } + } + + return nil +} + +type commandList []*Command + +func (c commandList) Less(i, j int) bool { + return c[i].Name < c[j].Name +} + +func (c commandList) Len() int { + return len(c) +} + +func (c commandList) Swap(i, j int) { + c[i], c[j] = c[j], c[i] +} + +func (c *Command) sortedVisibleCommands() []*Command { + ret := commandList(c.visibleCommands()) + sort.Sort(ret) + + return []*Command(ret) +} + +func (c *Command) visibleCommands() []*Command { + ret := make([]*Command, 0, len(c.commands)) + + for _, cmd := range c.commands { + if !cmd.Hidden { + ret = append(ret, cmd) + } + } + + return ret +} + +func (c *Command) match(name string) bool { + if c.Name == name { + return true + } + + for _, v := range c.Aliases { + if v == name { + return true + } + } + + return false +} + +func (c *Command) hasCliOptions() bool { + ret := false + + c.eachGroup(func(g *Group) { + if g.isBuiltinHelp { + return + } + + for _, opt := range g.options { + if opt.canCli() { + ret = true + } + } + }) + + return ret +} + +func (c *Command) fillParseState(s *parseState) { + s.positional = make([]*Arg, len(c.args)) + copy(s.positional, c.args) + + s.lookup = c.makeLookup() + s.command = c +} diff --git a/vendor/github.com/jessevdk/go-flags/command_test.go b/vendor/github.com/jessevdk/go-flags/command_test.go new file mode 100644 index 0000000..e7e3089 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/command_test.go @@ -0,0 +1,544 @@ +package flags + +import ( + "fmt" + "testing" +) + +func TestCommandInline(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Command struct { + G bool `short:"g"` + } `command:"cmd"` + }{} + + p, ret := assertParserSuccess(t, &opts, "-v", "cmd", "-g") + + assertStringArray(t, ret, []string{}) + + if p.Active == nil { + t.Errorf("Expected active command") + } + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !opts.Command.G { + t.Errorf("Expected Command.G to be true") + } + + if p.Command.Find("cmd") != p.Active { + t.Errorf("Expected to find command `cmd' to be active") + } +} + +func TestCommandInlineMulti(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + C1 struct { + } `command:"c1"` + + C2 struct { + G bool `short:"g"` + } `command:"c2"` + }{} + + p, ret := assertParserSuccess(t, &opts, "-v", "c2", "-g") + + assertStringArray(t, ret, []string{}) + + if p.Active == nil { + t.Errorf("Expected active command") + } + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !opts.C2.G { + t.Errorf("Expected C2.G to be true") + } + + if p.Command.Find("c1") == nil { + t.Errorf("Expected to find command `c1'") + } + + if c2 := p.Command.Find("c2"); c2 == nil { + t.Errorf("Expected to find command `c2'") + } else if c2 != p.Active { + t.Errorf("Expected to find command `c2' to be active") + } +} + +func TestCommandFlagOrder1(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Command struct { + G bool `short:"g"` + } `command:"cmd"` + }{} + + assertParseFail(t, ErrUnknownFlag, "unknown flag `g'", &opts, "-v", "-g", "cmd") +} + +func TestCommandFlagOrder2(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Command struct { + G bool `short:"g"` + } `command:"cmd"` + }{} + + assertParseSuccess(t, &opts, "cmd", "-v", "-g") + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !opts.Command.G { + t.Errorf("Expected Command.G to be true") + } +} + +func TestCommandFlagOrderSub(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Command struct { + G bool `short:"g"` + + SubCommand struct { + B bool `short:"b"` + } `command:"sub"` + } `command:"cmd"` + }{} + + assertParseSuccess(t, &opts, "cmd", "sub", "-v", "-g", "-b") + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !opts.Command.G { + t.Errorf("Expected Command.G to be true") + } + + if !opts.Command.SubCommand.B { + t.Errorf("Expected Command.SubCommand.B to be true") + } +} + +func TestCommandFlagOverride1(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Command struct { + Value bool `short:"v"` + } `command:"cmd"` + }{} + + assertParseSuccess(t, &opts, "-v", "cmd") + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if opts.Command.Value { + t.Errorf("Expected Command.Value to be false") + } +} + +func TestCommandFlagOverride2(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Command struct { + Value bool `short:"v"` + } `command:"cmd"` + }{} + + assertParseSuccess(t, &opts, "cmd", "-v") + + if opts.Value { + t.Errorf("Expected Value to be false") + } + + if !opts.Command.Value { + t.Errorf("Expected Command.Value to be true") + } +} + +func TestCommandFlagOverrideSub(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Command struct { + Value bool `short:"v"` + + SubCommand struct { + Value bool `short:"v"` + } `command:"sub"` + } `command:"cmd"` + }{} + + assertParseSuccess(t, &opts, "cmd", "sub", "-v") + + if opts.Value { + t.Errorf("Expected Value to be false") + } + + if opts.Command.Value { + t.Errorf("Expected Command.Value to be false") + } + + if !opts.Command.SubCommand.Value { + t.Errorf("Expected Command.Value to be true") + } +} + +func TestCommandFlagOverrideSub2(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Command struct { + Value bool `short:"v"` + + SubCommand struct { + G bool `short:"g"` + } `command:"sub"` + } `command:"cmd"` + }{} + + assertParseSuccess(t, &opts, "cmd", "sub", "-v") + + if opts.Value { + t.Errorf("Expected Value to be false") + } + + if !opts.Command.Value { + t.Errorf("Expected Command.Value to be true") + } +} + +func TestCommandEstimate(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Cmd1 struct { + } `command:"remove"` + + Cmd2 struct { + } `command:"add"` + }{} + + p := NewParser(&opts, None) + _, err := p.ParseArgs([]string{}) + + assertError(t, err, ErrCommandRequired, "Please specify one command of: add or remove") +} + +func TestCommandEstimate2(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Cmd1 struct { + } `command:"remove"` + + Cmd2 struct { + } `command:"add"` + }{} + + p := NewParser(&opts, None) + _, err := p.ParseArgs([]string{"rmive"}) + + assertError(t, err, ErrUnknownCommand, "Unknown command `rmive', did you mean `remove'?") +} + +type testCommand struct { + G bool `short:"g"` + Executed bool + EArgs []string +} + +func (c *testCommand) Execute(args []string) error { + c.Executed = true + c.EArgs = args + + return nil +} + +func TestCommandExecute(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Command testCommand `command:"cmd"` + }{} + + assertParseSuccess(t, &opts, "-v", "cmd", "-g", "a", "b") + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !opts.Command.Executed { + t.Errorf("Did not execute command") + } + + if !opts.Command.G { + t.Errorf("Expected Command.C to be true") + } + + assertStringArray(t, opts.Command.EArgs, []string{"a", "b"}) +} + +func TestCommandClosest(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Cmd1 struct { + } `command:"remove"` + + Cmd2 struct { + } `command:"add"` + }{} + + args := assertParseFail(t, ErrUnknownCommand, "Unknown command `addd', did you mean `add'?", &opts, "-v", "addd") + + assertStringArray(t, args, []string{"addd"}) +} + +func TestCommandAdd(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + }{} + + var cmd = struct { + G bool `short:"g"` + }{} + + p := NewParser(&opts, Default) + c, err := p.AddCommand("cmd", "", "", &cmd) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + ret, err := p.ParseArgs([]string{"-v", "cmd", "-g", "rest"}) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + assertStringArray(t, ret, []string{"rest"}) + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !cmd.G { + t.Errorf("Expected Command.G to be true") + } + + if p.Command.Find("cmd") != c { + t.Errorf("Expected to find command `cmd'") + } + + if p.Commands()[0] != c { + t.Errorf("Expected command %#v, but got %#v", c, p.Commands()[0]) + } + + if c.Options()[0].ShortName != 'g' { + t.Errorf("Expected short name `g' but got %v", c.Options()[0].ShortName) + } +} + +func TestCommandNestedInline(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Command struct { + G bool `short:"g"` + + Nested struct { + N string `long:"n"` + } `command:"nested"` + } `command:"cmd"` + }{} + + p, ret := assertParserSuccess(t, &opts, "-v", "cmd", "-g", "nested", "--n", "n", "rest") + + assertStringArray(t, ret, []string{"rest"}) + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !opts.Command.G { + t.Errorf("Expected Command.G to be true") + } + + assertString(t, opts.Command.Nested.N, "n") + + if c := p.Command.Find("cmd"); c == nil { + t.Errorf("Expected to find command `cmd'") + } else { + if c != p.Active { + t.Errorf("Expected `cmd' to be the active parser command") + } + + if nested := c.Find("nested"); nested == nil { + t.Errorf("Expected to find command `nested'") + } else if nested != c.Active { + t.Errorf("Expected to find command `nested' to be the active `cmd' command") + } + } +} + +func TestRequiredOnCommand(t *testing.T) { + var opts = struct { + Value bool `short:"v" required:"true"` + + Command struct { + G bool `short:"g"` + } `command:"cmd"` + }{} + + assertParseFail(t, ErrRequired, fmt.Sprintf("the required flag `%cv' was not specified", defaultShortOptDelimiter), &opts, "cmd") +} + +func TestRequiredAllOnCommand(t *testing.T) { + var opts = struct { + Value bool `short:"v" required:"true"` + Missing bool `long:"missing" required:"true"` + + Command struct { + G bool `short:"g"` + } `command:"cmd"` + }{} + + assertParseFail(t, ErrRequired, fmt.Sprintf("the required flags `%smissing' and `%cv' were not specified", defaultLongOptDelimiter, defaultShortOptDelimiter), &opts, "cmd") +} + +func TestDefaultOnCommand(t *testing.T) { + var opts = struct { + Command struct { + G string `short:"g" default:"value"` + } `command:"cmd"` + }{} + + assertParseSuccess(t, &opts, "cmd") + + if opts.Command.G != "value" { + t.Errorf("Expected G to be \"value\"") + } +} + +func TestSubcommandsOptional(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Cmd1 struct { + } `command:"remove"` + + Cmd2 struct { + } `command:"add"` + }{} + + p := NewParser(&opts, None) + p.SubcommandsOptional = true + + _, err := p.ParseArgs([]string{"-v"}) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + if !opts.Value { + t.Errorf("Expected Value to be true") + } +} + +func TestCommandAlias(t *testing.T) { + var opts = struct { + Command struct { + G string `short:"g" default:"value"` + } `command:"cmd" alias:"cm"` + }{} + + assertParseSuccess(t, &opts, "cm") + + if opts.Command.G != "value" { + t.Errorf("Expected G to be \"value\"") + } +} + +func TestSubCommandFindOptionByLongFlag(t *testing.T) { + var opts struct { + Testing bool `long:"testing" description:"Testing"` + } + + var cmd struct { + Other bool `long:"other" description:"Other"` + } + + p := NewParser(&opts, Default) + c, _ := p.AddCommand("command", "Short", "Long", &cmd) + + opt := c.FindOptionByLongName("other") + + if opt == nil { + t.Errorf("Expected option, but found none") + } + + assertString(t, opt.LongName, "other") + + opt = c.FindOptionByLongName("testing") + + if opt == nil { + t.Errorf("Expected option, but found none") + } + + assertString(t, opt.LongName, "testing") +} + +func TestSubCommandFindOptionByShortFlag(t *testing.T) { + var opts struct { + Testing bool `short:"t" description:"Testing"` + } + + var cmd struct { + Other bool `short:"o" description:"Other"` + } + + p := NewParser(&opts, Default) + c, _ := p.AddCommand("command", "Short", "Long", &cmd) + + opt := c.FindOptionByShortName('o') + + if opt == nil { + t.Errorf("Expected option, but found none") + } + + if opt.ShortName != 'o' { + t.Errorf("Expected 'o', but got %v", opt.ShortName) + } + + opt = c.FindOptionByShortName('t') + + if opt == nil { + t.Errorf("Expected option, but found none") + } + + if opt.ShortName != 't' { + t.Errorf("Expected 'o', but got %v", opt.ShortName) + } +} diff --git a/vendor/github.com/jessevdk/go-flags/completion.go b/vendor/github.com/jessevdk/go-flags/completion.go new file mode 100644 index 0000000..894f1d6 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/completion.go @@ -0,0 +1,300 @@ +package flags + +import ( + "fmt" + "path/filepath" + "reflect" + "sort" + "strings" + "unicode/utf8" +) + +// Completion is a type containing information of a completion. +type Completion struct { + // The completed item + Item string + + // A description of the completed item (optional) + Description string +} + +type completions []Completion + +func (c completions) Len() int { + return len(c) +} + +func (c completions) Less(i, j int) bool { + return c[i].Item < c[j].Item +} + +func (c completions) Swap(i, j int) { + c[i], c[j] = c[j], c[i] +} + +// Completer is an interface which can be implemented by types +// to provide custom command line argument completion. +type Completer interface { + // Complete receives a prefix representing a (partial) value + // for its type and should provide a list of possible valid + // completions. + Complete(match string) []Completion +} + +type completion struct { + parser *Parser +} + +// Filename is a string alias which provides filename completion. +type Filename string + +func completionsWithoutDescriptions(items []string) []Completion { + ret := make([]Completion, len(items)) + + for i, v := range items { + ret[i].Item = v + } + + return ret +} + +// Complete returns a list of existing files with the given +// prefix. +func (f *Filename) Complete(match string) []Completion { + ret, _ := filepath.Glob(match + "*") + return completionsWithoutDescriptions(ret) +} + +func (c *completion) skipPositional(s *parseState, n int) { + if n >= len(s.positional) { + s.positional = nil + } else { + s.positional = s.positional[n:] + } +} + +func (c *completion) completeOptionNames(names map[string]*Option, prefix string, match string) []Completion { + n := make([]Completion, 0, len(names)) + + for k, opt := range names { + if strings.HasPrefix(k, match) { + n = append(n, Completion{ + Item: prefix + k, + Description: opt.Description, + }) + } + } + + return n +} + +func (c *completion) completeLongNames(s *parseState, prefix string, match string) []Completion { + return c.completeOptionNames(s.lookup.longNames, prefix, match) +} + +func (c *completion) completeShortNames(s *parseState, prefix string, match string) []Completion { + if len(match) != 0 { + return []Completion{ + Completion{ + Item: prefix + match, + }, + } + } + + return c.completeOptionNames(s.lookup.shortNames, prefix, match) +} + +func (c *completion) completeCommands(s *parseState, match string) []Completion { + n := make([]Completion, 0, len(s.command.commands)) + + for _, cmd := range s.command.commands { + if cmd.data != c && strings.HasPrefix(cmd.Name, match) { + n = append(n, Completion{ + Item: cmd.Name, + Description: cmd.ShortDescription, + }) + } + } + + return n +} + +func (c *completion) completeValue(value reflect.Value, prefix string, match string) []Completion { + i := value.Interface() + + var ret []Completion + + if cmp, ok := i.(Completer); ok { + ret = cmp.Complete(match) + } else if value.CanAddr() { + if cmp, ok = value.Addr().Interface().(Completer); ok { + ret = cmp.Complete(match) + } + } + + for i, v := range ret { + ret[i].Item = prefix + v.Item + } + + return ret +} + +func (c *completion) completeArg(arg *Arg, prefix string, match string) []Completion { + if arg.isRemaining() { + // For remaining positional args (that are parsed into a slice), complete + // based on the element type. + return c.completeValue(reflect.New(arg.value.Type().Elem()), prefix, match) + } + + return c.completeValue(arg.value, prefix, match) +} + +func (c *completion) complete(args []string) []Completion { + if len(args) == 0 { + args = []string{""} + } + + s := &parseState{ + args: args, + } + + c.parser.fillParseState(s) + + var opt *Option + + for len(s.args) > 1 { + arg := s.pop() + + if (c.parser.Options&PassDoubleDash) != None && arg == "--" { + opt = nil + c.skipPositional(s, len(s.args)-1) + + break + } + + if argumentIsOption(arg) { + prefix, optname, islong := stripOptionPrefix(arg) + optname, _, argument := splitOption(prefix, optname, islong) + + if argument == nil { + var o *Option + canarg := true + + if islong { + o = s.lookup.longNames[optname] + } else { + for i, r := range optname { + sname := string(r) + o = s.lookup.shortNames[sname] + + if o == nil { + break + } + + if i == 0 && o.canArgument() && len(optname) != len(sname) { + canarg = false + break + } + } + } + + if o == nil && (c.parser.Options&PassAfterNonOption) != None { + opt = nil + c.skipPositional(s, len(s.args)-1) + + break + } else if o != nil && o.canArgument() && !o.OptionalArgument && canarg { + if len(s.args) > 1 { + s.pop() + } else { + opt = o + } + } + } + } else { + if len(s.positional) > 0 { + if !s.positional[0].isRemaining() { + // Don't advance beyond a remaining positional arg (because + // it consumes all subsequent args). + s.positional = s.positional[1:] + } + } else if cmd, ok := s.lookup.commands[arg]; ok { + cmd.fillParseState(s) + } + + opt = nil + } + } + + lastarg := s.args[len(s.args)-1] + var ret []Completion + + if opt != nil { + // Completion for the argument of 'opt' + ret = c.completeValue(opt.value, "", lastarg) + } else if argumentStartsOption(lastarg) { + // Complete the option + prefix, optname, islong := stripOptionPrefix(lastarg) + optname, split, argument := splitOption(prefix, optname, islong) + + if argument == nil && !islong { + rname, n := utf8.DecodeRuneInString(optname) + sname := string(rname) + + if opt := s.lookup.shortNames[sname]; opt != nil && opt.canArgument() { + ret = c.completeValue(opt.value, prefix+sname, optname[n:]) + } else { + ret = c.completeShortNames(s, prefix, optname) + } + } else if argument != nil { + if islong { + opt = s.lookup.longNames[optname] + } else { + opt = s.lookup.shortNames[optname] + } + + if opt != nil { + ret = c.completeValue(opt.value, prefix+optname+split, *argument) + } + } else if islong { + ret = c.completeLongNames(s, prefix, optname) + } else { + ret = c.completeShortNames(s, prefix, optname) + } + } else if len(s.positional) > 0 { + // Complete for positional argument + ret = c.completeArg(s.positional[0], "", lastarg) + } else if len(s.command.commands) > 0 { + // Complete for command + ret = c.completeCommands(s, lastarg) + } + + sort.Sort(completions(ret)) + return ret +} + +func (c *completion) print(items []Completion, showDescriptions bool) { + if showDescriptions && len(items) > 1 { + maxl := 0 + + for _, v := range items { + if len(v.Item) > maxl { + maxl = len(v.Item) + } + } + + for _, v := range items { + fmt.Printf("%s", v.Item) + + if len(v.Description) > 0 { + fmt.Printf("%s # %s", strings.Repeat(" ", maxl-len(v.Item)), v.Description) + } + + fmt.Printf("\n") + } + } else { + for _, v := range items { + fmt.Println(v.Item) + } + } +} diff --git a/vendor/github.com/jessevdk/go-flags/completion_test.go b/vendor/github.com/jessevdk/go-flags/completion_test.go new file mode 100644 index 0000000..f440fd7 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/completion_test.go @@ -0,0 +1,294 @@ +package flags + +import ( + "bytes" + "io" + "os" + "path" + "path/filepath" + "reflect" + "runtime" + "strings" + "testing" +) + +type TestComplete struct { +} + +func (t *TestComplete) Complete(match string) []Completion { + options := []string{ + "hello world", + "hello universe", + "hello multiverse", + } + + ret := make([]Completion, 0, len(options)) + + for _, o := range options { + if strings.HasPrefix(o, match) { + ret = append(ret, Completion{ + Item: o, + }) + } + } + + return ret +} + +var completionTestOptions struct { + Verbose bool `short:"v" long:"verbose" description:"Verbose messages"` + Debug bool `short:"d" long:"debug" description:"Enable debug"` + Version bool `long:"version" description:"Show version"` + Required bool `long:"required" required:"true" description:"This is required"` + + AddCommand struct { + Positional struct { + Filename Filename + } `positional-args:"yes"` + } `command:"add" description:"add an item"` + + AddMultiCommand struct { + Positional struct { + Filename []Filename + } `positional-args:"yes"` + } `command:"add-multi" description:"add multiple items"` + + RemoveCommand struct { + Other bool `short:"o"` + File Filename `short:"f" long:"filename"` + } `command:"rm" description:"remove an item"` + + RenameCommand struct { + Completed TestComplete `short:"c" long:"completed"` + } `command:"rename" description:"rename an item"` +} + +type completionTest struct { + Args []string + Completed []string + ShowDescriptions bool +} + +var completionTests []completionTest + +func init() { + _, sourcefile, _, _ := runtime.Caller(0) + completionTestSourcedir := filepath.Join(filepath.SplitList(path.Dir(sourcefile))...) + + completionTestFilename := []string{filepath.Join(completionTestSourcedir, "completion.go"), filepath.Join(completionTestSourcedir, "completion_test.go")} + + completionTests = []completionTest{ + { + // Short names + []string{"-"}, + []string{"-d", "-v"}, + false, + }, + + { + // Short names concatenated + []string{"-dv"}, + []string{"-dv"}, + false, + }, + + { + // Long names + []string{"--"}, + []string{"--debug", "--required", "--verbose", "--version"}, + false, + }, + + { + // Long names with descriptions + []string{"--"}, + []string{ + "--debug # Enable debug", + "--required # This is required", + "--verbose # Verbose messages", + "--version # Show version", + }, + true, + }, + + { + // Long names partial + []string{"--ver"}, + []string{"--verbose", "--version"}, + false, + }, + + { + // Commands + []string{""}, + []string{"add", "add-multi", "rename", "rm"}, + false, + }, + + { + // Commands with descriptions + []string{""}, + []string{ + "add # add an item", + "add-multi # add multiple items", + "rename # rename an item", + "rm # remove an item", + }, + true, + }, + + { + // Commands partial + []string{"r"}, + []string{"rename", "rm"}, + false, + }, + + { + // Positional filename + []string{"add", filepath.Join(completionTestSourcedir, "completion")}, + completionTestFilename, + false, + }, + + { + // Multiple positional filename (1 arg) + []string{"add-multi", filepath.Join(completionTestSourcedir, "completion")}, + completionTestFilename, + false, + }, + { + // Multiple positional filename (2 args) + []string{"add-multi", filepath.Join(completionTestSourcedir, "completion.go"), filepath.Join(completionTestSourcedir, "completion")}, + completionTestFilename, + false, + }, + { + // Multiple positional filename (3 args) + []string{"add-multi", filepath.Join(completionTestSourcedir, "completion.go"), filepath.Join(completionTestSourcedir, "completion.go"), filepath.Join(completionTestSourcedir, "completion")}, + completionTestFilename, + false, + }, + + { + // Flag filename + []string{"rm", "-f", path.Join(completionTestSourcedir, "completion")}, + completionTestFilename, + false, + }, + + { + // Flag short concat last filename + []string{"rm", "-of", path.Join(completionTestSourcedir, "completion")}, + completionTestFilename, + false, + }, + + { + // Flag concat filename + []string{"rm", "-f" + path.Join(completionTestSourcedir, "completion")}, + []string{"-f" + completionTestFilename[0], "-f" + completionTestFilename[1]}, + false, + }, + + { + // Flag equal concat filename + []string{"rm", "-f=" + path.Join(completionTestSourcedir, "completion")}, + []string{"-f=" + completionTestFilename[0], "-f=" + completionTestFilename[1]}, + false, + }, + + { + // Flag concat long filename + []string{"rm", "--filename=" + path.Join(completionTestSourcedir, "completion")}, + []string{"--filename=" + completionTestFilename[0], "--filename=" + completionTestFilename[1]}, + false, + }, + + { + // Flag long filename + []string{"rm", "--filename", path.Join(completionTestSourcedir, "completion")}, + completionTestFilename, + false, + }, + + { + // Custom completed + []string{"rename", "-c", "hello un"}, + []string{"hello universe"}, + false, + }, + } +} + +func TestCompletion(t *testing.T) { + p := NewParser(&completionTestOptions, Default) + c := &completion{parser: p} + + for _, test := range completionTests { + if test.ShowDescriptions { + continue + } + + ret := c.complete(test.Args) + items := make([]string, len(ret)) + + for i, v := range ret { + items[i] = v.Item + } + + if !reflect.DeepEqual(items, test.Completed) { + t.Errorf("Args: %#v, %#v\n Expected: %#v\n Got: %#v", test.Args, test.ShowDescriptions, test.Completed, items) + } + } +} + +func TestParserCompletion(t *testing.T) { + for _, test := range completionTests { + if test.ShowDescriptions { + os.Setenv("GO_FLAGS_COMPLETION", "verbose") + } else { + os.Setenv("GO_FLAGS_COMPLETION", "1") + } + + tmp := os.Stdout + + r, w, _ := os.Pipe() + os.Stdout = w + + out := make(chan string) + + go func() { + var buf bytes.Buffer + + io.Copy(&buf, r) + + out <- buf.String() + }() + + p := NewParser(&completionTestOptions, None) + + p.CompletionHandler = func(items []Completion) { + comp := &completion{parser: p} + comp.print(items, test.ShowDescriptions) + } + + _, err := p.ParseArgs(test.Args) + + w.Close() + + os.Stdout = tmp + + if err != nil { + t.Fatalf("Unexpected error: %s", err) + } + + got := strings.Split(strings.Trim(<-out, "\n"), "\n") + + if !reflect.DeepEqual(got, test.Completed) { + t.Errorf("Expected: %#v\nGot: %#v", test.Completed, got) + } + } + + os.Setenv("GO_FLAGS_COMPLETION", "") +} diff --git a/vendor/github.com/jessevdk/go-flags/convert.go b/vendor/github.com/jessevdk/go-flags/convert.go new file mode 100644 index 0000000..938c3ac --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/convert.go @@ -0,0 +1,341 @@ +// Copyright 2012 Jesse van den Kieboom. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flags + +import ( + "fmt" + "reflect" + "strconv" + "strings" + "time" +) + +// Marshaler is the interface implemented by types that can marshal themselves +// to a string representation of the flag. +type Marshaler interface { + // MarshalFlag marshals a flag value to its string representation. + MarshalFlag() (string, error) +} + +// Unmarshaler is the interface implemented by types that can unmarshal a flag +// argument to themselves. The provided value is directly passed from the +// command line. +type Unmarshaler interface { + // UnmarshalFlag unmarshals a string value representation to the flag + // value (which therefore needs to be a pointer receiver). + UnmarshalFlag(value string) error +} + +func getBase(options multiTag, base int) (int, error) { + sbase := options.Get("base") + + var err error + var ivbase int64 + + if sbase != "" { + ivbase, err = strconv.ParseInt(sbase, 10, 32) + base = int(ivbase) + } + + return base, err +} + +func convertMarshal(val reflect.Value) (bool, string, error) { + // Check first for the Marshaler interface + if val.Type().NumMethod() > 0 && val.CanInterface() { + if marshaler, ok := val.Interface().(Marshaler); ok { + ret, err := marshaler.MarshalFlag() + return true, ret, err + } + } + + return false, "", nil +} + +func convertToString(val reflect.Value, options multiTag) (string, error) { + if ok, ret, err := convertMarshal(val); ok { + return ret, err + } + + tp := val.Type() + + // Support for time.Duration + if tp == reflect.TypeOf((*time.Duration)(nil)).Elem() { + stringer := val.Interface().(fmt.Stringer) + return stringer.String(), nil + } + + switch tp.Kind() { + case reflect.String: + return val.String(), nil + case reflect.Bool: + if val.Bool() { + return "true", nil + } + + return "false", nil + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + base, err := getBase(options, 10) + + if err != nil { + return "", err + } + + return strconv.FormatInt(val.Int(), base), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + base, err := getBase(options, 10) + + if err != nil { + return "", err + } + + return strconv.FormatUint(val.Uint(), base), nil + case reflect.Float32, reflect.Float64: + return strconv.FormatFloat(val.Float(), 'g', -1, tp.Bits()), nil + case reflect.Slice: + if val.Len() == 0 { + return "", nil + } + + ret := "[" + + for i := 0; i < val.Len(); i++ { + if i != 0 { + ret += ", " + } + + item, err := convertToString(val.Index(i), options) + + if err != nil { + return "", err + } + + ret += item + } + + return ret + "]", nil + case reflect.Map: + ret := "{" + + for i, key := range val.MapKeys() { + if i != 0 { + ret += ", " + } + + keyitem, err := convertToString(key, options) + + if err != nil { + return "", err + } + + item, err := convertToString(val.MapIndex(key), options) + + if err != nil { + return "", err + } + + ret += keyitem + ":" + item + } + + return ret + "}", nil + case reflect.Ptr: + return convertToString(reflect.Indirect(val), options) + case reflect.Interface: + if !val.IsNil() { + return convertToString(val.Elem(), options) + } + } + + return "", nil +} + +func convertUnmarshal(val string, retval reflect.Value) (bool, error) { + if retval.Type().NumMethod() > 0 && retval.CanInterface() { + if unmarshaler, ok := retval.Interface().(Unmarshaler); ok { + return true, unmarshaler.UnmarshalFlag(val) + } + } + + if retval.Type().Kind() != reflect.Ptr && retval.CanAddr() { + return convertUnmarshal(val, retval.Addr()) + } + + if retval.Type().Kind() == reflect.Interface && !retval.IsNil() { + return convertUnmarshal(val, retval.Elem()) + } + + return false, nil +} + +func convert(val string, retval reflect.Value, options multiTag) error { + if ok, err := convertUnmarshal(val, retval); ok { + return err + } + + tp := retval.Type() + + // Support for time.Duration + if tp == reflect.TypeOf((*time.Duration)(nil)).Elem() { + parsed, err := time.ParseDuration(val) + + if err != nil { + return err + } + + retval.SetInt(int64(parsed)) + return nil + } + + switch tp.Kind() { + case reflect.String: + retval.SetString(val) + case reflect.Bool: + if val == "" { + retval.SetBool(true) + } else { + b, err := strconv.ParseBool(val) + + if err != nil { + return err + } + + retval.SetBool(b) + } + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + base, err := getBase(options, 10) + + if err != nil { + return err + } + + parsed, err := strconv.ParseInt(val, base, tp.Bits()) + + if err != nil { + return err + } + + retval.SetInt(parsed) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + base, err := getBase(options, 10) + + if err != nil { + return err + } + + parsed, err := strconv.ParseUint(val, base, tp.Bits()) + + if err != nil { + return err + } + + retval.SetUint(parsed) + case reflect.Float32, reflect.Float64: + parsed, err := strconv.ParseFloat(val, tp.Bits()) + + if err != nil { + return err + } + + retval.SetFloat(parsed) + case reflect.Slice: + elemtp := tp.Elem() + + elemvalptr := reflect.New(elemtp) + elemval := reflect.Indirect(elemvalptr) + + if err := convert(val, elemval, options); err != nil { + return err + } + + retval.Set(reflect.Append(retval, elemval)) + case reflect.Map: + parts := strings.SplitN(val, ":", 2) + + key := parts[0] + var value string + + if len(parts) == 2 { + value = parts[1] + } + + keytp := tp.Key() + keyval := reflect.New(keytp) + + if err := convert(key, keyval, options); err != nil { + return err + } + + valuetp := tp.Elem() + valueval := reflect.New(valuetp) + + if err := convert(value, valueval, options); err != nil { + return err + } + + if retval.IsNil() { + retval.Set(reflect.MakeMap(tp)) + } + + retval.SetMapIndex(reflect.Indirect(keyval), reflect.Indirect(valueval)) + case reflect.Ptr: + if retval.IsNil() { + retval.Set(reflect.New(retval.Type().Elem())) + } + + return convert(val, reflect.Indirect(retval), options) + case reflect.Interface: + if !retval.IsNil() { + return convert(val, retval.Elem(), options) + } + } + + return nil +} + +func isPrint(s string) bool { + for _, c := range s { + if !strconv.IsPrint(c) { + return false + } + } + + return true +} + +func quoteIfNeeded(s string) string { + if !isPrint(s) { + return strconv.Quote(s) + } + + return s +} + +func quoteIfNeededV(s []string) []string { + ret := make([]string, len(s)) + + for i, v := range s { + ret[i] = quoteIfNeeded(v) + } + + return ret +} + +func quoteV(s []string) []string { + ret := make([]string, len(s)) + + for i, v := range s { + ret[i] = strconv.Quote(v) + } + + return ret +} + +func unquoteIfPossible(s string) (string, error) { + if len(s) == 0 || s[0] != '"' { + return s, nil + } + + return strconv.Unquote(s) +} diff --git a/vendor/github.com/jessevdk/go-flags/convert_test.go b/vendor/github.com/jessevdk/go-flags/convert_test.go new file mode 100644 index 0000000..ef131dc --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/convert_test.go @@ -0,0 +1,159 @@ +package flags + +import ( + "testing" + "time" +) + +func expectConvert(t *testing.T, o *Option, expected string) { + s, err := convertToString(o.value, o.tag) + + if err != nil { + t.Errorf("Unexpected error: %v", err) + return + } + + assertString(t, s, expected) +} + +func TestConvertToString(t *testing.T) { + d, _ := time.ParseDuration("1h2m4s") + + var opts = struct { + String string `long:"string"` + + Int int `long:"int"` + Int8 int8 `long:"int8"` + Int16 int16 `long:"int16"` + Int32 int32 `long:"int32"` + Int64 int64 `long:"int64"` + + Uint uint `long:"uint"` + Uint8 uint8 `long:"uint8"` + Uint16 uint16 `long:"uint16"` + Uint32 uint32 `long:"uint32"` + Uint64 uint64 `long:"uint64"` + + Float32 float32 `long:"float32"` + Float64 float64 `long:"float64"` + + Duration time.Duration `long:"duration"` + + Bool bool `long:"bool"` + + IntSlice []int `long:"int-slice"` + IntFloatMap map[int]float64 `long:"int-float-map"` + + PtrBool *bool `long:"ptr-bool"` + Interface interface{} `long:"interface"` + + Int32Base int32 `long:"int32-base" base:"16"` + Uint32Base uint32 `long:"uint32-base" base:"16"` + }{ + "string", + + -2, + -1, + 0, + 1, + 2, + + 1, + 2, + 3, + 4, + 5, + + 1.2, + -3.4, + + d, + true, + + []int{-3, 4, -2}, + map[int]float64{-2: 4.5}, + + new(bool), + float32(5.2), + + -5823, + 4232, + } + + p := NewNamedParser("test", Default) + grp, _ := p.AddGroup("test group", "", &opts) + + expects := []string{ + "string", + "-2", + "-1", + "0", + "1", + "2", + + "1", + "2", + "3", + "4", + "5", + + "1.2", + "-3.4", + + "1h2m4s", + "true", + + "[-3, 4, -2]", + "{-2:4.5}", + + "false", + "5.2", + + "-16bf", + "1088", + } + + for i, v := range grp.Options() { + expectConvert(t, v, expects[i]) + } +} + +func TestConvertToStringInvalidIntBase(t *testing.T) { + var opts = struct { + Int int `long:"int" base:"no"` + }{ + 2, + } + + p := NewNamedParser("test", Default) + grp, _ := p.AddGroup("test group", "", &opts) + o := grp.Options()[0] + + _, err := convertToString(o.value, o.tag) + + if err != nil { + err = newErrorf(ErrMarshal, "%v", err) + } + + assertError(t, err, ErrMarshal, "strconv.ParseInt: parsing \"no\": invalid syntax") +} + +func TestConvertToStringInvalidUintBase(t *testing.T) { + var opts = struct { + Uint uint `long:"uint" base:"no"` + }{ + 2, + } + + p := NewNamedParser("test", Default) + grp, _ := p.AddGroup("test group", "", &opts) + o := grp.Options()[0] + + _, err := convertToString(o.value, o.tag) + + if err != nil { + err = newErrorf(ErrMarshal, "%v", err) + } + + assertError(t, err, ErrMarshal, "strconv.ParseInt: parsing \"no\": invalid syntax") +} diff --git a/vendor/github.com/jessevdk/go-flags/error.go b/vendor/github.com/jessevdk/go-flags/error.go new file mode 100644 index 0000000..05528d8 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/error.go @@ -0,0 +1,134 @@ +package flags + +import ( + "fmt" +) + +// ErrorType represents the type of error. +type ErrorType uint + +const ( + // ErrUnknown indicates a generic error. + ErrUnknown ErrorType = iota + + // ErrExpectedArgument indicates that an argument was expected. + ErrExpectedArgument + + // ErrUnknownFlag indicates an unknown flag. + ErrUnknownFlag + + // ErrUnknownGroup indicates an unknown group. + ErrUnknownGroup + + // ErrMarshal indicates a marshalling error while converting values. + ErrMarshal + + // ErrHelp indicates that the built-in help was shown (the error + // contains the help message). + ErrHelp + + // ErrNoArgumentForBool indicates that an argument was given for a + // boolean flag (which don't not take any arguments). + ErrNoArgumentForBool + + // ErrRequired indicates that a required flag was not provided. + ErrRequired + + // ErrShortNameTooLong indicates that a short flag name was specified, + // longer than one character. + ErrShortNameTooLong + + // ErrDuplicatedFlag indicates that a short or long flag has been + // defined more than once + ErrDuplicatedFlag + + // ErrTag indicates an error while parsing flag tags. + ErrTag + + // ErrCommandRequired indicates that a command was required but not + // specified + ErrCommandRequired + + // ErrUnknownCommand indicates that an unknown command was specified. + ErrUnknownCommand + + // ErrInvalidChoice indicates an invalid option value which only allows + // a certain number of choices. + ErrInvalidChoice + + // ErrInvalidTag indicates an invalid tag or invalid use of an existing tag + ErrInvalidTag +) + +func (e ErrorType) String() string { + switch e { + case ErrUnknown: + return "unknown" + case ErrExpectedArgument: + return "expected argument" + case ErrUnknownFlag: + return "unknown flag" + case ErrUnknownGroup: + return "unknown group" + case ErrMarshal: + return "marshal" + case ErrHelp: + return "help" + case ErrNoArgumentForBool: + return "no argument for bool" + case ErrRequired: + return "required" + case ErrShortNameTooLong: + return "short name too long" + case ErrDuplicatedFlag: + return "duplicated flag" + case ErrTag: + return "tag" + case ErrCommandRequired: + return "command required" + case ErrUnknownCommand: + return "unknown command" + case ErrInvalidChoice: + return "invalid choice" + case ErrInvalidTag: + return "invalid tag" + } + + return "unrecognized error type" +} + +// Error represents a parser error. The error returned from Parse is of this +// type. The error contains both a Type and Message. +type Error struct { + // The type of error + Type ErrorType + + // The error message + Message string +} + +// Error returns the error's message +func (e *Error) Error() string { + return e.Message +} + +func newError(tp ErrorType, message string) *Error { + return &Error{ + Type: tp, + Message: message, + } +} + +func newErrorf(tp ErrorType, format string, args ...interface{}) *Error { + return newError(tp, fmt.Sprintf(format, args...)) +} + +func wrapError(err error) *Error { + ret, ok := err.(*Error) + + if !ok { + return newError(ErrUnknown, err.Error()) + } + + return ret +} diff --git a/vendor/github.com/jessevdk/go-flags/example_test.go b/vendor/github.com/jessevdk/go-flags/example_test.go new file mode 100644 index 0000000..f7be2bb --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/example_test.go @@ -0,0 +1,110 @@ +// Example of use of the flags package. +package flags + +import ( + "fmt" + "os/exec" +) + +func Example() { + var opts struct { + // Slice of bool will append 'true' each time the option + // is encountered (can be set multiple times, like -vvv) + Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"` + + // Example of automatic marshalling to desired type (uint) + Offset uint `long:"offset" description:"Offset"` + + // Example of a callback, called each time the option is found. + Call func(string) `short:"c" description:"Call phone number"` + + // Example of a required flag + Name string `short:"n" long:"name" description:"A name" required:"true"` + + // Example of a value name + File string `short:"f" long:"file" description:"A file" value-name:"FILE"` + + // Example of a pointer + Ptr *int `short:"p" description:"A pointer to an integer"` + + // Example of a slice of strings + StringSlice []string `short:"s" description:"A slice of strings"` + + // Example of a slice of pointers + PtrSlice []*string `long:"ptrslice" description:"A slice of pointers to string"` + + // Example of a map + IntMap map[string]int `long:"intmap" description:"A map from string to int"` + + // Example of a filename (useful for completion) + Filename Filename `long:"filename" description:"A filename"` + + // Example of positional arguments + Args struct { + Id string + Num int + Rest []string + } `positional-args:"yes" required:"yes"` + } + + // Callback which will invoke callto: to call a number. + // Note that this works just on OS X (and probably only with + // Skype) but it shows the idea. + opts.Call = func(num string) { + cmd := exec.Command("open", "callto:"+num) + cmd.Start() + cmd.Process.Release() + } + + // Make some fake arguments to parse. + args := []string{ + "-vv", + "--offset=5", + "-n", "Me", + "-p", "3", + "-s", "hello", + "-s", "world", + "--ptrslice", "hello", + "--ptrslice", "world", + "--intmap", "a:1", + "--intmap", "b:5", + "--filename", "hello.go", + "id", + "10", + "remaining1", + "remaining2", + } + + // Parse flags from `args'. Note that here we use flags.ParseArgs for + // the sake of making a working example. Normally, you would simply use + // flags.Parse(&opts) which uses os.Args + _, err := ParseArgs(&opts, args) + + if err != nil { + panic(err) + } + + fmt.Printf("Verbosity: %v\n", opts.Verbose) + fmt.Printf("Offset: %d\n", opts.Offset) + fmt.Printf("Name: %s\n", opts.Name) + fmt.Printf("Ptr: %d\n", *opts.Ptr) + fmt.Printf("StringSlice: %v\n", opts.StringSlice) + fmt.Printf("PtrSlice: [%v %v]\n", *opts.PtrSlice[0], *opts.PtrSlice[1]) + fmt.Printf("IntMap: [a:%v b:%v]\n", opts.IntMap["a"], opts.IntMap["b"]) + fmt.Printf("Filename: %v\n", opts.Filename) + fmt.Printf("Args.Id: %s\n", opts.Args.Id) + fmt.Printf("Args.Num: %d\n", opts.Args.Num) + fmt.Printf("Args.Rest: %v\n", opts.Args.Rest) + + // Output: Verbosity: [true true] + // Offset: 5 + // Name: Me + // Ptr: 3 + // StringSlice: [hello world] + // PtrSlice: [hello world] + // IntMap: [a:1 b:5] + // Filename: hello.go + // Args.Id: id + // Args.Num: 10 + // Args.Rest: [remaining1 remaining2] +} diff --git a/vendor/github.com/jessevdk/go-flags/flags.go b/vendor/github.com/jessevdk/go-flags/flags.go new file mode 100644 index 0000000..757d42a --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/flags.go @@ -0,0 +1,256 @@ +// Copyright 2012 Jesse van den Kieboom. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package flags provides an extensive command line option parser. +The flags package is similar in functionality to the go built-in flag package +but provides more options and uses reflection to provide a convenient and +succinct way of specifying command line options. + + +Supported features + +The following features are supported in go-flags: + + Options with short names (-v) + Options with long names (--verbose) + Options with and without arguments (bool v.s. other type) + Options with optional arguments and default values + Option default values from ENVIRONMENT_VARIABLES, including slice and map values + Multiple option groups each containing a set of options + Generate and print well-formatted help message + Passing remaining command line arguments after -- (optional) + Ignoring unknown command line options (optional) + Supports -I/usr/include -I=/usr/include -I /usr/include option argument specification + Supports multiple short options -aux + Supports all primitive go types (string, int{8..64}, uint{8..64}, float) + Supports same option multiple times (can store in slice or last option counts) + Supports maps + Supports function callbacks + Supports namespaces for (nested) option groups + +Additional features specific to Windows: + Options with short names (/v) + Options with long names (/verbose) + Windows-style options with arguments use a colon as the delimiter + Modify generated help message with Windows-style / options + + +Basic usage + +The flags package uses structs, reflection and struct field tags +to allow users to specify command line options. This results in very simple +and concise specification of your application options. For example: + + type Options struct { + Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"` + } + +This specifies one option with a short name -v and a long name --verbose. +When either -v or --verbose is found on the command line, a 'true' value +will be appended to the Verbose field. e.g. when specifying -vvv, the +resulting value of Verbose will be {[true, true, true]}. + +Slice options work exactly the same as primitive type options, except that +whenever the option is encountered, a value is appended to the slice. + +Map options from string to primitive type are also supported. On the command +line, you specify the value for such an option as key:value. For example + + type Options struct { + AuthorInfo string[string] `short:"a"` + } + +Then, the AuthorInfo map can be filled with something like +-a name:Jesse -a "surname:van den Kieboom". + +Finally, for full control over the conversion between command line argument +values and options, user defined types can choose to implement the Marshaler +and Unmarshaler interfaces. + + +Available field tags + +The following is a list of tags for struct fields supported by go-flags: + + short: the short name of the option (single character) + long: the long name of the option + required: whether an option is required to appear on the command + line. If a required option is not present, the parser will + return ErrRequired (optional) + description: the description of the option (optional) + long-description: the long description of the option. Currently only + displayed in generated man pages (optional) + no-flag: if non-empty this field is ignored as an option (optional) + + optional: whether an argument of the option is optional. When an + argument is optional it can only be specified using + --option=argument (optional) + optional-value: the value of an optional option when the option occurs + without an argument. This tag can be specified multiple + times in the case of maps or slices (optional) + default: the default value of an option. This tag can be specified + multiple times in the case of slices or maps (optional) + default-mask: when specified, this value will be displayed in the help + instead of the actual default value. This is useful + mostly for hiding otherwise sensitive information from + showing up in the help. If default-mask takes the special + value "-", then no default value will be shown at all + (optional) + env: the default value of the option is overridden from the + specified environment variable, if one has been defined. + (optional) + env-delim: the 'env' default value from environment is split into + multiple values with the given delimiter string, use with + slices and maps (optional) + value-name: the name of the argument value (to be shown in the help) + (optional) + choice: limits the values for an option to a set of values. + This tag can be specified mltiple times (optional) + hidden: the option is not visible in the help or man page. + + base: a base (radix) used to convert strings to integer values, the + default base is 10 (i.e. decimal) (optional) + + ini-name: the explicit ini option name (optional) + no-ini: if non-empty this field is ignored as an ini option + (optional) + + group: when specified on a struct field, makes the struct + field a separate group with the given name (optional) + namespace: when specified on a group struct field, the namespace + gets prepended to every option's long name and + subgroup's namespace of this group, separated by + the parser's namespace delimiter (optional) + command: when specified on a struct field, makes the struct + field a (sub)command with the given name (optional) + subcommands-optional: when specified on a command struct field, makes + any subcommands of that command optional (optional) + alias: when specified on a command struct field, adds the + specified name as an alias for the command. Can be + be specified multiple times to add more than one + alias (optional) + positional-args: when specified on a field with a struct type, + uses the fields of that struct to parse remaining + positional command line arguments into (in order + of the fields). If a field has a slice type, + then all remaining arguments will be added to it. + Positional arguments are optional by default, + unless the "required" tag is specified together + with the "positional-args" tag. The "required" tag + can also be set on the individual rest argument + fields, to require only the first N positional + arguments. If the "required" tag is set on the + rest arguments slice, then its value determines + the minimum amount of rest arguments that needs to + be provided (e.g. `required:"2"`) (optional) + positional-arg-name: used on a field in a positional argument struct; name + of the positional argument placeholder to be shown in + the help (optional) + +Either the `short:` tag or the `long:` must be specified to make the field eligible as an +option. + + +Option groups + +Option groups are a simple way to semantically separate your options. All +options in a particular group are shown together in the help under the name +of the group. Namespaces can be used to specify option long names more +precisely and emphasize the options affiliation to their group. + +There are currently three ways to specify option groups. + + 1. Use NewNamedParser specifying the various option groups. + 2. Use AddGroup to add a group to an existing parser. + 3. Add a struct field to the top-level options annotated with the + group:"group-name" tag. + + + +Commands + +The flags package also has basic support for commands. Commands are often +used in monolithic applications that support various commands or actions. +Take git for example, all of the add, commit, checkout, etc. are called +commands. Using commands you can easily separate multiple functions of your +application. + +There are currently two ways to specify a command. + + 1. Use AddCommand on an existing parser. + 2. Add a struct field to your options struct annotated with the + command:"command-name" tag. + +The most common, idiomatic way to implement commands is to define a global +parser instance and implement each command in a separate file. These +command files should define a go init function which calls AddCommand on +the global parser. + +When parsing ends and there is an active command and that command implements +the Commander interface, then its Execute method will be run with the +remaining command line arguments. + +Command structs can have options which become valid to parse after the +command has been specified on the command line, in addition to the options +of all the parent commands. I.e. considering a -v flag on the parser and an +add command, the following are equivalent: + + ./app -v add + ./app add -v + +However, if the -v flag is defined on the add command, then the first of +the two examples above would fail since the -v flag is not defined before +the add command. + + +Completion + +go-flags has builtin support to provide bash completion of flags, commands +and argument values. To use completion, the binary which uses go-flags +can be invoked in a special environment to list completion of the current +command line argument. It should be noted that this `executes` your application, +and it is up to the user to make sure there are no negative side effects (for +example from init functions). + +Setting the environment variable `GO_FLAGS_COMPLETION=1` enables completion +by replacing the argument parsing routine with the completion routine which +outputs completions for the passed arguments. The basic invocation to +complete a set of arguments is therefore: + + GO_FLAGS_COMPLETION=1 ./completion-example arg1 arg2 arg3 + +where `completion-example` is the binary, `arg1` and `arg2` are +the current arguments, and `arg3` (the last argument) is the argument +to be completed. If the GO_FLAGS_COMPLETION is set to "verbose", then +descriptions of possible completion items will also be shown, if there +are more than 1 completion items. + +To use this with bash completion, a simple file can be written which +calls the binary which supports go-flags completion: + + _completion_example() { + # All arguments except the first one + args=("${COMP_WORDS[@]:1:$COMP_CWORD}") + + # Only split on newlines + local IFS=$'\n' + + # Call completion (note that the first element of COMP_WORDS is + # the executable itself) + COMPREPLY=($(GO_FLAGS_COMPLETION=1 ${COMP_WORDS[0]} "${args[@]}")) + return 0 + } + + complete -F _completion_example completion-example + +Completion requires the parser option PassDoubleDash and is therefore enforced if the environment variable GO_FLAGS_COMPLETION is set. + +Customized completion for argument values is supported by implementing +the flags.Completer interface for the argument value type. An example +of a type which does so is the flags.Filename type, an alias of string +allowing simple filename completion. A slice or array argument value +whose element type implements flags.Completer will also be completed. +*/ +package flags diff --git a/vendor/github.com/jessevdk/go-flags/group.go b/vendor/github.com/jessevdk/go-flags/group.go new file mode 100644 index 0000000..6472420 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/group.go @@ -0,0 +1,385 @@ +// Copyright 2012 Jesse van den Kieboom. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flags + +import ( + "errors" + "reflect" + "strings" + "unicode/utf8" + "unsafe" +) + +// ErrNotPointerToStruct indicates that a provided data container is not +// a pointer to a struct. Only pointers to structs are valid data containers +// for options. +var ErrNotPointerToStruct = errors.New("provided data is not a pointer to struct") + +// Group represents an option group. Option groups can be used to logically +// group options together under a description. Groups are only used to provide +// more structure to options both for the user (as displayed in the help message) +// and for you, since groups can be nested. +type Group struct { + // A short description of the group. The + // short description is primarily used in the built-in generated help + // message + ShortDescription string + + // A long description of the group. The long + // description is primarily used to present information on commands + // (Command embeds Group) in the built-in generated help and man pages. + LongDescription string + + // The namespace of the group + Namespace string + + // If true, the group is not displayed in the help or man page + Hidden bool + + // The parent of the group or nil if it has no parent + parent interface{} + + // All the options in the group + options []*Option + + // All the subgroups + groups []*Group + + // Whether the group represents the built-in help group + isBuiltinHelp bool + + data interface{} +} + +type scanHandler func(reflect.Value, *reflect.StructField) (bool, error) + +// AddGroup adds a new group to the command with the given name and data. The +// data needs to be a pointer to a struct from which the fields indicate which +// options are in the group. +func (g *Group) AddGroup(shortDescription string, longDescription string, data interface{}) (*Group, error) { + group := newGroup(shortDescription, longDescription, data) + + group.parent = g + + if err := group.scan(); err != nil { + return nil, err + } + + g.groups = append(g.groups, group) + return group, nil +} + +// Groups returns the list of groups embedded in this group. +func (g *Group) Groups() []*Group { + return g.groups +} + +// Options returns the list of options in this group. +func (g *Group) Options() []*Option { + return g.options +} + +// Find locates the subgroup with the given short description and returns it. +// If no such group can be found Find will return nil. Note that the description +// is matched case insensitively. +func (g *Group) Find(shortDescription string) *Group { + lshortDescription := strings.ToLower(shortDescription) + + var ret *Group + + g.eachGroup(func(gg *Group) { + if gg != g && strings.ToLower(gg.ShortDescription) == lshortDescription { + ret = gg + } + }) + + return ret +} + +func (g *Group) findOption(matcher func(*Option) bool) (option *Option) { + g.eachGroup(func(g *Group) { + for _, opt := range g.options { + if option == nil && matcher(opt) { + option = opt + } + } + }) + + return option +} + +// Find an option that is part of the group, or any of its subgroups, +// by matching its long name (including the option namespace). +func (g *Group) FindOptionByLongName(longName string) *Option { + return g.findOption(func(option *Option) bool { + return option.LongNameWithNamespace() == longName + }) +} + +// Find an option that is part of the group, or any of its subgroups, +// by matching its short name. +func (g *Group) FindOptionByShortName(shortName rune) *Option { + return g.findOption(func(option *Option) bool { + return option.ShortName == shortName + }) +} + +func newGroup(shortDescription string, longDescription string, data interface{}) *Group { + return &Group{ + ShortDescription: shortDescription, + LongDescription: longDescription, + + data: data, + } +} + +func (g *Group) optionByName(name string, namematch func(*Option, string) bool) *Option { + prio := 0 + var retopt *Option + + g.eachGroup(func(g *Group) { + for _, opt := range g.options { + if namematch != nil && namematch(opt, name) && prio < 4 { + retopt = opt + prio = 4 + } + + if name == opt.field.Name && prio < 3 { + retopt = opt + prio = 3 + } + + if name == opt.LongNameWithNamespace() && prio < 2 { + retopt = opt + prio = 2 + } + + if opt.ShortName != 0 && name == string(opt.ShortName) && prio < 1 { + retopt = opt + prio = 1 + } + } + }) + + return retopt +} + +func (g *Group) eachGroup(f func(*Group)) { + f(g) + + for _, gg := range g.groups { + gg.eachGroup(f) + } +} + +func (g *Group) scanStruct(realval reflect.Value, sfield *reflect.StructField, handler scanHandler) error { + stype := realval.Type() + + if sfield != nil { + if ok, err := handler(realval, sfield); err != nil { + return err + } else if ok { + return nil + } + } + + for i := 0; i < stype.NumField(); i++ { + field := stype.Field(i) + + // PkgName is set only for non-exported fields, which we ignore + if field.PkgPath != "" && !field.Anonymous { + continue + } + + mtag := newMultiTag(string(field.Tag)) + + if err := mtag.Parse(); err != nil { + return err + } + + // Skip fields with the no-flag tag + if mtag.Get("no-flag") != "" { + continue + } + + // Dive deep into structs or pointers to structs + kind := field.Type.Kind() + fld := realval.Field(i) + + if kind == reflect.Struct { + if err := g.scanStruct(fld, &field, handler); err != nil { + return err + } + } else if kind == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct { + if fld.IsNil() { + fld.Set(reflect.New(fld.Type().Elem())) + } + + if err := g.scanStruct(reflect.Indirect(fld), &field, handler); err != nil { + return err + } + } + + longname := mtag.Get("long") + shortname := mtag.Get("short") + + // Need at least either a short or long name + if longname == "" && shortname == "" && mtag.Get("ini-name") == "" { + continue + } + + short := rune(0) + rc := utf8.RuneCountInString(shortname) + + if rc > 1 { + return newErrorf(ErrShortNameTooLong, + "short names can only be 1 character long, not `%s'", + shortname) + + } else if rc == 1 { + short, _ = utf8.DecodeRuneInString(shortname) + } + + description := mtag.Get("description") + def := mtag.GetMany("default") + + optionalValue := mtag.GetMany("optional-value") + valueName := mtag.Get("value-name") + defaultMask := mtag.Get("default-mask") + + optional := (mtag.Get("optional") != "") + required := (mtag.Get("required") != "") + choices := mtag.GetMany("choice") + hidden := (mtag.Get("hidden") != "") + + option := &Option{ + Description: description, + ShortName: short, + LongName: longname, + Default: def, + EnvDefaultKey: mtag.Get("env"), + EnvDefaultDelim: mtag.Get("env-delim"), + OptionalArgument: optional, + OptionalValue: optionalValue, + Required: required, + ValueName: valueName, + DefaultMask: defaultMask, + Choices: choices, + Hidden: hidden, + + group: g, + + field: field, + value: realval.Field(i), + tag: mtag, + } + + if option.isBool() && option.Default != nil { + return newErrorf(ErrInvalidTag, + "boolean flag `%s' may not have default values, they always default to `false' and can only be turned on", + option.shortAndLongName()) + } + + g.options = append(g.options, option) + } + + return nil +} + +func (g *Group) checkForDuplicateFlags() *Error { + shortNames := make(map[rune]*Option) + longNames := make(map[string]*Option) + + var duplicateError *Error + + g.eachGroup(func(g *Group) { + for _, option := range g.options { + if option.LongName != "" { + longName := option.LongNameWithNamespace() + + if otherOption, ok := longNames[longName]; ok { + duplicateError = newErrorf(ErrDuplicatedFlag, "option `%s' uses the same long name as option `%s'", option, otherOption) + return + } + longNames[longName] = option + } + if option.ShortName != 0 { + if otherOption, ok := shortNames[option.ShortName]; ok { + duplicateError = newErrorf(ErrDuplicatedFlag, "option `%s' uses the same short name as option `%s'", option, otherOption) + return + } + shortNames[option.ShortName] = option + } + } + }) + + return duplicateError +} + +func (g *Group) scanSubGroupHandler(realval reflect.Value, sfield *reflect.StructField) (bool, error) { + mtag := newMultiTag(string(sfield.Tag)) + + if err := mtag.Parse(); err != nil { + return true, err + } + + subgroup := mtag.Get("group") + + if len(subgroup) != 0 { + ptrval := reflect.NewAt(realval.Type(), unsafe.Pointer(realval.UnsafeAddr())) + description := mtag.Get("description") + + group, err := g.AddGroup(subgroup, description, ptrval.Interface()) + if err != nil { + return true, err + } + + group.Namespace = mtag.Get("namespace") + group.Hidden = mtag.Get("hidden") != "" + + return true, nil + } + + return false, nil +} + +func (g *Group) scanType(handler scanHandler) error { + // Get all the public fields in the data struct + ptrval := reflect.ValueOf(g.data) + + if ptrval.Type().Kind() != reflect.Ptr { + panic(ErrNotPointerToStruct) + } + + stype := ptrval.Type().Elem() + + if stype.Kind() != reflect.Struct { + panic(ErrNotPointerToStruct) + } + + realval := reflect.Indirect(ptrval) + + if err := g.scanStruct(realval, nil, handler); err != nil { + return err + } + + if err := g.checkForDuplicateFlags(); err != nil { + return err + } + + return nil +} + +func (g *Group) scan() error { + return g.scanType(g.scanSubGroupHandler) +} + +func (g *Group) groupByName(name string) *Group { + if len(name) == 0 { + return g + } + + return g.Find(name) +} diff --git a/vendor/github.com/jessevdk/go-flags/group_test.go b/vendor/github.com/jessevdk/go-flags/group_test.go new file mode 100644 index 0000000..18cd6c1 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/group_test.go @@ -0,0 +1,255 @@ +package flags + +import ( + "testing" +) + +func TestGroupInline(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Group struct { + G bool `short:"g"` + } `group:"Grouped Options"` + }{} + + p, ret := assertParserSuccess(t, &opts, "-v", "-g") + + assertStringArray(t, ret, []string{}) + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !opts.Group.G { + t.Errorf("Expected Group.G to be true") + } + + if p.Command.Group.Find("Grouped Options") == nil { + t.Errorf("Expected to find group `Grouped Options'") + } +} + +func TestGroupAdd(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + }{} + + var grp = struct { + G bool `short:"g"` + }{} + + p := NewParser(&opts, Default) + g, err := p.AddGroup("Grouped Options", "", &grp) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + ret, err := p.ParseArgs([]string{"-v", "-g", "rest"}) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + assertStringArray(t, ret, []string{"rest"}) + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !grp.G { + t.Errorf("Expected Group.G to be true") + } + + if p.Command.Group.Find("Grouped Options") != g { + t.Errorf("Expected to find group `Grouped Options'") + } + + if p.Groups()[1] != g { + t.Errorf("Expected group %#v, but got %#v", g, p.Groups()[0]) + } + + if g.Options()[0].ShortName != 'g' { + t.Errorf("Expected short name `g' but got %v", g.Options()[0].ShortName) + } +} + +func TestGroupNestedInline(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Group struct { + G bool `short:"g"` + + Nested struct { + N string `long:"n"` + } `group:"Nested Options"` + } `group:"Grouped Options"` + }{} + + p, ret := assertParserSuccess(t, &opts, "-v", "-g", "--n", "n", "rest") + + assertStringArray(t, ret, []string{"rest"}) + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !opts.Group.G { + t.Errorf("Expected Group.G to be true") + } + + assertString(t, opts.Group.Nested.N, "n") + + if p.Command.Group.Find("Grouped Options") == nil { + t.Errorf("Expected to find group `Grouped Options'") + } + + if p.Command.Group.Find("Nested Options") == nil { + t.Errorf("Expected to find group `Nested Options'") + } +} + +func TestGroupNestedInlineNamespace(t *testing.T) { + var opts = struct { + Opt string `long:"opt"` + + Group struct { + Opt string `long:"opt"` + Group struct { + Opt string `long:"opt"` + } `group:"Subsubgroup" namespace:"sap"` + } `group:"Subgroup" namespace:"sip"` + }{} + + p, ret := assertParserSuccess(t, &opts, "--opt", "a", "--sip.opt", "b", "--sip.sap.opt", "c", "rest") + + assertStringArray(t, ret, []string{"rest"}) + + assertString(t, opts.Opt, "a") + assertString(t, opts.Group.Opt, "b") + assertString(t, opts.Group.Group.Opt, "c") + + for _, name := range []string{"Subgroup", "Subsubgroup"} { + if p.Command.Group.Find(name) == nil { + t.Errorf("Expected to find group '%s'", name) + } + } +} + +func TestDuplicateShortFlags(t *testing.T) { + var opts struct { + Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"` + Variables []string `short:"v" long:"variable" description:"Set a variable value."` + } + + args := []string{ + "--verbose", + "-v", "123", + "-v", "456", + } + + _, err := ParseArgs(&opts, args) + + if err == nil { + t.Errorf("Expected an error with type ErrDuplicatedFlag") + } else { + err2 := err.(*Error) + if err2.Type != ErrDuplicatedFlag { + t.Errorf("Expected an error with type ErrDuplicatedFlag") + } + } +} + +func TestDuplicateLongFlags(t *testing.T) { + var opts struct { + Test1 []bool `short:"a" long:"testing" description:"Test 1"` + Test2 []string `short:"b" long:"testing" description:"Test 2."` + } + + args := []string{ + "--testing", + } + + _, err := ParseArgs(&opts, args) + + if err == nil { + t.Errorf("Expected an error with type ErrDuplicatedFlag") + } else { + err2 := err.(*Error) + if err2.Type != ErrDuplicatedFlag { + t.Errorf("Expected an error with type ErrDuplicatedFlag") + } + } +} + +func TestFindOptionByLongFlag(t *testing.T) { + var opts struct { + Testing bool `long:"testing" description:"Testing"` + } + + p := NewParser(&opts, Default) + opt := p.FindOptionByLongName("testing") + + if opt == nil { + t.Errorf("Expected option, but found none") + } + + assertString(t, opt.LongName, "testing") +} + +func TestFindOptionByShortFlag(t *testing.T) { + var opts struct { + Testing bool `short:"t" description:"Testing"` + } + + p := NewParser(&opts, Default) + opt := p.FindOptionByShortName('t') + + if opt == nil { + t.Errorf("Expected option, but found none") + } + + if opt.ShortName != 't' { + t.Errorf("Expected 't', but got %v", opt.ShortName) + } +} + +func TestFindOptionByLongFlagInSubGroup(t *testing.T) { + var opts struct { + Group struct { + Testing bool `long:"testing" description:"Testing"` + } `group:"sub-group"` + } + + p := NewParser(&opts, Default) + opt := p.FindOptionByLongName("testing") + + if opt == nil { + t.Errorf("Expected option, but found none") + } + + assertString(t, opt.LongName, "testing") +} + +func TestFindOptionByShortFlagInSubGroup(t *testing.T) { + var opts struct { + Group struct { + Testing bool `short:"t" description:"Testing"` + } `group:"sub-group"` + } + + p := NewParser(&opts, Default) + opt := p.FindOptionByShortName('t') + + if opt == nil { + t.Errorf("Expected option, but found none") + } + + if opt.ShortName != 't' { + t.Errorf("Expected 't', but got %v", opt.ShortName) + } +} diff --git a/vendor/github.com/jessevdk/go-flags/help.go b/vendor/github.com/jessevdk/go-flags/help.go new file mode 100644 index 0000000..aac78de --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/help.go @@ -0,0 +1,473 @@ +// Copyright 2012 Jesse van den Kieboom. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flags + +import ( + "bufio" + "bytes" + "fmt" + "io" + "runtime" + "strings" + "unicode/utf8" +) + +type alignmentInfo struct { + maxLongLen int + hasShort bool + hasValueName bool + terminalColumns int + indent bool +} + +const ( + paddingBeforeOption = 2 + distanceBetweenOptionAndDescription = 2 +) + +func (a *alignmentInfo) descriptionStart() int { + ret := a.maxLongLen + distanceBetweenOptionAndDescription + + if a.hasShort { + ret += 2 + } + + if a.maxLongLen > 0 { + ret += 4 + } + + if a.hasValueName { + ret += 3 + } + + return ret +} + +func (a *alignmentInfo) updateLen(name string, indent bool) { + l := utf8.RuneCountInString(name) + + if indent { + l = l + 4 + } + + if l > a.maxLongLen { + a.maxLongLen = l + } +} + +func (p *Parser) getAlignmentInfo() alignmentInfo { + ret := alignmentInfo{ + maxLongLen: 0, + hasShort: false, + hasValueName: false, + terminalColumns: getTerminalColumns(), + } + + if ret.terminalColumns <= 0 { + ret.terminalColumns = 80 + } + + var prevcmd *Command + + p.eachActiveGroup(func(c *Command, grp *Group) { + if c != prevcmd { + for _, arg := range c.args { + ret.updateLen(arg.Name, c != p.Command) + } + } + + for _, info := range grp.options { + if !info.canCli() { + continue + } + + if info.ShortName != 0 { + ret.hasShort = true + } + + if len(info.ValueName) > 0 { + ret.hasValueName = true + } + + l := info.LongNameWithNamespace() + info.ValueName + + if len(info.Choices) != 0 { + l += "[" + strings.Join(info.Choices, "|") + "]" + } + + ret.updateLen(l, c != p.Command) + } + }) + + return ret +} + +func wrapText(s string, l int, prefix string) string { + var ret string + + // Basic text wrapping of s at spaces to fit in l + lines := strings.Split(s, "\n") + + for _, line := range lines { + var retline string + + line = strings.TrimSpace(line) + + for len(line) > l { + // Try to split on space + suffix := "" + + pos := strings.LastIndex(line[:l], " ") + + if pos < 0 { + pos = l - 1 + suffix = "-\n" + } + + if len(retline) != 0 { + retline += "\n" + prefix + } + + retline += strings.TrimSpace(line[:pos]) + suffix + line = strings.TrimSpace(line[pos:]) + } + + if len(line) > 0 { + if len(retline) != 0 { + retline += "\n" + prefix + } + + retline += line + } + + if len(ret) > 0 { + ret += "\n" + + if len(retline) > 0 { + ret += prefix + } + } + + ret += retline + } + + return ret +} + +func (p *Parser) writeHelpOption(writer *bufio.Writer, option *Option, info alignmentInfo) { + line := &bytes.Buffer{} + + prefix := paddingBeforeOption + + if info.indent { + prefix += 4 + } + + if option.Hidden { + return + } + + line.WriteString(strings.Repeat(" ", prefix)) + + if option.ShortName != 0 { + line.WriteRune(defaultShortOptDelimiter) + line.WriteRune(option.ShortName) + } else if info.hasShort { + line.WriteString(" ") + } + + descstart := info.descriptionStart() + paddingBeforeOption + + if len(option.LongName) > 0 { + if option.ShortName != 0 { + line.WriteString(", ") + } else if info.hasShort { + line.WriteString(" ") + } + + line.WriteString(defaultLongOptDelimiter) + line.WriteString(option.LongNameWithNamespace()) + } + + if option.canArgument() { + line.WriteRune(defaultNameArgDelimiter) + + if len(option.ValueName) > 0 { + line.WriteString(option.ValueName) + } + + if len(option.Choices) > 0 { + line.WriteString("[" + strings.Join(option.Choices, "|") + "]") + } + } + + written := line.Len() + line.WriteTo(writer) + + if option.Description != "" { + dw := descstart - written + writer.WriteString(strings.Repeat(" ", dw)) + + var def string + + if len(option.DefaultMask) != 0 && option.DefaultMask != "-" { + def = option.DefaultMask + } else { + def = option.defaultLiteral + } + + var envDef string + if option.EnvDefaultKey != "" { + var envPrintable string + if runtime.GOOS == "windows" { + envPrintable = "%" + option.EnvDefaultKey + "%" + } else { + envPrintable = "$" + option.EnvDefaultKey + } + envDef = fmt.Sprintf(" [%s]", envPrintable) + } + + var desc string + + if def != "" { + desc = fmt.Sprintf("%s (default: %v)%s", option.Description, def, envDef) + } else { + desc = option.Description + envDef + } + + writer.WriteString(wrapText(desc, + info.terminalColumns-descstart, + strings.Repeat(" ", descstart))) + } + + writer.WriteString("\n") +} + +func maxCommandLength(s []*Command) int { + if len(s) == 0 { + return 0 + } + + ret := len(s[0].Name) + + for _, v := range s[1:] { + l := len(v.Name) + + if l > ret { + ret = l + } + } + + return ret +} + +// WriteHelp writes a help message containing all the possible options and +// their descriptions to the provided writer. Note that the HelpFlag parser +// option provides a convenient way to add a -h/--help option group to the +// command line parser which will automatically show the help messages using +// this method. +func (p *Parser) WriteHelp(writer io.Writer) { + if writer == nil { + return + } + + wr := bufio.NewWriter(writer) + aligninfo := p.getAlignmentInfo() + + cmd := p.Command + + for cmd.Active != nil { + cmd = cmd.Active + } + + if p.Name != "" { + wr.WriteString("Usage:\n") + wr.WriteString(" ") + + allcmd := p.Command + + for allcmd != nil { + var usage string + + if allcmd == p.Command { + if len(p.Usage) != 0 { + usage = p.Usage + } else if p.Options&HelpFlag != 0 { + usage = "[OPTIONS]" + } + } else if us, ok := allcmd.data.(Usage); ok { + usage = us.Usage() + } else if allcmd.hasCliOptions() { + usage = fmt.Sprintf("[%s-OPTIONS]", allcmd.Name) + } + + if len(usage) != 0 { + fmt.Fprintf(wr, " %s %s", allcmd.Name, usage) + } else { + fmt.Fprintf(wr, " %s", allcmd.Name) + } + + if len(allcmd.args) > 0 { + fmt.Fprintf(wr, " ") + } + + for i, arg := range allcmd.args { + if i != 0 { + fmt.Fprintf(wr, " ") + } + + name := arg.Name + + if arg.isRemaining() { + name = name + "..." + } + + if !allcmd.ArgsRequired { + fmt.Fprintf(wr, "[%s]", name) + } else { + fmt.Fprintf(wr, "%s", name) + } + } + + if allcmd.Active == nil && len(allcmd.commands) > 0 { + var co, cc string + + if allcmd.SubcommandsOptional { + co, cc = "[", "]" + } else { + co, cc = "<", ">" + } + + visibleCommands := allcmd.visibleCommands() + + if len(visibleCommands) > 3 { + fmt.Fprintf(wr, " %scommand%s", co, cc) + } else { + subcommands := allcmd.sortedVisibleCommands() + names := make([]string, len(subcommands)) + + for i, subc := range subcommands { + names[i] = subc.Name + } + + fmt.Fprintf(wr, " %s%s%s", co, strings.Join(names, " | "), cc) + } + } + + allcmd = allcmd.Active + } + + fmt.Fprintln(wr) + + if len(cmd.LongDescription) != 0 { + fmt.Fprintln(wr) + + t := wrapText(cmd.LongDescription, + aligninfo.terminalColumns, + "") + + fmt.Fprintln(wr, t) + } + } + + c := p.Command + + for c != nil { + printcmd := c != p.Command + + c.eachGroup(func(grp *Group) { + first := true + + // Skip built-in help group for all commands except the top-level + // parser + if grp.Hidden || (grp.isBuiltinHelp && c != p.Command) { + return + } + + for _, info := range grp.options { + if !info.canCli() || info.Hidden { + continue + } + + if printcmd { + fmt.Fprintf(wr, "\n[%s command options]\n", c.Name) + aligninfo.indent = true + printcmd = false + } + + if first && cmd.Group != grp { + fmt.Fprintln(wr) + + if aligninfo.indent { + wr.WriteString(" ") + } + + fmt.Fprintf(wr, "%s:\n", grp.ShortDescription) + first = false + } + + p.writeHelpOption(wr, info, aligninfo) + } + }) + + var args []*Arg + for _, arg := range c.args { + if arg.Description != "" { + args = append(args, arg) + } + } + + if len(args) > 0 { + if c == p.Command { + fmt.Fprintf(wr, "\nArguments:\n") + } else { + fmt.Fprintf(wr, "\n[%s command arguments]\n", c.Name) + } + + maxlen := aligninfo.descriptionStart() + + for _, arg := range args { + prefix := strings.Repeat(" ", paddingBeforeOption) + fmt.Fprintf(wr, "%s%s", prefix, arg.Name) + + if len(arg.Description) > 0 { + align := strings.Repeat(" ", maxlen-len(arg.Name)-1) + fmt.Fprintf(wr, ":%s%s", align, arg.Description) + } + + fmt.Fprintln(wr) + } + } + + c = c.Active + } + + scommands := cmd.sortedVisibleCommands() + + if len(scommands) > 0 { + maxnamelen := maxCommandLength(scommands) + + fmt.Fprintln(wr) + fmt.Fprintln(wr, "Available commands:") + + for _, c := range scommands { + fmt.Fprintf(wr, " %s", c.Name) + + if len(c.ShortDescription) > 0 { + pad := strings.Repeat(" ", maxnamelen-len(c.Name)) + fmt.Fprintf(wr, "%s %s", pad, c.ShortDescription) + + if len(c.Aliases) > 0 { + fmt.Fprintf(wr, " (aliases: %s)", strings.Join(c.Aliases, ", ")) + } + + } + + fmt.Fprintln(wr) + } + } + + wr.Flush() +} diff --git a/vendor/github.com/jessevdk/go-flags/help_test.go b/vendor/github.com/jessevdk/go-flags/help_test.go new file mode 100644 index 0000000..1dcbe7f --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/help_test.go @@ -0,0 +1,462 @@ +package flags + +import ( + "bytes" + "fmt" + "os" + "runtime" + "testing" + "time" +) + +type helpOptions struct { + Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information" ini-name:"verbose"` + Call func(string) `short:"c" description:"Call phone number" ini-name:"call"` + PtrSlice []*string `long:"ptrslice" description:"A slice of pointers to string"` + EmptyDescription bool `long:"empty-description"` + + Default string `long:"default" default:"Some\nvalue" description:"Test default value"` + DefaultArray []string `long:"default-array" default:"Some value" default:"Other\tvalue" description:"Test default array value"` + DefaultMap map[string]string `long:"default-map" default:"some:value" default:"another:value" description:"Testdefault map value"` + EnvDefault1 string `long:"env-default1" default:"Some value" env:"ENV_DEFAULT" description:"Test env-default1 value"` + EnvDefault2 string `long:"env-default2" env:"ENV_DEFAULT" description:"Test env-default2 value"` + OptionWithArgName string `long:"opt-with-arg-name" value-name:"something" description:"Option with named argument"` + OptionWithChoices string `long:"opt-with-choices" value-name:"choice" choice:"dog" choice:"cat" description:"Option with choices"` + Hidden string `long:"hidden" description:"Hidden option" hidden:"yes"` + + OnlyIni string `ini-name:"only-ini" description:"Option only available in ini"` + + Other struct { + StringSlice []string `short:"s" default:"some" default:"value" description:"A slice of strings"` + IntMap map[string]int `long:"intmap" default:"a:1" description:"A map from string to int" ini-name:"int-map"` + } `group:"Other Options"` + + HiddenGroup struct { + InsideHiddenGroup string `long:"inside-hidden-group" description:"Inside hidden group"` + } `group:"Hidden group" hidden:"yes"` + + Group struct { + Opt string `long:"opt" description:"This is a subgroup option"` + HiddenInsideGroup string `long:"hidden-inside-group" description:"Hidden inside group" hidden:"yes"` + + Group struct { + Opt string `long:"opt" description:"This is a subsubgroup option"` + } `group:"Subsubgroup" namespace:"sap"` + } `group:"Subgroup" namespace:"sip"` + + Command struct { + ExtraVerbose []bool `long:"extra-verbose" description:"Use for extra verbosity"` + } `command:"command" alias:"cm" alias:"cmd" description:"A command"` + + HiddenCommand struct { + ExtraVerbose []bool `long:"extra-verbose" description:"Use for extra verbosity"` + } `command:"hidden-command" description:"A hidden command" hidden:"yes"` + + Args struct { + Filename string `positional-arg-name:"filename" description:"A filename"` + Number int `positional-arg-name:"num" description:"A number"` + HiddenInHelp float32 `positional-arg-name:"hidden-in-help" required:"yes"` + } `positional-args:"yes"` +} + +func TestHelp(t *testing.T) { + oldEnv := EnvSnapshot() + defer oldEnv.Restore() + os.Setenv("ENV_DEFAULT", "env-def") + + var opts helpOptions + p := NewNamedParser("TestHelp", HelpFlag) + p.AddGroup("Application Options", "The application options", &opts) + + _, err := p.ParseArgs([]string{"--help"}) + + if err == nil { + t.Fatalf("Expected help error") + } + + if e, ok := err.(*Error); !ok { + t.Fatalf("Expected flags.Error, but got %T", err) + } else { + if e.Type != ErrHelp { + t.Errorf("Expected flags.ErrHelp type, but got %s", e.Type) + } + + var expected string + + if runtime.GOOS == "windows" { + expected = `Usage: + TestHelp [OPTIONS] [filename] [num] [hidden-in-help] + + +Application Options: + /v, /verbose Show verbose debug information + /c: Call phone number + /ptrslice: A slice of pointers to string + /empty-description + /default: Test default value (default: + "Some\nvalue") + /default-array: Test default array value (default: + Some value, "Other\tvalue") + /default-map: Testdefault map value (default: + some:value, another:value) + /env-default1: Test env-default1 value (default: + Some value) [%ENV_DEFAULT%] + /env-default2: Test env-default2 value + [%ENV_DEFAULT%] + /opt-with-arg-name:something Option with named argument + /opt-with-choices:choice[dog|cat] Option with choices + +Other Options: + /s: A slice of strings (default: some, + value) + /intmap: A map from string to int (default: + a:1) + +Subgroup: + /sip.opt: This is a subgroup option + +Subsubgroup: + /sip.sap.opt: This is a subsubgroup option + +Help Options: + /? Show this help message + /h, /help Show this help message + +Arguments: + filename: A filename + num: A number + +Available commands: + command A command (aliases: cm, cmd) +` + } else { + expected = `Usage: + TestHelp [OPTIONS] [filename] [num] [hidden-in-help] + +Application Options: + -v, --verbose Show verbose debug information + -c= Call phone number + --ptrslice= A slice of pointers to string + --empty-description + --default= Test default value (default: + "Some\nvalue") + --default-array= Test default array value (default: + Some value, "Other\tvalue") + --default-map= Testdefault map value (default: + some:value, another:value) + --env-default1= Test env-default1 value (default: + Some value) [$ENV_DEFAULT] + --env-default2= Test env-default2 value + [$ENV_DEFAULT] + --opt-with-arg-name=something Option with named argument + --opt-with-choices=choice[dog|cat] Option with choices + +Other Options: + -s= A slice of strings (default: some, + value) + --intmap= A map from string to int (default: + a:1) + +Subgroup: + --sip.opt= This is a subgroup option + +Subsubgroup: + --sip.sap.opt= This is a subsubgroup option + +Help Options: + -h, --help Show this help message + +Arguments: + filename: A filename + num: A number + +Available commands: + command A command (aliases: cm, cmd) +` + } + + assertDiff(t, e.Message, expected, "help message") + } +} + +func TestMan(t *testing.T) { + oldEnv := EnvSnapshot() + defer oldEnv.Restore() + os.Setenv("ENV_DEFAULT", "env-def") + + var opts helpOptions + p := NewNamedParser("TestMan", HelpFlag) + p.ShortDescription = "Test manpage generation" + p.LongDescription = "This is a somewhat `longer' description of what this does" + p.AddGroup("Application Options", "The application options", &opts) + + p.Commands()[0].LongDescription = "Longer `command' description" + + var buf bytes.Buffer + p.WriteManPage(&buf) + + got := buf.String() + + tt := time.Now() + + var envDefaultName string + + if runtime.GOOS == "windows" { + envDefaultName = "%ENV_DEFAULT%" + } else { + envDefaultName = "$ENV_DEFAULT" + } + + expected := fmt.Sprintf(`.TH TestMan 1 "%s" +.SH NAME +TestMan \- Test manpage generation +.SH SYNOPSIS +\fBTestMan\fP [OPTIONS] +.SH DESCRIPTION +This is a somewhat \fBlonger\fP description of what this does +.SH OPTIONS +.TP +\fB\fB\-v\fR, \fB\-\-verbose\fR\fP +Show verbose debug information +.TP +\fB\fB\-c\fR\fP +Call phone number +.TP +\fB\fB\-\-ptrslice\fR\fP +A slice of pointers to string +.TP +\fB\fB\-\-empty-description\fR\fP +.TP +\fB\fB\-\-default\fR \fP +Test default value +.TP +\fB\fB\-\-default-array\fR \fP +Test default array value +.TP +\fB\fB\-\-default-map\fR \fP +Testdefault map value +.TP +\fB\fB\-\-env-default1\fR \fP +Test env-default1 value +.TP +\fB\fB\-\-env-default2\fR \fP +Test env-default2 value +.TP +\fB\fB\-\-opt-with-arg-name\fR \fIsomething\fR\fP +Option with named argument +.TP +\fB\fB\-\-opt-with-choices\fR \fIchoice\fR\fP +Option with choices +.TP +\fB\fB\-s\fR \fP +A slice of strings +.TP +\fB\fB\-\-intmap\fR \fP +A map from string to int +.TP +\fB\fB\-\-sip.opt\fR\fP +This is a subgroup option +.TP +\fB\fB\-\-sip.sap.opt\fR\fP +This is a subsubgroup option +.SH COMMANDS +.SS command +A command + +Longer \fBcommand\fP description + +\fBUsage\fP: TestMan [OPTIONS] command [command-OPTIONS] +.TP + +\fBAliases\fP: cm, cmd + +.TP +\fB\fB\-\-extra-verbose\fR\fP +Use for extra verbosity +`, tt.Format("2 January 2006"), envDefaultName) + + assertDiff(t, got, expected, "man page") +} + +type helpCommandNoOptions struct { + Command struct { + } `command:"command" description:"A command"` +} + +func TestHelpCommand(t *testing.T) { + oldEnv := EnvSnapshot() + defer oldEnv.Restore() + os.Setenv("ENV_DEFAULT", "env-def") + + var opts helpCommandNoOptions + p := NewNamedParser("TestHelpCommand", HelpFlag) + p.AddGroup("Application Options", "The application options", &opts) + + _, err := p.ParseArgs([]string{"command", "--help"}) + + if err == nil { + t.Fatalf("Expected help error") + } + + if e, ok := err.(*Error); !ok { + t.Fatalf("Expected flags.Error, but got %T", err) + } else { + if e.Type != ErrHelp { + t.Errorf("Expected flags.ErrHelp type, but got %s", e.Type) + } + + var expected string + + if runtime.GOOS == "windows" { + expected = `Usage: + TestHelpCommand [OPTIONS] command + +Help Options: + /? Show this help message + /h, /help Show this help message +` + } else { + expected = `Usage: + TestHelpCommand [OPTIONS] command + +Help Options: + -h, --help Show this help message +` + } + + assertDiff(t, e.Message, expected, "help message") + } +} + +func TestHelpDefaults(t *testing.T) { + var expected string + + if runtime.GOOS == "windows" { + expected = `Usage: + TestHelpDefaults [OPTIONS] + +Application Options: + /with-default: With default (default: default-value) + /without-default: Without default + /with-programmatic-default: With programmatic default (default: + default-value) + +Help Options: + /? Show this help message + /h, /help Show this help message +` + } else { + expected = `Usage: + TestHelpDefaults [OPTIONS] + +Application Options: + --with-default= With default (default: default-value) + --without-default= Without default + --with-programmatic-default= With programmatic default (default: + default-value) + +Help Options: + -h, --help Show this help message +` + } + + tests := []struct { + Args []string + Output string + }{ + { + Args: []string{"-h"}, + Output: expected, + }, + { + Args: []string{"--with-default", "other-value", "--with-programmatic-default", "other-value", "-h"}, + Output: expected, + }, + } + + for _, test := range tests { + var opts struct { + WithDefault string `long:"with-default" default:"default-value" description:"With default"` + WithoutDefault string `long:"without-default" description:"Without default"` + WithProgrammaticDefault string `long:"with-programmatic-default" description:"With programmatic default"` + } + + opts.WithProgrammaticDefault = "default-value" + + p := NewNamedParser("TestHelpDefaults", HelpFlag) + p.AddGroup("Application Options", "The application options", &opts) + + _, err := p.ParseArgs(test.Args) + + if err == nil { + t.Fatalf("Expected help error") + } + + if e, ok := err.(*Error); !ok { + t.Fatalf("Expected flags.Error, but got %T", err) + } else { + if e.Type != ErrHelp { + t.Errorf("Expected flags.ErrHelp type, but got %s", e.Type) + } + + assertDiff(t, e.Message, test.Output, "help message") + } + } +} + +func TestHelpRestArgs(t *testing.T) { + opts := struct { + Verbose bool `short:"v"` + }{} + + p := NewNamedParser("TestHelpDefaults", HelpFlag) + p.AddGroup("Application Options", "The application options", &opts) + + retargs, err := p.ParseArgs([]string{"-h", "-v", "rest"}) + + if err == nil { + t.Fatalf("Expected help error") + } + + assertStringArray(t, retargs, []string{"-v", "rest"}) +} + +func TestWrapText(t *testing.T) { + s := "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + + got := wrapText(s, 60, " ") + expected := `Lorem ipsum dolor sit amet, consectetur adipisicing elit, + sed do eiusmod tempor incididunt ut labore et dolore magna + aliqua. Ut enim ad minim veniam, quis nostrud exercitation + ullamco laboris nisi ut aliquip ex ea commodo consequat. + Duis aute irure dolor in reprehenderit in voluptate velit + esse cillum dolore eu fugiat nulla pariatur. Excepteur sint + occaecat cupidatat non proident, sunt in culpa qui officia + deserunt mollit anim id est laborum.` + + assertDiff(t, got, expected, "wrapped text") +} + +func TestWrapParagraph(t *testing.T) { + s := "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n\n" + s += "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n\n" + s += "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\n\n" + s += "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n" + + got := wrapText(s, 60, " ") + expected := `Lorem ipsum dolor sit amet, consectetur adipisicing elit, + sed do eiusmod tempor incididunt ut labore et dolore magna + aliqua. + + Ut enim ad minim veniam, quis nostrud exercitation ullamco + laboris nisi ut aliquip ex ea commodo consequat. + + Duis aute irure dolor in reprehenderit in voluptate velit + esse cillum dolore eu fugiat nulla pariatur. + + Excepteur sint occaecat cupidatat non proident, sunt in + culpa qui officia deserunt mollit anim id est laborum. +` + + assertDiff(t, got, expected, "wrapped paragraph") +} diff --git a/vendor/github.com/jessevdk/go-flags/ini.go b/vendor/github.com/jessevdk/go-flags/ini.go new file mode 100644 index 0000000..cfdf57c --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/ini.go @@ -0,0 +1,593 @@ +package flags + +import ( + "bufio" + "fmt" + "io" + "os" + "reflect" + "sort" + "strconv" + "strings" +) + +// IniError contains location information on where an error occured. +type IniError struct { + // The error message. + Message string + + // The filename of the file in which the error occurred. + File string + + // The line number at which the error occurred. + LineNumber uint +} + +// Error provides a "file:line: message" formatted message of the ini error. +func (x *IniError) Error() string { + return fmt.Sprintf( + "%s:%d: %s", + x.File, + x.LineNumber, + x.Message, + ) +} + +// IniOptions for writing +type IniOptions uint + +const ( + // IniNone indicates no options. + IniNone IniOptions = 0 + + // IniIncludeDefaults indicates that default values should be written. + IniIncludeDefaults = 1 << iota + + // IniCommentDefaults indicates that if IniIncludeDefaults is used + // options with default values are written but commented out. + IniCommentDefaults + + // IniIncludeComments indicates that comments containing the description + // of an option should be written. + IniIncludeComments + + // IniDefault provides a default set of options. + IniDefault = IniIncludeComments +) + +// IniParser is a utility to read and write flags options from and to ini +// formatted strings. +type IniParser struct { + parser *Parser +} + +type iniValue struct { + Name string + Value string + Quoted bool + LineNumber uint +} + +type iniSection []iniValue + +type ini struct { + File string + Sections map[string]iniSection +} + +// NewIniParser creates a new ini parser for a given Parser. +func NewIniParser(p *Parser) *IniParser { + return &IniParser{ + parser: p, + } +} + +// IniParse is a convenience function to parse command line options with default +// settings from an ini formatted file. The provided data is a pointer to a struct +// representing the default option group (named "Application Options"). For +// more control, use flags.NewParser. +func IniParse(filename string, data interface{}) error { + p := NewParser(data, Default) + + return NewIniParser(p).ParseFile(filename) +} + +// ParseFile parses flags from an ini formatted file. See Parse for more +// information on the ini file format. The returned errors can be of the type +// flags.Error or flags.IniError. +func (i *IniParser) ParseFile(filename string) error { + i.parser.clearIsSet() + + ini, err := readIniFromFile(filename) + + if err != nil { + return err + } + + return i.parse(ini) +} + +// Parse parses flags from an ini format. You can use ParseFile as a +// convenience function to parse from a filename instead of a general +// io.Reader. +// +// The format of the ini file is as follows: +// +// [Option group name] +// option = value +// +// Each section in the ini file represents an option group or command in the +// flags parser. The default flags parser option group (i.e. when using +// flags.Parse) is named 'Application Options'. The ini option name is matched +// in the following order: +// +// 1. Compared to the ini-name tag on the option struct field (if present) +// 2. Compared to the struct field name +// 3. Compared to the option long name (if present) +// 4. Compared to the option short name (if present) +// +// Sections for nested groups and commands can be addressed using a dot `.' +// namespacing notation (i.e [subcommand.Options]). Group section names are +// matched case insensitive. +// +// The returned errors can be of the type flags.Error or flags.IniError. +func (i *IniParser) Parse(reader io.Reader) error { + i.parser.clearIsSet() + + ini, err := readIni(reader, "") + + if err != nil { + return err + } + + return i.parse(ini) +} + +// WriteFile writes the flags as ini format into a file. See WriteIni +// for more information. The returned error occurs when the specified file +// could not be opened for writing. +func (i *IniParser) WriteFile(filename string, options IniOptions) error { + return writeIniToFile(i, filename, options) +} + +// Write writes the current values of all the flags to an ini format. +// See Parse for more information on the ini file format. You typically +// call this only after settings have been parsed since the default values of each +// option are stored just before parsing the flags (this is only relevant when +// IniIncludeDefaults is _not_ set in options). +func (i *IniParser) Write(writer io.Writer, options IniOptions) { + writeIni(i, writer, options) +} + +func readFullLine(reader *bufio.Reader) (string, error) { + var line []byte + + for { + l, more, err := reader.ReadLine() + + if err != nil { + return "", err + } + + if line == nil && !more { + return string(l), nil + } + + line = append(line, l...) + + if !more { + break + } + } + + return string(line), nil +} + +func optionIniName(option *Option) string { + name := option.tag.Get("_read-ini-name") + + if len(name) != 0 { + return name + } + + name = option.tag.Get("ini-name") + + if len(name) != 0 { + return name + } + + return option.field.Name +} + +func writeGroupIni(cmd *Command, group *Group, namespace string, writer io.Writer, options IniOptions) { + var sname string + + if len(namespace) != 0 { + sname = namespace + } + + if cmd.Group != group && len(group.ShortDescription) != 0 { + if len(sname) != 0 { + sname += "." + } + + sname += group.ShortDescription + } + + sectionwritten := false + comments := (options & IniIncludeComments) != IniNone + + for _, option := range group.options { + if option.isFunc() || option.Hidden { + continue + } + + if len(option.tag.Get("no-ini")) != 0 { + continue + } + + val := option.value + + if (options&IniIncludeDefaults) == IniNone && option.valueIsDefault() { + continue + } + + if !sectionwritten { + fmt.Fprintf(writer, "[%s]\n", sname) + sectionwritten = true + } + + if comments && len(option.Description) != 0 { + fmt.Fprintf(writer, "; %s\n", option.Description) + } + + oname := optionIniName(option) + + commentOption := (options&(IniIncludeDefaults|IniCommentDefaults)) == IniIncludeDefaults|IniCommentDefaults && option.valueIsDefault() + + kind := val.Type().Kind() + switch kind { + case reflect.Slice: + kind = val.Type().Elem().Kind() + + if val.Len() == 0 { + writeOption(writer, oname, kind, "", "", true, option.iniQuote) + } else { + for idx := 0; idx < val.Len(); idx++ { + v, _ := convertToString(val.Index(idx), option.tag) + + writeOption(writer, oname, kind, "", v, commentOption, option.iniQuote) + } + } + case reflect.Map: + kind = val.Type().Elem().Kind() + + if val.Len() == 0 { + writeOption(writer, oname, kind, "", "", true, option.iniQuote) + } else { + mkeys := val.MapKeys() + keys := make([]string, len(val.MapKeys())) + kkmap := make(map[string]reflect.Value) + + for i, k := range mkeys { + keys[i], _ = convertToString(k, option.tag) + kkmap[keys[i]] = k + } + + sort.Strings(keys) + + for _, k := range keys { + v, _ := convertToString(val.MapIndex(kkmap[k]), option.tag) + + writeOption(writer, oname, kind, k, v, commentOption, option.iniQuote) + } + } + default: + v, _ := convertToString(val, option.tag) + + writeOption(writer, oname, kind, "", v, commentOption, option.iniQuote) + } + + if comments { + fmt.Fprintln(writer) + } + } + + if sectionwritten && !comments { + fmt.Fprintln(writer) + } +} + +func writeOption(writer io.Writer, optionName string, optionType reflect.Kind, optionKey string, optionValue string, commentOption bool, forceQuote bool) { + if forceQuote || (optionType == reflect.String && !isPrint(optionValue)) { + optionValue = strconv.Quote(optionValue) + } + + comment := "" + if commentOption { + comment = "; " + } + + fmt.Fprintf(writer, "%s%s =", comment, optionName) + + if optionKey != "" { + fmt.Fprintf(writer, " %s:%s", optionKey, optionValue) + } else if optionValue != "" { + fmt.Fprintf(writer, " %s", optionValue) + } + + fmt.Fprintln(writer) +} + +func writeCommandIni(command *Command, namespace string, writer io.Writer, options IniOptions) { + command.eachGroup(func(group *Group) { + if !group.Hidden { + writeGroupIni(command, group, namespace, writer, options) + } + }) + + for _, c := range command.commands { + var nns string + + if c.Hidden { + continue + } + + if len(namespace) != 0 { + nns = c.Name + "." + nns + } else { + nns = c.Name + } + + writeCommandIni(c, nns, writer, options) + } +} + +func writeIni(parser *IniParser, writer io.Writer, options IniOptions) { + writeCommandIni(parser.parser.Command, "", writer, options) +} + +func writeIniToFile(parser *IniParser, filename string, options IniOptions) error { + file, err := os.Create(filename) + + if err != nil { + return err + } + + defer file.Close() + + writeIni(parser, file, options) + + return nil +} + +func readIniFromFile(filename string) (*ini, error) { + file, err := os.Open(filename) + + if err != nil { + return nil, err + } + + defer file.Close() + + return readIni(file, filename) +} + +func readIni(contents io.Reader, filename string) (*ini, error) { + ret := &ini{ + File: filename, + Sections: make(map[string]iniSection), + } + + reader := bufio.NewReader(contents) + + // Empty global section + section := make(iniSection, 0, 10) + sectionname := "" + + ret.Sections[sectionname] = section + + var lineno uint + + for { + line, err := readFullLine(reader) + + if err == io.EOF { + break + } else if err != nil { + return nil, err + } + + lineno++ + line = strings.TrimSpace(line) + + // Skip empty lines and lines starting with ; (comments) + if len(line) == 0 || line[0] == ';' || line[0] == '#' { + continue + } + + if line[0] == '[' { + if line[0] != '[' || line[len(line)-1] != ']' { + return nil, &IniError{ + Message: "malformed section header", + File: filename, + LineNumber: lineno, + } + } + + name := strings.TrimSpace(line[1 : len(line)-1]) + + if len(name) == 0 { + return nil, &IniError{ + Message: "empty section name", + File: filename, + LineNumber: lineno, + } + } + + sectionname = name + section = ret.Sections[name] + + if section == nil { + section = make(iniSection, 0, 10) + ret.Sections[name] = section + } + + continue + } + + // Parse option here + keyval := strings.SplitN(line, "=", 2) + + if len(keyval) != 2 { + return nil, &IniError{ + Message: fmt.Sprintf("malformed key=value (%s)", line), + File: filename, + LineNumber: lineno, + } + } + + name := strings.TrimSpace(keyval[0]) + value := strings.TrimSpace(keyval[1]) + quoted := false + + if len(value) != 0 && value[0] == '"' { + if v, err := strconv.Unquote(value); err == nil { + value = v + + quoted = true + } else { + return nil, &IniError{ + Message: err.Error(), + File: filename, + LineNumber: lineno, + } + } + } + + section = append(section, iniValue{ + Name: name, + Value: value, + Quoted: quoted, + LineNumber: lineno, + }) + + ret.Sections[sectionname] = section + } + + return ret, nil +} + +func (i *IniParser) matchingGroups(name string) []*Group { + if len(name) == 0 { + var ret []*Group + + i.parser.eachGroup(func(g *Group) { + ret = append(ret, g) + }) + + return ret + } + + g := i.parser.groupByName(name) + + if g != nil { + return []*Group{g} + } + + return nil +} + +func (i *IniParser) parse(ini *ini) error { + p := i.parser + + var quotesLookup = make(map[*Option]bool) + + for name, section := range ini.Sections { + groups := i.matchingGroups(name) + + if len(groups) == 0 { + return newErrorf(ErrUnknownGroup, "could not find option group `%s'", name) + } + + for _, inival := range section { + var opt *Option + + for _, group := range groups { + opt = group.optionByName(inival.Name, func(o *Option, n string) bool { + return strings.ToLower(o.tag.Get("ini-name")) == strings.ToLower(n) + }) + + if opt != nil && len(opt.tag.Get("no-ini")) != 0 { + opt = nil + } + + if opt != nil { + break + } + } + + if opt == nil { + if (p.Options & IgnoreUnknown) == None { + return &IniError{ + Message: fmt.Sprintf("unknown option: %s", inival.Name), + File: ini.File, + LineNumber: inival.LineNumber, + } + } + + continue + } + + pval := &inival.Value + + if !opt.canArgument() && len(inival.Value) == 0 { + pval = nil + } else { + if opt.value.Type().Kind() == reflect.Map { + parts := strings.SplitN(inival.Value, ":", 2) + + // only handle unquoting + if len(parts) == 2 && parts[1][0] == '"' { + if v, err := strconv.Unquote(parts[1]); err == nil { + parts[1] = v + + inival.Quoted = true + } else { + return &IniError{ + Message: err.Error(), + File: ini.File, + LineNumber: inival.LineNumber, + } + } + + s := parts[0] + ":" + parts[1] + + pval = &s + } + } + } + + if err := opt.set(pval); err != nil { + return &IniError{ + Message: err.Error(), + File: ini.File, + LineNumber: inival.LineNumber, + } + } + + // either all INI values are quoted or only values who need quoting + if _, ok := quotesLookup[opt]; !inival.Quoted || !ok { + quotesLookup[opt] = inival.Quoted + } + + opt.tag.Set("_read-ini-name", inival.Name) + } + } + + for opt, quoted := range quotesLookup { + opt.iniQuote = quoted + } + + return nil +} diff --git a/vendor/github.com/jessevdk/go-flags/ini_test.go b/vendor/github.com/jessevdk/go-flags/ini_test.go new file mode 100644 index 0000000..dfe49ce --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/ini_test.go @@ -0,0 +1,950 @@ +package flags + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "reflect" + "strings" + "testing" +) + +func TestWriteIni(t *testing.T) { + oldEnv := EnvSnapshot() + defer oldEnv.Restore() + os.Setenv("ENV_DEFAULT", "env-def") + + var tests = []struct { + args []string + options IniOptions + expected string + }{ + { + []string{"-vv", "--intmap=a:2", "--intmap", "b:3", "filename", "0", "3.14", "command"}, + IniDefault, + `[Application Options] +; Show verbose debug information +verbose = true +verbose = true + +; Test env-default1 value +EnvDefault1 = env-def + +; Test env-default2 value +EnvDefault2 = env-def + +[Other Options] +; A map from string to int +int-map = a:2 +int-map = b:3 + +`, + }, + { + []string{"-vv", "--intmap=a:2", "--intmap", "b:3", "filename", "0", "3.14", "command"}, + IniDefault | IniIncludeDefaults, + `[Application Options] +; Show verbose debug information +verbose = true +verbose = true + +; A slice of pointers to string +; PtrSlice = + +EmptyDescription = false + +; Test default value +Default = "Some\nvalue" + +; Test default array value +DefaultArray = Some value +DefaultArray = "Other\tvalue" + +; Testdefault map value +DefaultMap = another:value +DefaultMap = some:value + +; Test env-default1 value +EnvDefault1 = env-def + +; Test env-default2 value +EnvDefault2 = env-def + +; Option with named argument +OptionWithArgName = + +; Option with choices +OptionWithChoices = + +; Option only available in ini +only-ini = + +[Other Options] +; A slice of strings +StringSlice = some +StringSlice = value + +; A map from string to int +int-map = a:2 +int-map = b:3 + +[Subgroup] +; This is a subgroup option +Opt = + +[Subsubgroup] +; This is a subsubgroup option +Opt = + +[command] +; Use for extra verbosity +; ExtraVerbose = + +`, + }, + { + []string{"filename", "0", "3.14", "command"}, + IniDefault | IniIncludeDefaults | IniCommentDefaults, + `[Application Options] +; Show verbose debug information +; verbose = + +; A slice of pointers to string +; PtrSlice = + +; EmptyDescription = false + +; Test default value +; Default = "Some\nvalue" + +; Test default array value +; DefaultArray = Some value +; DefaultArray = "Other\tvalue" + +; Testdefault map value +; DefaultMap = another:value +; DefaultMap = some:value + +; Test env-default1 value +EnvDefault1 = env-def + +; Test env-default2 value +EnvDefault2 = env-def + +; Option with named argument +; OptionWithArgName = + +; Option with choices +; OptionWithChoices = + +; Option only available in ini +; only-ini = + +[Other Options] +; A slice of strings +; StringSlice = some +; StringSlice = value + +; A map from string to int +; int-map = a:1 + +[Subgroup] +; This is a subgroup option +; Opt = + +[Subsubgroup] +; This is a subsubgroup option +; Opt = + +[command] +; Use for extra verbosity +; ExtraVerbose = + +`, + }, + { + []string{"--default=New value", "--default-array=New value", "--default-map=new:value", "filename", "0", "3.14", "command"}, + IniDefault | IniIncludeDefaults | IniCommentDefaults, + `[Application Options] +; Show verbose debug information +; verbose = + +; A slice of pointers to string +; PtrSlice = + +; EmptyDescription = false + +; Test default value +Default = New value + +; Test default array value +DefaultArray = New value + +; Testdefault map value +DefaultMap = new:value + +; Test env-default1 value +EnvDefault1 = env-def + +; Test env-default2 value +EnvDefault2 = env-def + +; Option with named argument +; OptionWithArgName = + +; Option with choices +; OptionWithChoices = + +; Option only available in ini +; only-ini = + +[Other Options] +; A slice of strings +; StringSlice = some +; StringSlice = value + +; A map from string to int +; int-map = a:1 + +[Subgroup] +; This is a subgroup option +; Opt = + +[Subsubgroup] +; This is a subsubgroup option +; Opt = + +[command] +; Use for extra verbosity +; ExtraVerbose = + +`, + }, + } + + for _, test := range tests { + var opts helpOptions + + p := NewNamedParser("TestIni", Default) + p.AddGroup("Application Options", "The application options", &opts) + + _, err := p.ParseArgs(test.args) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + inip := NewIniParser(p) + + var b bytes.Buffer + inip.Write(&b, test.options) + + got := b.String() + expected := test.expected + + msg := fmt.Sprintf("with arguments %+v and ini options %b", test.args, test.options) + assertDiff(t, got, expected, msg) + } +} + +func TestReadIni_flagEquivalent(t *testing.T) { + type options struct { + Opt1 bool `long:"opt1"` + + Group1 struct { + Opt2 bool `long:"opt2"` + } `group:"group1"` + + Group2 struct { + Opt3 bool `long:"opt3"` + } `group:"group2" namespace:"ns1"` + + Cmd1 struct { + Opt4 bool `long:"opt4"` + Opt5 bool `long:"foo.opt5"` + + Group1 struct { + Opt6 bool `long:"opt6"` + Opt7 bool `long:"foo.opt7"` + } `group:"group1"` + + Group2 struct { + Opt8 bool `long:"opt8"` + } `group:"group2" namespace:"ns1"` + } `command:"cmd1"` + } + + a := ` +opt1=true + +[group1] +opt2=true + +[group2] +ns1.opt3=true + +[cmd1] +opt4=true +foo.opt5=true + +[cmd1.group1] +opt6=true +foo.opt7=true + +[cmd1.group2] +ns1.opt8=true +` + b := ` +opt1=true +opt2=true +ns1.opt3=true + +[cmd1] +opt4=true +foo.opt5=true +opt6=true +foo.opt7=true +ns1.opt8=true +` + + parse := func(readIni string) (opts options, writeIni string) { + p := NewNamedParser("TestIni", Default) + p.AddGroup("Application Options", "The application options", &opts) + + inip := NewIniParser(p) + err := inip.Parse(strings.NewReader(readIni)) + + if err != nil { + t.Fatalf("Unexpected error: %s\n\nFile:\n%s", err, readIni) + } + + var b bytes.Buffer + inip.Write(&b, Default) + + return opts, b.String() + } + + aOpt, aIni := parse(a) + bOpt, bIni := parse(b) + + assertDiff(t, aIni, bIni, "") + if !reflect.DeepEqual(aOpt, bOpt) { + t.Errorf("not equal") + } +} + +func TestReadIni(t *testing.T) { + var opts helpOptions + + p := NewNamedParser("TestIni", Default) + p.AddGroup("Application Options", "The application options", &opts) + + inip := NewIniParser(p) + + inic := ` +; Show verbose debug information +verbose = true +verbose = true + +DefaultMap = another:"value\n1" +DefaultMap = some:value 2 + +[Application Options] +; A slice of pointers to string +; PtrSlice = + +; Test default value +Default = "New\nvalue" + +; Test env-default1 value +EnvDefault1 = New value + +[Other Options] +# A slice of strings +StringSlice = "some\nvalue" +StringSlice = another value + +; A map from string to int +int-map = a:2 +int-map = b:3 + +` + + b := strings.NewReader(inic) + err := inip.Parse(b) + + if err != nil { + t.Fatalf("Unexpected error: %s", err) + } + + assertBoolArray(t, opts.Verbose, []bool{true, true}) + + if v := map[string]string{"another": "value\n1", "some": "value 2"}; !reflect.DeepEqual(opts.DefaultMap, v) { + t.Fatalf("Expected %#v for DefaultMap but got %#v", v, opts.DefaultMap) + } + + assertString(t, opts.Default, "New\nvalue") + + assertString(t, opts.EnvDefault1, "New value") + + assertStringArray(t, opts.Other.StringSlice, []string{"some\nvalue", "another value"}) + + if v, ok := opts.Other.IntMap["a"]; !ok { + t.Errorf("Expected \"a\" in Other.IntMap") + } else if v != 2 { + t.Errorf("Expected Other.IntMap[\"a\"] = 2, but got %v", v) + } + + if v, ok := opts.Other.IntMap["b"]; !ok { + t.Errorf("Expected \"b\" in Other.IntMap") + } else if v != 3 { + t.Errorf("Expected Other.IntMap[\"b\"] = 3, but got %v", v) + } +} + +func TestReadAndWriteIni(t *testing.T) { + var tests = []struct { + options IniOptions + read string + write string + }{ + { + IniIncludeComments, + `[Application Options] +; Show verbose debug information +verbose = true +verbose = true + +; Test default value +Default = "quote me" + +; Test default array value +DefaultArray = 1 +DefaultArray = "2" +DefaultArray = 3 + +; Testdefault map value +; DefaultMap = + +; Test env-default1 value +EnvDefault1 = env-def + +; Test env-default2 value +EnvDefault2 = env-def + +[Other Options] +; A slice of strings +; StringSlice = + +; A map from string to int +int-map = a:2 +int-map = b:"3" + +`, + `[Application Options] +; Show verbose debug information +verbose = true +verbose = true + +; Test default value +Default = "quote me" + +; Test default array value +DefaultArray = 1 +DefaultArray = 2 +DefaultArray = 3 + +; Testdefault map value +; DefaultMap = + +; Test env-default1 value +EnvDefault1 = env-def + +; Test env-default2 value +EnvDefault2 = env-def + +[Other Options] +; A slice of strings +; StringSlice = + +; A map from string to int +int-map = a:2 +int-map = b:3 + +`, + }, + { + IniIncludeComments, + `[Application Options] +; Show verbose debug information +verbose = true +verbose = true + +; Test default value +Default = "quote me" + +; Test default array value +DefaultArray = "1" +DefaultArray = "2" +DefaultArray = "3" + +; Testdefault map value +; DefaultMap = + +; Test env-default1 value +EnvDefault1 = env-def + +; Test env-default2 value +EnvDefault2 = env-def + +[Other Options] +; A slice of strings +; StringSlice = + +; A map from string to int +int-map = a:"2" +int-map = b:"3" + +`, + `[Application Options] +; Show verbose debug information +verbose = true +verbose = true + +; Test default value +Default = "quote me" + +; Test default array value +DefaultArray = "1" +DefaultArray = "2" +DefaultArray = "3" + +; Testdefault map value +; DefaultMap = + +; Test env-default1 value +EnvDefault1 = env-def + +; Test env-default2 value +EnvDefault2 = env-def + +[Other Options] +; A slice of strings +; StringSlice = + +; A map from string to int +int-map = a:"2" +int-map = b:"3" + +`, + }, + } + + for _, test := range tests { + var opts helpOptions + + p := NewNamedParser("TestIni", Default) + p.AddGroup("Application Options", "The application options", &opts) + + inip := NewIniParser(p) + + read := strings.NewReader(test.read) + err := inip.Parse(read) + if err != nil { + t.Fatalf("Unexpected error: %s", err) + } + + var write bytes.Buffer + inip.Write(&write, test.options) + + got := write.String() + + msg := fmt.Sprintf("with ini options %b", test.options) + assertDiff(t, got, test.write, msg) + } +} + +func TestReadIniWrongQuoting(t *testing.T) { + var tests = []struct { + iniFile string + lineNumber uint + }{ + { + iniFile: `Default = "New\nvalue`, + lineNumber: 1, + }, + { + iniFile: `StringSlice = "New\nvalue`, + lineNumber: 1, + }, + { + iniFile: `StringSlice = "New\nvalue" + StringSlice = "Second\nvalue`, + lineNumber: 2, + }, + { + iniFile: `DefaultMap = some:"value`, + lineNumber: 1, + }, + { + iniFile: `DefaultMap = some:value + DefaultMap = another:"value`, + lineNumber: 2, + }, + } + + for _, test := range tests { + var opts helpOptions + + p := NewNamedParser("TestIni", Default) + p.AddGroup("Application Options", "The application options", &opts) + + inip := NewIniParser(p) + + inic := test.iniFile + + b := strings.NewReader(inic) + err := inip.Parse(b) + + if err == nil { + t.Fatalf("Expect error") + } + + iniError := err.(*IniError) + + if iniError.LineNumber != test.lineNumber { + t.Fatalf("Expect error on line %d", test.lineNumber) + } + } +} + +func TestIniCommands(t *testing.T) { + var opts struct { + Value string `short:"v" long:"value"` + + Add struct { + Name int `short:"n" long:"name" ini-name:"AliasName"` + + Other struct { + O string `short:"o" long:"other"` + } `group:"Other Options"` + } `command:"add"` + } + + p := NewNamedParser("TestIni", Default) + p.AddGroup("Application Options", "The application options", &opts) + + inip := NewIniParser(p) + + inic := `[Application Options] +value = some value + +[add] +AliasName = 5 + +[add.Other Options] +other = subgroup + +` + + b := strings.NewReader(inic) + err := inip.Parse(b) + + if err != nil { + t.Fatalf("Unexpected error: %s", err) + } + + assertString(t, opts.Value, "some value") + + if opts.Add.Name != 5 { + t.Errorf("Expected opts.Add.Name to be 5, but got %v", opts.Add.Name) + } + + assertString(t, opts.Add.Other.O, "subgroup") + + // Test writing it back + buf := &bytes.Buffer{} + + inip.Write(buf, IniDefault) + + assertDiff(t, buf.String(), inic, "ini contents") +} + +func TestIniNoIni(t *testing.T) { + var opts struct { + NoValue string `short:"n" long:"novalue" no-ini:"yes"` + Value string `short:"v" long:"value"` + } + + p := NewNamedParser("TestIni", Default) + p.AddGroup("Application Options", "The application options", &opts) + + inip := NewIniParser(p) + + // read INI + inic := `[Application Options] +novalue = some value +value = some other value +` + + b := strings.NewReader(inic) + err := inip.Parse(b) + + if err == nil { + t.Fatalf("Expected error") + } + + iniError := err.(*IniError) + + if v := uint(2); iniError.LineNumber != v { + t.Errorf("Expected opts.Add.Name to be %d, but got %d", v, iniError.LineNumber) + } + + if v := "unknown option: novalue"; iniError.Message != v { + t.Errorf("Expected opts.Add.Name to be %s, but got %s", v, iniError.Message) + } + + // write INI + opts.NoValue = "some value" + opts.Value = "some other value" + + file, err := ioutil.TempFile("", "") + if err != nil { + t.Fatalf("Cannot create temporary file: %s", err) + } + defer os.Remove(file.Name()) + + err = inip.WriteFile(file.Name(), IniIncludeDefaults) + if err != nil { + t.Fatalf("Could not write ini file: %s", err) + } + + found, err := ioutil.ReadFile(file.Name()) + if err != nil { + t.Fatalf("Could not read written ini file: %s", err) + } + + expected := "[Application Options]\nValue = some other value\n\n" + + assertDiff(t, string(found), expected, "ini content") +} + +func TestIniParse(t *testing.T) { + file, err := ioutil.TempFile("", "") + if err != nil { + t.Fatalf("Cannot create temporary file: %s", err) + } + defer os.Remove(file.Name()) + + _, err = file.WriteString("value = 123") + if err != nil { + t.Fatalf("Cannot write to temporary file: %s", err) + } + + file.Close() + + var opts struct { + Value int `long:"value"` + } + + err = IniParse(file.Name(), &opts) + if err != nil { + t.Fatalf("Could not parse ini: %s", err) + } + + if opts.Value != 123 { + t.Fatalf("Expected Value to be \"123\" but was \"%d\"", opts.Value) + } +} + +func TestIniCliOverrides(t *testing.T) { + file, err := ioutil.TempFile("", "") + + if err != nil { + t.Fatalf("Cannot create temporary file: %s", err) + } + + defer os.Remove(file.Name()) + + _, err = file.WriteString("values = 123\n") + _, err = file.WriteString("values = 456\n") + + if err != nil { + t.Fatalf("Cannot write to temporary file: %s", err) + } + + file.Close() + + var opts struct { + Values []int `long:"values"` + } + + p := NewParser(&opts, Default) + err = NewIniParser(p).ParseFile(file.Name()) + + if err != nil { + t.Fatalf("Could not parse ini: %s", err) + } + + _, err = p.ParseArgs([]string{"--values", "111", "--values", "222"}) + + if err != nil { + t.Fatalf("Failed to parse arguments: %s", err) + } + + if len(opts.Values) != 2 { + t.Fatalf("Expected Values to contain two elements, but got %d", len(opts.Values)) + } + + if opts.Values[0] != 111 { + t.Fatalf("Expected Values[0] to be 111, but got '%d'", opts.Values[0]) + } + + if opts.Values[1] != 222 { + t.Fatalf("Expected Values[0] to be 222, but got '%d'", opts.Values[1]) + } +} + +func TestIniOverrides(t *testing.T) { + file, err := ioutil.TempFile("", "") + + if err != nil { + t.Fatalf("Cannot create temporary file: %s", err) + } + + defer os.Remove(file.Name()) + + _, err = file.WriteString("value-with-default = \"ini-value\"\n") + _, err = file.WriteString("value-with-default-override-cli = \"ini-value\"\n") + + if err != nil { + t.Fatalf("Cannot write to temporary file: %s", err) + } + + file.Close() + + var opts struct { + ValueWithDefault string `long:"value-with-default" default:"value"` + ValueWithDefaultOverrideCli string `long:"value-with-default-override-cli" default:"value"` + } + + p := NewParser(&opts, Default) + err = NewIniParser(p).ParseFile(file.Name()) + + if err != nil { + t.Fatalf("Could not parse ini: %s", err) + } + + _, err = p.ParseArgs([]string{"--value-with-default-override-cli", "cli-value"}) + + if err != nil { + t.Fatalf("Failed to parse arguments: %s", err) + } + + assertString(t, opts.ValueWithDefault, "ini-value") + assertString(t, opts.ValueWithDefaultOverrideCli, "cli-value") +} + +func TestWriteFile(t *testing.T) { + file, err := ioutil.TempFile("", "") + if err != nil { + t.Fatalf("Cannot create temporary file: %s", err) + } + defer os.Remove(file.Name()) + + var opts struct { + Value int `long:"value"` + } + + opts.Value = 123 + + p := NewParser(&opts, Default) + ini := NewIniParser(p) + + err = ini.WriteFile(file.Name(), IniIncludeDefaults) + if err != nil { + t.Fatalf("Could not write ini file: %s", err) + } + + found, err := ioutil.ReadFile(file.Name()) + if err != nil { + t.Fatalf("Could not read written ini file: %s", err) + } + + expected := "[Application Options]\nValue = 123\n\n" + + assertDiff(t, string(found), expected, "ini content") +} + +func TestOverwriteRequiredOptions(t *testing.T) { + var tests = []struct { + args []string + expected []string + }{ + { + args: []string{"--value", "from CLI"}, + expected: []string{ + "from CLI", + "from default", + }, + }, + { + args: []string{"--value", "from CLI", "--default", "from CLI"}, + expected: []string{ + "from CLI", + "from CLI", + }, + }, + { + args: []string{"--config", "no file name"}, + expected: []string{ + "from INI", + "from INI", + }, + }, + { + args: []string{"--value", "from CLI before", "--default", "from CLI before", "--config", "no file name"}, + expected: []string{ + "from INI", + "from INI", + }, + }, + { + args: []string{"--value", "from CLI before", "--default", "from CLI before", "--config", "no file name", "--value", "from CLI after", "--default", "from CLI after"}, + expected: []string{ + "from CLI after", + "from CLI after", + }, + }, + } + + for _, test := range tests { + var opts struct { + Config func(s string) error `long:"config" no-ini:"true"` + Value string `long:"value" required:"true"` + Default string `long:"default" required:"true" default:"from default"` + } + + p := NewParser(&opts, Default) + + opts.Config = func(s string) error { + ini := NewIniParser(p) + + return ini.Parse(bytes.NewBufferString("value = from INI\ndefault = from INI")) + } + + _, err := p.ParseArgs(test.args) + if err != nil { + t.Fatalf("Unexpected error %s with args %+v", err, test.args) + } + + if opts.Value != test.expected[0] { + t.Fatalf("Expected Value to be \"%s\" but was \"%s\" with args %+v", test.expected[0], opts.Value, test.args) + } + + if opts.Default != test.expected[1] { + t.Fatalf("Expected Default to be \"%s\" but was \"%s\" with args %+v", test.expected[1], opts.Default, test.args) + } + } +} diff --git a/vendor/github.com/jessevdk/go-flags/long_test.go b/vendor/github.com/jessevdk/go-flags/long_test.go new file mode 100644 index 0000000..02fc8c7 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/long_test.go @@ -0,0 +1,85 @@ +package flags + +import ( + "testing" +) + +func TestLong(t *testing.T) { + var opts = struct { + Value bool `long:"value"` + }{} + + ret := assertParseSuccess(t, &opts, "--value") + + assertStringArray(t, ret, []string{}) + + if !opts.Value { + t.Errorf("Expected Value to be true") + } +} + +func TestLongArg(t *testing.T) { + var opts = struct { + Value string `long:"value"` + }{} + + ret := assertParseSuccess(t, &opts, "--value", "value") + + assertStringArray(t, ret, []string{}) + assertString(t, opts.Value, "value") +} + +func TestLongArgEqual(t *testing.T) { + var opts = struct { + Value string `long:"value"` + }{} + + ret := assertParseSuccess(t, &opts, "--value=value") + + assertStringArray(t, ret, []string{}) + assertString(t, opts.Value, "value") +} + +func TestLongDefault(t *testing.T) { + var opts = struct { + Value string `long:"value" default:"value"` + }{} + + ret := assertParseSuccess(t, &opts) + + assertStringArray(t, ret, []string{}) + assertString(t, opts.Value, "value") +} + +func TestLongOptional(t *testing.T) { + var opts = struct { + Value string `long:"value" optional:"yes" optional-value:"value"` + }{} + + ret := assertParseSuccess(t, &opts, "--value") + + assertStringArray(t, ret, []string{}) + assertString(t, opts.Value, "value") +} + +func TestLongOptionalArg(t *testing.T) { + var opts = struct { + Value string `long:"value" optional:"yes" optional-value:"value"` + }{} + + ret := assertParseSuccess(t, &opts, "--value", "no") + + assertStringArray(t, ret, []string{"no"}) + assertString(t, opts.Value, "value") +} + +func TestLongOptionalArgEqual(t *testing.T) { + var opts = struct { + Value string `long:"value" optional:"yes" optional-value:"value"` + }{} + + ret := assertParseSuccess(t, &opts, "--value=value", "no") + + assertStringArray(t, ret, []string{"no"}) + assertString(t, opts.Value, "value") +} diff --git a/vendor/github.com/jessevdk/go-flags/man.go b/vendor/github.com/jessevdk/go-flags/man.go new file mode 100644 index 0000000..8e4a8b7 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/man.go @@ -0,0 +1,194 @@ +package flags + +import ( + "fmt" + "io" + "runtime" + "strings" + "time" +) + +func manQuote(s string) string { + return strings.Replace(s, "\\", "\\\\", -1) +} + +func formatForMan(wr io.Writer, s string) { + for { + idx := strings.IndexRune(s, '`') + + if idx < 0 { + fmt.Fprintf(wr, "%s", manQuote(s)) + break + } + + fmt.Fprintf(wr, "%s", manQuote(s[:idx])) + + s = s[idx+1:] + idx = strings.IndexRune(s, '\'') + + if idx < 0 { + fmt.Fprintf(wr, "%s", manQuote(s)) + break + } + + fmt.Fprintf(wr, "\\fB%s\\fP", manQuote(s[:idx])) + s = s[idx+1:] + } +} + +func writeManPageOptions(wr io.Writer, grp *Group) { + grp.eachGroup(func(group *Group) { + if group.Hidden { + return + } + + for _, opt := range group.options { + if !opt.canCli() || opt.Hidden { + continue + } + + fmt.Fprintln(wr, ".TP") + fmt.Fprintf(wr, "\\fB") + + if opt.ShortName != 0 { + fmt.Fprintf(wr, "\\fB\\-%c\\fR", opt.ShortName) + } + + if len(opt.LongName) != 0 { + if opt.ShortName != 0 { + fmt.Fprintf(wr, ", ") + } + + fmt.Fprintf(wr, "\\fB\\-\\-%s\\fR", manQuote(opt.LongNameWithNamespace())) + } + + if len(opt.ValueName) != 0 || opt.OptionalArgument { + if opt.OptionalArgument { + fmt.Fprintf(wr, " [\\fI%s=%s\\fR]", manQuote(opt.ValueName), manQuote(strings.Join(quoteV(opt.OptionalValue), ", "))) + } else { + fmt.Fprintf(wr, " \\fI%s\\fR", manQuote(opt.ValueName)) + } + } + + if len(opt.Default) != 0 { + fmt.Fprintf(wr, " ", manQuote(strings.Join(quoteV(opt.Default), ", "))) + } else if len(opt.EnvDefaultKey) != 0 { + if runtime.GOOS == "windows" { + fmt.Fprintf(wr, " ", manQuote(opt.EnvDefaultKey)) + } else { + fmt.Fprintf(wr, " ", manQuote(opt.EnvDefaultKey)) + } + } + + if opt.Required { + fmt.Fprintf(wr, " (\\fIrequired\\fR)") + } + + fmt.Fprintln(wr, "\\fP") + + if len(opt.Description) != 0 { + formatForMan(wr, opt.Description) + fmt.Fprintln(wr, "") + } + } + }) +} + +func writeManPageSubcommands(wr io.Writer, name string, root *Command) { + commands := root.sortedVisibleCommands() + + for _, c := range commands { + var nn string + + if c.Hidden { + continue + } + + if len(name) != 0 { + nn = name + " " + c.Name + } else { + nn = c.Name + } + + writeManPageCommand(wr, nn, root, c) + } +} + +func writeManPageCommand(wr io.Writer, name string, root *Command, command *Command) { + fmt.Fprintf(wr, ".SS %s\n", name) + fmt.Fprintln(wr, command.ShortDescription) + + if len(command.LongDescription) > 0 { + fmt.Fprintln(wr, "") + + cmdstart := fmt.Sprintf("The %s command", manQuote(command.Name)) + + if strings.HasPrefix(command.LongDescription, cmdstart) { + fmt.Fprintf(wr, "The \\fI%s\\fP command", manQuote(command.Name)) + + formatForMan(wr, command.LongDescription[len(cmdstart):]) + fmt.Fprintln(wr, "") + } else { + formatForMan(wr, command.LongDescription) + fmt.Fprintln(wr, "") + } + } + + var usage string + if us, ok := command.data.(Usage); ok { + usage = us.Usage() + } else if command.hasCliOptions() { + usage = fmt.Sprintf("[%s-OPTIONS]", command.Name) + } + + var pre string + if root.hasCliOptions() { + pre = fmt.Sprintf("%s [OPTIONS] %s", root.Name, command.Name) + } else { + pre = fmt.Sprintf("%s %s", root.Name, command.Name) + } + + if len(usage) > 0 { + fmt.Fprintf(wr, "\n\\fBUsage\\fP: %s %s\n.TP\n", manQuote(pre), manQuote(usage)) + } + + if len(command.Aliases) > 0 { + fmt.Fprintf(wr, "\n\\fBAliases\\fP: %s\n\n", manQuote(strings.Join(command.Aliases, ", "))) + } + + writeManPageOptions(wr, command.Group) + writeManPageSubcommands(wr, name, command) +} + +// WriteManPage writes a basic man page in groff format to the specified +// writer. +func (p *Parser) WriteManPage(wr io.Writer) { + t := time.Now() + + fmt.Fprintf(wr, ".TH %s 1 \"%s\"\n", manQuote(p.Name), t.Format("2 January 2006")) + fmt.Fprintln(wr, ".SH NAME") + fmt.Fprintf(wr, "%s \\- %s\n", manQuote(p.Name), manQuote(p.ShortDescription)) + fmt.Fprintln(wr, ".SH SYNOPSIS") + + usage := p.Usage + + if len(usage) == 0 { + usage = "[OPTIONS]" + } + + fmt.Fprintf(wr, "\\fB%s\\fP %s\n", manQuote(p.Name), manQuote(usage)) + fmt.Fprintln(wr, ".SH DESCRIPTION") + + formatForMan(wr, p.LongDescription) + fmt.Fprintln(wr, "") + + fmt.Fprintln(wr, ".SH OPTIONS") + + writeManPageOptions(wr, p.Command.Group) + + if len(p.visibleCommands()) > 0 { + fmt.Fprintln(wr, ".SH COMMANDS") + + writeManPageSubcommands(wr, "", p.Command) + } +} diff --git a/vendor/github.com/jessevdk/go-flags/marshal_test.go b/vendor/github.com/jessevdk/go-flags/marshal_test.go new file mode 100644 index 0000000..095e9e4 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/marshal_test.go @@ -0,0 +1,97 @@ +package flags + +import ( + "fmt" + "testing" +) + +type marshalled string + +func (m *marshalled) UnmarshalFlag(value string) error { + if value == "yes" { + *m = "true" + } else if value == "no" { + *m = "false" + } else { + return fmt.Errorf("`%s' is not a valid value, please specify `yes' or `no'", value) + } + + return nil +} + +func (m marshalled) MarshalFlag() (string, error) { + if m == "true" { + return "yes", nil + } + + return "no", nil +} + +type marshalledError bool + +func (m marshalledError) MarshalFlag() (string, error) { + return "", newErrorf(ErrMarshal, "Failed to marshal") +} + +func TestUnmarshal(t *testing.T) { + var opts = struct { + Value marshalled `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-v=yes") + + assertStringArray(t, ret, []string{}) + + if opts.Value != "true" { + t.Errorf("Expected Value to be \"true\"") + } +} + +func TestUnmarshalDefault(t *testing.T) { + var opts = struct { + Value marshalled `short:"v" default:"yes"` + }{} + + ret := assertParseSuccess(t, &opts) + + assertStringArray(t, ret, []string{}) + + if opts.Value != "true" { + t.Errorf("Expected Value to be \"true\"") + } +} + +func TestUnmarshalOptional(t *testing.T) { + var opts = struct { + Value marshalled `short:"v" optional:"yes" optional-value:"yes"` + }{} + + ret := assertParseSuccess(t, &opts, "-v") + + assertStringArray(t, ret, []string{}) + + if opts.Value != "true" { + t.Errorf("Expected Value to be \"true\"") + } +} + +func TestUnmarshalError(t *testing.T) { + var opts = struct { + Value marshalled `short:"v"` + }{} + + assertParseFail(t, ErrMarshal, fmt.Sprintf("invalid argument for flag `%cv' (expected flags.marshalled): `invalid' is not a valid value, please specify `yes' or `no'", defaultShortOptDelimiter), &opts, "-vinvalid") +} + +func TestMarshalError(t *testing.T) { + var opts = struct { + Value marshalledError `short:"v"` + }{} + + p := NewParser(&opts, Default) + o := p.Command.Groups()[0].Options()[0] + + _, err := convertToString(o.value, o.tag) + + assertError(t, err, ErrMarshal, "Failed to marshal") +} diff --git a/vendor/github.com/jessevdk/go-flags/multitag.go b/vendor/github.com/jessevdk/go-flags/multitag.go new file mode 100644 index 0000000..96bb1a3 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/multitag.go @@ -0,0 +1,140 @@ +package flags + +import ( + "strconv" +) + +type multiTag struct { + value string + cache map[string][]string +} + +func newMultiTag(v string) multiTag { + return multiTag{ + value: v, + } +} + +func (x *multiTag) scan() (map[string][]string, error) { + v := x.value + + ret := make(map[string][]string) + + // This is mostly copied from reflect.StructTag.Get + for v != "" { + i := 0 + + // Skip whitespace + for i < len(v) && v[i] == ' ' { + i++ + } + + v = v[i:] + + if v == "" { + break + } + + // Scan to colon to find key + i = 0 + + for i < len(v) && v[i] != ' ' && v[i] != ':' && v[i] != '"' { + i++ + } + + if i >= len(v) { + return nil, newErrorf(ErrTag, "expected `:' after key name, but got end of tag (in `%v`)", x.value) + } + + if v[i] != ':' { + return nil, newErrorf(ErrTag, "expected `:' after key name, but got `%v' (in `%v`)", v[i], x.value) + } + + if i+1 >= len(v) { + return nil, newErrorf(ErrTag, "expected `\"' to start tag value at end of tag (in `%v`)", x.value) + } + + if v[i+1] != '"' { + return nil, newErrorf(ErrTag, "expected `\"' to start tag value, but got `%v' (in `%v`)", v[i+1], x.value) + } + + name := v[:i] + v = v[i+1:] + + // Scan quoted string to find value + i = 1 + + for i < len(v) && v[i] != '"' { + if v[i] == '\n' { + return nil, newErrorf(ErrTag, "unexpected newline in tag value `%v' (in `%v`)", name, x.value) + } + + if v[i] == '\\' { + i++ + } + i++ + } + + if i >= len(v) { + return nil, newErrorf(ErrTag, "expected end of tag value `\"' at end of tag (in `%v`)", x.value) + } + + val, err := strconv.Unquote(v[:i+1]) + + if err != nil { + return nil, newErrorf(ErrTag, "Malformed value of tag `%v:%v` => %v (in `%v`)", name, v[:i+1], err, x.value) + } + + v = v[i+1:] + + ret[name] = append(ret[name], val) + } + + return ret, nil +} + +func (x *multiTag) Parse() error { + vals, err := x.scan() + x.cache = vals + + return err +} + +func (x *multiTag) cached() map[string][]string { + if x.cache == nil { + cache, _ := x.scan() + + if cache == nil { + cache = make(map[string][]string) + } + + x.cache = cache + } + + return x.cache +} + +func (x *multiTag) Get(key string) string { + c := x.cached() + + if v, ok := c[key]; ok { + return v[len(v)-1] + } + + return "" +} + +func (x *multiTag) GetMany(key string) []string { + c := x.cached() + return c[key] +} + +func (x *multiTag) Set(key string, value string) { + c := x.cached() + c[key] = []string{value} +} + +func (x *multiTag) SetMany(key string, value []string) { + c := x.cached() + c[key] = value +} diff --git a/vendor/github.com/jessevdk/go-flags/option.go b/vendor/github.com/jessevdk/go-flags/option.go new file mode 100644 index 0000000..b2a69c7 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/option.go @@ -0,0 +1,434 @@ +package flags + +import ( + "bytes" + "fmt" + "reflect" + "strings" + "syscall" + "unicode/utf8" +) + +// Option flag information. Contains a description of the option, short and +// long name as well as a default value and whether an argument for this +// flag is optional. +type Option struct { + // The description of the option flag. This description is shown + // automatically in the built-in help. + Description string + + // The short name of the option (a single character). If not 0, the + // option flag can be 'activated' using -. Either ShortName + // or LongName needs to be non-empty. + ShortName rune + + // The long name of the option. If not "", the option flag can be + // activated using --. Either ShortName or LongName needs + // to be non-empty. + LongName string + + // The default value of the option. + Default []string + + // The optional environment default value key name. + EnvDefaultKey string + + // The optional delimiter string for EnvDefaultKey values. + EnvDefaultDelim string + + // If true, specifies that the argument to an option flag is optional. + // When no argument to the flag is specified on the command line, the + // value of OptionalValue will be set in the field this option represents. + // This is only valid for non-boolean options. + OptionalArgument bool + + // The optional value of the option. The optional value is used when + // the option flag is marked as having an OptionalArgument. This means + // that when the flag is specified, but no option argument is given, + // the value of the field this option represents will be set to + // OptionalValue. This is only valid for non-boolean options. + OptionalValue []string + + // If true, the option _must_ be specified on the command line. If the + // option is not specified, the parser will generate an ErrRequired type + // error. + Required bool + + // A name for the value of an option shown in the Help as --flag [ValueName] + ValueName string + + // A mask value to show in the help instead of the default value. This + // is useful for hiding sensitive information in the help, such as + // passwords. + DefaultMask string + + // If non empty, only a certain set of values is allowed for an option. + Choices []string + + // If true, the option is not displayed in the help or man page + Hidden bool + + // The group which the option belongs to + group *Group + + // The struct field which the option represents. + field reflect.StructField + + // The struct field value which the option represents. + value reflect.Value + + // Determines if the option will be always quoted in the INI output + iniQuote bool + + tag multiTag + isSet bool + preventDefault bool + + defaultLiteral string +} + +// LongNameWithNamespace returns the option's long name with the group namespaces +// prepended by walking up the option's group tree. Namespaces and the long name +// itself are separated by the parser's namespace delimiter. If the long name is +// empty an empty string is returned. +func (option *Option) LongNameWithNamespace() string { + if len(option.LongName) == 0 { + return "" + } + + // fetch the namespace delimiter from the parser which is always at the + // end of the group hierarchy + namespaceDelimiter := "" + g := option.group + + for { + if p, ok := g.parent.(*Parser); ok { + namespaceDelimiter = p.NamespaceDelimiter + + break + } + + switch i := g.parent.(type) { + case *Command: + g = i.Group + case *Group: + g = i + } + } + + // concatenate long name with namespace + longName := option.LongName + g = option.group + + for g != nil { + if g.Namespace != "" { + longName = g.Namespace + namespaceDelimiter + longName + } + + switch i := g.parent.(type) { + case *Command: + g = i.Group + case *Group: + g = i + case *Parser: + g = nil + } + } + + return longName +} + +// String converts an option to a human friendly readable string describing the +// option. +func (option *Option) String() string { + var s string + var short string + + if option.ShortName != 0 { + data := make([]byte, utf8.RuneLen(option.ShortName)) + utf8.EncodeRune(data, option.ShortName) + short = string(data) + + if len(option.LongName) != 0 { + s = fmt.Sprintf("%s%s, %s%s", + string(defaultShortOptDelimiter), short, + defaultLongOptDelimiter, option.LongNameWithNamespace()) + } else { + s = fmt.Sprintf("%s%s", string(defaultShortOptDelimiter), short) + } + } else if len(option.LongName) != 0 { + s = fmt.Sprintf("%s%s", defaultLongOptDelimiter, option.LongNameWithNamespace()) + } + + return s +} + +// Value returns the option value as an interface{}. +func (option *Option) Value() interface{} { + return option.value.Interface() +} + +// IsSet returns true if option has been set +func (option *Option) IsSet() bool { + return option.isSet +} + +// Set the value of an option to the specified value. An error will be returned +// if the specified value could not be converted to the corresponding option +// value type. +func (option *Option) set(value *string) error { + kind := option.value.Type().Kind() + + if (kind == reflect.Map || kind == reflect.Slice) && !option.isSet { + option.empty() + } + + option.isSet = true + option.preventDefault = true + + if len(option.Choices) != 0 { + found := false + + for _, choice := range option.Choices { + if choice == *value { + found = true + break + } + } + + if !found { + allowed := strings.Join(option.Choices[0:len(option.Choices)-1], ", ") + + if len(option.Choices) > 1 { + allowed += " or " + option.Choices[len(option.Choices)-1] + } + + return newErrorf(ErrInvalidChoice, + "Invalid value `%s' for option `%s'. Allowed values are: %s", + *value, option, allowed) + } + } + + if option.isFunc() { + return option.call(value) + } else if value != nil { + return convert(*value, option.value, option.tag) + } + + return convert("", option.value, option.tag) +} + +func (option *Option) canCli() bool { + return option.ShortName != 0 || len(option.LongName) != 0 +} + +func (option *Option) canArgument() bool { + if u := option.isUnmarshaler(); u != nil { + return true + } + + return !option.isBool() +} + +func (option *Option) emptyValue() reflect.Value { + tp := option.value.Type() + + if tp.Kind() == reflect.Map { + return reflect.MakeMap(tp) + } + + return reflect.Zero(tp) +} + +func (option *Option) empty() { + if !option.isFunc() { + option.value.Set(option.emptyValue()) + } +} + +func (option *Option) clearDefault() { + usedDefault := option.Default + + if envKey := option.EnvDefaultKey; envKey != "" { + // os.Getenv() makes no distinction between undefined and + // empty values, so we use syscall.Getenv() + if value, ok := syscall.Getenv(envKey); ok { + if option.EnvDefaultDelim != "" { + usedDefault = strings.Split(value, + option.EnvDefaultDelim) + } else { + usedDefault = []string{value} + } + } + } + + if len(usedDefault) > 0 { + option.empty() + + for _, d := range usedDefault { + option.set(&d) + } + } else { + tp := option.value.Type() + + switch tp.Kind() { + case reflect.Map: + if option.value.IsNil() { + option.empty() + } + case reflect.Slice: + if option.value.IsNil() { + option.empty() + } + } + } +} + +func (option *Option) valueIsDefault() bool { + // Check if the value of the option corresponds to its + // default value + emptyval := option.emptyValue() + + checkvalptr := reflect.New(emptyval.Type()) + checkval := reflect.Indirect(checkvalptr) + + checkval.Set(emptyval) + + if len(option.Default) != 0 { + for _, v := range option.Default { + convert(v, checkval, option.tag) + } + } + + return reflect.DeepEqual(option.value.Interface(), checkval.Interface()) +} + +func (option *Option) isUnmarshaler() Unmarshaler { + v := option.value + + for { + if !v.CanInterface() { + break + } + + i := v.Interface() + + if u, ok := i.(Unmarshaler); ok { + return u + } + + if !v.CanAddr() { + break + } + + v = v.Addr() + } + + return nil +} + +func (option *Option) isBool() bool { + tp := option.value.Type() + + for { + switch tp.Kind() { + case reflect.Bool: + return true + case reflect.Slice: + return (tp.Elem().Kind() == reflect.Bool) + case reflect.Func: + return tp.NumIn() == 0 + case reflect.Ptr: + tp = tp.Elem() + default: + return false + } + } +} + +func (option *Option) isFunc() bool { + return option.value.Type().Kind() == reflect.Func +} + +func (option *Option) call(value *string) error { + var retval []reflect.Value + + if value == nil { + retval = option.value.Call(nil) + } else { + tp := option.value.Type().In(0) + + val := reflect.New(tp) + val = reflect.Indirect(val) + + if err := convert(*value, val, option.tag); err != nil { + return err + } + + retval = option.value.Call([]reflect.Value{val}) + } + + if len(retval) == 1 && retval[0].Type() == reflect.TypeOf((*error)(nil)).Elem() { + if retval[0].Interface() == nil { + return nil + } + + return retval[0].Interface().(error) + } + + return nil +} + +func (option *Option) updateDefaultLiteral() { + defs := option.Default + def := "" + + if len(defs) == 0 && option.canArgument() { + var showdef bool + + switch option.field.Type.Kind() { + case reflect.Func, reflect.Ptr: + showdef = !option.value.IsNil() + case reflect.Slice, reflect.String, reflect.Array: + showdef = option.value.Len() > 0 + case reflect.Map: + showdef = !option.value.IsNil() && option.value.Len() > 0 + default: + zeroval := reflect.Zero(option.field.Type) + showdef = !reflect.DeepEqual(zeroval.Interface(), option.value.Interface()) + } + + if showdef { + def, _ = convertToString(option.value, option.tag) + } + } else if len(defs) != 0 { + l := len(defs) - 1 + + for i := 0; i < l; i++ { + def += quoteIfNeeded(defs[i]) + ", " + } + + def += quoteIfNeeded(defs[l]) + } + + option.defaultLiteral = def +} + +func (option *Option) shortAndLongName() string { + ret := &bytes.Buffer{} + + if option.ShortName != 0 { + ret.WriteRune(defaultShortOptDelimiter) + ret.WriteRune(option.ShortName) + } + + if len(option.LongName) != 0 { + if option.ShortName != 0 { + ret.WriteRune('/') + } + + ret.WriteString(option.LongName) + } + + return ret.String() +} diff --git a/vendor/github.com/jessevdk/go-flags/options_test.go b/vendor/github.com/jessevdk/go-flags/options_test.go new file mode 100644 index 0000000..b0fe9f4 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/options_test.go @@ -0,0 +1,45 @@ +package flags + +import ( + "testing" +) + +func TestPassDoubleDash(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + }{} + + p := NewParser(&opts, PassDoubleDash) + ret, err := p.ParseArgs([]string{"-v", "--", "-v", "-g"}) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + assertStringArray(t, ret, []string{"-v", "-g"}) +} + +func TestPassAfterNonOption(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + }{} + + p := NewParser(&opts, PassAfterNonOption) + ret, err := p.ParseArgs([]string{"-v", "arg", "-v", "-g"}) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + assertStringArray(t, ret, []string{"arg", "-v", "-g"}) +} diff --git a/vendor/github.com/jessevdk/go-flags/optstyle_other.go b/vendor/github.com/jessevdk/go-flags/optstyle_other.go new file mode 100644 index 0000000..29ca4b6 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/optstyle_other.go @@ -0,0 +1,67 @@ +// +build !windows + +package flags + +import ( + "strings" +) + +const ( + defaultShortOptDelimiter = '-' + defaultLongOptDelimiter = "--" + defaultNameArgDelimiter = '=' +) + +func argumentStartsOption(arg string) bool { + return len(arg) > 0 && arg[0] == '-' +} + +func argumentIsOption(arg string) bool { + if len(arg) > 1 && arg[0] == '-' && arg[1] != '-' { + return true + } + + if len(arg) > 2 && arg[0] == '-' && arg[1] == '-' && arg[2] != '-' { + return true + } + + return false +} + +// stripOptionPrefix returns the option without the prefix and whether or +// not the option is a long option or not. +func stripOptionPrefix(optname string) (prefix string, name string, islong bool) { + if strings.HasPrefix(optname, "--") { + return "--", optname[2:], true + } else if strings.HasPrefix(optname, "-") { + return "-", optname[1:], false + } + + return "", optname, false +} + +// splitOption attempts to split the passed option into a name and an argument. +// When there is no argument specified, nil will be returned for it. +func splitOption(prefix string, option string, islong bool) (string, string, *string) { + pos := strings.Index(option, "=") + + if (islong && pos >= 0) || (!islong && pos == 1) { + rest := option[pos+1:] + return option[:pos], "=", &rest + } + + return option, "", nil +} + +// addHelpGroup adds a new group that contains default help parameters. +func (c *Command) addHelpGroup(showHelp func() error) *Group { + var help struct { + ShowHelp func() error `short:"h" long:"help" description:"Show this help message"` + } + + help.ShowHelp = showHelp + ret, _ := c.AddGroup("Help Options", "", &help) + ret.isBuiltinHelp = true + + return ret +} diff --git a/vendor/github.com/jessevdk/go-flags/optstyle_windows.go b/vendor/github.com/jessevdk/go-flags/optstyle_windows.go new file mode 100644 index 0000000..a51de9c --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/optstyle_windows.go @@ -0,0 +1,106 @@ +package flags + +import ( + "strings" +) + +// Windows uses a front slash for both short and long options. Also it uses +// a colon for name/argument delimter. +const ( + defaultShortOptDelimiter = '/' + defaultLongOptDelimiter = "/" + defaultNameArgDelimiter = ':' +) + +func argumentStartsOption(arg string) bool { + return len(arg) > 0 && (arg[0] == '-' || arg[0] == '/') +} + +func argumentIsOption(arg string) bool { + // Windows-style options allow front slash for the option + // delimiter. + if len(arg) > 1 && arg[0] == '/' { + return true + } + + if len(arg) > 1 && arg[0] == '-' && arg[1] != '-' { + return true + } + + if len(arg) > 2 && arg[0] == '-' && arg[1] == '-' && arg[2] != '-' { + return true + } + + return false +} + +// stripOptionPrefix returns the option without the prefix and whether or +// not the option is a long option or not. +func stripOptionPrefix(optname string) (prefix string, name string, islong bool) { + // Determine if the argument is a long option or not. Windows + // typically supports both long and short options with a single + // front slash as the option delimiter, so handle this situation + // nicely. + possplit := 0 + + if strings.HasPrefix(optname, "--") { + possplit = 2 + islong = true + } else if strings.HasPrefix(optname, "-") { + possplit = 1 + islong = false + } else if strings.HasPrefix(optname, "/") { + possplit = 1 + islong = len(optname) > 2 + } + + return optname[:possplit], optname[possplit:], islong +} + +// splitOption attempts to split the passed option into a name and an argument. +// When there is no argument specified, nil will be returned for it. +func splitOption(prefix string, option string, islong bool) (string, string, *string) { + if len(option) == 0 { + return option, "", nil + } + + // Windows typically uses a colon for the option name and argument + // delimiter while POSIX typically uses an equals. Support both styles, + // but don't allow the two to be mixed. That is to say /foo:bar and + // --foo=bar are acceptable, but /foo=bar and --foo:bar are not. + var pos int + var sp string + + if prefix == "/" { + sp = ":" + pos = strings.Index(option, sp) + } else if len(prefix) > 0 { + sp = "=" + pos = strings.Index(option, sp) + } + + if (islong && pos >= 0) || (!islong && pos == 1) { + rest := option[pos+1:] + return option[:pos], sp, &rest + } + + return option, "", nil +} + +// addHelpGroup adds a new group that contains default help parameters. +func (c *Command) addHelpGroup(showHelp func() error) *Group { + // Windows CLI applications typically use /? for help, so make both + // that available as well as the POSIX style h and help. + var help struct { + ShowHelpWindows func() error `short:"?" description:"Show this help message"` + ShowHelpPosix func() error `short:"h" long:"help" description:"Show this help message"` + } + + help.ShowHelpWindows = showHelp + help.ShowHelpPosix = showHelp + + ret, _ := c.AddGroup("Help Options", "", &help) + ret.isBuiltinHelp = true + + return ret +} diff --git a/vendor/github.com/jessevdk/go-flags/parser.go b/vendor/github.com/jessevdk/go-flags/parser.go new file mode 100644 index 0000000..f9e07ee --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/parser.go @@ -0,0 +1,652 @@ +// Copyright 2012 Jesse van den Kieboom. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flags + +import ( + "bytes" + "fmt" + "os" + "path" + "sort" + "strings" + "unicode/utf8" +) + +// A Parser provides command line option parsing. It can contain several +// option groups each with their own set of options. +type Parser struct { + // Embedded, see Command for more information + *Command + + // A usage string to be displayed in the help message. + Usage string + + // Option flags changing the behavior of the parser. + Options Options + + // NamespaceDelimiter separates group namespaces and option long names + NamespaceDelimiter string + + // UnknownOptionsHandler is a function which gets called when the parser + // encounters an unknown option. The function receives the unknown option + // name, a SplitArgument which specifies its value if set with an argument + // separator, and the remaining command line arguments. + // It should return a new list of remaining arguments to continue parsing, + // or an error to indicate a parse failure. + UnknownOptionHandler func(option string, arg SplitArgument, args []string) ([]string, error) + + // CompletionHandler is a function gets called to handle the completion of + // items. By default, the items are printed and the application is exited. + // You can override this default behavior by specifying a custom CompletionHandler. + CompletionHandler func(items []Completion) + + internalError error +} + +// SplitArgument represents the argument value of an option that was passed using +// an argument separator. +type SplitArgument interface { + // String returns the option's value as a string, and a boolean indicating + // if the option was present. + Value() (string, bool) +} + +type strArgument struct { + value *string +} + +func (s strArgument) Value() (string, bool) { + if s.value == nil { + return "", false + } + + return *s.value, true +} + +// Options provides parser options that change the behavior of the option +// parser. +type Options uint + +const ( + // None indicates no options. + None Options = 0 + + // HelpFlag adds a default Help Options group to the parser containing + // -h and --help options. When either -h or --help is specified on the + // command line, the parser will return the special error of type + // ErrHelp. When PrintErrors is also specified, then the help message + // will also be automatically printed to os.Stderr. + HelpFlag = 1 << iota + + // PassDoubleDash passes all arguments after a double dash, --, as + // remaining command line arguments (i.e. they will not be parsed for + // flags). + PassDoubleDash + + // IgnoreUnknown ignores any unknown options and passes them as + // remaining command line arguments instead of generating an error. + IgnoreUnknown + + // PrintErrors prints any errors which occurred during parsing to + // os.Stderr. + PrintErrors + + // PassAfterNonOption passes all arguments after the first non option + // as remaining command line arguments. This is equivalent to strict + // POSIX processing. + PassAfterNonOption + + // Default is a convenient default set of options which should cover + // most of the uses of the flags package. + Default = HelpFlag | PrintErrors | PassDoubleDash +) + +type parseState struct { + arg string + args []string + retargs []string + positional []*Arg + err error + + command *Command + lookup lookup +} + +// Parse is a convenience function to parse command line options with default +// settings. The provided data is a pointer to a struct representing the +// default option group (named "Application Options"). For more control, use +// flags.NewParser. +func Parse(data interface{}) ([]string, error) { + return NewParser(data, Default).Parse() +} + +// ParseArgs is a convenience function to parse command line options with default +// settings. The provided data is a pointer to a struct representing the +// default option group (named "Application Options"). The args argument is +// the list of command line arguments to parse. If you just want to parse the +// default program command line arguments (i.e. os.Args), then use flags.Parse +// instead. For more control, use flags.NewParser. +func ParseArgs(data interface{}, args []string) ([]string, error) { + return NewParser(data, Default).ParseArgs(args) +} + +// NewParser creates a new parser. It uses os.Args[0] as the application +// name and then calls Parser.NewNamedParser (see Parser.NewNamedParser for +// more details). The provided data is a pointer to a struct representing the +// default option group (named "Application Options"), or nil if the default +// group should not be added. The options parameter specifies a set of options +// for the parser. +func NewParser(data interface{}, options Options) *Parser { + p := NewNamedParser(path.Base(os.Args[0]), options) + + if data != nil { + g, err := p.AddGroup("Application Options", "", data) + + if err == nil { + g.parent = p + } + + p.internalError = err + } + + return p +} + +// NewNamedParser creates a new parser. The appname is used to display the +// executable name in the built-in help message. Option groups and commands can +// be added to this parser by using AddGroup and AddCommand. +func NewNamedParser(appname string, options Options) *Parser { + p := &Parser{ + Command: newCommand(appname, "", "", nil), + Options: options, + NamespaceDelimiter: ".", + } + + p.Command.parent = p + + return p +} + +// Parse parses the command line arguments from os.Args using Parser.ParseArgs. +// For more detailed information see ParseArgs. +func (p *Parser) Parse() ([]string, error) { + return p.ParseArgs(os.Args[1:]) +} + +// ParseArgs parses the command line arguments according to the option groups that +// were added to the parser. On successful parsing of the arguments, the +// remaining, non-option, arguments (if any) are returned. The returned error +// indicates a parsing error and can be used with PrintError to display +// contextual information on where the error occurred exactly. +// +// When the common help group has been added (AddHelp) and either -h or --help +// was specified in the command line arguments, a help message will be +// automatically printed if the PrintErrors option is enabled. +// Furthermore, the special error type ErrHelp is returned. +// It is up to the caller to exit the program if so desired. +func (p *Parser) ParseArgs(args []string) ([]string, error) { + if p.internalError != nil { + return nil, p.internalError + } + + p.eachOption(func(c *Command, g *Group, option *Option) { + option.isSet = false + option.updateDefaultLiteral() + }) + + // Add built-in help group to all commands if necessary + if (p.Options & HelpFlag) != None { + p.addHelpGroups(p.showBuiltinHelp) + } + + compval := os.Getenv("GO_FLAGS_COMPLETION") + + if len(compval) != 0 { + comp := &completion{parser: p} + items := comp.complete(args) + + if p.CompletionHandler != nil { + p.CompletionHandler(items) + } else { + comp.print(items, compval == "verbose") + os.Exit(0) + } + + return nil, nil + } + + s := &parseState{ + args: args, + retargs: make([]string, 0, len(args)), + } + + p.fillParseState(s) + + for !s.eof() { + arg := s.pop() + + // When PassDoubleDash is set and we encounter a --, then + // simply append all the rest as arguments and break out + if (p.Options&PassDoubleDash) != None && arg == "--" { + s.addArgs(s.args...) + break + } + + if !argumentIsOption(arg) { + // Note: this also sets s.err, so we can just check for + // nil here and use s.err later + if p.parseNonOption(s) != nil { + break + } + + continue + } + + var err error + + prefix, optname, islong := stripOptionPrefix(arg) + optname, _, argument := splitOption(prefix, optname, islong) + + if islong { + err = p.parseLong(s, optname, argument) + } else { + err = p.parseShort(s, optname, argument) + } + + if err != nil { + ignoreUnknown := (p.Options & IgnoreUnknown) != None + parseErr := wrapError(err) + + if parseErr.Type != ErrUnknownFlag || (!ignoreUnknown && p.UnknownOptionHandler == nil) { + s.err = parseErr + break + } + + if ignoreUnknown { + s.addArgs(arg) + } else if p.UnknownOptionHandler != nil { + modifiedArgs, err := p.UnknownOptionHandler(optname, strArgument{argument}, s.args) + + if err != nil { + s.err = err + break + } + + s.args = modifiedArgs + } + } + } + + if s.err == nil { + p.eachOption(func(c *Command, g *Group, option *Option) { + if option.preventDefault { + return + } + + option.clearDefault() + }) + + s.checkRequired(p) + } + + var reterr error + + if s.err != nil { + reterr = s.err + } else if len(s.command.commands) != 0 && !s.command.SubcommandsOptional { + reterr = s.estimateCommand() + } else if cmd, ok := s.command.data.(Commander); ok { + reterr = cmd.Execute(s.retargs) + } + + if reterr != nil { + var retargs []string + + if ourErr, ok := reterr.(*Error); !ok || ourErr.Type != ErrHelp { + retargs = append([]string{s.arg}, s.args...) + } else { + retargs = s.args + } + + return retargs, p.printError(reterr) + } + + return s.retargs, nil +} + +func (p *parseState) eof() bool { + return len(p.args) == 0 +} + +func (p *parseState) pop() string { + if p.eof() { + return "" + } + + p.arg = p.args[0] + p.args = p.args[1:] + + return p.arg +} + +func (p *parseState) peek() string { + if p.eof() { + return "" + } + + return p.args[0] +} + +func (p *parseState) checkRequired(parser *Parser) error { + c := parser.Command + + var required []*Option + + for c != nil { + c.eachGroup(func(g *Group) { + for _, option := range g.options { + if !option.isSet && option.Required { + required = append(required, option) + } + } + }) + + c = c.Active + } + + if len(required) == 0 { + if len(p.positional) > 0 { + var reqnames []string + + for _, arg := range p.positional { + argRequired := (!arg.isRemaining() && p.command.ArgsRequired) || arg.Required != 0 + + if !argRequired { + continue + } + + if arg.isRemaining() { + if arg.value.Len() < arg.Required { + var arguments string + + if arg.Required > 1 { + arguments = "arguments, but got only " + fmt.Sprintf("%d", arg.value.Len()) + } else { + arguments = "argument" + } + + reqnames = append(reqnames, "`"+arg.Name+" (at least "+fmt.Sprintf("%d", arg.Required)+" "+arguments+")`") + } + } else { + reqnames = append(reqnames, "`"+arg.Name+"`") + } + } + + if len(reqnames) == 0 { + return nil + } + + var msg string + + if len(reqnames) == 1 { + msg = fmt.Sprintf("the required argument %s was not provided", reqnames[0]) + } else { + msg = fmt.Sprintf("the required arguments %s and %s were not provided", + strings.Join(reqnames[:len(reqnames)-1], ", "), reqnames[len(reqnames)-1]) + } + + p.err = newError(ErrRequired, msg) + return p.err + } + + return nil + } + + names := make([]string, 0, len(required)) + + for _, k := range required { + names = append(names, "`"+k.String()+"'") + } + + sort.Strings(names) + + var msg string + + if len(names) == 1 { + msg = fmt.Sprintf("the required flag %s was not specified", names[0]) + } else { + msg = fmt.Sprintf("the required flags %s and %s were not specified", + strings.Join(names[:len(names)-1], ", "), names[len(names)-1]) + } + + p.err = newError(ErrRequired, msg) + return p.err +} + +func (p *parseState) estimateCommand() error { + commands := p.command.sortedVisibleCommands() + cmdnames := make([]string, len(commands)) + + for i, v := range commands { + cmdnames[i] = v.Name + } + + var msg string + var errtype ErrorType + + if len(p.retargs) != 0 { + c, l := closestChoice(p.retargs[0], cmdnames) + msg = fmt.Sprintf("Unknown command `%s'", p.retargs[0]) + errtype = ErrUnknownCommand + + if float32(l)/float32(len(c)) < 0.5 { + msg = fmt.Sprintf("%s, did you mean `%s'?", msg, c) + } else if len(cmdnames) == 1 { + msg = fmt.Sprintf("%s. You should use the %s command", + msg, + cmdnames[0]) + } else { + msg = fmt.Sprintf("%s. Please specify one command of: %s or %s", + msg, + strings.Join(cmdnames[:len(cmdnames)-1], ", "), + cmdnames[len(cmdnames)-1]) + } + } else { + errtype = ErrCommandRequired + + if len(cmdnames) == 1 { + msg = fmt.Sprintf("Please specify the %s command", cmdnames[0]) + } else { + msg = fmt.Sprintf("Please specify one command of: %s or %s", + strings.Join(cmdnames[:len(cmdnames)-1], ", "), + cmdnames[len(cmdnames)-1]) + } + } + + return newError(errtype, msg) +} + +func (p *Parser) parseOption(s *parseState, name string, option *Option, canarg bool, argument *string) (err error) { + if !option.canArgument() { + if argument != nil { + return newErrorf(ErrNoArgumentForBool, "bool flag `%s' cannot have an argument", option) + } + + err = option.set(nil) + } else if argument != nil || (canarg && !s.eof()) { + var arg string + + if argument != nil { + arg = *argument + } else { + arg = s.pop() + + if argumentIsOption(arg) { + return newErrorf(ErrExpectedArgument, "expected argument for flag `%s', but got option `%s'", option, arg) + } else if p.Options&PassDoubleDash != 0 && arg == "--" { + return newErrorf(ErrExpectedArgument, "expected argument for flag `%s', but got double dash `--'", option) + } + } + + if option.tag.Get("unquote") != "false" { + arg, err = unquoteIfPossible(arg) + } + + if err == nil { + err = option.set(&arg) + } + } else if option.OptionalArgument { + option.empty() + + for _, v := range option.OptionalValue { + err = option.set(&v) + + if err != nil { + break + } + } + } else { + err = newErrorf(ErrExpectedArgument, "expected argument for flag `%s'", option) + } + + if err != nil { + if _, ok := err.(*Error); !ok { + err = newErrorf(ErrMarshal, "invalid argument for flag `%s' (expected %s): %s", + option, + option.value.Type(), + err.Error()) + } + } + + return err +} + +func (p *Parser) parseLong(s *parseState, name string, argument *string) error { + if option := s.lookup.longNames[name]; option != nil { + // Only long options that are required can consume an argument + // from the argument list + canarg := !option.OptionalArgument + + return p.parseOption(s, name, option, canarg, argument) + } + + return newErrorf(ErrUnknownFlag, "unknown flag `%s'", name) +} + +func (p *Parser) splitShortConcatArg(s *parseState, optname string) (string, *string) { + c, n := utf8.DecodeRuneInString(optname) + + if n == len(optname) { + return optname, nil + } + + first := string(c) + + if option := s.lookup.shortNames[first]; option != nil && option.canArgument() { + arg := optname[n:] + return first, &arg + } + + return optname, nil +} + +func (p *Parser) parseShort(s *parseState, optname string, argument *string) error { + if argument == nil { + optname, argument = p.splitShortConcatArg(s, optname) + } + + for i, c := range optname { + shortname := string(c) + + if option := s.lookup.shortNames[shortname]; option != nil { + // Only the last short argument can consume an argument from + // the arguments list, and only if it's non optional + canarg := (i+utf8.RuneLen(c) == len(optname)) && !option.OptionalArgument + + if err := p.parseOption(s, shortname, option, canarg, argument); err != nil { + return err + } + } else { + return newErrorf(ErrUnknownFlag, "unknown flag `%s'", shortname) + } + + // Only the first option can have a concatted argument, so just + // clear argument here + argument = nil + } + + return nil +} + +func (p *parseState) addArgs(args ...string) error { + for len(p.positional) > 0 && len(args) > 0 { + arg := p.positional[0] + + if err := convert(args[0], arg.value, arg.tag); err != nil { + return err + } + + if !arg.isRemaining() { + p.positional = p.positional[1:] + } + + args = args[1:] + } + + p.retargs = append(p.retargs, args...) + return nil +} + +func (p *Parser) parseNonOption(s *parseState) error { + if len(s.positional) > 0 { + return s.addArgs(s.arg) + } + + if cmd := s.lookup.commands[s.arg]; cmd != nil { + s.command.Active = cmd + cmd.fillParseState(s) + } else if (p.Options & PassAfterNonOption) != None { + // If PassAfterNonOption is set then all remaining arguments + // are considered positional + if err := s.addArgs(s.arg); err != nil { + return err + } + + if err := s.addArgs(s.args...); err != nil { + return err + } + + s.args = []string{} + } else { + return s.addArgs(s.arg) + } + + return nil +} + +func (p *Parser) showBuiltinHelp() error { + var b bytes.Buffer + + p.WriteHelp(&b) + return newError(ErrHelp, b.String()) +} + +func (p *Parser) printError(err error) error { + if err != nil && (p.Options&PrintErrors) != None { + fmt.Fprintln(os.Stderr, err) + } + + return err +} + +func (p *Parser) clearIsSet() { + p.eachCommand(func(c *Command) { + c.eachGroup(func(g *Group) { + for _, option := range g.options { + option.isSet = false + } + }) + }, true) +} diff --git a/vendor/github.com/jessevdk/go-flags/parser_test.go b/vendor/github.com/jessevdk/go-flags/parser_test.go new file mode 100644 index 0000000..32afc69 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/parser_test.go @@ -0,0 +1,500 @@ +package flags + +import ( + "fmt" + "os" + "reflect" + "runtime" + "strconv" + "strings" + "testing" + "time" +) + +type defaultOptions struct { + Int int `long:"i"` + IntDefault int `long:"id" default:"1"` + + Float64 float64 `long:"f"` + Float64Default float64 `long:"fd" default:"-3.14"` + + NumericFlag bool `short:"3"` + + String string `long:"str"` + StringDefault string `long:"strd" default:"abc"` + StringNotUnquoted string `long:"strnot" unquote:"false"` + + Time time.Duration `long:"t"` + TimeDefault time.Duration `long:"td" default:"1m"` + + Map map[string]int `long:"m"` + MapDefault map[string]int `long:"md" default:"a:1"` + + Slice []int `long:"s"` + SliceDefault []int `long:"sd" default:"1" default:"2"` +} + +func TestDefaults(t *testing.T) { + var tests = []struct { + msg string + args []string + expected defaultOptions + }{ + { + msg: "no arguments, expecting default values", + args: []string{}, + expected: defaultOptions{ + Int: 0, + IntDefault: 1, + + Float64: 0.0, + Float64Default: -3.14, + + NumericFlag: false, + + String: "", + StringDefault: "abc", + + Time: 0, + TimeDefault: time.Minute, + + Map: map[string]int{}, + MapDefault: map[string]int{"a": 1}, + + Slice: []int{}, + SliceDefault: []int{1, 2}, + }, + }, + { + msg: "non-zero value arguments, expecting overwritten arguments", + args: []string{"--i=3", "--id=3", "--f=-2.71", "--fd=2.71", "-3", "--str=def", "--strd=def", "--t=3ms", "--td=3ms", "--m=c:3", "--md=c:3", "--s=3", "--sd=3"}, + expected: defaultOptions{ + Int: 3, + IntDefault: 3, + + Float64: -2.71, + Float64Default: 2.71, + + NumericFlag: true, + + String: "def", + StringDefault: "def", + + Time: 3 * time.Millisecond, + TimeDefault: 3 * time.Millisecond, + + Map: map[string]int{"c": 3}, + MapDefault: map[string]int{"c": 3}, + + Slice: []int{3}, + SliceDefault: []int{3}, + }, + }, + { + msg: "zero value arguments, expecting overwritten arguments", + args: []string{"--i=0", "--id=0", "--f=0", "--fd=0", "--str", "", "--strd=\"\"", "--t=0ms", "--td=0s", "--m=:0", "--md=:0", "--s=0", "--sd=0"}, + expected: defaultOptions{ + Int: 0, + IntDefault: 0, + + Float64: 0, + Float64Default: 0, + + String: "", + StringDefault: "", + + Time: 0, + TimeDefault: 0, + + Map: map[string]int{"": 0}, + MapDefault: map[string]int{"": 0}, + + Slice: []int{0}, + SliceDefault: []int{0}, + }, + }, + } + + for _, test := range tests { + var opts defaultOptions + + _, err := ParseArgs(&opts, test.args) + if err != nil { + t.Fatalf("%s:\nUnexpected error: %v", test.msg, err) + } + + if opts.Slice == nil { + opts.Slice = []int{} + } + + if !reflect.DeepEqual(opts, test.expected) { + t.Errorf("%s:\nUnexpected options with arguments %+v\nexpected\n%+v\nbut got\n%+v\n", test.msg, test.args, test.expected, opts) + } + } +} + +func TestNoDefaultsForBools(t *testing.T) { + var opts struct { + DefaultBool bool `short:"d" default:"true"` + } + + if runtime.GOOS == "windows" { + assertParseFail(t, ErrInvalidTag, "boolean flag `/d' may not have default values, they always default to `false' and can only be turned on", &opts) + } else { + assertParseFail(t, ErrInvalidTag, "boolean flag `-d' may not have default values, they always default to `false' and can only be turned on", &opts) + } +} + +func TestUnquoting(t *testing.T) { + var tests = []struct { + arg string + err error + value string + }{ + { + arg: "\"abc", + err: strconv.ErrSyntax, + value: "", + }, + { + arg: "\"\"abc\"", + err: strconv.ErrSyntax, + value: "", + }, + { + arg: "\"abc\"", + err: nil, + value: "abc", + }, + { + arg: "\"\\\"abc\\\"\"", + err: nil, + value: "\"abc\"", + }, + { + arg: "\"\\\"abc\"", + err: nil, + value: "\"abc", + }, + } + + for _, test := range tests { + var opts defaultOptions + + for _, delimiter := range []bool{false, true} { + p := NewParser(&opts, None) + + var err error + if delimiter { + _, err = p.ParseArgs([]string{"--str=" + test.arg, "--strnot=" + test.arg}) + } else { + _, err = p.ParseArgs([]string{"--str", test.arg, "--strnot", test.arg}) + } + + if test.err == nil { + if err != nil { + t.Fatalf("Expected no error but got: %v", err) + } + + if test.value != opts.String { + t.Fatalf("Expected String to be %q but got %q", test.value, opts.String) + } + if q := strconv.Quote(test.value); q != opts.StringNotUnquoted { + t.Fatalf("Expected StringDefault to be %q but got %q", q, opts.StringNotUnquoted) + } + } else { + if err == nil { + t.Fatalf("Expected error") + } else if e, ok := err.(*Error); ok { + if strings.HasPrefix(e.Message, test.err.Error()) { + t.Fatalf("Expected error message to end with %q but got %v", test.err.Error(), e.Message) + } + } + } + } + } +} + +// envRestorer keeps a copy of a set of env variables and can restore the env from them +type envRestorer struct { + env map[string]string +} + +func (r *envRestorer) Restore() { + os.Clearenv() + for k, v := range r.env { + os.Setenv(k, v) + } +} + +// EnvSnapshot returns a snapshot of the currently set env variables +func EnvSnapshot() *envRestorer { + r := envRestorer{make(map[string]string)} + for _, kv := range os.Environ() { + parts := strings.SplitN(kv, "=", 2) + if len(parts) != 2 { + panic("got a weird env variable: " + kv) + } + r.env[parts[0]] = parts[1] + } + return &r +} + +type envDefaultOptions struct { + Int int `long:"i" default:"1" env:"TEST_I"` + Time time.Duration `long:"t" default:"1m" env:"TEST_T"` + Map map[string]int `long:"m" default:"a:1" env:"TEST_M" env-delim:";"` + Slice []int `long:"s" default:"1" default:"2" env:"TEST_S" env-delim:","` +} + +func TestEnvDefaults(t *testing.T) { + var tests = []struct { + msg string + args []string + expected envDefaultOptions + env map[string]string + }{ + { + msg: "no arguments, no env, expecting default values", + args: []string{}, + expected: envDefaultOptions{ + Int: 1, + Time: time.Minute, + Map: map[string]int{"a": 1}, + Slice: []int{1, 2}, + }, + }, + { + msg: "no arguments, env defaults, expecting env default values", + args: []string{}, + expected: envDefaultOptions{ + Int: 2, + Time: 2 * time.Minute, + Map: map[string]int{"a": 2, "b": 3}, + Slice: []int{4, 5, 6}, + }, + env: map[string]string{ + "TEST_I": "2", + "TEST_T": "2m", + "TEST_M": "a:2;b:3", + "TEST_S": "4,5,6", + }, + }, + { + msg: "non-zero value arguments, expecting overwritten arguments", + args: []string{"--i=3", "--t=3ms", "--m=c:3", "--s=3"}, + expected: envDefaultOptions{ + Int: 3, + Time: 3 * time.Millisecond, + Map: map[string]int{"c": 3}, + Slice: []int{3}, + }, + env: map[string]string{ + "TEST_I": "2", + "TEST_T": "2m", + "TEST_M": "a:2;b:3", + "TEST_S": "4,5,6", + }, + }, + { + msg: "zero value arguments, expecting overwritten arguments", + args: []string{"--i=0", "--t=0ms", "--m=:0", "--s=0"}, + expected: envDefaultOptions{ + Int: 0, + Time: 0, + Map: map[string]int{"": 0}, + Slice: []int{0}, + }, + env: map[string]string{ + "TEST_I": "2", + "TEST_T": "2m", + "TEST_M": "a:2;b:3", + "TEST_S": "4,5,6", + }, + }, + } + + oldEnv := EnvSnapshot() + defer oldEnv.Restore() + + for _, test := range tests { + var opts envDefaultOptions + oldEnv.Restore() + for envKey, envValue := range test.env { + os.Setenv(envKey, envValue) + } + _, err := ParseArgs(&opts, test.args) + if err != nil { + t.Fatalf("%s:\nUnexpected error: %v", test.msg, err) + } + + if opts.Slice == nil { + opts.Slice = []int{} + } + + if !reflect.DeepEqual(opts, test.expected) { + t.Errorf("%s:\nUnexpected options with arguments %+v\nexpected\n%+v\nbut got\n%+v\n", test.msg, test.args, test.expected, opts) + } + } +} + +func TestOptionAsArgument(t *testing.T) { + var tests = []struct { + args []string + expectError bool + errType ErrorType + errMsg string + rest []string + }{ + { + // short option must not be accepted as argument + args: []string{"--string-slice", "foobar", "--string-slice", "-o"}, + expectError: true, + errType: ErrExpectedArgument, + errMsg: "expected argument for flag `" + defaultLongOptDelimiter + "string-slice', but got option `-o'", + }, + { + // long option must not be accepted as argument + args: []string{"--string-slice", "foobar", "--string-slice", "--other-option"}, + expectError: true, + errType: ErrExpectedArgument, + errMsg: "expected argument for flag `" + defaultLongOptDelimiter + "string-slice', but got option `--other-option'", + }, + { + // long option must not be accepted as argument + args: []string{"--string-slice", "--"}, + expectError: true, + errType: ErrExpectedArgument, + errMsg: "expected argument for flag `" + defaultLongOptDelimiter + "string-slice', but got double dash `--'", + }, + { + // quoted and appended option should be accepted as argument (even if it looks like an option) + args: []string{"--string-slice", "foobar", "--string-slice=\"--other-option\""}, + }, + { + // Accept any single character arguments including '-' + args: []string{"--string-slice", "-"}, + }, + { + // Do not accept arguments which start with '-' even if the next character is a digit + args: []string{"--string-slice", "-3.14"}, + expectError: true, + errType: ErrExpectedArgument, + errMsg: "expected argument for flag `" + defaultLongOptDelimiter + "string-slice', but got option `-3.14'", + }, + { + // Do not accept arguments which start with '-' if the next character is not a digit + args: []string{"--string-slice", "-character"}, + expectError: true, + errType: ErrExpectedArgument, + errMsg: "expected argument for flag `" + defaultLongOptDelimiter + "string-slice', but got option `-character'", + }, + { + args: []string{"-o", "-", "-"}, + rest: []string{"-", "-"}, + }, + } + var opts struct { + StringSlice []string `long:"string-slice"` + OtherOption bool `long:"other-option" short:"o"` + } + + for _, test := range tests { + if test.expectError { + assertParseFail(t, test.errType, test.errMsg, &opts, test.args...) + } else { + args := assertParseSuccess(t, &opts, test.args...) + + assertStringArray(t, args, test.rest) + } + } +} + +func TestUnknownFlagHandler(t *testing.T) { + + var opts struct { + Flag1 string `long:"flag1"` + Flag2 string `long:"flag2"` + } + + p := NewParser(&opts, None) + + var unknownFlag1 string + var unknownFlag2 bool + var unknownFlag3 string + + // Set up a callback to intercept unknown options during parsing + p.UnknownOptionHandler = func(option string, arg SplitArgument, args []string) ([]string, error) { + if option == "unknownFlag1" { + if argValue, ok := arg.Value(); ok { + unknownFlag1 = argValue + return args, nil + } + // consume a value from remaining args list + unknownFlag1 = args[0] + return args[1:], nil + } else if option == "unknownFlag2" { + // treat this one as a bool switch, don't consume any args + unknownFlag2 = true + return args, nil + } else if option == "unknownFlag3" { + if argValue, ok := arg.Value(); ok { + unknownFlag3 = argValue + return args, nil + } + // consume a value from remaining args list + unknownFlag3 = args[0] + return args[1:], nil + } + + return args, fmt.Errorf("Unknown flag: %v", option) + } + + // Parse args containing some unknown flags, verify that + // our callback can handle all of them + _, err := p.ParseArgs([]string{"--flag1=stuff", "--unknownFlag1", "blah", "--unknownFlag2", "--unknownFlag3=baz", "--flag2=foo"}) + + if err != nil { + assertErrorf(t, "Parser returned unexpected error %v", err) + } + + assertString(t, opts.Flag1, "stuff") + assertString(t, opts.Flag2, "foo") + assertString(t, unknownFlag1, "blah") + assertString(t, unknownFlag3, "baz") + + if !unknownFlag2 { + assertErrorf(t, "Flag should have been set by unknown handler, but had value: %v", unknownFlag2) + } + + // Parse args with unknown flags that callback doesn't handle, verify it returns error + _, err = p.ParseArgs([]string{"--flag1=stuff", "--unknownFlagX", "blah", "--flag2=foo"}) + + if err == nil { + assertErrorf(t, "Parser should have returned error, but returned nil") + } +} + +func TestChoices(t *testing.T) { + var opts struct { + Choice string `long:"choose" choice:"v1" choice:"v2"` + } + + assertParseFail(t, ErrInvalidChoice, "Invalid value `invalid' for option `"+defaultLongOptDelimiter+"choose'. Allowed values are: v1 or v2", &opts, "--choose", "invalid") + assertParseSuccess(t, &opts, "--choose", "v2") + assertString(t, opts.Choice, "v2") +} + +func TestEmbedded(t *testing.T) { + type embedded struct { + V bool `short:"v"` + } + var opts struct { + embedded + } + + assertParseSuccess(t, &opts, "-v") + if !opts.V { + t.Errorf("Expected V to be true") + } +} diff --git a/vendor/github.com/jessevdk/go-flags/pointer_test.go b/vendor/github.com/jessevdk/go-flags/pointer_test.go new file mode 100644 index 0000000..e17445f --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/pointer_test.go @@ -0,0 +1,81 @@ +package flags + +import ( + "testing" +) + +func TestPointerBool(t *testing.T) { + var opts = struct { + Value *bool `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-v") + + assertStringArray(t, ret, []string{}) + + if !*opts.Value { + t.Errorf("Expected Value to be true") + } +} + +func TestPointerString(t *testing.T) { + var opts = struct { + Value *string `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-v", "value") + + assertStringArray(t, ret, []string{}) + assertString(t, *opts.Value, "value") +} + +func TestPointerSlice(t *testing.T) { + var opts = struct { + Value *[]string `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-v", "value1", "-v", "value2") + + assertStringArray(t, ret, []string{}) + assertStringArray(t, *opts.Value, []string{"value1", "value2"}) +} + +func TestPointerMap(t *testing.T) { + var opts = struct { + Value *map[string]int `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-v", "k1:2", "-v", "k2:-5") + + assertStringArray(t, ret, []string{}) + + if v, ok := (*opts.Value)["k1"]; !ok { + t.Errorf("Expected key \"k1\" to exist") + } else if v != 2 { + t.Errorf("Expected \"k1\" to be 2, but got %#v", v) + } + + if v, ok := (*opts.Value)["k2"]; !ok { + t.Errorf("Expected key \"k2\" to exist") + } else if v != -5 { + t.Errorf("Expected \"k2\" to be -5, but got %#v", v) + } +} + +type PointerGroup struct { + Value bool `short:"v"` +} + +func TestPointerGroup(t *testing.T) { + var opts = struct { + Group *PointerGroup `group:"Group Options"` + }{} + + ret := assertParseSuccess(t, &opts, "-v") + + assertStringArray(t, ret, []string{}) + + if !opts.Group.Value { + t.Errorf("Expected Group.Value to be true") + } +} diff --git a/vendor/github.com/jessevdk/go-flags/short_test.go b/vendor/github.com/jessevdk/go-flags/short_test.go new file mode 100644 index 0000000..95712c1 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/short_test.go @@ -0,0 +1,194 @@ +package flags + +import ( + "fmt" + "testing" +) + +func TestShort(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-v") + + assertStringArray(t, ret, []string{}) + + if !opts.Value { + t.Errorf("Expected Value to be true") + } +} + +func TestShortTooLong(t *testing.T) { + var opts = struct { + Value bool `short:"vv"` + }{} + + assertParseFail(t, ErrShortNameTooLong, "short names can only be 1 character long, not `vv'", &opts) +} + +func TestShortRequired(t *testing.T) { + var opts = struct { + Value bool `short:"v" required:"true"` + }{} + + assertParseFail(t, ErrRequired, fmt.Sprintf("the required flag `%cv' was not specified", defaultShortOptDelimiter), &opts) +} + +func TestShortMultiConcat(t *testing.T) { + var opts = struct { + V bool `short:"v"` + O bool `short:"o"` + F bool `short:"f"` + }{} + + ret := assertParseSuccess(t, &opts, "-vo", "-f") + + assertStringArray(t, ret, []string{}) + + if !opts.V { + t.Errorf("Expected V to be true") + } + + if !opts.O { + t.Errorf("Expected O to be true") + } + + if !opts.F { + t.Errorf("Expected F to be true") + } +} + +func TestShortMultiRequiredConcat(t *testing.T) { + var opts = struct { + V bool `short:"v" required:"true"` + O bool `short:"o" required:"true"` + F bool `short:"f" required:"true"` + }{} + + ret := assertParseSuccess(t, &opts, "-vo", "-f") + + assertStringArray(t, ret, []string{}) + + if !opts.V { + t.Errorf("Expected V to be true") + } + + if !opts.O { + t.Errorf("Expected O to be true") + } + + if !opts.F { + t.Errorf("Expected F to be true") + } +} + +func TestShortMultiSlice(t *testing.T) { + var opts = struct { + Values []bool `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-v", "-v") + + assertStringArray(t, ret, []string{}) + assertBoolArray(t, opts.Values, []bool{true, true}) +} + +func TestShortMultiSliceConcat(t *testing.T) { + var opts = struct { + Values []bool `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-vvv") + + assertStringArray(t, ret, []string{}) + assertBoolArray(t, opts.Values, []bool{true, true, true}) +} + +func TestShortWithEqualArg(t *testing.T) { + var opts = struct { + Value string `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-v=value") + + assertStringArray(t, ret, []string{}) + assertString(t, opts.Value, "value") +} + +func TestShortWithArg(t *testing.T) { + var opts = struct { + Value string `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-vvalue") + + assertStringArray(t, ret, []string{}) + assertString(t, opts.Value, "value") +} + +func TestShortArg(t *testing.T) { + var opts = struct { + Value string `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-v", "value") + + assertStringArray(t, ret, []string{}) + assertString(t, opts.Value, "value") +} + +func TestShortMultiWithEqualArg(t *testing.T) { + var opts = struct { + F []bool `short:"f"` + Value string `short:"v"` + }{} + + assertParseFail(t, ErrExpectedArgument, fmt.Sprintf("expected argument for flag `%cv'", defaultShortOptDelimiter), &opts, "-ffv=value") +} + +func TestShortMultiArg(t *testing.T) { + var opts = struct { + F []bool `short:"f"` + Value string `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-ffv", "value") + + assertStringArray(t, ret, []string{}) + assertBoolArray(t, opts.F, []bool{true, true}) + assertString(t, opts.Value, "value") +} + +func TestShortMultiArgConcatFail(t *testing.T) { + var opts = struct { + F []bool `short:"f"` + Value string `short:"v"` + }{} + + assertParseFail(t, ErrExpectedArgument, fmt.Sprintf("expected argument for flag `%cv'", defaultShortOptDelimiter), &opts, "-ffvvalue") +} + +func TestShortMultiArgConcat(t *testing.T) { + var opts = struct { + F []bool `short:"f"` + Value string `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-vff") + + assertStringArray(t, ret, []string{}) + assertString(t, opts.Value, "ff") +} + +func TestShortOptional(t *testing.T) { + var opts = struct { + F []bool `short:"f"` + Value string `short:"v" optional:"yes" optional-value:"value"` + }{} + + ret := assertParseSuccess(t, &opts, "-fv", "f") + + assertStringArray(t, ret, []string{"f"}) + assertString(t, opts.Value, "value") +} diff --git a/vendor/github.com/jessevdk/go-flags/tag_test.go b/vendor/github.com/jessevdk/go-flags/tag_test.go new file mode 100644 index 0000000..9daa740 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/tag_test.go @@ -0,0 +1,38 @@ +package flags + +import ( + "testing" +) + +func TestTagMissingColon(t *testing.T) { + var opts = struct { + Value bool `short` + }{} + + assertParseFail(t, ErrTag, "expected `:' after key name, but got end of tag (in `short`)", &opts, "") +} + +func TestTagMissingValue(t *testing.T) { + var opts = struct { + Value bool `short:` + }{} + + assertParseFail(t, ErrTag, "expected `\"' to start tag value at end of tag (in `short:`)", &opts, "") +} + +func TestTagMissingQuote(t *testing.T) { + var opts = struct { + Value bool `short:"v` + }{} + + assertParseFail(t, ErrTag, "expected end of tag value `\"' at end of tag (in `short:\"v`)", &opts, "") +} + +func TestTagNewline(t *testing.T) { + var opts = struct { + Value bool `long:"verbose" description:"verbose +something"` + }{} + + assertParseFail(t, ErrTag, "unexpected newline in tag value `description' (in `long:\"verbose\" description:\"verbose\nsomething\"`)", &opts, "") +} diff --git a/vendor/github.com/jessevdk/go-flags/termsize.go b/vendor/github.com/jessevdk/go-flags/termsize.go new file mode 100644 index 0000000..df97e7e --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/termsize.go @@ -0,0 +1,28 @@ +// +build !windows,!plan9,!solaris + +package flags + +import ( + "syscall" + "unsafe" +) + +type winsize struct { + row, col uint16 + xpixel, ypixel uint16 +} + +func getTerminalColumns() int { + ws := winsize{} + + if tIOCGWINSZ != 0 { + syscall.Syscall(syscall.SYS_IOCTL, + uintptr(0), + uintptr(tIOCGWINSZ), + uintptr(unsafe.Pointer(&ws))) + + return int(ws.col) + } + + return 80 +} diff --git a/vendor/github.com/jessevdk/go-flags/termsize_linux.go b/vendor/github.com/jessevdk/go-flags/termsize_linux.go new file mode 100644 index 0000000..e3975e2 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/termsize_linux.go @@ -0,0 +1,7 @@ +// +build linux + +package flags + +const ( + tIOCGWINSZ = 0x5413 +) diff --git a/vendor/github.com/jessevdk/go-flags/termsize_nosysioctl.go b/vendor/github.com/jessevdk/go-flags/termsize_nosysioctl.go new file mode 100644 index 0000000..2a9bbe0 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/termsize_nosysioctl.go @@ -0,0 +1,7 @@ +// +build windows plan9 solaris + +package flags + +func getTerminalColumns() int { + return 80 +} diff --git a/vendor/github.com/jessevdk/go-flags/termsize_other.go b/vendor/github.com/jessevdk/go-flags/termsize_other.go new file mode 100644 index 0000000..3082151 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/termsize_other.go @@ -0,0 +1,7 @@ +// +build !darwin,!freebsd,!netbsd,!openbsd,!linux + +package flags + +const ( + tIOCGWINSZ = 0 +) diff --git a/vendor/github.com/jessevdk/go-flags/termsize_unix.go b/vendor/github.com/jessevdk/go-flags/termsize_unix.go new file mode 100644 index 0000000..fcc1186 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/termsize_unix.go @@ -0,0 +1,7 @@ +// +build darwin freebsd netbsd openbsd + +package flags + +const ( + tIOCGWINSZ = 0x40087468 +) diff --git a/vendor/github.com/jessevdk/go-flags/unknown_test.go b/vendor/github.com/jessevdk/go-flags/unknown_test.go new file mode 100644 index 0000000..858be45 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/unknown_test.go @@ -0,0 +1,66 @@ +package flags + +import ( + "testing" +) + +func TestUnknownFlags(t *testing.T) { + var opts = struct { + Verbose []bool `short:"v" long:"verbose" description:"Verbose output"` + }{} + + args := []string{ + "-f", + } + + p := NewParser(&opts, 0) + args, err := p.ParseArgs(args) + + if err == nil { + t.Fatal("Expected error for unknown argument") + } +} + +func TestIgnoreUnknownFlags(t *testing.T) { + var opts = struct { + Verbose []bool `short:"v" long:"verbose" description:"Verbose output"` + }{} + + args := []string{ + "hello", + "world", + "-v", + "--foo=bar", + "--verbose", + "-f", + } + + p := NewParser(&opts, IgnoreUnknown) + args, err := p.ParseArgs(args) + + if err != nil { + t.Fatal(err) + } + + exargs := []string{ + "hello", + "world", + "--foo=bar", + "-f", + } + + issame := (len(args) == len(exargs)) + + if issame { + for i := 0; i < len(args); i++ { + if args[i] != exargs[i] { + issame = false + break + } + } + } + + if !issame { + t.Fatalf("Expected %v but got %v", exargs, args) + } +} diff --git a/vendor/github.com/klauspost/compress/LICENSE b/vendor/github.com/klauspost/compress/LICENSE new file mode 100644 index 0000000..7448756 --- /dev/null +++ b/vendor/github.com/klauspost/compress/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/klauspost/compress/README.md b/vendor/github.com/klauspost/compress/README.md new file mode 100644 index 0000000..f142db7 --- /dev/null +++ b/vendor/github.com/klauspost/compress/README.md @@ -0,0 +1,330 @@ +# compress + +This package is based on an optimized Deflate function, which is used by gzip/zip/zlib packages. + +It offers slightly better compression at lower compression settings, and up to 3x faster encoding at highest compression level. + +* [High Throughput Benchmark](http://blog.klauspost.com/go-gzipdeflate-benchmarks/). +* [Small Payload/Webserver Benchmarks](http://blog.klauspost.com/gzip-performance-for-go-webservers/). +* [Linear Time Compression](http://blog.klauspost.com/constant-time-gzipzip-compression/). +* [Re-balancing Deflate Compression Levels](https://blog.klauspost.com/rebalancing-deflate-compression-levels/) + +[![Build Status](https://travis-ci.org/klauspost/compress.svg?branch=master)](https://travis-ci.org/klauspost/compress) + +# changelog +* Mar 24, 2016: Always attempt Huffman encoding on level 4-7. This improves base 64 encoded data compression. +* Mar 24, 2016: Small speedup for level 1-3. +* Feb 19, 2016: Faster bit writer, level -2 is 15% faster, level 1 is 4% faster. +* Feb 19, 2016: Handle small payloads faster in level 1-3. +* Feb 19, 2016: Added faster level 2 + 3 compression modes. +* Feb 19, 2016: [Rebalanced compression levels](https://blog.klauspost.com/rebalancing-deflate-compression-levels/), so there is a more even progresssion in terms of compression. New default level is 5. +* Feb 14, 2016: Snappy: Merge upstream changes. +* Feb 14, 2016: Snappy: Fix aggressive skipping. +* Feb 14, 2016: Snappy: Update benchmark. +* Feb 13, 2016: Deflate: Fixed assembler problem that could lead to sub-optimal compression. +* Feb 12, 2016: Snappy: Added AMD64 SSE 4.2 optimizations to matching, which makes easy to compress material run faster. Typical speedup is around 25%. +* Feb 9, 2016: Added Snappy package fork. This version is 5-7% faster, much more on hard to compress content. +* Jan 30, 2016: Optimize level 1 to 3 by not considering static dictionary or storing uncompressed. ~4-5% speedup. +* Jan 16, 2016: Optimization on deflate level 1,2,3 compression. +* Jan 8 2016: Merge [CL 18317](https://go-review.googlesource.com/#/c/18317): fix reading, writing of zip64 archives. +* Dec 8 2015: Make level 1 and -2 deterministic even if write size differs. +* Dec 8 2015: Split encoding functions, so hashing and matching can potentially be inlined. 1-3% faster on AMD64. 5% faster on other platforms. +* Dec 8 2015: Fixed rare [one byte out-of bounds read](https://github.com/klauspost/compress/issues/20). Please update! +* Nov 23 2015: Optimization on token writer. ~2-4% faster. Contributed by [@dsnet](https://github.com/dsnet). +* Nov 20 2015: Small optimization to bit writer on 64 bit systems. +* Nov 17 2015: Fixed out-of-bound errors if the underlying Writer returned an error. See [#15](https://github.com/klauspost/compress/issues/15). +* Nov 12 2015: Added [io.WriterTo](https://golang.org/pkg/io/#WriterTo) support to gzip/inflate. +* Nov 11 2015: Merged [CL 16669](https://go-review.googlesource.com/#/c/16669/4): archive/zip: enable overriding (de)compressors per file +* Oct 15 2015: Added skipping on uncompressible data. Random data speed up >5x. + +# usage + +The packages are drop-in replacements for standard libraries. Simply replace the import path to use them: + +| old import | new import | +|--------------------|-----------------------------------------| +| `compress/gzip` | `github.com/klauspost/compress/gzip` | +| `compress/zlib` | `github.com/klauspost/compress/zlib` | +| `archive/zip` | `github.com/klauspost/compress/zip` | +| `compress/deflate` | `github.com/klauspost/compress/deflate` | +| `github.com/golang/snappy` | `github.com/klauspost/compress/snappy` | + +You may also be interested in [pgzip](https://github.com/klauspost/pgzip), which is a drop in replacement for gzip, which support multithreaded compression on big files and the optimized [crc32](https://github.com/klauspost/crc32) package used by these packages. + +The packages contains the same as the standard library, so you can use the godoc for that: [gzip](http://golang.org/pkg/compress/gzip/), [zip](http://golang.org/pkg/archive/zip/), [zlib](http://golang.org/pkg/compress/zlib/), [flate](http://golang.org/pkg/compress/flate/), [snappy](http://golang.org/pkg/compress/snappy/). + +Currently there is only minor speedup on decompression (mostly CRC32 calculation). + +# deflate optimizations + +* Minimum matches are 4 bytes, this leads to fewer searches and better compression. +* Stronger hash (iSCSI CRC32) for matches on x64 with SSE 4.2 support. This leads to fewer hash collisions. +* Literal byte matching using SSE 4.2 for faster match comparisons. +* Bulk hashing on matches. +* Much faster dictionary indexing with `NewWriterDict()`/`Reset()`. +* Make Bit Coder faster by assuming we are on a 64 bit CPU. +* Level 1 compression replaced by converted "Snappy" algorithm. +* Uncompressible content is detected and skipped faster. +* A lot of branching eliminated by having two encoders for levels 2+3 and 4+. +* All heap memory allocations eliminated. + +``` +benchmark old ns/op new ns/op delta +BenchmarkEncodeDigitsSpeed1e4-4 554029 265175 -52.14% +BenchmarkEncodeDigitsSpeed1e5-4 3908558 2416595 -38.17% +BenchmarkEncodeDigitsSpeed1e6-4 37546692 24875330 -33.75% +BenchmarkEncodeDigitsDefault1e4-4 781510 486322 -37.77% +BenchmarkEncodeDigitsDefault1e5-4 15530248 6740175 -56.60% +BenchmarkEncodeDigitsDefault1e6-4 174915710 76498625 -56.27% +BenchmarkEncodeDigitsCompress1e4-4 769995 485652 -36.93% +BenchmarkEncodeDigitsCompress1e5-4 15450113 6929589 -55.15% +BenchmarkEncodeDigitsCompress1e6-4 175114660 73348495 -58.11% +BenchmarkEncodeTwainSpeed1e4-4 560122 275977 -50.73% +BenchmarkEncodeTwainSpeed1e5-4 3740978 2506095 -33.01% +BenchmarkEncodeTwainSpeed1e6-4 35542802 21904440 -38.37% +BenchmarkEncodeTwainDefault1e4-4 828534 549026 -33.74% +BenchmarkEncodeTwainDefault1e5-4 13667153 7528455 -44.92% +BenchmarkEncodeTwainDefault1e6-4 141191770 79952170 -43.37% +BenchmarkEncodeTwainCompress1e4-4 830050 545694 -34.26% +BenchmarkEncodeTwainCompress1e5-4 16620852 8460600 -49.10% +BenchmarkEncodeTwainCompress1e6-4 193326820 90808750 -53.03% + +benchmark old MB/s new MB/s speedup +BenchmarkEncodeDigitsSpeed1e4-4 18.05 37.71 2.09x +BenchmarkEncodeDigitsSpeed1e5-4 25.58 41.38 1.62x +BenchmarkEncodeDigitsSpeed1e6-4 26.63 40.20 1.51x +BenchmarkEncodeDigitsDefault1e4-4 12.80 20.56 1.61x +BenchmarkEncodeDigitsDefault1e5-4 6.44 14.84 2.30x +BenchmarkEncodeDigitsDefault1e6-4 5.72 13.07 2.28x +BenchmarkEncodeDigitsCompress1e4-4 12.99 20.59 1.59x +BenchmarkEncodeDigitsCompress1e5-4 6.47 14.43 2.23x +BenchmarkEncodeDigitsCompress1e6-4 5.71 13.63 2.39x +BenchmarkEncodeTwainSpeed1e4-4 17.85 36.23 2.03x +BenchmarkEncodeTwainSpeed1e5-4 26.73 39.90 1.49x +BenchmarkEncodeTwainSpeed1e6-4 28.14 45.65 1.62x +BenchmarkEncodeTwainDefault1e4-4 12.07 18.21 1.51x +BenchmarkEncodeTwainDefault1e5-4 7.32 13.28 1.81x +BenchmarkEncodeTwainDefault1e6-4 7.08 12.51 1.77x +BenchmarkEncodeTwainCompress1e4-4 12.05 18.33 1.52x +BenchmarkEncodeTwainCompress1e5-4 6.02 11.82 1.96x +BenchmarkEncodeTwainCompress1e6-4 5.17 11.01 2.13x +``` +* "Speed" is compression level 1 +* "Default" is compression level 6 +* "Compress" is compression level 9 +* Test files are [Digits](https://github.com/klauspost/compress/blob/master/testdata/e.txt) (no matches) and [Twain](https://github.com/klauspost/compress/blob/master/testdata/Mark.Twain-Tom.Sawyer.txt) (plain text) . + +As can be seen it shows a very good speedup all across the line. + +`Twain` is a much more realistic benchmark, and will be closer to JSON/HTML performance. Here speed is equivalent or faster, up to 2 times. + +**Without assembly**. This is what you can expect on systems that does not have amd64 and SSE 4: +``` +benchmark old ns/op new ns/op delta +BenchmarkEncodeDigitsSpeed1e4-4 554029 249558 -54.96% +BenchmarkEncodeDigitsSpeed1e5-4 3908558 2295216 -41.28% +BenchmarkEncodeDigitsSpeed1e6-4 37546692 22594905 -39.82% +BenchmarkEncodeDigitsDefault1e4-4 781510 579850 -25.80% +BenchmarkEncodeDigitsDefault1e5-4 15530248 10096561 -34.99% +BenchmarkEncodeDigitsDefault1e6-4 174915710 111470780 -36.27% +BenchmarkEncodeDigitsCompress1e4-4 769995 579708 -24.71% +BenchmarkEncodeDigitsCompress1e5-4 15450113 10266373 -33.55% +BenchmarkEncodeDigitsCompress1e6-4 175114660 110170120 -37.09% +BenchmarkEncodeTwainSpeed1e4-4 560122 260679 -53.46% +BenchmarkEncodeTwainSpeed1e5-4 3740978 2097372 -43.94% +BenchmarkEncodeTwainSpeed1e6-4 35542802 20353449 -42.74% +BenchmarkEncodeTwainDefault1e4-4 828534 646016 -22.03% +BenchmarkEncodeTwainDefault1e5-4 13667153 10056369 -26.42% +BenchmarkEncodeTwainDefault1e6-4 141191770 105268770 -25.44% +BenchmarkEncodeTwainCompress1e4-4 830050 642401 -22.61% +BenchmarkEncodeTwainCompress1e5-4 16620852 11157081 -32.87% +BenchmarkEncodeTwainCompress1e6-4 193326820 121780770 -37.01% + +benchmark old MB/s new MB/s speedup +BenchmarkEncodeDigitsSpeed1e4-4 18.05 40.07 2.22x +BenchmarkEncodeDigitsSpeed1e5-4 25.58 43.57 1.70x +BenchmarkEncodeDigitsSpeed1e6-4 26.63 44.26 1.66x +BenchmarkEncodeDigitsDefault1e4-4 12.80 17.25 1.35x +BenchmarkEncodeDigitsDefault1e5-4 6.44 9.90 1.54x +BenchmarkEncodeDigitsDefault1e6-4 5.72 8.97 1.57x +BenchmarkEncodeDigitsCompress1e4-4 12.99 17.25 1.33x +BenchmarkEncodeDigitsCompress1e5-4 6.47 9.74 1.51x +BenchmarkEncodeDigitsCompress1e6-4 5.71 9.08 1.59x +BenchmarkEncodeTwainSpeed1e4-4 17.85 38.36 2.15x +BenchmarkEncodeTwainSpeed1e5-4 26.73 47.68 1.78x +BenchmarkEncodeTwainSpeed1e6-4 28.14 49.13 1.75x +BenchmarkEncodeTwainDefault1e4-4 12.07 15.48 1.28x +BenchmarkEncodeTwainDefault1e5-4 7.32 9.94 1.36x +BenchmarkEncodeTwainDefault1e6-4 7.08 9.50 1.34x +BenchmarkEncodeTwainCompress1e4-4 12.05 15.57 1.29x +BenchmarkEncodeTwainCompress1e5-4 6.02 8.96 1.49x +BenchmarkEncodeTwainCompress1e6-4 5.17 8.21 1.59x +``` +So even without the assembly optimizations there is a general speedup across the board. + +## level 1-3 "snappy" compression + +Level 1 "Best Speed" is completely replaced by a converted version of the algorithm found in Snappy, modified to be fully +compatible with the deflate bitstream (and thus still compatible with all existing zlib/gzip libraries and tools). +This version is considerably faster than the "old" deflate at level 1. It does however come at a compression loss, usually in the order of 3-4% compared to the old level 1. However, the speed is usually 1.75 times that of the fastest deflate mode. + +In my previous experiments the most common case for "level 1" was that it provided no significant speedup, only lower compression compared to level 2 and sometimes even 3. However, the modified Snappy algorithm provides a very good sweet spot. Usually about 75% faster and with only little compression loss. Therefore I decided to *replace* level 1 with this mode entirely. + +Input is split into blocks of 64kb of, and they are encoded independently (no backreferences across blocks) for the best speed. Contrary to Snappy the output is entropy-encoded, so you will almost always see better compression than Snappy. But Snappy is still about twice as fast as Snappy in deflate mode. + +Level 2 and 3 have also been replaced. Level 2 is capable is matching between blocks and level 3 checks up to two hashes for matches before choosing the longest for encoding the match. + +## compression levels + +This table shows the compression at each level, and the percentage of the output size compared to output +at the similar level with the standard library. Compression data is `Twain`, see above. + +(Not up-to-date after rebalancing) + +| Level | Bytes | % size | +|-------|--------|--------| +| 1 | 194622 | 103.7% | +| 2 | 174684 | 96.85% | +| 3 | 170301 | 98.45% | +| 4 | 165253 | 97.69% | +| 5 | 161274 | 98.65% | +| 6 | 160464 | 99.71% | +| 7 | 160304 | 99.87% | +| 8 | 160279 | 99.99% | +| 9 | 160279 | 99.99% | + +To interpret and example, this version of deflate compresses input of 407287 bytes to 161274 bytes at level 5, which is 98.6% of the size of what the standard library produces; 161274 bytes. + +This means that from level 4 you can expect a compression level increase of a few percent. Level 1 is about 3% worse, as descibed above. + +# linear time compression + +This compression library adds a special compression level, named `ConstantCompression`, which allows near linear time compression. This is done by completely disabling matching of previous data, and only reduce the number of bits to represent each character. + +This means that often used characters, like 'e' and ' ' (space) in text use the fewest bits to represent, and rare characters like '¤' takes more bits to represent. For more information see [wikipedia](https://en.wikipedia.org/wiki/Huffman_coding) or this nice [video](https://youtu.be/ZdooBTdW5bM). + +Since this type of compression has much less variance, the compression speed is mostly unaffected by the input data, and is usually more than *180MB/s* for a single core. + +The downside is that the compression ratio is usually considerably worse than even the fastest conventional compression. The compression raio can never be better than 8:1 (12.5%). + +The linear time compression can be used as a "better than nothing" mode, where you cannot risk the encoder to slow down on some content. For comparison, the size of the "Twain" text is *233460 bytes* (+29% vs. level 1) and encode speed is 144MB/s (4.5x level 1). So in this case you trade a 30% size increase for a 4 times speedup. + +For more information see my blog post on [Fast Linear Time Compression](http://blog.klauspost.com/constant-time-gzipzip-compression/). + +# gzip/zip optimizations + * Uses the faster deflate + * Uses SSE 4.2 CRC32 calculations. + +Speed increase is up to 3x of the standard library, but usually around 2x. + +This is close to a real world benchmark as you will get. A 2.3MB JSON file. (NOTE: not up-to-date) + +``` +benchmark old ns/op new ns/op delta +BenchmarkGzipL1-4 95212470 59938275 -37.05% +BenchmarkGzipL2-4 102069730 76349195 -25.20% +BenchmarkGzipL3-4 115472770 82492215 -28.56% +BenchmarkGzipL4-4 153197780 107570890 -29.78% +BenchmarkGzipL5-4 203930260 134387930 -34.10% +BenchmarkGzipL6-4 233172100 145495400 -37.60% +BenchmarkGzipL7-4 297190260 197926950 -33.40% +BenchmarkGzipL8-4 512819750 376244733 -26.63% +BenchmarkGzipL9-4 563366800 403266833 -28.42% + +benchmark old MB/s new MB/s speedup +BenchmarkGzipL1-4 52.11 82.78 1.59x +BenchmarkGzipL2-4 48.61 64.99 1.34x +BenchmarkGzipL3-4 42.97 60.15 1.40x +BenchmarkGzipL4-4 32.39 46.13 1.42x +BenchmarkGzipL5-4 24.33 36.92 1.52x +BenchmarkGzipL6-4 21.28 34.10 1.60x +BenchmarkGzipL7-4 16.70 25.07 1.50x +BenchmarkGzipL8-4 9.68 13.19 1.36x +BenchmarkGzipL9-4 8.81 12.30 1.40x +``` + +Multithreaded compression using [pgzip](https://github.com/klauspost/pgzip) comparison, Quadcore, CPU = 8: + +(Not updated, old numbers) + +``` +benchmark old ns/op new ns/op delta +BenchmarkGzipL1 96155500 25981486 -72.98% +BenchmarkGzipL2 101905830 24601408 -75.86% +BenchmarkGzipL3 113506490 26321506 -76.81% +BenchmarkGzipL4 143708220 31761818 -77.90% +BenchmarkGzipL5 188210770 39602266 -78.96% +BenchmarkGzipL6 209812000 40402313 -80.74% +BenchmarkGzipL7 270015440 56103210 -79.22% +BenchmarkGzipL8 461359700 91255220 -80.22% +BenchmarkGzipL9 498361833 88755075 -82.19% + +benchmark old MB/s new MB/s speedup +BenchmarkGzipL1 51.60 190.97 3.70x +BenchmarkGzipL2 48.69 201.69 4.14x +BenchmarkGzipL3 43.71 188.51 4.31x +BenchmarkGzipL4 34.53 156.22 4.52x +BenchmarkGzipL5 26.36 125.29 4.75x +BenchmarkGzipL6 23.65 122.81 5.19x +BenchmarkGzipL7 18.38 88.44 4.81x +BenchmarkGzipL8 10.75 54.37 5.06x +BenchmarkGzipL9 9.96 55.90 5.61x +``` + +# snappy package + +### This is still in development, and should not be used for critical applications. + +The Snappy package contains some optimizations over the standard package. + +This speeds up mainly **hard** and **easy** to compress material. + +Here are the "standard" benchmarks, compared to current Snappy master (13 feb 2016). + +## Speed +``` +name old speed new speed delta +WordsDecode1e3-8 405MB/s ± 5% 444MB/s ± 1% +9.60% (p=0.045 n=3+3) +WordsEncode1e1-8 4.55MB/s ± 1% 98.93MB/s ± 2% +2075.95% (p=0.000 n=3+3) +WordsEncode1e2-8 36.4MB/s ± 0% 166.1MB/s ± 3% +356.03% (p=0.000 n=3+3) +WordsEncode1e3-8 129MB/s ± 0% 185MB/s ± 1% +43.82% (p=0.000 n=3+3) +WordsEncode1e5-8 125MB/s ± 1% 140MB/s ± 2% +11.77% (p=0.005 n=3+3) +WordsEncode1e6-8 121MB/s ± 3% 134MB/s ± 0% +11.15% (p=0.026 n=3+3) +RandomEncode-8 2.80GB/s ± 2% 2.68GB/s ± 1% -4.32% (p=0.019 n=3+3) +_UFlat3-8 746MB/s ± 2% 812MB/s ± 1% +8.90% (p=0.004 n=3+3) +_UFlat4-8 2.50GB/s ± 1% 3.06GB/s ± 1% +22.68% (p=0.000 n=3+3) +_ZFlat0-8 284MB/s ± 1% 362MB/s ± 1% +27.45% (p=0.000 n=3+3) +_ZFlat2-8 2.85GB/s ± 0% 3.71GB/s ± 1% +30.21% (p=0.000 n=3+3) +_ZFlat3-8 64.5MB/s ± 1% 216.9MB/s ± 2% +236.02% (p=0.000 n=3+3) +_ZFlat4-8 415MB/s ± 1% 2000MB/s ± 1% +382.43% (p=0.000 n=3+3) +_ZFlat5-8 282MB/s ± 1% 354MB/s ± 2% +25.67% (p=0.003 n=3+3) +_ZFlat6-8 124MB/s ± 1% 136MB/s ± 2% +9.84% (p=0.013 n=3+3) +_ZFlat7-8 116MB/s ± 2% 127MB/s ± 1% +10.12% (p=0.002 n=3+3) +_ZFlat8-8 128MB/s ± 1% 142MB/s ± 1% +11.38% (p=0.000 n=3+3) +_ZFlat9-8 111MB/s ± 2% 120MB/s ± 1% +8.45% (p=0.009 n=3+3) +_ZFlat10-8 318MB/s ± 1% 439MB/s ± 1% +38.16% (p=0.000 n=3+3) +_ZFlat11-8 183MB/s ± 0% 226MB/s ± 3% +23.53% (p=0.004 n=3+3) +``` +Only significant differences are included. + +## Size Comparison: +``` +name data insize outsize ref red. ref-red r-delta +Flat0: html 102400 23317 23330 77.23% 77.23% 0.01% +Flat1: urls 712086 337290 335282 52.63% 52.63% -0.28% +Flat2: jpg 123093 123035 123032 0.05% 0.05% -0.00% +Flat3: jpg_200 123093 123035 123032 0.05% 0.05% -0.00% +Flat4: pdf 102400 84897 83754 17.09% 17.09% -1.12% +Flat5: html4 409600 92689 92366 77.37% 77.37% -0.08% +Flat6: txt1 152089 89544 89495 41.12% 41.12% -0.03% +Flat7: txt2 129301 80531 80518 37.72% 37.72% -0.01% +Flat8: txt3 426754 238857 238849 44.03% 44.03% -0.00% +Flat9: txt4 481861 324755 325047 32.60% 32.60% 0.06% +Flat10: pb 118588 24723 23392 79.15% 79.15% -1.12% +Flat11: gaviota 184320 73963 73962 59.87% 59.87% -0.00% +``` +r-delta is difference in compression. Negative means this package performs worse. + +# license + +This code is licensed under the same conditions as the original Go code. See LICENSE file. diff --git a/vendor/github.com/klauspost/compress/flate/asm_test.go b/vendor/github.com/klauspost/compress/flate/asm_test.go new file mode 100644 index 0000000..4c4a1c3 --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/asm_test.go @@ -0,0 +1,193 @@ +// Copyright 2015, Klaus Post, see LICENSE for details. + +//+build amd64 + +package flate + +import ( + "math/rand" + "testing" +) + +func TestCRC(t *testing.T) { + if !useSSE42 { + t.Skip("Skipping CRC test, no SSE 4.2 available") + } + for _, x := range deflateTests { + y := x.out + if len(y) >= minMatchLength { + t.Logf("In: %v, Out:0x%08x", y[0:minMatchLength], crc32sse(y[0:minMatchLength])) + } + } +} + +func TestCRCBulk(t *testing.T) { + if !useSSE42 { + t.Skip("Skipping CRC test, no SSE 4.2 available") + } + for _, x := range deflateTests { + y := x.out + y = append(y, y...) + y = append(y, y...) + y = append(y, y...) + y = append(y, y...) + y = append(y, y...) + y = append(y, y...) + if !testing.Short() { + y = append(y, y...) + y = append(y, y...) + } + y = append(y, 1) + if len(y) >= minMatchLength { + for j := len(y) - 1; j >= 4; j-- { + + // Create copy, so we easier detect of-of-bound reads + test := make([]byte, j) + test2 := make([]byte, j) + copy(test, y[:j]) + copy(test2, y[:j]) + + // We allocate one more than we need to test for unintentional overwrites + dst := make([]hash, j-3+1) + ref := make([]hash, j-3+1) + for i := range dst { + dst[i] = hash(i + 100) + ref[i] = hash(i + 101) + } + // Last entry must NOT be overwritten. + dst[j-3] = 0x1234 + ref[j-3] = 0x1234 + + // Do two encodes we can compare + crc32sseAll(test, dst) + crc32sseAll(test2, ref) + + // Check all values + for i, got := range dst { + if i == j-3 { + if dst[i] != 0x1234 { + t.Fatalf("end of expected dst overwritten, was %08x", uint32(dst[i])) + } + continue + } + expect := crc32sse(y[i : i+4]) + if got != expect && got == hash(i)+100 { + t.Errorf("Len:%d Index:%d, expected 0x%08x but not modified", len(y), i, uint32(expect)) + } else if got != expect { + t.Errorf("Len:%d Index:%d, got 0x%08x expected:0x%08x", len(y), i, uint32(got), uint32(expect)) + } + expect = ref[i] + if got != expect { + t.Errorf("Len:%d Index:%d, got 0x%08x expected:0x%08x", len(y), i, got, expect) + } + } + } + } + } +} + +func TestMatchLen(t *testing.T) { + if !useSSE42 { + t.Skip("Skipping Matchlen test, no SSE 4.2 available") + } + // Maximum length tested + var maxLen = 512 + + // Skips per iteration + is, js, ks := 3, 2, 1 + if testing.Short() { + is, js, ks = 7, 5, 3 + } + + a := make([]byte, maxLen) + b := make([]byte, maxLen) + bb := make([]byte, maxLen) + rand.Seed(1) + for i := range a { + a[i] = byte(rand.Int63()) + b[i] = byte(rand.Int63()) + } + + // Test different lengths + for i := 0; i < maxLen; i += is { + // Test different dst offsets. + for j := 0; j < maxLen-1; j += js { + copy(bb, b) + // Test different src offsets + for k := i - 1; k >= 0; k -= ks { + copy(bb[j:], a[k:i]) + maxTest := maxLen - j + if maxTest > maxLen-k { + maxTest = maxLen - k + } + got := matchLenSSE4(a[k:], bb[j:], maxTest) + expect := matchLenReference(a[k:], bb[j:], maxTest) + if got > maxTest || got < 0 { + t.Fatalf("unexpected result %d (len:%d, src offset: %d, dst offset:%d)", got, maxTest, k, j) + } + if got != expect { + t.Fatalf("Mismatch, expected %d, got %d", expect, got) + } + } + } + } +} + +// matchLenReference is a reference matcher. +func matchLenReference(a, b []byte, max int) int { + for i := 0; i < max; i++ { + if a[i] != b[i] { + return i + } + } + return max +} + +func TestHistogram(t *testing.T) { + if !useSSE42 { + t.Skip("Skipping Matchlen test, no SSE 4.2 available") + } + // Maximum length tested + const maxLen = 65536 + var maxOff = 8 + + // Skips per iteration + is, js := 5, 3 + if testing.Short() { + is, js = 9, 1 + maxOff = 1 + } + + a := make([]byte, maxLen+maxOff) + rand.Seed(1) + for i := range a { + a[i] = byte(rand.Int63()) + } + + // Test different lengths + for i := 0; i <= maxLen; i += is { + // Test different offsets + for j := 0; j < maxOff; j += js { + var got [256]int32 + var reference [256]int32 + + histogram(a[j:i+j], got[:]) + histogramReference(a[j:i+j], reference[:]) + for k := range got { + if got[k] != reference[k] { + t.Fatalf("mismatch at len:%d, offset:%d, value %d: (got) %d != %d (expected)", i, j, k, got[k], reference[k]) + } + } + } + } +} + +// histogramReference is a reference +func histogramReference(b []byte, h []int32) { + if len(h) < 256 { + panic("Histogram too small") + } + for _, t := range b { + h[t]++ + } +} diff --git a/vendor/github.com/klauspost/compress/flate/copy.go b/vendor/github.com/klauspost/compress/flate/copy.go new file mode 100644 index 0000000..a3200a8 --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/copy.go @@ -0,0 +1,32 @@ +// Copyright 2012 The Go 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 flate + +// forwardCopy is like the built-in copy function except that it always goes +// forward from the start, even if the dst and src overlap. +// It is equivalent to: +// for i := 0; i < n; i++ { +// mem[dst+i] = mem[src+i] +// } +func forwardCopy(mem []byte, dst, src, n int) { + if dst <= src { + copy(mem[dst:dst+n], mem[src:src+n]) + return + } + for { + if dst >= src+n { + copy(mem[dst:dst+n], mem[src:src+n]) + return + } + // There is some forward overlap. The destination + // will be filled with a repeated pattern of mem[src:src+k]. + // We copy one instance of the pattern here, then repeat. + // Each time around this loop k will double. + k := dst - src + copy(mem[dst:dst+k], mem[src:src+k]) + n -= k + dst += k + } +} diff --git a/vendor/github.com/klauspost/compress/flate/copy_test.go b/vendor/github.com/klauspost/compress/flate/copy_test.go new file mode 100644 index 0000000..2011b15 --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/copy_test.go @@ -0,0 +1,54 @@ +// Copyright 2012 The Go 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 flate + +import ( + "testing" +) + +func TestForwardCopy(t *testing.T) { + testCases := []struct { + dst0, dst1 int + src0, src1 int + want string + }{ + {0, 9, 0, 9, "012345678"}, + {0, 5, 4, 9, "45678"}, + {4, 9, 0, 5, "01230"}, + {1, 6, 3, 8, "34567"}, + {3, 8, 1, 6, "12121"}, + {0, 9, 3, 6, "345"}, + {3, 6, 0, 9, "012"}, + {1, 6, 0, 9, "00000"}, + {0, 4, 7, 8, "7"}, + {0, 1, 6, 8, "6"}, + {4, 4, 6, 9, ""}, + {2, 8, 6, 6, ""}, + {0, 0, 0, 0, ""}, + } + for _, tc := range testCases { + b := []byte("0123456789") + n := tc.dst1 - tc.dst0 + if tc.src1-tc.src0 < n { + n = tc.src1 - tc.src0 + } + forwardCopy(b, tc.dst0, tc.src0, n) + got := string(b[tc.dst0 : tc.dst0+n]) + if got != tc.want { + t.Errorf("dst=b[%d:%d], src=b[%d:%d]: got %q, want %q", + tc.dst0, tc.dst1, tc.src0, tc.src1, got, tc.want) + } + // Check that the bytes outside of dst[:n] were not modified. + for i, x := range b { + if i >= tc.dst0 && i < tc.dst0+n { + continue + } + if int(x) != '0'+i { + t.Errorf("dst=b[%d:%d], src=b[%d:%d]: copy overrun at b[%d]: got '%c', want '%c'", + tc.dst0, tc.dst1, tc.src0, tc.src1, i, x, '0'+i) + } + } + } +} diff --git a/vendor/github.com/klauspost/compress/flate/crc32_amd64.go b/vendor/github.com/klauspost/compress/flate/crc32_amd64.go new file mode 100644 index 0000000..45d52f6 --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/crc32_amd64.go @@ -0,0 +1,39 @@ +//+build !noasm +//+build !appengine + +// Copyright 2015, Klaus Post, see LICENSE for details. + +package flate + +import ( + "github.com/klauspost/cpuid" +) + +// crc32sse returns a hash for the first 4 bytes of the slice +// len(a) must be >= 4. +//go:noescape +func crc32sse(a []byte) hash + +// crc32sseAll calculates hashes for each 4-byte set in a. +// dst must be east len(a) - 4 in size. +// The size is not checked by the assembly. +//go:noescape +func crc32sseAll(a []byte, dst []hash) + +// matchLenSSE4 returns the number of matching bytes in a and b +// up to length 'max'. Both slices must be at least 'max' +// bytes in size. +// It uses the PCMPESTRI SSE 4.2 instruction. +//go:noescape +func matchLenSSE4(a, b []byte, max int) int + +// histogram accumulates a histogram of b in h. +// h must be at least 256 entries in length, +// and must be cleared before calling this function. +//go:noescape +func histogram(b []byte, h []int32) + +// Detect SSE 4.2 feature. +func init() { + useSSE42 = cpuid.CPU.SSE42() +} diff --git a/vendor/github.com/klauspost/compress/flate/crc32_amd64.s b/vendor/github.com/klauspost/compress/flate/crc32_amd64.s new file mode 100644 index 0000000..bfa0fda --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/crc32_amd64.s @@ -0,0 +1,219 @@ +//+build !noasm +//+build !appengine + +// Copyright 2015, Klaus Post, see LICENSE for details. + +// func crc32sse(a []byte) hash +TEXT ·crc32sse(SB), 4, $0 + MOVQ a+0(FP), R10 + XORQ BX, BX + + // CRC32 dword (R10), EBX + BYTE $0xF2; BYTE $0x41; BYTE $0x0f + BYTE $0x38; BYTE $0xf1; BYTE $0x1a + + MOVL BX, ret+24(FP) + RET + +// func crc32sseAll(a []byte, dst []hash) +TEXT ·crc32sseAll(SB), 4, $0 + MOVQ a+0(FP), R8 // R8: src + MOVQ a_len+8(FP), R10 // input length + MOVQ dst+24(FP), R9 // R9: dst + SUBQ $4, R10 + JS end + JZ one_crc + MOVQ R10, R13 + SHRQ $2, R10 // len/4 + ANDQ $3, R13 // len&3 + XORQ BX, BX + ADDQ $1, R13 + TESTQ R10, R10 + JZ rem_loop + +crc_loop: + MOVQ (R8), R11 + XORQ BX, BX + XORQ DX, DX + XORQ DI, DI + MOVQ R11, R12 + SHRQ $8, R11 + MOVQ R12, AX + MOVQ R11, CX + SHRQ $16, R12 + SHRQ $16, R11 + MOVQ R12, SI + + // CRC32 EAX, EBX + BYTE $0xF2; BYTE $0x0f + BYTE $0x38; BYTE $0xf1; BYTE $0xd8 + + // CRC32 ECX, EDX + BYTE $0xF2; BYTE $0x0f + BYTE $0x38; BYTE $0xf1; BYTE $0xd1 + + // CRC32 ESI, EDI + BYTE $0xF2; BYTE $0x0f + BYTE $0x38; BYTE $0xf1; BYTE $0xfe + MOVL BX, (R9) + MOVL DX, 4(R9) + MOVL DI, 8(R9) + + XORQ BX, BX + MOVL R11, AX + + // CRC32 EAX, EBX + BYTE $0xF2; BYTE $0x0f + BYTE $0x38; BYTE $0xf1; BYTE $0xd8 + MOVL BX, 12(R9) + + ADDQ $16, R9 + ADDQ $4, R8 + XORQ BX, BX + SUBQ $1, R10 + JNZ crc_loop + +rem_loop: + MOVL (R8), AX + + // CRC32 EAX, EBX + BYTE $0xF2; BYTE $0x0f + BYTE $0x38; BYTE $0xf1; BYTE $0xd8 + + MOVL BX, (R9) + ADDQ $4, R9 + ADDQ $1, R8 + XORQ BX, BX + SUBQ $1, R13 + JNZ rem_loop + +end: + RET + +one_crc: + MOVQ $1, R13 + XORQ BX, BX + JMP rem_loop + +// func matchLenSSE4(a, b []byte, max int) int +TEXT ·matchLenSSE4(SB), 4, $0 + MOVQ a+0(FP), SI // RSI: &a + MOVQ b+24(FP), DI // RDI: &b + MOVQ max+48(FP), R10 // R10: max + XORQ R11, R11 // R11: match length + MOVQ R10, R12 // R12: Remainder + SHRQ $4, R10 // max / 16 + MOVQ $16, AX // Set length for PCMPESTRI + MOVQ $16, DX // Set length for PCMPESTRI + ANDQ $15, R12 // max & 15 + TESTQ R10, R10 + JZ matchlen_verysmall + +loopback_matchlen: + MOVOU (SI), X0 // a[x] + MOVOU (DI), X1 // b[x] + + // PCMPESTRI $0x18, X1, X0 + // 0x18 = _SIDD_UBYTE_OPS (0x0) | _SIDD_CMP_EQUAL_EACH (0x8) | _SIDD_NEGATIVE_POLARITY (0x10) + BYTE $0x66; BYTE $0x0f; BYTE $0x3a + BYTE $0x61; BYTE $0xc1; BYTE $0x18 + + JC match_ended + + ADDQ $16, SI + ADDQ $16, DI + ADDQ $16, R11 + + SUBQ $1, R10 + JNZ loopback_matchlen + + // Check the remainder using REP CMPSB +matchlen_verysmall: + TESTQ R12, R12 + JZ done_matchlen + MOVQ R12, CX + ADDQ R12, R11 + + // Compare CX bytes at [SI] [DI] + // Subtract one from CX for every match. + // Terminates when CX is zero (checked pre-compare) + CLD + REP; CMPSB + + // Check if last was a match. + JZ done_matchlen + + // Subtract remanding bytes. + SUBQ CX, R11 + SUBQ $1, R11 + MOVQ R11, ret+56(FP) + RET + +match_ended: + ADDQ CX, R11 + +done_matchlen: + MOVQ R11, ret+56(FP) + RET + +// func histogram(b []byte, h []int32) +TEXT ·histogram(SB), 4, $0 + MOVQ b+0(FP), SI // SI: &b + MOVQ b_len+8(FP), R9 // R9: len(b) + MOVQ h+24(FP), DI // DI: Histogram + MOVQ R9, R8 + SHRQ $3, R8 + JZ hist1 + XORQ R11, R11 + +loop_hist8: + MOVQ (SI), R10 + + MOVB R10, R11 + INCL (DI)(R11*4) + SHRQ $8, R10 + + MOVB R10, R11 + INCL (DI)(R11*4) + SHRQ $8, R10 + + MOVB R10, R11 + INCL (DI)(R11*4) + SHRQ $8, R10 + + MOVB R10, R11 + INCL (DI)(R11*4) + SHRQ $8, R10 + + MOVB R10, R11 + INCL (DI)(R11*4) + SHRQ $8, R10 + + MOVB R10, R11 + INCL (DI)(R11*4) + SHRQ $8, R10 + + MOVB R10, R11 + INCL (DI)(R11*4) + SHRQ $8, R10 + + INCL (DI)(R10*4) + + ADDQ $8, SI + DECQ R8 + JNZ loop_hist8 + +hist1: + ANDQ $7, R9 + JZ end_hist + XORQ R10, R10 + +loop_hist1: + MOVB (SI), R10 + INCL (DI)(R10*4) + INCQ SI + DECQ R9 + JNZ loop_hist1 + +end_hist: + RET diff --git a/vendor/github.com/klauspost/compress/flate/crc32_noasm.go b/vendor/github.com/klauspost/compress/flate/crc32_noasm.go new file mode 100644 index 0000000..1c6d23e --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/crc32_noasm.go @@ -0,0 +1,34 @@ +//+build !amd64 noasm appengine + +// Copyright 2015, Klaus Post, see LICENSE for details. + +package flate + +func init() { + useSSE42 = false +} + +// crc32sse should never be called. +func crc32sse(a []byte) hash { + panic("no assembler") +} + +// crc32sseAll should never be called. +func crc32sseAll(a []byte, dst []hash) { + panic("no assembler") +} + +// matchLenSSE4 should never be called. +func matchLenSSE4(a, b []byte, max int) int { + panic("no assembler") + return 0 +} + +// histogram accumulates a histogram of b in h. +// h must be at least 256 entries in length, +// and must be cleared before calling this function. +func histogram(b []byte, h []int32) { + for _, t := range b { + h[t]++ + } +} diff --git a/vendor/github.com/klauspost/compress/flate/deflate.go b/vendor/github.com/klauspost/compress/flate/deflate.go new file mode 100644 index 0000000..5b84d80 --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/deflate.go @@ -0,0 +1,1357 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Copyright (c) 2015 Klaus Post +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flate + +import ( + "fmt" + "io" + "math" +) + +const ( + NoCompression = 0 + BestSpeed = 1 + BestCompression = 9 + DefaultCompression = -1 + ConstantCompression = -2 // Does only Huffman encoding + logWindowSize = 15 + windowSize = 1 << logWindowSize + windowMask = windowSize - 1 + logMaxOffsetSize = 15 // Standard DEFLATE + minMatchLength = 4 // The smallest match that the compressor looks for + maxMatchLength = 258 // The longest match for the compressor + minOffsetSize = 1 // The shortest offset that makes any sense + + // The maximum number of tokens we put into a single flat block, just too + // stop things from getting too large. + maxFlateBlockTokens = 1 << 14 + maxStoreBlockSize = 65535 + hashBits = 17 // After 17 performance degrades + hashSize = 1 << hashBits + hashMask = (1 << hashBits) - 1 + hashShift = (hashBits + minMatchLength - 1) / minMatchLength + maxHashOffset = 1 << 24 + + skipNever = math.MaxInt32 +) + +var useSSE42 bool + +type compressionLevel struct { + good, lazy, nice, chain, fastSkipHashing, level int +} + +// Compression levels have been rebalanced from zlib deflate defaults +// to give a bigger spread in speed and compression. +// See https://blog.klauspost.com/rebalancing-deflate-compression-levels/ +var levels = []compressionLevel{ + {}, // 0 + // Level 1+2 uses snappy algorithm - values not used + {0, 0, 0, 0, 0, 1}, + {0, 0, 0, 0, 0, 2}, + // For levels 3-6 we don't bother trying with lazy matches. + // Lazy matching is at least 30% slower, with 1.5% increase. + {4, 0, 8, 4, 4, 3}, + {4, 0, 12, 6, 5, 4}, + {6, 0, 24, 16, 6, 5}, + {8, 0, 32, 32, 7, 6}, + // Levels 7-9 use increasingly more lazy matching + // and increasingly stringent conditions for "good enough". + {4, 8, 16, 16, skipNever, 7}, + {6, 16, 32, 64, skipNever, 8}, + {32, 258, 258, 4096, skipNever, 9}, +} + +type hashid uint32 + +type compressor struct { + compressionLevel + + w *huffmanBitWriter + bulkHasher func([]byte, []hash) + + // compression algorithm + fill func(*compressor, []byte) int // copy data to window + step func(*compressor) // process window + sync bool // requesting flush + + // Input hash chains + // hashHead[hashValue] contains the largest inputIndex with the specified hash value + // If hashHead[hashValue] is within the current window, then + // hashPrev[hashHead[hashValue] & windowMask] contains the previous index + // with the same hash value. + chainHead int + hashHead []hashid + hashPrev []hashid + hashOffset int + + // input window: unprocessed data is window[index:windowEnd] + index int + window []byte + windowEnd int + blockStart int // window index where current tokens start + byteAvailable bool // if true, still need to process window[index-1]. + + // queued output tokens + tokens tokens + + // deflate state + length int + offset int + hash hash + maxInsertIndex int + err error + ii uint16 // position of last match, intended to overflow to reset. + + snap snappyEnc + hashMatch [maxMatchLength + minMatchLength]hash +} + +type hash int32 + +func (d *compressor) fillDeflate(b []byte) int { + if d.index >= 2*windowSize-(minMatchLength+maxMatchLength) { + // shift the window by windowSize + copy(d.window, d.window[windowSize:2*windowSize]) + d.index -= windowSize + d.windowEnd -= windowSize + if d.blockStart >= windowSize { + d.blockStart -= windowSize + } else { + d.blockStart = math.MaxInt32 + } + d.hashOffset += windowSize + if d.hashOffset > maxHashOffset { + delta := d.hashOffset - 1 + d.hashOffset -= delta + d.chainHead -= delta + for i, v := range d.hashPrev { + if int(v) > delta { + d.hashPrev[i] = hashid(int(v) - delta) + } else { + d.hashPrev[i] = 0 + } + } + for i, v := range d.hashHead { + if int(v) > delta { + d.hashHead[i] = hashid(int(v) - delta) + } else { + d.hashHead[i] = 0 + } + } + } + } + n := copy(d.window[d.windowEnd:], b) + d.windowEnd += n + return n +} + +func (d *compressor) writeBlock(tok tokens, index int, eof bool) error { + if index > 0 || eof { + var window []byte + if d.blockStart <= index { + window = d.window[d.blockStart:index] + } + d.blockStart = index + d.w.writeBlock(tok, eof, window) + return d.w.err + } + return nil +} + +// writeBlockSkip writes the current block and uses the number of tokens +// to determine if the block should be stored on no matches, or +// only huffman encoded. +func (d *compressor) writeBlockSkip(tok tokens, index int, eof bool) error { + if index > 0 || eof { + if d.blockStart <= index { + window := d.window[d.blockStart:index] + // If we removed less than a 64th of all literals + // we huffman compress the block. + if tok.n > len(window)-(tok.n>>6) { + d.w.writeBlockHuff(eof, window) + } else { + // Write a dynamic huffman block. + d.w.writeBlockDynamic(tok, eof, window) + } + } else { + d.w.writeBlock(tok, eof, nil) + } + d.blockStart = index + return d.w.err + } + return nil +} + +// fillWindow will fill the current window with the supplied +// dictionary and calculate all hashes. +// This is much faster than doing a full encode. +// Should only be used after a start/reset. +func (d *compressor) fillWindow(b []byte) { + // Do not fill window if we are in store-only mode, + // use constant or Snappy compression. + switch d.compressionLevel.level { + case 0, 1, 2: + return + } + // If we are given too much, cut it. + if len(b) > windowSize { + b = b[len(b)-windowSize:] + } + // Add all to window. + n := copy(d.window[d.windowEnd:], b) + + // Calculate 256 hashes at the time (more L1 cache hits) + loops := (n + 256 - minMatchLength) / 256 + for j := 0; j < loops; j++ { + startindex := j * 256 + end := startindex + 256 + minMatchLength - 1 + if end > n { + end = n + } + tocheck := d.window[startindex:end] + dstSize := len(tocheck) - minMatchLength + 1 + + if dstSize <= 0 { + continue + } + + dst := d.hashMatch[:dstSize] + d.bulkHasher(tocheck, dst) + var newH hash + for i, val := range dst { + di := i + startindex + newH = val & hashMask + // Get previous value with the same hash. + // Our chain should point to the previous value. + d.hashPrev[di&windowMask] = d.hashHead[newH] + // Set the head of the hash chain to us. + d.hashHead[newH] = hashid(di + d.hashOffset) + } + d.hash = newH + } + // Update window information. + d.windowEnd += n + d.index = n +} + +// Try to find a match starting at index whose length is greater than prevSize. +// We only look at chainCount possibilities before giving up. +// pos = d.index, prevHead = d.chainHead-d.hashOffset, prevLength=minMatchLength-1, lookahead +func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead int) (length, offset int, ok bool) { + minMatchLook := maxMatchLength + if lookahead < minMatchLook { + minMatchLook = lookahead + } + + win := d.window[0 : pos+minMatchLook] + + // We quit when we get a match that's at least nice long + nice := len(win) - pos + if d.nice < nice { + nice = d.nice + } + + // If we've got a match that's good enough, only look in 1/4 the chain. + tries := d.chain + length = prevLength + if length >= d.good { + tries >>= 2 + } + + wEnd := win[pos+length] + wPos := win[pos:] + minIndex := pos - windowSize + + for i := prevHead; tries > 0; tries-- { + if wEnd == win[i+length] { + n := matchLen(win[i:], wPos, minMatchLook) + + if n > length && (n > minMatchLength || pos-i <= 4096) { + length = n + offset = pos - i + ok = true + if n >= nice { + // The match is good enough that we don't try to find a better one. + break + } + wEnd = win[pos+n] + } + } + if i == minIndex { + // hashPrev[i & windowMask] has already been overwritten, so stop now. + break + } + i = int(d.hashPrev[i&windowMask]) - d.hashOffset + if i < minIndex || i < 0 { + break + } + } + return +} + +// Try to find a match starting at index whose length is greater than prevSize. +// We only look at chainCount possibilities before giving up. +// pos = d.index, prevHead = d.chainHead-d.hashOffset, prevLength=minMatchLength-1, lookahead +func (d *compressor) findMatchSSE(pos int, prevHead int, prevLength int, lookahead int) (length, offset int, ok bool) { + minMatchLook := maxMatchLength + if lookahead < minMatchLook { + minMatchLook = lookahead + } + + win := d.window[0 : pos+minMatchLook] + + // We quit when we get a match that's at least nice long + nice := len(win) - pos + if d.nice < nice { + nice = d.nice + } + + // If we've got a match that's good enough, only look in 1/4 the chain. + tries := d.chain + length = prevLength + if length >= d.good { + tries >>= 2 + } + + wEnd := win[pos+length] + wPos := win[pos:] + minIndex := pos - windowSize + + for i := prevHead; tries > 0; tries-- { + if wEnd == win[i+length] { + n := matchLenSSE4(win[i:], wPos, minMatchLook) + + if n > length && (n > minMatchLength || pos-i <= 4096) { + length = n + offset = pos - i + ok = true + if n >= nice { + // The match is good enough that we don't try to find a better one. + break + } + wEnd = win[pos+n] + } + } + if i == minIndex { + // hashPrev[i & windowMask] has already been overwritten, so stop now. + break + } + i = int(d.hashPrev[i&windowMask]) - d.hashOffset + if i < minIndex || i < 0 { + break + } + } + return +} + +func (d *compressor) writeStoredBlock(buf []byte) error { + if d.w.writeStoredHeader(len(buf), false); d.w.err != nil { + return d.w.err + } + d.w.writeBytes(buf) + return d.w.err +} + +// oldHash is the hash function used when no native crc32 calculation +// or similar is present. +func oldHash(b []byte) hash { + return hash(b[0])<<(hashShift*3) + hash(b[1])<<(hashShift*2) + hash(b[2])< d.windowEnd { + panic("index > windowEnd") + } + lookahead := d.windowEnd - d.index + if lookahead < minMatchLength+maxMatchLength { + if !d.sync { + return + } + if sanity && d.index > d.windowEnd { + panic("index > windowEnd") + } + if lookahead == 0 { + if d.tokens.n > 0 { + if d.err = d.writeBlockSkip(d.tokens, d.index, false); d.err != nil { + return + } + d.tokens.n = 0 + } + return + } + } + if d.index < d.maxInsertIndex { + // Update the hash + d.hash = oldHash(d.window[d.index:d.index+minMatchLength]) & hashMask + ch := d.hashHead[d.hash] + d.chainHead = int(ch) + d.hashPrev[d.index&windowMask] = ch + d.hashHead[d.hash] = hashid(d.index + d.hashOffset) + } + d.length = minMatchLength - 1 + d.offset = 0 + minIndex := d.index - windowSize + if minIndex < 0 { + minIndex = 0 + } + + if d.chainHead-d.hashOffset >= minIndex && lookahead > minMatchLength-1 { + if newLength, newOffset, ok := d.findMatch(d.index, d.chainHead-d.hashOffset, minMatchLength-1, lookahead); ok { + d.length = newLength + d.offset = newOffset + } + } + if d.length >= minMatchLength { + d.ii = 0 + // There was a match at the previous step, and the current match is + // not better. Output the previous match. + // "d.length-3" should NOT be "d.length-minMatchLength", since the format always assume 3 + d.tokens.tokens[d.tokens.n] = matchToken(uint32(d.length-3), uint32(d.offset-minOffsetSize)) + d.tokens.n++ + // Insert in the hash table all strings up to the end of the match. + // index and index-1 are already inserted. If there is not enough + // lookahead, the last two strings are not inserted into the hash + // table. + if d.length <= d.fastSkipHashing { + var newIndex int + newIndex = d.index + d.length + // Calculate missing hashes + end := newIndex + if end > d.maxInsertIndex { + end = d.maxInsertIndex + } + end += minMatchLength - 1 + startindex := d.index + 1 + if startindex > d.maxInsertIndex { + startindex = d.maxInsertIndex + } + tocheck := d.window[startindex:end] + dstSize := len(tocheck) - minMatchLength + 1 + if dstSize > 0 { + dst := d.hashMatch[:dstSize] + oldBulkHash(tocheck, dst) + var newH hash + for i, val := range dst { + di := i + startindex + newH = val & hashMask + // Get previous value with the same hash. + // Our chain should point to the previous value. + d.hashPrev[di&windowMask] = d.hashHead[newH] + // Set the head of the hash chain to us. + d.hashHead[newH] = hashid(di + d.hashOffset) + } + d.hash = newH + } + d.index = newIndex + } else { + // For matches this long, we don't bother inserting each individual + // item into the table. + d.index += d.length + if d.index < d.maxInsertIndex { + d.hash = oldHash(d.window[d.index:d.index+minMatchLength]) & hashMask + } + } + if d.tokens.n == maxFlateBlockTokens { + // The block includes the current character + if d.err = d.writeBlockSkip(d.tokens, d.index, false); d.err != nil { + return + } + d.tokens.n = 0 + } + } else { + d.ii++ + end := d.index + int(d.ii>>uint(d.fastSkipHashing)) + 1 + if end > d.windowEnd { + end = d.windowEnd + } + for i := d.index; i < end; i++ { + d.tokens.tokens[d.tokens.n] = literalToken(uint32(d.window[i])) + d.tokens.n++ + if d.tokens.n == maxFlateBlockTokens { + if d.err = d.writeBlockSkip(d.tokens, i+1, false); d.err != nil { + return + } + d.tokens.n = 0 + } + } + d.index = end + } + } +} + +// deflateLazy is the same as deflate, but with d.fastSkipHashing == skipNever, +// meaning it always has lazy matching on. +func (d *compressor) deflateLazy() { + // Sanity enables additional runtime tests. + // It's intended to be used during development + // to supplement the currently ad-hoc unit tests. + const sanity = false + + if d.windowEnd-d.index < minMatchLength+maxMatchLength && !d.sync { + return + } + + d.maxInsertIndex = d.windowEnd - (minMatchLength - 1) + if d.index < d.maxInsertIndex { + d.hash = oldHash(d.window[d.index:d.index+minMatchLength]) & hashMask + } + + for { + if sanity && d.index > d.windowEnd { + panic("index > windowEnd") + } + lookahead := d.windowEnd - d.index + if lookahead < minMatchLength+maxMatchLength { + if !d.sync { + return + } + if sanity && d.index > d.windowEnd { + panic("index > windowEnd") + } + if lookahead == 0 { + // Flush current output block if any. + if d.byteAvailable { + // There is still one pending token that needs to be flushed + d.tokens.tokens[d.tokens.n] = literalToken(uint32(d.window[d.index-1])) + d.tokens.n++ + d.byteAvailable = false + } + if d.tokens.n > 0 { + if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil { + return + } + d.tokens.n = 0 + } + return + } + } + if d.index < d.maxInsertIndex { + // Update the hash + d.hash = oldHash(d.window[d.index:d.index+minMatchLength]) & hashMask + ch := d.hashHead[d.hash] + d.chainHead = int(ch) + d.hashPrev[d.index&windowMask] = ch + d.hashHead[d.hash] = hashid(d.index + d.hashOffset) + } + prevLength := d.length + prevOffset := d.offset + d.length = minMatchLength - 1 + d.offset = 0 + minIndex := d.index - windowSize + if minIndex < 0 { + minIndex = 0 + } + + if d.chainHead-d.hashOffset >= minIndex && lookahead > prevLength && prevLength < d.lazy { + if newLength, newOffset, ok := d.findMatch(d.index, d.chainHead-d.hashOffset, minMatchLength-1, lookahead); ok { + d.length = newLength + d.offset = newOffset + } + } + if prevLength >= minMatchLength && d.length <= prevLength { + // There was a match at the previous step, and the current match is + // not better. Output the previous match. + d.tokens.tokens[d.tokens.n] = matchToken(uint32(prevLength-3), uint32(prevOffset-minOffsetSize)) + d.tokens.n++ + + // Insert in the hash table all strings up to the end of the match. + // index and index-1 are already inserted. If there is not enough + // lookahead, the last two strings are not inserted into the hash + // table. + var newIndex int + newIndex = d.index + prevLength - 1 + // Calculate missing hashes + end := newIndex + if end > d.maxInsertIndex { + end = d.maxInsertIndex + } + end += minMatchLength - 1 + startindex := d.index + 1 + if startindex > d.maxInsertIndex { + startindex = d.maxInsertIndex + } + tocheck := d.window[startindex:end] + dstSize := len(tocheck) - minMatchLength + 1 + if dstSize > 0 { + dst := d.hashMatch[:dstSize] + oldBulkHash(tocheck, dst) + var newH hash + for i, val := range dst { + di := i + startindex + newH = val & hashMask + // Get previous value with the same hash. + // Our chain should point to the previous value. + d.hashPrev[di&windowMask] = d.hashHead[newH] + // Set the head of the hash chain to us. + d.hashHead[newH] = hashid(di + d.hashOffset) + } + d.hash = newH + } + + d.index = newIndex + d.byteAvailable = false + d.length = minMatchLength - 1 + if d.tokens.n == maxFlateBlockTokens { + // The block includes the current character + if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil { + return + } + d.tokens.n = 0 + } + } else { + // Reset, if we got a match this run. + if d.length >= minMatchLength { + d.ii = 0 + } + // We have a byte waiting. Emit it. + if d.byteAvailable { + d.ii++ + d.tokens.tokens[d.tokens.n] = literalToken(uint32(d.window[d.index-1])) + d.tokens.n++ + if d.tokens.n == maxFlateBlockTokens { + if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil { + return + } + d.tokens.n = 0 + } + d.index++ + + // If we have a long run of no matches, skip additional bytes + // Resets when d.ii overflows after 64KB. + if d.ii > 31 { + n := int(d.ii >> 6) + for j := 0; j < n; j++ { + if d.index >= d.windowEnd-1 { + break + } + + d.tokens.tokens[d.tokens.n] = literalToken(uint32(d.window[d.index-1])) + d.tokens.n++ + if d.tokens.n == maxFlateBlockTokens { + if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil { + return + } + d.tokens.n = 0 + } + d.index++ + } + // Flush last byte + d.tokens.tokens[d.tokens.n] = literalToken(uint32(d.window[d.index-1])) + d.tokens.n++ + d.byteAvailable = false + // d.length = minMatchLength - 1 // not needed, since d.ii is reset above, so it should never be > minMatchLength + if d.tokens.n == maxFlateBlockTokens { + if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil { + return + } + d.tokens.n = 0 + } + } + } else { + d.index++ + d.byteAvailable = true + } + } + } +} + +// Assumes that d.fastSkipHashing != skipNever, +// otherwise use deflateLazySSE +func (d *compressor) deflateSSE() { + + // Sanity enables additional runtime tests. + // It's intended to be used during development + // to supplement the currently ad-hoc unit tests. + const sanity = false + + if d.windowEnd-d.index < minMatchLength+maxMatchLength && !d.sync { + return + } + + d.maxInsertIndex = d.windowEnd - (minMatchLength - 1) + if d.index < d.maxInsertIndex { + d.hash = oldHash(d.window[d.index:d.index+minMatchLength]) & hashMask + } + + for { + if sanity && d.index > d.windowEnd { + panic("index > windowEnd") + } + lookahead := d.windowEnd - d.index + if lookahead < minMatchLength+maxMatchLength { + if !d.sync { + return + } + if sanity && d.index > d.windowEnd { + panic("index > windowEnd") + } + if lookahead == 0 { + if d.tokens.n > 0 { + if d.err = d.writeBlockSkip(d.tokens, d.index, false); d.err != nil { + return + } + d.tokens.n = 0 + } + return + } + } + if d.index < d.maxInsertIndex { + // Update the hash + d.hash = crc32sse(d.window[d.index:d.index+minMatchLength]) & hashMask + ch := d.hashHead[d.hash] + d.chainHead = int(ch) + d.hashPrev[d.index&windowMask] = ch + d.hashHead[d.hash] = hashid(d.index + d.hashOffset) + } + d.length = minMatchLength - 1 + d.offset = 0 + minIndex := d.index - windowSize + if minIndex < 0 { + minIndex = 0 + } + + if d.chainHead-d.hashOffset >= minIndex && lookahead > minMatchLength-1 { + if newLength, newOffset, ok := d.findMatchSSE(d.index, d.chainHead-d.hashOffset, minMatchLength-1, lookahead); ok { + d.length = newLength + d.offset = newOffset + } + } + if d.length >= minMatchLength { + d.ii = 0 + // There was a match at the previous step, and the current match is + // not better. Output the previous match. + // "d.length-3" should NOT be "d.length-minMatchLength", since the format always assume 3 + d.tokens.tokens[d.tokens.n] = matchToken(uint32(d.length-3), uint32(d.offset-minOffsetSize)) + d.tokens.n++ + // Insert in the hash table all strings up to the end of the match. + // index and index-1 are already inserted. If there is not enough + // lookahead, the last two strings are not inserted into the hash + // table. + if d.length <= d.fastSkipHashing { + var newIndex int + newIndex = d.index + d.length + // Calculate missing hashes + end := newIndex + if end > d.maxInsertIndex { + end = d.maxInsertIndex + } + end += minMatchLength - 1 + startindex := d.index + 1 + if startindex > d.maxInsertIndex { + startindex = d.maxInsertIndex + } + tocheck := d.window[startindex:end] + dstSize := len(tocheck) - minMatchLength + 1 + if dstSize > 0 { + dst := d.hashMatch[:dstSize] + + crc32sseAll(tocheck, dst) + var newH hash + for i, val := range dst { + di := i + startindex + newH = val & hashMask + // Get previous value with the same hash. + // Our chain should point to the previous value. + d.hashPrev[di&windowMask] = d.hashHead[newH] + // Set the head of the hash chain to us. + d.hashHead[newH] = hashid(di + d.hashOffset) + } + d.hash = newH + } + d.index = newIndex + } else { + // For matches this long, we don't bother inserting each individual + // item into the table. + d.index += d.length + if d.index < d.maxInsertIndex { + d.hash = crc32sse(d.window[d.index:d.index+minMatchLength]) & hashMask + } + } + if d.tokens.n == maxFlateBlockTokens { + // The block includes the current character + if d.err = d.writeBlockSkip(d.tokens, d.index, false); d.err != nil { + return + } + d.tokens.n = 0 + } + } else { + d.ii++ + end := d.index + int(d.ii>>uint(d.fastSkipHashing)) + 1 + if end > d.windowEnd { + end = d.windowEnd + } + for i := d.index; i < end; i++ { + d.tokens.tokens[d.tokens.n] = literalToken(uint32(d.window[i])) + d.tokens.n++ + if d.tokens.n == maxFlateBlockTokens { + if d.err = d.writeBlockSkip(d.tokens, i+1, false); d.err != nil { + return + } + d.tokens.n = 0 + } + } + d.index = end + } + } +} + +// deflateLazy is the same as deflate, but with d.fastSkipHashing == skipNever, +// meaning it always has lazy matching on. +func (d *compressor) deflateLazySSE() { + // Sanity enables additional runtime tests. + // It's intended to be used during development + // to supplement the currently ad-hoc unit tests. + const sanity = false + + if d.windowEnd-d.index < minMatchLength+maxMatchLength && !d.sync { + return + } + + d.maxInsertIndex = d.windowEnd - (minMatchLength - 1) + if d.index < d.maxInsertIndex { + d.hash = crc32sse(d.window[d.index:d.index+minMatchLength]) & hashMask + } + + for { + if sanity && d.index > d.windowEnd { + panic("index > windowEnd") + } + lookahead := d.windowEnd - d.index + if lookahead < minMatchLength+maxMatchLength { + if !d.sync { + return + } + if sanity && d.index > d.windowEnd { + panic("index > windowEnd") + } + if lookahead == 0 { + // Flush current output block if any. + if d.byteAvailable { + // There is still one pending token that needs to be flushed + d.tokens.tokens[d.tokens.n] = literalToken(uint32(d.window[d.index-1])) + d.tokens.n++ + d.byteAvailable = false + } + if d.tokens.n > 0 { + if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil { + return + } + d.tokens.n = 0 + } + return + } + } + if d.index < d.maxInsertIndex { + // Update the hash + d.hash = crc32sse(d.window[d.index:d.index+minMatchLength]) & hashMask + ch := d.hashHead[d.hash] + d.chainHead = int(ch) + d.hashPrev[d.index&windowMask] = ch + d.hashHead[d.hash] = hashid(d.index + d.hashOffset) + } + prevLength := d.length + prevOffset := d.offset + d.length = minMatchLength - 1 + d.offset = 0 + minIndex := d.index - windowSize + if minIndex < 0 { + minIndex = 0 + } + + if d.chainHead-d.hashOffset >= minIndex && lookahead > prevLength && prevLength < d.lazy { + if newLength, newOffset, ok := d.findMatchSSE(d.index, d.chainHead-d.hashOffset, minMatchLength-1, lookahead); ok { + d.length = newLength + d.offset = newOffset + } + } + if prevLength >= minMatchLength && d.length <= prevLength { + // There was a match at the previous step, and the current match is + // not better. Output the previous match. + d.tokens.tokens[d.tokens.n] = matchToken(uint32(prevLength-3), uint32(prevOffset-minOffsetSize)) + d.tokens.n++ + + // Insert in the hash table all strings up to the end of the match. + // index and index-1 are already inserted. If there is not enough + // lookahead, the last two strings are not inserted into the hash + // table. + var newIndex int + newIndex = d.index + prevLength - 1 + // Calculate missing hashes + end := newIndex + if end > d.maxInsertIndex { + end = d.maxInsertIndex + } + end += minMatchLength - 1 + startindex := d.index + 1 + if startindex > d.maxInsertIndex { + startindex = d.maxInsertIndex + } + tocheck := d.window[startindex:end] + dstSize := len(tocheck) - minMatchLength + 1 + if dstSize > 0 { + dst := d.hashMatch[:dstSize] + crc32sseAll(tocheck, dst) + var newH hash + for i, val := range dst { + di := i + startindex + newH = val & hashMask + // Get previous value with the same hash. + // Our chain should point to the previous value. + d.hashPrev[di&windowMask] = d.hashHead[newH] + // Set the head of the hash chain to us. + d.hashHead[newH] = hashid(di + d.hashOffset) + } + d.hash = newH + } + + d.index = newIndex + d.byteAvailable = false + d.length = minMatchLength - 1 + if d.tokens.n == maxFlateBlockTokens { + // The block includes the current character + if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil { + return + } + d.tokens.n = 0 + } + } else { + // Reset, if we got a match this run. + if d.length >= minMatchLength { + d.ii = 0 + } + // We have a byte waiting. Emit it. + if d.byteAvailable { + d.ii++ + d.tokens.tokens[d.tokens.n] = literalToken(uint32(d.window[d.index-1])) + d.tokens.n++ + if d.tokens.n == maxFlateBlockTokens { + if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil { + return + } + d.tokens.n = 0 + } + d.index++ + + // If we have a long run of no matches, skip additional bytes + // Resets when d.ii overflows after 64KB. + if d.ii > 31 { + n := int(d.ii >> 6) + for j := 0; j < n; j++ { + if d.index >= d.windowEnd-1 { + break + } + + d.tokens.tokens[d.tokens.n] = literalToken(uint32(d.window[d.index-1])) + d.tokens.n++ + if d.tokens.n == maxFlateBlockTokens { + if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil { + return + } + d.tokens.n = 0 + } + d.index++ + } + // Flush last byte + d.tokens.tokens[d.tokens.n] = literalToken(uint32(d.window[d.index-1])) + d.tokens.n++ + d.byteAvailable = false + // d.length = minMatchLength - 1 // not needed, since d.ii is reset above, so it should never be > minMatchLength + if d.tokens.n == maxFlateBlockTokens { + if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil { + return + } + d.tokens.n = 0 + } + } + } else { + d.index++ + d.byteAvailable = true + } + } + } +} + +func (d *compressor) fillStore(b []byte) int { + n := copy(d.window[d.windowEnd:], b) + d.windowEnd += n + return n +} + +func (d *compressor) store() { + if d.windowEnd > 0 { + d.err = d.writeStoredBlock(d.window[:d.windowEnd]) + } + d.windowEnd = 0 +} + +// fillHuff will fill the buffer with data for huffman-only compression. +// The number of bytes copied is returned. +func (d *compressor) fillHuff(b []byte) int { + n := copy(d.window[d.windowEnd:], b) + d.windowEnd += n + return n +} + +// storeHuff will compress and store the currently added data, +// if enough has been accumulated or we at the end of the stream. +// Any error that occurred will be in d.err +func (d *compressor) storeHuff() { + // We only compress if we have maxStoreBlockSize or we are at end-of-stream + if d.windowEnd < maxStoreBlockSize && !d.sync { + return + } + if d.windowEnd == 0 { + return + } + d.w.writeBlockHuff(false, d.window[:d.windowEnd]) + d.err = d.w.err + d.windowEnd = 0 +} + +// storeHuff will compress and store the currently added data, +// if enough has been accumulated or we at the end of the stream. +// Any error that occurred will be in d.err +func (d *compressor) storeSnappy() { + // We only compress if we have maxStoreBlockSize. + if d.windowEnd < maxStoreBlockSize { + if !d.sync { + return + } + // Handle extremely small sizes. + if d.windowEnd < 128 { + if d.windowEnd == 0 { + return + } + if d.windowEnd <= 32 { + d.err = d.writeStoredBlock(d.window[:d.windowEnd]) + d.tokens.n = 0 + d.windowEnd = 0 + } else { + d.w.writeBlockHuff(false, d.window[:d.windowEnd]) + d.err = d.w.err + } + d.tokens.n = 0 + d.windowEnd = 0 + return + } + } + + d.snap.Encode(&d.tokens, d.window[:d.windowEnd]) + // If we made zero matches, store the block as is. + if d.tokens.n == d.windowEnd { + d.err = d.writeStoredBlock(d.window[:d.windowEnd]) + // If we removed less than 1/16th, huffman compress the block. + } else if d.tokens.n > d.windowEnd-(d.windowEnd>>4) { + d.w.writeBlockHuff(false, d.window[:d.windowEnd]) + d.err = d.w.err + } else { + d.w.writeBlockDynamic(d.tokens, false, d.window[:d.windowEnd]) + d.err = d.w.err + } + d.tokens.n = 0 + d.windowEnd = 0 +} + +// write will add input byte to the stream. +// Unless an error occurs all bytes will be consumed. +func (d *compressor) write(b []byte) (n int, err error) { + if d.err != nil { + return 0, d.err + } + n = len(b) + for len(b) > 0 { + d.step(d) + b = b[d.fill(d, b):] + if d.err != nil { + return 0, d.err + } + } + return n, d.err +} + +func (d *compressor) syncFlush() error { + d.sync = true + if d.err != nil { + return d.err + } + d.step(d) + if d.err == nil { + d.w.writeStoredHeader(0, false) + d.w.flush() + d.err = d.w.err + } + d.sync = false + return d.err +} + +func (d *compressor) init(w io.Writer, level int) (err error) { + d.w = newHuffmanBitWriter(w) + + switch { + case level == NoCompression: + d.window = make([]byte, maxStoreBlockSize) + d.fill = (*compressor).fillStore + d.step = (*compressor).store + case level == ConstantCompression: + d.window = make([]byte, maxStoreBlockSize) + d.fill = (*compressor).fillHuff + d.step = (*compressor).storeHuff + case level >= 1 && level <= 3: + d.snap = newSnappy(level) + d.window = make([]byte, maxStoreBlockSize) + d.fill = (*compressor).fillHuff + d.step = (*compressor).storeSnappy + d.tokens.tokens = make([]token, maxStoreBlockSize+1) + case level == DefaultCompression: + level = 5 + fallthrough + case 4 <= level && level <= 9: + d.compressionLevel = levels[level] + d.initDeflate() + d.fill = (*compressor).fillDeflate + if d.fastSkipHashing == skipNever { + if useSSE42 { + d.step = (*compressor).deflateLazySSE + } else { + d.step = (*compressor).deflateLazy + } + } else { + if useSSE42 { + d.step = (*compressor).deflateSSE + } else { + d.step = (*compressor).deflate + + } + } + default: + return fmt.Errorf("flate: invalid compression level %d: want value in range [-2, 9]", level) + } + return nil +} + +// Used for zeroing the hash slice +var hzeroes [256]hashid + +// reset the state of the compressor. +func (d *compressor) reset(w io.Writer) { + d.w.reset(w) + d.sync = false + d.err = nil + // We only need to reset a few things for Snappy. + if d.snap != nil { + d.snap.Reset() + d.windowEnd = 0 + d.tokens.n = 0 + return + } + switch d.compressionLevel.chain { + case 0: + // level was NoCompression or ConstantCompresssion. + d.windowEnd = 0 + default: + d.chainHead = -1 + for s := d.hashHead; len(s) > 0; { + n := copy(s, hzeroes[:]) + s = s[n:] + } + for s := d.hashPrev; len(s) > 0; s = s[len(hzeroes):] { + copy(s, hzeroes[:]) + } + d.hashOffset = 1 + + d.index, d.windowEnd = 0, 0 + d.blockStart, d.byteAvailable = 0, false + + d.tokens.n = 0 + d.length = minMatchLength - 1 + d.offset = 0 + d.hash = 0 + d.ii = 0 + d.maxInsertIndex = 0 + } +} + +func (d *compressor) close() error { + if d.err != nil { + return d.err + } + d.sync = true + d.step(d) + if d.err != nil { + return d.err + } + if d.w.writeStoredHeader(0, true); d.w.err != nil { + return d.w.err + } + d.w.flush() + return d.w.err +} + +// NewWriter returns a new Writer compressing data at the given level. +// Following zlib, levels range from 1 (BestSpeed) to 9 (BestCompression); +// higher levels typically run slower but compress more. +// Level 0 (NoCompression) does not attempt any compression; it only adds the +// necessary DEFLATE framing. +// Level -1 (DefaultCompression) uses the default compression level. +// Level -2 (ConstantCompression) will use Huffman compression only, giving +// a very fast compression for all types of input, but sacrificing considerable +// compression efficiency. +// +// If level is in the range [-2, 9] then the error returned will be nil. +// Otherwise the error returned will be non-nil. +func NewWriter(w io.Writer, level int) (*Writer, error) { + var dw Writer + if err := dw.d.init(w, level); err != nil { + return nil, err + } + return &dw, nil +} + +// NewWriterDict is like NewWriter but initializes the new +// Writer with a preset dictionary. The returned Writer behaves +// as if the dictionary had been written to it without producing +// any compressed output. The compressed data written to w +// can only be decompressed by a Reader initialized with the +// same dictionary. +func NewWriterDict(w io.Writer, level int, dict []byte) (*Writer, error) { + dw := &dictWriter{w} + zw, err := NewWriter(dw, level) + if err != nil { + return nil, err + } + zw.d.fillWindow(dict) + zw.dict = append(zw.dict, dict...) // duplicate dictionary for Reset method. + return zw, err +} + +type dictWriter struct { + w io.Writer +} + +func (w *dictWriter) Write(b []byte) (n int, err error) { + return w.w.Write(b) +} + +// A Writer takes data written to it and writes the compressed +// form of that data to an underlying writer (see NewWriter). +type Writer struct { + d compressor + dict []byte +} + +// Write writes data to w, which will eventually write the +// compressed form of data to its underlying writer. +func (w *Writer) Write(data []byte) (n int, err error) { + return w.d.write(data) +} + +// Flush flushes any pending compressed data to the underlying writer. +// It is useful mainly in compressed network protocols, to ensure that +// a remote reader has enough data to reconstruct a packet. +// Flush does not return until the data has been written. +// If the underlying writer returns an error, Flush returns that error. +// +// In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH. +func (w *Writer) Flush() error { + // For more about flushing: + // http://www.bolet.org/~pornin/deflate-flush.html + return w.d.syncFlush() +} + +// Close flushes and closes the writer. +func (w *Writer) Close() error { + return w.d.close() +} + +// Reset discards the writer's state and makes it equivalent to +// the result of NewWriter or NewWriterDict called with dst +// and w's level and dictionary. +func (w *Writer) Reset(dst io.Writer) { + if dw, ok := w.d.w.w.(*dictWriter); ok { + // w was created with NewWriterDict + dw.w = dst + w.d.reset(dw) + w.d.fillWindow(w.dict) + } else { + // w was created with NewWriter + w.d.reset(dst) + } +} + +// ResetDict discards the writer's state and makes it equivalent to +// the result of NewWriter or NewWriterDict called with dst +// and w's level, but sets a specific dictionary. +func (w *Writer) ResetDict(dst io.Writer, dict []byte) { + w.dict = dict + w.d.reset(dst) + w.d.fillWindow(w.dict) +} diff --git a/vendor/github.com/klauspost/compress/flate/deflate_test.go b/vendor/github.com/klauspost/compress/flate/deflate_test.go new file mode 100644 index 0000000..4ba12b8 --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/deflate_test.go @@ -0,0 +1,632 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Copyright (c) 2015 Klaus Post +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flate + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "reflect" + "strings" + "sync" + "testing" +) + +type deflateTest struct { + in []byte + level int + out []byte +} + +type deflateInflateTest struct { + in []byte +} + +type reverseBitsTest struct { + in uint16 + bitCount uint8 + out uint16 +} + +var deflateTests = []*deflateTest{ + {[]byte{}, 0, []byte{1, 0, 0, 255, 255}}, + {[]byte{0x11}, BestCompression, []byte{18, 4, 4, 0, 0, 255, 255}}, + {[]byte{0x11}, BestCompression, []byte{18, 4, 4, 0, 0, 255, 255}}, + {[]byte{0x11}, BestCompression, []byte{18, 4, 4, 0, 0, 255, 255}}, + + {[]byte{0x11}, 0, []byte{0, 1, 0, 254, 255, 17, 1, 0, 0, 255, 255}}, + {[]byte{0x11, 0x12}, 0, []byte{0, 2, 0, 253, 255, 17, 18, 1, 0, 0, 255, 255}}, + {[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 0, + []byte{0, 8, 0, 247, 255, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0, 0, 255, 255}, + }, + {[]byte{}, 1, []byte{1, 0, 0, 255, 255}}, + {[]byte{0x11}, BestCompression, []byte{18, 4, 4, 0, 0, 255, 255}}, + {[]byte{0x11, 0x12}, BestCompression, []byte{18, 20, 2, 4, 0, 0, 255, 255}}, + {[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, BestCompression, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}}, + {[]byte{}, 9, []byte{1, 0, 0, 255, 255}}, + {[]byte{0x11}, 9, []byte{18, 4, 4, 0, 0, 255, 255}}, + {[]byte{0x11, 0x12}, 9, []byte{18, 20, 2, 4, 0, 0, 255, 255}}, + {[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 9, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}}, +} + +var deflateInflateTests = []*deflateInflateTest{ + {[]byte{}}, + {[]byte{0x11}}, + {[]byte{0x11, 0x12}}, + {[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}}, + {[]byte{0x11, 0x10, 0x13, 0x41, 0x21, 0x21, 0x41, 0x13, 0x87, 0x78, 0x13}}, + {largeDataChunk()}, +} + +var reverseBitsTests = []*reverseBitsTest{ + {1, 1, 1}, + {1, 2, 2}, + {1, 3, 4}, + {1, 4, 8}, + {1, 5, 16}, + {17, 5, 17}, + {257, 9, 257}, + {29, 5, 23}, +} + +func largeDataChunk() []byte { + result := make([]byte, 100000) + for i := range result { + result[i] = byte(i * i & 0xFF) + } + return result +} + +func TestCRCBulkOld(t *testing.T) { + for _, x := range deflateTests { + y := x.out + if len(y) >= minMatchLength { + y = append(y, y...) + for j := 4; j < len(y); j++ { + y := y[:j] + dst := make([]hash, len(y)-minMatchLength+1) + for i := range dst { + dst[i] = hash(i + 100) + } + oldBulkHash(y, dst) + for i, val := range dst { + got := val & hashMask + expect := oldHash(y[i:]) & hashMask + if got != expect && got == hash(i)+100 { + t.Errorf("Len:%d Index:%d, expected 0x%08x but not modified", len(y), i, expect) + } else if got != expect { + t.Errorf("Len:%d Index:%d, got 0x%08x expected:0x%08x", len(y), i, got, expect) + } else { + //t.Logf("Len:%d Index:%d OK (0x%08x)", len(y), i, got) + } + } + } + } + } +} + +func TestDeflate(t *testing.T) { + for _, h := range deflateTests { + var buf bytes.Buffer + w, err := NewWriter(&buf, h.level) + if err != nil { + t.Errorf("NewWriter: %v", err) + continue + } + w.Write(h.in) + w.Close() + if !bytes.Equal(buf.Bytes(), h.out) { + t.Errorf("Deflate(%d, %x) = \n%#v, want \n%#v", h.level, h.in, buf.Bytes(), h.out) + } + } +} + +// A sparseReader returns a stream consisting of 0s followed by 1<<16 1s. +// This tests missing hash references in a very large input. +type sparseReader struct { + l int64 + cur int64 +} + +func (r *sparseReader) Read(b []byte) (n int, err error) { + if r.cur >= r.l { + return 0, io.EOF + } + n = len(b) + cur := r.cur + int64(n) + if cur > r.l { + n -= int(cur - r.l) + cur = r.l + } + for i := range b[0:n] { + if r.cur+int64(i) >= r.l-1<<16 { + b[i] = 1 + } else { + b[i] = 0 + } + } + r.cur = cur + return +} + +func TestVeryLongSparseChunk(t *testing.T) { + if testing.Short() { + t.Skip("skipping sparse chunk during short test") + } + w, err := NewWriter(ioutil.Discard, 1) + if err != nil { + t.Errorf("NewWriter: %v", err) + return + } + if _, err = io.Copy(w, &sparseReader{l: 23E8}); err != nil { + t.Errorf("Compress failed: %v", err) + return + } +} + +type syncBuffer struct { + buf bytes.Buffer + mu sync.RWMutex + closed bool + ready chan bool +} + +func newSyncBuffer() *syncBuffer { + return &syncBuffer{ready: make(chan bool, 1)} +} + +func (b *syncBuffer) Read(p []byte) (n int, err error) { + for { + b.mu.RLock() + n, err = b.buf.Read(p) + b.mu.RUnlock() + if n > 0 || b.closed { + return + } + <-b.ready + } +} + +func (b *syncBuffer) signal() { + select { + case b.ready <- true: + default: + } +} + +func (b *syncBuffer) Write(p []byte) (n int, err error) { + n, err = b.buf.Write(p) + b.signal() + return +} + +func (b *syncBuffer) WriteMode() { + b.mu.Lock() +} + +func (b *syncBuffer) ReadMode() { + b.mu.Unlock() + b.signal() +} + +func (b *syncBuffer) Close() error { + b.closed = true + b.signal() + return nil +} + +func testSync(t *testing.T, level int, input []byte, name string) { + if len(input) == 0 { + return + } + + t.Logf("--testSync %d, %d, %s", level, len(input), name) + buf := newSyncBuffer() + buf1 := new(bytes.Buffer) + buf.WriteMode() + w, err := NewWriter(io.MultiWriter(buf, buf1), level) + if err != nil { + t.Errorf("NewWriter: %v", err) + return + } + r := NewReader(buf) + + // Write half the input and read back. + for i := 0; i < 2; i++ { + var lo, hi int + if i == 0 { + lo, hi = 0, (len(input)+1)/2 + } else { + lo, hi = (len(input)+1)/2, len(input) + } + t.Logf("#%d: write %d-%d", i, lo, hi) + if _, err := w.Write(input[lo:hi]); err != nil { + t.Errorf("testSync: write: %v", err) + return + } + if i == 0 { + if err := w.Flush(); err != nil { + t.Errorf("testSync: flush: %v", err) + return + } + } else { + if err := w.Close(); err != nil { + t.Errorf("testSync: close: %v", err) + } + } + buf.ReadMode() + out := make([]byte, hi-lo+1) + m, err := io.ReadAtLeast(r, out, hi-lo) + t.Logf("#%d: read %d", i, m) + if m != hi-lo || err != nil { + t.Errorf("testSync/%d (%d, %d, %s): read %d: %d, %v (%d left)", i, level, len(input), name, hi-lo, m, err, buf.buf.Len()) + return + } + if !bytes.Equal(input[lo:hi], out[:hi-lo]) { + t.Errorf("testSync/%d: read wrong bytes: %x vs %x", i, input[lo:hi], out[:hi-lo]) + return + } + // This test originally checked that after reading + // the first half of the input, there was nothing left + // in the read buffer (buf.buf.Len() != 0) but that is + // not necessarily the case: the write Flush may emit + // some extra framing bits that are not necessary + // to process to obtain the first half of the uncompressed + // data. The test ran correctly most of the time, because + // the background goroutine had usually read even + // those extra bits by now, but it's not a useful thing to + // check. + buf.WriteMode() + } + buf.ReadMode() + out := make([]byte, 10) + if n, err := r.Read(out); n > 0 || err != io.EOF { + t.Errorf("testSync (%d, %d, %s): final Read: %d, %v (hex: %x)", level, len(input), name, n, err, out[0:n]) + } + if buf.buf.Len() != 0 { + t.Errorf("testSync (%d, %d, %s): extra data at end", level, len(input), name) + } + r.Close() + + // stream should work for ordinary reader too + r = NewReader(buf1) + out, err = ioutil.ReadAll(r) + if err != nil { + t.Errorf("testSync: read: %s", err) + return + } + r.Close() + if !bytes.Equal(input, out) { + t.Errorf("testSync: decompress(compress(data)) != data: level=%d input=%s", level, name) + } +} + +func testToFromWithLevelAndLimit(t *testing.T, level int, input []byte, name string, limit int) { + var buffer bytes.Buffer + w, err := NewWriter(&buffer, level) + if err != nil { + t.Errorf("NewWriter: %v", err) + return + } + w.Write(input) + w.Close() + if limit > 0 && buffer.Len() > limit { + t.Errorf("level: %d, len(compress(data)) = %d > limit = %d", level, buffer.Len(), limit) + return + } + if limit > 0 { + t.Logf("level: %d - Size:%.2f%%, %d b\n", level, float64(buffer.Len()*100)/float64(limit), buffer.Len()) + } + r := NewReader(&buffer) + out, err := ioutil.ReadAll(r) + if err != nil { + t.Errorf("read: %s", err) + return + } + r.Close() + if !bytes.Equal(input, out) { + t.Errorf("decompress(compress(data)) != data: level=%d input=%s", level, name) + return + } + testSync(t, level, input, name) +} + +func testToFromWithLimit(t *testing.T, input []byte, name string, limit [11]int) { + for i := 0; i < 10; i++ { + testToFromWithLevelAndLimit(t, i, input, name, limit[i]) + } + testToFromWithLevelAndLimit(t, -2, input, name, limit[10]) +} + +func TestDeflateInflate(t *testing.T) { + for i, h := range deflateInflateTests { + testToFromWithLimit(t, h.in, fmt.Sprintf("#%d", i), [11]int{}) + } +} + +func TestReverseBits(t *testing.T) { + for _, h := range reverseBitsTests { + if v := reverseBits(h.in, h.bitCount); v != h.out { + t.Errorf("reverseBits(%v,%v) = %v, want %v", + h.in, h.bitCount, v, h.out) + } + } +} + +type deflateInflateStringTest struct { + filename string + label string + limit [11]int // Number 11 is ConstantCompression +} + +var deflateInflateStringTests = []deflateInflateStringTest{ + { + "../testdata/e.txt", + "2.718281828...", + [...]int{100018, 67900, 50960, 51150, 50930, 50790, 50790, 50790, 50790, 50790, 43683 + 100}, + }, + { + "../testdata/Mark.Twain-Tom.Sawyer.txt", + "Mark.Twain-Tom.Sawyer", + [...]int{407330, 195000, 185361, 180974, 169160, 164476, 162936, 160506, 160295, 160295, 233460 + 100}, + }, +} + +func TestDeflateInflateString(t *testing.T) { + for _, test := range deflateInflateStringTests { + gold, err := ioutil.ReadFile(test.filename) + if err != nil { + t.Error(err) + } + // Remove returns that may be present on Windows + neutral := strings.Map(func(r rune) rune { + if r != '\r' { + return r + } + return -1 + }, string(gold)) + + testToFromWithLimit(t, []byte(neutral), test.label, test.limit) + + if testing.Short() { + break + } + } +} + +func TestReaderDict(t *testing.T) { + const ( + dict = "hello world" + text = "hello again world" + ) + var b bytes.Buffer + w, err := NewWriter(&b, 5) + if err != nil { + t.Fatalf("NewWriter: %v", err) + } + w.Write([]byte(dict)) + w.Flush() + b.Reset() + w.Write([]byte(text)) + w.Close() + + r := NewReaderDict(&b, []byte(dict)) + data, err := ioutil.ReadAll(r) + if err != nil { + t.Fatal(err) + } + if string(data) != "hello again world" { + t.Fatalf("read returned %q want %q", string(data), text) + } +} + +func TestWriterDict(t *testing.T) { + const ( + dict = "hello world Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." + text = "hello world Lorem ipsum dolor sit amet" + ) + // This test is sensitive to algorithm changes that skip + // data in favour of speed. Higher levels are less prone to this + // so we test level 4-9. + for l := 4; l < 9; l++ { + var b bytes.Buffer + w, err := NewWriter(&b, l) + if err != nil { + t.Fatalf("level %d, NewWriter: %v", l, err) + } + w.Write([]byte(dict)) + w.Flush() + b.Reset() + w.Write([]byte(text)) + w.Close() + + var b1 bytes.Buffer + w, _ = NewWriterDict(&b1, l, []byte(dict)) + w.Write([]byte(text)) + w.Close() + + if !bytes.Equal(b1.Bytes(), b.Bytes()) { + t.Errorf("level %d, writer wrote\n%v\n want\n%v", l, b1.Bytes(), b.Bytes()) + } + } +} + +// See http://code.google.com/p/go/issues/detail?id=2508 +func TestRegression2508(t *testing.T) { + if testing.Short() { + t.Logf("test disabled with -short") + return + } + w, err := NewWriter(ioutil.Discard, 1) + if err != nil { + t.Fatalf("NewWriter: %v", err) + } + buf := make([]byte, 1024) + for i := 0; i < 131072; i++ { + if _, err := w.Write(buf); err != nil { + t.Fatalf("writer failed: %v", err) + } + } + w.Close() +} + +func TestWriterReset(t *testing.T) { + for level := -2; level <= 9; level++ { + if level == -1 { + level++ + } + if testing.Short() && level > 1 { + break + } + w, err := NewWriter(ioutil.Discard, level) + if err != nil { + t.Fatalf("NewWriter: %v", err) + } + buf := []byte("hello world") + for i := 0; i < 1024; i++ { + w.Write(buf) + } + w.Reset(ioutil.Discard) + + wref, err := NewWriter(ioutil.Discard, level) + if err != nil { + t.Fatalf("NewWriter: %v", err) + } + + // DeepEqual doesn't compare functions. + w.d.fill, wref.d.fill = nil, nil + w.d.step, wref.d.step = nil, nil + w.d.bulkHasher, wref.d.bulkHasher = nil, nil + w.d.snap, wref.d.snap = nil, nil + + // hashMatch is always overwritten when used. + copy(w.d.hashMatch[:], wref.d.hashMatch[:]) + if w.d.tokens.n != 0 { + t.Errorf("level %d Writer not reset after Reset. %d tokens were present", level, w.d.tokens.n) + } + // As long as the length is 0, we don't care about the content. + w.d.tokens = wref.d.tokens + + // We don't care if there are values in the window, as long as it is at d.index is 0 + w.d.window = wref.d.window + if !reflect.DeepEqual(w, wref) { + t.Errorf("level %d Writer not reset after Reset", level) + } + } + testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriter(w, NoCompression) }) + testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriter(w, DefaultCompression) }) + testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriter(w, BestCompression) }) + testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriter(w, ConstantCompression) }) + dict := []byte("we are the world") + testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriterDict(w, NoCompression, dict) }) + testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriterDict(w, DefaultCompression, dict) }) + testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriterDict(w, BestCompression, dict) }) + testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriterDict(w, ConstantCompression, dict) }) +} + +func testResetOutput(t *testing.T, newWriter func(w io.Writer) (*Writer, error)) { + buf := new(bytes.Buffer) + w, err := newWriter(buf) + if err != nil { + t.Fatalf("NewWriter: %v", err) + } + b := []byte("hello world") + for i := 0; i < 1024; i++ { + w.Write(b) + } + w.Close() + out1 := buf.Bytes() + + buf2 := new(bytes.Buffer) + w.Reset(buf2) + for i := 0; i < 1024; i++ { + w.Write(b) + } + w.Close() + out2 := buf2.Bytes() + + if len(out1) != len(out2) { + t.Errorf("got %d, expected %d bytes", len(out2), len(out1)) + } + if bytes.Compare(out1, out2) != 0 { + mm := 0 + for i, b := range out1[:len(out2)] { + if b != out2[i] { + t.Errorf("mismatch index %d: %02x, expected %02x", i, out2[i], b) + } + mm++ + if mm == 10 { + t.Fatal("Stopping") + } + } + } + t.Logf("got %d bytes", len(out1)) +} + +// A writer that fails after N writes. +type errorWriter struct { + N int +} + +func (e *errorWriter) Write(b []byte) (int, error) { + if e.N <= 0 { + return 0, io.ErrClosedPipe + } + e.N-- + return len(b), nil +} + +// Test if errors from the underlying writer is passed upwards. +func TestWriteError(t *testing.T) { + buf := new(bytes.Buffer) + for i := 0; i < 1024*1024; i++ { + buf.WriteString(fmt.Sprintf("asdasfasf%d%dfghfgujyut%dyutyu\n", i, i, i)) + } + in := buf.Bytes() + for l := -2; l < 10; l++ { + for fail := 1; fail <= 512; fail *= 2 { + // Fail after 2 writes + ew := &errorWriter{N: fail} + w, err := NewWriter(ew, l) + if err != nil { + t.Errorf("NewWriter: level %d: %v", l, err) + } + n, err := io.Copy(w, bytes.NewBuffer(in)) + if err == nil { + t.Errorf("Level %d: Expected an error, writer was %#v", l, ew) + } + n2, err := w.Write([]byte{1, 2, 2, 3, 4, 5}) + if n2 != 0 { + t.Error("Level", l, "Expected 0 length write, got", n) + } + if err == nil { + t.Error("Level", l, "Expected an error") + } + err = w.Flush() + if err == nil { + t.Error("Level", l, "Expected an error on close") + } + err = w.Close() + if err == nil { + t.Error("Level", l, "Expected an error on close") + } + + w.Reset(ioutil.Discard) + n2, err = w.Write([]byte{1, 2, 3, 4, 5, 6}) + if err != nil { + t.Error("Level", l, "Got unexpected error after reset:", err) + } + if n2 == 0 { + t.Error("Level", l, "Got 0 length write, expected > 0") + } + if testing.Short() { + return + } + } + } + +} diff --git a/vendor/github.com/klauspost/compress/flate/fixedhuff.go b/vendor/github.com/klauspost/compress/flate/fixedhuff.go new file mode 100644 index 0000000..7df8b9a --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/fixedhuff.go @@ -0,0 +1,78 @@ +// Copyright 2013 The Go 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 flate + +// autogenerated by go run gen.go -output fixedhuff.go, DO NOT EDIT + +var fixedHuffmanDecoder = huffmanDecoder{ + 7, + [huffmanNumChunks]uint32{ + 0x1007, 0x0508, 0x0108, 0x1188, 0x1107, 0x0708, 0x0308, 0x0c09, + 0x1087, 0x0608, 0x0208, 0x0a09, 0x0008, 0x0808, 0x0408, 0x0e09, + 0x1047, 0x0588, 0x0188, 0x0909, 0x1147, 0x0788, 0x0388, 0x0d09, + 0x10c7, 0x0688, 0x0288, 0x0b09, 0x0088, 0x0888, 0x0488, 0x0f09, + 0x1027, 0x0548, 0x0148, 0x11c8, 0x1127, 0x0748, 0x0348, 0x0c89, + 0x10a7, 0x0648, 0x0248, 0x0a89, 0x0048, 0x0848, 0x0448, 0x0e89, + 0x1067, 0x05c8, 0x01c8, 0x0989, 0x1167, 0x07c8, 0x03c8, 0x0d89, + 0x10e7, 0x06c8, 0x02c8, 0x0b89, 0x00c8, 0x08c8, 0x04c8, 0x0f89, + 0x1017, 0x0528, 0x0128, 0x11a8, 0x1117, 0x0728, 0x0328, 0x0c49, + 0x1097, 0x0628, 0x0228, 0x0a49, 0x0028, 0x0828, 0x0428, 0x0e49, + 0x1057, 0x05a8, 0x01a8, 0x0949, 0x1157, 0x07a8, 0x03a8, 0x0d49, + 0x10d7, 0x06a8, 0x02a8, 0x0b49, 0x00a8, 0x08a8, 0x04a8, 0x0f49, + 0x1037, 0x0568, 0x0168, 0x11e8, 0x1137, 0x0768, 0x0368, 0x0cc9, + 0x10b7, 0x0668, 0x0268, 0x0ac9, 0x0068, 0x0868, 0x0468, 0x0ec9, + 0x1077, 0x05e8, 0x01e8, 0x09c9, 0x1177, 0x07e8, 0x03e8, 0x0dc9, + 0x10f7, 0x06e8, 0x02e8, 0x0bc9, 0x00e8, 0x08e8, 0x04e8, 0x0fc9, + 0x1007, 0x0518, 0x0118, 0x1198, 0x1107, 0x0718, 0x0318, 0x0c29, + 0x1087, 0x0618, 0x0218, 0x0a29, 0x0018, 0x0818, 0x0418, 0x0e29, + 0x1047, 0x0598, 0x0198, 0x0929, 0x1147, 0x0798, 0x0398, 0x0d29, + 0x10c7, 0x0698, 0x0298, 0x0b29, 0x0098, 0x0898, 0x0498, 0x0f29, + 0x1027, 0x0558, 0x0158, 0x11d8, 0x1127, 0x0758, 0x0358, 0x0ca9, + 0x10a7, 0x0658, 0x0258, 0x0aa9, 0x0058, 0x0858, 0x0458, 0x0ea9, + 0x1067, 0x05d8, 0x01d8, 0x09a9, 0x1167, 0x07d8, 0x03d8, 0x0da9, + 0x10e7, 0x06d8, 0x02d8, 0x0ba9, 0x00d8, 0x08d8, 0x04d8, 0x0fa9, + 0x1017, 0x0538, 0x0138, 0x11b8, 0x1117, 0x0738, 0x0338, 0x0c69, + 0x1097, 0x0638, 0x0238, 0x0a69, 0x0038, 0x0838, 0x0438, 0x0e69, + 0x1057, 0x05b8, 0x01b8, 0x0969, 0x1157, 0x07b8, 0x03b8, 0x0d69, + 0x10d7, 0x06b8, 0x02b8, 0x0b69, 0x00b8, 0x08b8, 0x04b8, 0x0f69, + 0x1037, 0x0578, 0x0178, 0x11f8, 0x1137, 0x0778, 0x0378, 0x0ce9, + 0x10b7, 0x0678, 0x0278, 0x0ae9, 0x0078, 0x0878, 0x0478, 0x0ee9, + 0x1077, 0x05f8, 0x01f8, 0x09e9, 0x1177, 0x07f8, 0x03f8, 0x0de9, + 0x10f7, 0x06f8, 0x02f8, 0x0be9, 0x00f8, 0x08f8, 0x04f8, 0x0fe9, + 0x1007, 0x0508, 0x0108, 0x1188, 0x1107, 0x0708, 0x0308, 0x0c19, + 0x1087, 0x0608, 0x0208, 0x0a19, 0x0008, 0x0808, 0x0408, 0x0e19, + 0x1047, 0x0588, 0x0188, 0x0919, 0x1147, 0x0788, 0x0388, 0x0d19, + 0x10c7, 0x0688, 0x0288, 0x0b19, 0x0088, 0x0888, 0x0488, 0x0f19, + 0x1027, 0x0548, 0x0148, 0x11c8, 0x1127, 0x0748, 0x0348, 0x0c99, + 0x10a7, 0x0648, 0x0248, 0x0a99, 0x0048, 0x0848, 0x0448, 0x0e99, + 0x1067, 0x05c8, 0x01c8, 0x0999, 0x1167, 0x07c8, 0x03c8, 0x0d99, + 0x10e7, 0x06c8, 0x02c8, 0x0b99, 0x00c8, 0x08c8, 0x04c8, 0x0f99, + 0x1017, 0x0528, 0x0128, 0x11a8, 0x1117, 0x0728, 0x0328, 0x0c59, + 0x1097, 0x0628, 0x0228, 0x0a59, 0x0028, 0x0828, 0x0428, 0x0e59, + 0x1057, 0x05a8, 0x01a8, 0x0959, 0x1157, 0x07a8, 0x03a8, 0x0d59, + 0x10d7, 0x06a8, 0x02a8, 0x0b59, 0x00a8, 0x08a8, 0x04a8, 0x0f59, + 0x1037, 0x0568, 0x0168, 0x11e8, 0x1137, 0x0768, 0x0368, 0x0cd9, + 0x10b7, 0x0668, 0x0268, 0x0ad9, 0x0068, 0x0868, 0x0468, 0x0ed9, + 0x1077, 0x05e8, 0x01e8, 0x09d9, 0x1177, 0x07e8, 0x03e8, 0x0dd9, + 0x10f7, 0x06e8, 0x02e8, 0x0bd9, 0x00e8, 0x08e8, 0x04e8, 0x0fd9, + 0x1007, 0x0518, 0x0118, 0x1198, 0x1107, 0x0718, 0x0318, 0x0c39, + 0x1087, 0x0618, 0x0218, 0x0a39, 0x0018, 0x0818, 0x0418, 0x0e39, + 0x1047, 0x0598, 0x0198, 0x0939, 0x1147, 0x0798, 0x0398, 0x0d39, + 0x10c7, 0x0698, 0x0298, 0x0b39, 0x0098, 0x0898, 0x0498, 0x0f39, + 0x1027, 0x0558, 0x0158, 0x11d8, 0x1127, 0x0758, 0x0358, 0x0cb9, + 0x10a7, 0x0658, 0x0258, 0x0ab9, 0x0058, 0x0858, 0x0458, 0x0eb9, + 0x1067, 0x05d8, 0x01d8, 0x09b9, 0x1167, 0x07d8, 0x03d8, 0x0db9, + 0x10e7, 0x06d8, 0x02d8, 0x0bb9, 0x00d8, 0x08d8, 0x04d8, 0x0fb9, + 0x1017, 0x0538, 0x0138, 0x11b8, 0x1117, 0x0738, 0x0338, 0x0c79, + 0x1097, 0x0638, 0x0238, 0x0a79, 0x0038, 0x0838, 0x0438, 0x0e79, + 0x1057, 0x05b8, 0x01b8, 0x0979, 0x1157, 0x07b8, 0x03b8, 0x0d79, + 0x10d7, 0x06b8, 0x02b8, 0x0b79, 0x00b8, 0x08b8, 0x04b8, 0x0f79, + 0x1037, 0x0578, 0x0178, 0x11f8, 0x1137, 0x0778, 0x0378, 0x0cf9, + 0x10b7, 0x0678, 0x0278, 0x0af9, 0x0078, 0x0878, 0x0478, 0x0ef9, + 0x1077, 0x05f8, 0x01f8, 0x09f9, 0x1177, 0x07f8, 0x03f8, 0x0df9, + 0x10f7, 0x06f8, 0x02f8, 0x0bf9, 0x00f8, 0x08f8, 0x04f8, 0x0ff9, + }, + nil, 0, +} diff --git a/vendor/github.com/klauspost/compress/flate/flate_test.go b/vendor/github.com/klauspost/compress/flate/flate_test.go new file mode 100644 index 0000000..3f67025 --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/flate_test.go @@ -0,0 +1,260 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This test tests some internals of the flate package. +// The tests in package compress/gzip serve as the +// end-to-end test of the decompressor. + +package flate + +import ( + "bytes" + "encoding/hex" + "io/ioutil" + "testing" +) + +// The following test should not panic. +func TestIssue5915(t *testing.T) { + bits := []int{4, 0, 0, 6, 4, 3, 2, 3, 3, 4, 4, 5, 0, 0, 0, 0, 5, 5, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 6, 0, 11, 0, 8, 0, 6, 6, 10, 8} + var h huffmanDecoder + if h.init(bits) { + t.Fatalf("Given sequence of bits is bad, and should not succeed.") + } +} + +// The following test should not panic. +func TestIssue5962(t *testing.T) { + bits := []int{4, 0, 0, 6, 4, 3, 2, 3, 3, 4, 4, 5, 0, 0, 0, 0, + 5, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11} + var h huffmanDecoder + if h.init(bits) { + t.Fatalf("Given sequence of bits is bad, and should not succeed.") + } +} + +// The following test should not panic. +func TestIssue6255(t *testing.T) { + bits1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11} + bits2 := []int{11, 13} + var h huffmanDecoder + if !h.init(bits1) { + t.Fatalf("Given sequence of bits is good and should succeed.") + } + if h.init(bits2) { + t.Fatalf("Given sequence of bits is bad and should not succeed.") + } +} + +func TestInvalidEncoding(t *testing.T) { + // Initialize Huffman decoder to recognize "0". + var h huffmanDecoder + if !h.init([]int{1}) { + t.Fatal("Failed to initialize Huffman decoder") + } + + // Initialize decompressor with invalid Huffman coding. + var f decompressor + f.r = bytes.NewReader([]byte{0xff}) + + _, err := f.huffSym(&h) + if err == nil { + t.Fatal("Should have rejected invalid bit sequence") + } +} + +func TestInvalidBits(t *testing.T) { + oversubscribed := []int{1, 2, 3, 4, 4, 5} + incomplete := []int{1, 2, 4, 4} + var h huffmanDecoder + if h.init(oversubscribed) { + t.Fatal("Should reject oversubscribed bit-length set") + } + if h.init(incomplete) { + t.Fatal("Should reject incomplete bit-length set") + } +} + +func TestStreams(t *testing.T) { + // To verify any of these hexstrings as valid or invalid flate streams + // according to the C zlib library, you can use the Python wrapper library: + // >>> hex_string = "010100feff11" + // >>> import zlib + // >>> zlib.decompress(hex_string.decode("hex"), -15) # Negative means raw DEFLATE + // '\x11' + + testCases := []struct { + desc string // Description of the stream + stream string // Hexstring of the input DEFLATE stream + want string // Expected result. Use "fail" to expect failure + }{{ + "degenerate HCLenTree", + "05e0010000000000100000000000000000000000000000000000000000000000" + + "00000000000000000004", + "fail", + }, { + "complete HCLenTree, empty HLitTree, empty HDistTree", + "05e0010400000000000000000000000000000000000000000000000000000000" + + "00000000000000000010", + "fail", + }, { + "empty HCLenTree", + "05e0010000000000000000000000000000000000000000000000000000000000" + + "00000000000000000010", + "fail", + }, { + "complete HCLenTree, complete HLitTree, empty HDistTree, use missing HDist symbol", + "000100feff000de0010400000000100000000000000000000000000000000000" + + "0000000000000000000000000000002c", + "fail", + }, { + "complete HCLenTree, complete HLitTree, degenerate HDistTree, use missing HDist symbol", + "000100feff000de0010000000000000000000000000000000000000000000000" + + "00000000000000000610000000004070", + "fail", + }, { + "complete HCLenTree, empty HLitTree, empty HDistTree", + "05e0010400000000100400000000000000000000000000000000000000000000" + + "0000000000000000000000000008", + "fail", + }, { + "complete HCLenTree, empty HLitTree, degenerate HDistTree", + "05e0010400000000100400000000000000000000000000000000000000000000" + + "0000000000000000000800000008", + "fail", + }, { + "complete HCLenTree, degenerate HLitTree, degenerate HDistTree, use missing HLit symbol", + "05e0010400000000100000000000000000000000000000000000000000000000" + + "0000000000000000001c", + "fail", + }, { + "complete HCLenTree, complete HLitTree, too large HDistTree", + "edff870500000000200400000000000000000000000000000000000000000000" + + "000000000000000000080000000000000004", + "fail", + }, { + "complete HCLenTree, complete HLitTree, empty HDistTree, excessive repeater code", + "edfd870500000000200400000000000000000000000000000000000000000000" + + "000000000000000000e8b100", + "fail", + }, { + "complete HCLenTree, complete HLitTree, empty HDistTree of normal length 30", + "05fd01240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" + + "ffffffffffffffffff07000000fe01", + "", + }, { + "complete HCLenTree, complete HLitTree, empty HDistTree of excessive length 31", + "05fe01240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" + + "ffffffffffffffffff07000000fc03", + "fail", + }, { + "complete HCLenTree, over-subscribed HLitTree, empty HDistTree", + "05e001240000000000fcffffffffffffffffffffffffffffffffffffffffffff" + + "ffffffffffffffffff07f00f", + "fail", + }, { + "complete HCLenTree, under-subscribed HLitTree, empty HDistTree", + "05e001240000000000fcffffffffffffffffffffffffffffffffffffffffffff" + + "fffffffffcffffffff07f00f", + "fail", + }, { + "complete HCLenTree, complete HLitTree with single code, empty HDistTree", + "05e001240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" + + "ffffffffffffffffff07f00f", + "01", + }, { + "complete HCLenTree, complete HLitTree with multiple codes, empty HDistTree", + "05e301240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" + + "ffffffffffffffffff07807f", + "01", + }, { + "complete HCLenTree, complete HLitTree, degenerate HDistTree, use valid HDist symbol", + "000100feff000de0010400000000100000000000000000000000000000000000" + + "0000000000000000000000000000003c", + "00000000", + }, { + "complete HCLenTree, degenerate HLitTree, degenerate HDistTree", + "05e0010400000000100000000000000000000000000000000000000000000000" + + "0000000000000000000c", + "", + }, { + "complete HCLenTree, degenerate HLitTree, empty HDistTree", + "05e0010400000000100000000000000000000000000000000000000000000000" + + "00000000000000000004", + "", + }, { + "complete HCLenTree, complete HLitTree, empty HDistTree, spanning repeater code", + "edfd870500000000200400000000000000000000000000000000000000000000" + + "000000000000000000e8b000", + "", + }, { + "complete HCLenTree with length codes, complete HLitTree, empty HDistTree", + "ede0010400000000100000000000000000000000000000000000000000000000" + + "0000000000000000000400004000", + "", + }, { + "complete HCLenTree, complete HLitTree, degenerate HDistTree, use valid HLit symbol 284 with count 31", + "000100feff00ede0010400000000100000000000000000000000000000000000" + + "000000000000000000000000000000040000407f00", + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "000000", + }, { + "complete HCLenTree, complete HLitTree, degenerate HDistTree, use valid HLit and HDist symbols", + "0cc2010d00000082b0ac4aff0eb07d27060000ffff", + "616263616263", + }, { + "fixed block, use reserved symbol 287", + "33180700", + "fail", + }, { + "raw block", + "010100feff11", + "11", + }, { + "issue 10426 - over-subscribed HCLenTree causes a hang", + "344c4a4e494d4b070000ff2e2eff2e2e2e2e2eff", + "fail", + }, { + "issue 11030 - empty HDistTree unexpectedly leads to error", + "05c0070600000080400fff37a0ca", + "", + }, { + "issue 11033 - empty HDistTree unexpectedly leads to error", + "050fb109c020cca5d017dcbca044881ee1034ec149c8980bbc413c2ab35be9dc" + + "b1473449922449922411202306ee97b0383a521b4ffdcf3217f9f7d3adb701", + "3130303634342068652e706870005d05355f7ed957ff084a90925d19e3ebc6d0" + + "c6d7", + }} + + for i, tc := range testCases { + data, err := hex.DecodeString(tc.stream) + if err != nil { + t.Fatal(err) + } + data, err = ioutil.ReadAll(NewReader(bytes.NewReader(data))) + if tc.want == "fail" { + if err == nil { + t.Errorf("#%d (%s): got nil error, want non-nil", i, tc.desc) + } + } else { + if err != nil { + t.Errorf("#%d (%s): %v", i, tc.desc, err) + continue + } + if got := hex.EncodeToString(data); got != tc.want { + t.Errorf("#%d (%s):\ngot %q\nwant %q", i, tc.desc, got, tc.want) + } + + } + } +} diff --git a/vendor/github.com/klauspost/compress/flate/gen.go b/vendor/github.com/klauspost/compress/flate/gen.go new file mode 100644 index 0000000..154c89a --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/gen.go @@ -0,0 +1,265 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +// This program generates fixedhuff.go +// Invoke as +// +// go run gen.go -output fixedhuff.go + +package main + +import ( + "bytes" + "flag" + "fmt" + "go/format" + "io/ioutil" + "log" +) + +var filename = flag.String("output", "fixedhuff.go", "output file name") + +const maxCodeLen = 16 + +// Note: the definition of the huffmanDecoder struct is copied from +// inflate.go, as it is private to the implementation. + +// chunk & 15 is number of bits +// chunk >> 4 is value, including table link + +const ( + huffmanChunkBits = 9 + huffmanNumChunks = 1 << huffmanChunkBits + huffmanCountMask = 15 + huffmanValueShift = 4 +) + +type huffmanDecoder struct { + min int // the minimum code length + chunks [huffmanNumChunks]uint32 // chunks as described above + links [][]uint32 // overflow links + linkMask uint32 // mask the width of the link table +} + +// Initialize Huffman decoding tables from array of code lengths. +// Following this function, h is guaranteed to be initialized into a complete +// tree (i.e., neither over-subscribed nor under-subscribed). The exception is a +// degenerate case where the tree has only a single symbol with length 1. Empty +// trees are permitted. +func (h *huffmanDecoder) init(bits []int) bool { + // Sanity enables additional runtime tests during Huffman + // table construction. It's intended to be used during + // development to supplement the currently ad-hoc unit tests. + const sanity = false + + if h.min != 0 { + *h = huffmanDecoder{} + } + + // Count number of codes of each length, + // compute min and max length. + var count [maxCodeLen]int + var min, max int + for _, n := range bits { + if n == 0 { + continue + } + if min == 0 || n < min { + min = n + } + if n > max { + max = n + } + count[n]++ + } + + // Empty tree. The decompressor.huffSym function will fail later if the tree + // is used. Technically, an empty tree is only valid for the HDIST tree and + // not the HCLEN and HLIT tree. However, a stream with an empty HCLEN tree + // is guaranteed to fail since it will attempt to use the tree to decode the + // codes for the HLIT and HDIST trees. Similarly, an empty HLIT tree is + // guaranteed to fail later since the compressed data section must be + // composed of at least one symbol (the end-of-block marker). + if max == 0 { + return true + } + + code := 0 + var nextcode [maxCodeLen]int + for i := min; i <= max; i++ { + code <<= 1 + nextcode[i] = code + code += count[i] + } + + // Check that the coding is complete (i.e., that we've + // assigned all 2-to-the-max possible bit sequences). + // Exception: To be compatible with zlib, we also need to + // accept degenerate single-code codings. See also + // TestDegenerateHuffmanCoding. + if code != 1< huffmanChunkBits { + numLinks := 1 << (uint(max) - huffmanChunkBits) + h.linkMask = uint32(numLinks - 1) + + // create link tables + link := nextcode[huffmanChunkBits+1] >> 1 + h.links = make([][]uint32, huffmanNumChunks-link) + for j := uint(link); j < huffmanNumChunks; j++ { + reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8 + reverse >>= uint(16 - huffmanChunkBits) + off := j - uint(link) + if sanity && h.chunks[reverse] != 0 { + panic("impossible: overwriting existing chunk") + } + h.chunks[reverse] = uint32(off<>8]) | int(reverseByte[code&0xff])<<8 + reverse >>= uint(16 - n) + if n <= huffmanChunkBits { + for off := reverse; off < len(h.chunks); off += 1 << uint(n) { + // We should never need to overwrite + // an existing chunk. Also, 0 is + // never a valid chunk, because the + // lower 4 "count" bits should be + // between 1 and 15. + if sanity && h.chunks[off] != 0 { + panic("impossible: overwriting existing chunk") + } + h.chunks[off] = chunk + } + } else { + j := reverse & (huffmanNumChunks - 1) + if sanity && h.chunks[j]&huffmanCountMask != huffmanChunkBits+1 { + // Longer codes should have been + // associated with a link table above. + panic("impossible: not an indirect chunk") + } + value := h.chunks[j] >> huffmanValueShift + linktab := h.links[value] + reverse >>= huffmanChunkBits + for off := reverse; off < len(linktab); off += 1 << uint(n-huffmanChunkBits) { + if sanity && linktab[off] != 0 { + panic("impossible: overwriting existing chunk") + } + linktab[off] = chunk + } + } + } + + if sanity { + // Above we've sanity checked that we never overwrote + // an existing entry. Here we additionally check that + // we filled the tables completely. + for i, chunk := range h.chunks { + if chunk == 0 { + // As an exception, in the degenerate + // single-code case, we allow odd + // chunks to be missing. + if code == 1 && i%2 == 1 { + continue + } + panic("impossible: missing chunk") + } + } + for _, linktab := range h.links { + for _, chunk := range linktab { + if chunk == 0 { + panic("impossible: missing chunk") + } + } + } + } + + return true +} + +func main() { + flag.Parse() + + var h huffmanDecoder + var bits [288]int + initReverseByte() + for i := 0; i < 144; i++ { + bits[i] = 8 + } + for i := 144; i < 256; i++ { + bits[i] = 9 + } + for i := 256; i < 280; i++ { + bits[i] = 7 + } + for i := 280; i < 288; i++ { + bits[i] = 8 + } + h.init(bits[:]) + if h.links != nil { + log.Fatal("Unexpected links table in fixed Huffman decoder") + } + + var buf bytes.Buffer + + fmt.Fprintf(&buf, `// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file.`+"\n\n") + + fmt.Fprintln(&buf, "package flate") + fmt.Fprintln(&buf) + fmt.Fprintln(&buf, "// autogenerated by go run gen.go -output fixedhuff.go, DO NOT EDIT") + fmt.Fprintln(&buf) + fmt.Fprintln(&buf, "var fixedHuffmanDecoder = huffmanDecoder{") + fmt.Fprintf(&buf, "\t%d,\n", h.min) + fmt.Fprintln(&buf, "\t[huffmanNumChunks]uint32{") + for i := 0; i < huffmanNumChunks; i++ { + if i&7 == 0 { + fmt.Fprintf(&buf, "\t\t") + } else { + fmt.Fprintf(&buf, " ") + } + fmt.Fprintf(&buf, "0x%04x,", h.chunks[i]) + if i&7 == 7 { + fmt.Fprintln(&buf) + } + } + fmt.Fprintln(&buf, "\t},") + fmt.Fprintln(&buf, "\tnil, 0,") + fmt.Fprintln(&buf, "}") + + data, err := format.Source(buf.Bytes()) + if err != nil { + log.Fatal(err) + } + err = ioutil.WriteFile(*filename, data, 0644) + if err != nil { + log.Fatal(err) + } +} + +var reverseByte [256]byte + +func initReverseByte() { + for x := 0; x < 256; x++ { + var result byte + for i := uint(0); i < 8; i++ { + result |= byte(((x >> i) & 1) << (7 - i)) + } + reverseByte[x] = result + } +} diff --git a/vendor/github.com/klauspost/compress/flate/huffman_bit_writer.go b/vendor/github.com/klauspost/compress/flate/huffman_bit_writer.go new file mode 100644 index 0000000..5f7ffdd --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/huffman_bit_writer.go @@ -0,0 +1,717 @@ +// Copyright 2009 The Go 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 flate + +import ( + "io" + "math" +) + +const ( + // The largest offset code. + offsetCodeCount = 30 + + // The special code used to mark the end of a block. + endBlockMarker = 256 + + // The first length code. + lengthCodesStart = 257 + + // The number of codegen codes. + codegenCodeCount = 19 + badCode = 255 + + // Output byte buffer size + // Must be multiple of 6 (48 bits) + 8 + bufferSize = 240 + 8 +) + +// The number of extra bits needed by length code X - LENGTH_CODES_START. +var lengthExtraBits = []int8{ + /* 257 */ 0, 0, 0, + /* 260 */ 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, + /* 270 */ 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, + /* 280 */ 4, 5, 5, 5, 5, 0, +} + +// The length indicated by length code X - LENGTH_CODES_START. +var lengthBase = []uint32{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, + 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, + 64, 80, 96, 112, 128, 160, 192, 224, 255, +} + +// offset code word extra bits. +var offsetExtraBits = []int8{ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, + 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, + 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, + /* extended window */ + 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, +} + +var offsetBase = []uint32{ + /* normal deflate */ + 0x000000, 0x000001, 0x000002, 0x000003, 0x000004, + 0x000006, 0x000008, 0x00000c, 0x000010, 0x000018, + 0x000020, 0x000030, 0x000040, 0x000060, 0x000080, + 0x0000c0, 0x000100, 0x000180, 0x000200, 0x000300, + 0x000400, 0x000600, 0x000800, 0x000c00, 0x001000, + 0x001800, 0x002000, 0x003000, 0x004000, 0x006000, + + /* extended window */ + 0x008000, 0x00c000, 0x010000, 0x018000, 0x020000, + 0x030000, 0x040000, 0x060000, 0x080000, 0x0c0000, + 0x100000, 0x180000, 0x200000, 0x300000, +} + +// The odd order in which the codegen code sizes are written. +var codegenOrder = []uint32{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15} + +type huffmanBitWriter struct { + w io.Writer + // Data waiting to be written is bytes[0:nbytes] + // and then the low nbits of bits. + bits uint64 + nbits uint + bytes [bufferSize]byte + nbytes int + literalFreq []int32 + offsetFreq []int32 + codegen []uint8 + codegenFreq []int32 + literalEncoding *huffmanEncoder + offsetEncoding *huffmanEncoder + codegenEncoding *huffmanEncoder + err error +} + +func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter { + return &huffmanBitWriter{ + w: w, + literalFreq: make([]int32, maxNumLit), + offsetFreq: make([]int32, offsetCodeCount), + codegen: make([]uint8, maxNumLit+offsetCodeCount+1), + codegenFreq: make([]int32, codegenCodeCount), + literalEncoding: newHuffmanEncoder(maxNumLit), + codegenEncoding: newHuffmanEncoder(codegenCodeCount), + offsetEncoding: newHuffmanEncoder(offsetCodeCount), + } +} + +func (w *huffmanBitWriter) reset(writer io.Writer) { + w.w = writer + w.bits, w.nbits, w.nbytes, w.err = 0, 0, 0, nil + w.bytes = [bufferSize]byte{} +} + +func (w *huffmanBitWriter) flush() { + if w.err != nil { + w.nbits = 0 + return + } + n := w.nbytes + for w.nbits != 0 { + w.bytes[n] = byte(w.bits) + w.bits >>= 8 + if w.nbits > 8 { // Avoid underflow + w.nbits -= 8 + } else { + w.nbits = 0 + } + n++ + } + w.bits = 0 + _, w.err = w.w.Write(w.bytes[0:n]) + w.nbytes = 0 +} + +func (w *huffmanBitWriter) writeBits(b int32, nb uint) { + w.bits |= uint64(b) << w.nbits + w.nbits += nb + if w.nbits >= 48 { + bits := w.bits + w.bits >>= 48 + w.nbits -= 48 + n := w.nbytes + w.bytes[n] = byte(bits) + w.bytes[n+1] = byte(bits >> 8) + w.bytes[n+2] = byte(bits >> 16) + w.bytes[n+3] = byte(bits >> 24) + w.bytes[n+4] = byte(bits >> 32) + w.bytes[n+5] = byte(bits >> 40) + n += 6 + if n >= bufferSize-8 { + _, w.err = w.w.Write(w.bytes[:bufferSize-8]) + n = 0 + } + w.nbytes = n + } +} + +func (w *huffmanBitWriter) writeBytes(bytes []byte) { + if w.err != nil { + return + } + n := w.nbytes + for w.nbits != 0 { + w.bytes[n] = byte(w.bits) + w.bits >>= 8 + w.nbits -= 8 + n++ + } + if w.nbits != 0 { + w.err = InternalError("writeBytes with unfinished bits") + return + } + if n != 0 { + _, w.err = w.w.Write(w.bytes[0:n]) + if w.err != nil { + return + } + } + w.nbytes = 0 + _, w.err = w.w.Write(bytes) +} + +// RFC 1951 3.2.7 specifies a special run-length encoding for specifying +// the literal and offset lengths arrays (which are concatenated into a single +// array). This method generates that run-length encoding. +// +// The result is written into the codegen array, and the frequencies +// of each code is written into the codegenFreq array. +// Codes 0-15 are single byte codes. Codes 16-18 are followed by additional +// information. Code badCode is an end marker +// +// numLiterals The number of literals in literalEncoding +// numOffsets The number of offsets in offsetEncoding +func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int, offenc *huffmanEncoder) { + for i := range w.codegenFreq { + w.codegenFreq[i] = 0 + } + // Note that we are using codegen both as a temporary variable for holding + // a copy of the frequencies, and as the place where we put the result. + // This is fine because the output is always shorter than the input used + // so far. + codegen := w.codegen // cache + // Copy the concatenated code sizes to codegen. Put a marker at the end. + cgnl := codegen[0:numLiterals] + for i := range cgnl { + cgnl[i] = uint8(w.literalEncoding.codes[i].bits()) + } + + cgnl = codegen[numLiterals : numLiterals+numOffsets] + for i := range cgnl { + cgnl[i] = uint8(offenc.codes[i].bits()) + } + codegen[numLiterals+numOffsets] = badCode + + size := codegen[0] + count := 1 + outIndex := 0 + for inIndex := 1; size != badCode; inIndex++ { + // INVARIANT: We have seen "count" copies of size that have not yet + // had output generated for them. + nextSize := codegen[inIndex] + if nextSize == size { + count++ + continue + } + // We need to generate codegen indicating "count" of size. + if size != 0 { + codegen[outIndex] = size + outIndex++ + w.codegenFreq[size]++ + count-- + for count >= 3 { + n := 6 + if n > count { + n = count + } + codegen[outIndex] = 16 + outIndex++ + codegen[outIndex] = uint8(n - 3) + outIndex++ + w.codegenFreq[16]++ + count -= n + } + } else { + for count >= 11 { + n := 138 + if n > count { + n = count + } + codegen[outIndex] = 18 + outIndex++ + codegen[outIndex] = uint8(n - 11) + outIndex++ + w.codegenFreq[18]++ + count -= n + } + if count >= 3 { + // count >= 3 && count <= 10 + codegen[outIndex] = 17 + outIndex++ + codegen[outIndex] = uint8(count - 3) + outIndex++ + w.codegenFreq[17]++ + count = 0 + } + } + count-- + for ; count >= 0; count-- { + codegen[outIndex] = size + outIndex++ + w.codegenFreq[size]++ + } + // Set up invariant for next time through the loop. + size = nextSize + count = 1 + } + // Marker indicating the end of the codegen. + codegen[outIndex] = badCode +} + +func (w *huffmanBitWriter) writeCode(c hcode) { + if w.err != nil { + return + } + w.bits |= uint64(c.code()) << w.nbits + w.nbits += c.bits() + if w.nbits >= 48 { + bits := w.bits + w.bits >>= 48 + w.nbits -= 48 + n := w.nbytes + w.bytes[n] = byte(bits) + w.bytes[n+1] = byte(bits >> 8) + w.bytes[n+2] = byte(bits >> 16) + w.bytes[n+3] = byte(bits >> 24) + w.bytes[n+4] = byte(bits >> 32) + w.bytes[n+5] = byte(bits >> 40) + n += 6 + if n >= bufferSize-8 { + _, w.err = w.w.Write(w.bytes[:bufferSize-8]) + n = 0 + } + w.nbytes = n + } + +} + +// Write the header of a dynamic Huffman block to the output stream. +// +// numLiterals The number of literals specified in codegen +// numOffsets The number of offsets specified in codegen +// numCodegens The number of codegens used in codegen +func (w *huffmanBitWriter) writeDynamicHeader(numLiterals int, numOffsets int, numCodegens int, isEof bool) { + if w.err != nil { + return + } + var firstBits int32 = 4 + if isEof { + firstBits = 5 + } + w.writeBits(firstBits, 3) + w.writeBits(int32(numLiterals-257), 5) + w.writeBits(int32(numOffsets-1), 5) + w.writeBits(int32(numCodegens-4), 4) + + for i := 0; i < numCodegens; i++ { + value := w.codegenEncoding.codes[codegenOrder[i]].bits() + w.writeBits(int32(value), 3) + } + + i := 0 + for { + var codeWord int = int(w.codegen[i]) + i++ + if codeWord == badCode { + break + } + // The low byte contains the actual code to generate. + w.writeCode(w.codegenEncoding.codes[uint32(codeWord)]) + + switch codeWord { + case 16: + w.writeBits(int32(w.codegen[i]), 2) + i++ + break + case 17: + w.writeBits(int32(w.codegen[i]), 3) + i++ + break + case 18: + w.writeBits(int32(w.codegen[i]), 7) + i++ + break + } + } +} + +func (w *huffmanBitWriter) writeStoredHeader(length int, isEof bool) { + if w.err != nil { + return + } + var flag int32 + if isEof { + flag = 1 + } + w.writeBits(flag, 3) + w.flush() + w.writeBits(int32(length), 16) + w.writeBits(int32(^uint16(length)), 16) +} + +func (w *huffmanBitWriter) writeFixedHeader(isEof bool) { + if w.err != nil { + return + } + // Indicate that we are a fixed Huffman block + var value int32 = 2 + if isEof { + value = 3 + } + w.writeBits(value, 3) +} + +func (w *huffmanBitWriter) writeBlock(tok tokens, eof bool, input []byte) { + if w.err != nil { + return + } + for i := range w.literalFreq { + w.literalFreq[i] = 0 + } + for i := range w.offsetFreq { + w.offsetFreq[i] = 0 + } + + tok.tokens[tok.n] = endBlockMarker + tokens := tok.tokens[0 : tok.n+1] + + for _, t := range tokens { + if t < matchType { + w.literalFreq[t.literal()]++ + } else { + length := t.length() + offset := t.offset() + w.literalFreq[lengthCodesStart+lengthCode(length)]++ + w.offsetFreq[offsetCode(offset)]++ + } + } + + // get the number of literals + numLiterals := len(w.literalFreq) + for w.literalFreq[numLiterals-1] == 0 { + numLiterals-- + } + // get the number of offsets + numOffsets := len(w.offsetFreq) + for numOffsets > 0 && w.offsetFreq[numOffsets-1] == 0 { + numOffsets-- + } + if numOffsets == 0 { + // We haven't found a single match. If we want to go with the dynamic encoding, + // we should count at least one offset to be sure that the offset huffman tree could be encoded. + w.offsetFreq[0] = 1 + numOffsets = 1 + } + + w.literalEncoding.generate(w.literalFreq, 15) + w.offsetEncoding.generate(w.offsetFreq, 15) + + storedBytes := 0 + if input != nil { + storedBytes = len(input) + } + var extraBits int64 + var storedSize int64 = math.MaxInt64 + if storedBytes <= maxStoreBlockSize && input != nil { + storedSize = int64((storedBytes + 5) * 8) + // We only bother calculating the costs of the extra bits required by + // the length of offset fields (which will be the same for both fixed + // and dynamic encoding), if we need to compare those two encodings + // against stored encoding. + for lengthCode := lengthCodesStart + 8; lengthCode < numLiterals; lengthCode++ { + // First eight length codes have extra size = 0. + extraBits += int64(w.literalFreq[lengthCode]) * int64(lengthExtraBits[lengthCode-lengthCodesStart]) + } + for offsetCode := 4; offsetCode < numOffsets; offsetCode++ { + // First four offset codes have extra size = 0. + extraBits += int64(w.offsetFreq[offsetCode]) * int64(offsetExtraBits[offsetCode]) + } + } + + // Figure out smallest code. + // Fixed Huffman baseline. + var size = int64(3) + + fixedLiteralEncoding.bitLength(w.literalFreq) + + fixedOffsetEncoding.bitLength(w.offsetFreq) + + extraBits + var literalEncoding = fixedLiteralEncoding + var offsetEncoding = fixedOffsetEncoding + + // Dynamic Huffman? + var numCodegens int + + // Generate codegen and codegenFrequencies, which indicates how to encode + // the literalEncoding and the offsetEncoding. + w.generateCodegen(numLiterals, numOffsets, w.offsetEncoding) + w.codegenEncoding.generate(w.codegenFreq, 7) + numCodegens = len(w.codegenFreq) + for numCodegens > 4 && w.codegenFreq[codegenOrder[numCodegens-1]] == 0 { + numCodegens-- + } + dynamicHeader := int64(3+5+5+4+(3*numCodegens)) + + w.codegenEncoding.bitLength(w.codegenFreq) + + int64(extraBits) + + int64(w.codegenFreq[16]*2) + + int64(w.codegenFreq[17]*3) + + int64(w.codegenFreq[18]*7) + dynamicSize := dynamicHeader + + w.literalEncoding.bitLength(w.literalFreq) + + w.offsetEncoding.bitLength(w.offsetFreq) + + if dynamicSize < size { + size = dynamicSize + literalEncoding = w.literalEncoding + offsetEncoding = w.offsetEncoding + } + + // Stored bytes? + if storedSize < size { + w.writeStoredHeader(storedBytes, eof) + w.writeBytes(input[0:storedBytes]) + return + } + + // Huffman. + if literalEncoding == fixedLiteralEncoding { + w.writeFixedHeader(eof) + } else { + w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof) + } + + leCodes := literalEncoding.codes + oeCodes := offsetEncoding.codes + for _, t := range tokens { + if t < matchType { + w.writeCode(leCodes[t.literal()]) + } else { + // Write the length + length := t.length() + lengthCode := lengthCode(length) + w.writeCode(leCodes[lengthCode+lengthCodesStart]) + extraLengthBits := uint(lengthExtraBits[lengthCode]) + if extraLengthBits > 0 { + extraLength := int32(length - lengthBase[lengthCode]) + w.writeBits(extraLength, extraLengthBits) + } + // Write the offset + offset := t.offset() + offsetCode := offsetCode(offset) + w.writeCode(oeCodes[offsetCode]) + extraOffsetBits := uint(offsetExtraBits[offsetCode]) + if extraOffsetBits > 0 { + extraOffset := int32(offset - offsetBase[offsetCode]) + w.writeBits(extraOffset, extraOffsetBits) + } + } + } +} + +// writeBlockDynamic will write a block as dynamic Huffman table +// compressed. This should be used, if the caller has a reasonable expectation +// that this block contains compressible data. +func (w *huffmanBitWriter) writeBlockDynamic(tok tokens, eof bool, input []byte) { + if w.err != nil { + return + } + for i := range w.literalFreq { + w.literalFreq[i] = 0 + } + for i := range w.offsetFreq { + w.offsetFreq[i] = 0 + } + + tok.tokens[tok.n] = endBlockMarker + tokens := tok.tokens[0 : tok.n+1] + + for _, t := range tokens { + if t < matchType { + w.literalFreq[t.literal()]++ + } else { + length := t.length() + offset := t.offset() + w.literalFreq[lengthCodesStart+lengthCode(length)]++ + w.offsetFreq[offsetCode(offset)]++ + } + } + + // get the number of literals + numLiterals := len(w.literalFreq) + for w.literalFreq[numLiterals-1] == 0 { + numLiterals-- + } + // get the number of offsets + numOffsets := len(w.offsetFreq) + for numOffsets > 0 && w.offsetFreq[numOffsets-1] == 0 { + numOffsets-- + } + if numOffsets == 0 { + // We haven't found a single match. If we want to go with the dynamic encoding, + // we should count at least one offset to be sure that the offset huffman tree could be encoded. + w.offsetFreq[0] = 1 + numOffsets = 1 + } + + w.literalEncoding.generate(w.literalFreq, 15) + w.offsetEncoding.generate(w.offsetFreq, 15) + + var numCodegens int + + // Generate codegen and codegenFrequencies, which indicates how to encode + // the literalEncoding and the offsetEncoding. + w.generateCodegen(numLiterals, numOffsets, w.offsetEncoding) + w.codegenEncoding.generate(w.codegenFreq, 7) + numCodegens = len(w.codegenFreq) + for numCodegens > 4 && w.codegenFreq[codegenOrder[numCodegens-1]] == 0 { + numCodegens-- + } + var literalEncoding = w.literalEncoding + var offsetEncoding = w.offsetEncoding + + // Write Huffman table. + w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof) + leCodes := literalEncoding.codes + oeCodes := offsetEncoding.codes + + for _, t := range tokens { + if t < matchType { + w.writeCode(leCodes[t.literal()]) + } else { + // Write the length + length := t.length() + lengthCode := lengthCode(length) + w.writeCode(leCodes[lengthCode+lengthCodesStart]) + extraLengthBits := uint(lengthExtraBits[lengthCode]) + if extraLengthBits > 0 { + extraLength := int32(length - lengthBase[lengthCode]) + w.writeBits(extraLength, extraLengthBits) + } + // Write the offset + offset := t.offset() + offsetCode := offsetCode(offset) + w.writeCode(oeCodes[offsetCode]) + extraOffsetBits := uint(offsetExtraBits[offsetCode]) + if extraOffsetBits > 0 { + extraOffset := int32(offset - offsetBase[offsetCode]) + w.writeBits(extraOffset, extraOffsetBits) + } + } + } +} + +// static offset encoder used for huffman only encoding. +var huffOffset *huffmanEncoder + +func init() { + var w = newHuffmanBitWriter(nil) + w.offsetFreq[0] = 1 + huffOffset = newHuffmanEncoder(offsetCodeCount) + huffOffset.generate(w.offsetFreq, 15) +} + +// writeBlockHuff will write a block of bytes as either +// Huffman encoded literals or uncompressed bytes if the +// results only gains very little from compression. +func (w *huffmanBitWriter) writeBlockHuff(eof bool, input []byte) { + if w.err != nil { + return + } + + // Clear histogram + for i := range w.literalFreq { + w.literalFreq[i] = 0 + } + + // Add everything as literals + histogram(input, w.literalFreq) + + w.literalFreq[endBlockMarker] = 1 + + const numLiterals = endBlockMarker + 1 + const numOffsets = 1 + + w.literalEncoding.generate(w.literalFreq, 15) + + // Figure out smallest code. + // Always use dynamic Huffman or Store + var numCodegens int + + // Generate codegen and codegenFrequencies, which indicates how to encode + // the literalEncoding and the offsetEncoding. + w.generateCodegen(numLiterals, numOffsets, huffOffset) + w.codegenEncoding.generate(w.codegenFreq, 7) + numCodegens = len(w.codegenFreq) + for numCodegens > 4 && w.codegenFreq[codegenOrder[numCodegens-1]] == 0 { + numCodegens-- + } + headerSize := int64(3+5+5+4+(3*numCodegens)) + + w.codegenEncoding.bitLength(w.codegenFreq) + + int64(w.codegenFreq[16]*2) + + int64(w.codegenFreq[17]*3) + + int64(w.codegenFreq[18]*7) + + // Includes EOB marker + size := headerSize + w.literalEncoding.bitLength(w.literalFreq) + + // Calculate stored size + var storedSize int64 = math.MaxInt64 + var storedBytes = len(input) + if storedBytes <= maxStoreBlockSize { + storedSize = int64(storedBytes+5) * 8 + } + + // Store bytes, if we don't get a reasonable improvement. + if storedSize < (size + size>>4) { + w.writeStoredHeader(storedBytes, eof) + w.writeBytes(input) + return + } + + // Huffman. + w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof) + encoding := w.literalEncoding.codes + for _, t := range input { + // Bitwriting inlined, ~30% speedup + c := encoding[t] + w.bits |= uint64(c.code()) << w.nbits + w.nbits += c.bits() + if w.nbits >= 48 { + bits := w.bits + w.bits >>= 48 + w.nbits -= 48 + n := w.nbytes + w.bytes[n] = byte(bits) + w.bytes[n+1] = byte(bits >> 8) + w.bytes[n+2] = byte(bits >> 16) + w.bytes[n+3] = byte(bits >> 24) + w.bytes[n+4] = byte(bits >> 32) + w.bytes[n+5] = byte(bits >> 40) + n += 6 + if n >= bufferSize-8 { + _, w.err = w.w.Write(w.bytes[:bufferSize-8]) + if w.err != nil { + return + } + w.nbytes = 0 + } else { + w.nbytes = n + } + } + } + w.writeCode(encoding[endBlockMarker]) +} diff --git a/vendor/github.com/klauspost/compress/flate/huffman_bit_writer_test.go b/vendor/github.com/klauspost/compress/flate/huffman_bit_writer_test.go new file mode 100644 index 0000000..09746a3 --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/huffman_bit_writer_test.go @@ -0,0 +1,368 @@ +package flate + +import ( + "bytes" + "flag" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + "testing" +) + +var update = flag.Bool("update", false, "update reference files") + +func init() { + flag.Parse() +} + +// TestBlockHuff will test huffman encoding against reference files +// to detect possible regressions. +// If encoding/bit allocation changes you can regenerate these files +// by using the -update switch. +func TestBlockHuff(t *testing.T) { + // determine input files + match, err := filepath.Glob("testdata/huffman-*.in") + if err != nil { + t.Fatal(err) + } + + for _, in := range match { + out := in // for files where input and output are identical + if strings.HasSuffix(in, ".in") { + out = in[:len(in)-len(".in")] + ".golden" + } + testBlockHuff(t, in, out) + } +} + +func testBlockHuff(t *testing.T, in, out string) { + all, err := ioutil.ReadFile(in) + if err != nil { + t.Fatal(err) + } + var buf bytes.Buffer + bw := newHuffmanBitWriter(&buf) + bw.writeBlockHuff(false, all) + bw.flush() + got := buf.Bytes() + + expected, err := ioutil.ReadFile(out) + if err != nil && !*update { + t.Error(out, "-", err) + return + } + + t.Logf("Testing %q", in) + if !bytes.Equal(got, expected) { + if *update { + if in != out { + t.Logf("Updating %q", out) + if err := ioutil.WriteFile(out, got, 0666); err != nil { + t.Error(err) + } + return + } + // in == out: don't accidentally destroy input + t.Errorf("WARNING: -update did not rewrite input file %s", in) + } + + t.Errorf("%q != %q (see %q)", in, out, in+".got") + if err := ioutil.WriteFile(in+".got", got, 0666); err != nil { + t.Error(err) + } + return + } + t.Log("Output ok") + + // Test if the writer produces the same output after reset. + buf.Reset() + bw.reset(&buf) + bw.writeBlockHuff(false, all) + bw.flush() + got = buf.Bytes() + if !bytes.Equal(got, expected) { + t.Errorf("after reset %q != %q (see %q)", in, out, in+".reset.got") + if err := ioutil.WriteFile(in+".reset.got", got, 0666); err != nil { + t.Error(err) + } + return + } + t.Log("Reset ok") + testWriterEOF(t, "huff", huffTest{input: in}, true) +} + +type huffTest struct { + tokens []token + input string // File name of input data matching the. + expect string // File name of data with the expected output with input available. + expectNoInput string // File name of the expected output when no input is available. +} + +var writeBlockTests = []huffTest{ + huffTest{ + input: "testdata/huffman-null-max.in", + expect: "testdata/huffman-null-max.%s.expect", + expectNoInput: "testdata/huffman-null-max.%s.expect-noinput", + tokens: []token{0x0, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x0, 0x0}, + }, + huffTest{ + input: "testdata/huffman-pi.in", + expect: "testdata/huffman-pi.%s.expect", + expectNoInput: "testdata/huffman-pi.%s.expect-noinput", + tokens: []token{0x33, 0x2e, 0x31, 0x34, 0x31, 0x35, 0x39, 0x32, 0x36, 0x35, 0x33, 0x35, 0x38, 0x39, 0x37, 0x39, 0x33, 0x32, 0x33, 0x38, 0x34, 0x36, 0x32, 0x36, 0x34, 0x33, 0x33, 0x38, 0x33, 0x32, 0x37, 0x39, 0x35, 0x30, 0x32, 0x38, 0x38, 0x34, 0x31, 0x39, 0x37, 0x31, 0x36, 0x39, 0x33, 0x39, 0x39, 0x33, 0x37, 0x35, 0x31, 0x30, 0x35, 0x38, 0x32, 0x30, 0x39, 0x37, 0x34, 0x39, 0x34, 0x34, 0x35, 0x39, 0x32, 0x33, 0x30, 0x37, 0x38, 0x31, 0x36, 0x34, 0x30, 0x36, 0x32, 0x38, 0x36, 0x32, 0x30, 0x38, 0x39, 0x39, 0x38, 0x36, 0x32, 0x38, 0x30, 0x33, 0x34, 0x38, 0x32, 0x35, 0x33, 0x34, 0x32, 0x31, 0x31, 0x37, 0x30, 0x36, 0x37, 0x39, 0x38, 0x32, 0x31, 0x34, 0x38, 0x30, 0x38, 0x36, 0x35, 0x31, 0x33, 0x32, 0x38, 0x32, 0x33, 0x30, 0x36, 0x36, 0x34, 0x37, 0x30, 0x39, 0x33, 0x38, 0x34, 0x34, 0x36, 0x30, 0x39, 0x35, 0x35, 0x30, 0x35, 0x38, 0x32, 0x32, 0x33, 0x31, 0x37, 0x32, 0x35, 0x33, 0x35, 0x39, 0x34, 0x30, 0x38, 0x31, 0x32, 0x38, 0x34, 0x38, 0x31, 0x31, 0x31, 0x37, 0x34, 0x4040007e, 0x34, 0x31, 0x30, 0x32, 0x37, 0x30, 0x31, 0x39, 0x33, 0x38, 0x35, 0x32, 0x31, 0x31, 0x30, 0x35, 0x35, 0x35, 0x39, 0x36, 0x34, 0x34, 0x36, 0x32, 0x32, 0x39, 0x34, 0x38, 0x39, 0x35, 0x34, 0x39, 0x33, 0x30, 0x33, 0x38, 0x31, 0x40400012, 0x32, 0x38, 0x38, 0x31, 0x30, 0x39, 0x37, 0x35, 0x36, 0x36, 0x35, 0x39, 0x33, 0x33, 0x34, 0x34, 0x36, 0x40400047, 0x37, 0x35, 0x36, 0x34, 0x38, 0x32, 0x33, 0x33, 0x37, 0x38, 0x36, 0x37, 0x38, 0x33, 0x31, 0x36, 0x35, 0x32, 0x37, 0x31, 0x32, 0x30, 0x31, 0x39, 0x30, 0x39, 0x31, 0x34, 0x4040001a, 0x35, 0x36, 0x36, 0x39, 0x32, 0x33, 0x34, 0x36, 0x404000b2, 0x36, 0x31, 0x30, 0x34, 0x35, 0x34, 0x33, 0x32, 0x36, 0x40400032, 0x31, 0x33, 0x33, 0x39, 0x33, 0x36, 0x30, 0x37, 0x32, 0x36, 0x30, 0x32, 0x34, 0x39, 0x31, 0x34, 0x31, 0x32, 0x37, 0x33, 0x37, 0x32, 0x34, 0x35, 0x38, 0x37, 0x30, 0x30, 0x36, 0x36, 0x30, 0x36, 0x33, 0x31, 0x35, 0x35, 0x38, 0x38, 0x31, 0x37, 0x34, 0x38, 0x38, 0x31, 0x35, 0x32, 0x30, 0x39, 0x32, 0x30, 0x39, 0x36, 0x32, 0x38, 0x32, 0x39, 0x32, 0x35, 0x34, 0x30, 0x39, 0x31, 0x37, 0x31, 0x35, 0x33, 0x36, 0x34, 0x33, 0x36, 0x37, 0x38, 0x39, 0x32, 0x35, 0x39, 0x30, 0x33, 0x36, 0x30, 0x30, 0x31, 0x31, 0x33, 0x33, 0x30, 0x35, 0x33, 0x30, 0x35, 0x34, 0x38, 0x38, 0x32, 0x30, 0x34, 0x36, 0x36, 0x35, 0x32, 0x31, 0x33, 0x38, 0x34, 0x31, 0x34, 0x36, 0x39, 0x35, 0x31, 0x39, 0x34, 0x31, 0x35, 0x31, 0x31, 0x36, 0x30, 0x39, 0x34, 0x33, 0x33, 0x30, 0x35, 0x37, 0x32, 0x37, 0x30, 0x33, 0x36, 0x35, 0x37, 0x35, 0x39, 0x35, 0x39, 0x31, 0x39, 0x35, 0x33, 0x30, 0x39, 0x32, 0x31, 0x38, 0x36, 0x31, 0x31, 0x37, 0x404000e9, 0x33, 0x32, 0x40400009, 0x39, 0x33, 0x31, 0x30, 0x35, 0x31, 0x31, 0x38, 0x35, 0x34, 0x38, 0x30, 0x37, 0x4040010e, 0x33, 0x37, 0x39, 0x39, 0x36, 0x32, 0x37, 0x34, 0x39, 0x35, 0x36, 0x37, 0x33, 0x35, 0x31, 0x38, 0x38, 0x35, 0x37, 0x35, 0x32, 0x37, 0x32, 0x34, 0x38, 0x39, 0x31, 0x32, 0x32, 0x37, 0x39, 0x33, 0x38, 0x31, 0x38, 0x33, 0x30, 0x31, 0x31, 0x39, 0x34, 0x39, 0x31, 0x32, 0x39, 0x38, 0x33, 0x33, 0x36, 0x37, 0x33, 0x33, 0x36, 0x32, 0x34, 0x34, 0x30, 0x36, 0x35, 0x36, 0x36, 0x34, 0x33, 0x30, 0x38, 0x36, 0x30, 0x32, 0x31, 0x33, 0x39, 0x34, 0x39, 0x34, 0x36, 0x33, 0x39, 0x35, 0x32, 0x32, 0x34, 0x37, 0x33, 0x37, 0x31, 0x39, 0x30, 0x37, 0x30, 0x32, 0x31, 0x37, 0x39, 0x38, 0x40800099, 0x37, 0x30, 0x32, 0x37, 0x37, 0x30, 0x35, 0x33, 0x39, 0x32, 0x31, 0x37, 0x31, 0x37, 0x36, 0x32, 0x39, 0x33, 0x31, 0x37, 0x36, 0x37, 0x35, 0x40800232, 0x37, 0x34, 0x38, 0x31, 0x40400006, 0x36, 0x36, 0x39, 0x34, 0x30, 0x404001e7, 0x30, 0x30, 0x30, 0x35, 0x36, 0x38, 0x31, 0x32, 0x37, 0x31, 0x34, 0x35, 0x32, 0x36, 0x33, 0x35, 0x36, 0x30, 0x38, 0x32, 0x37, 0x37, 0x38, 0x35, 0x37, 0x37, 0x31, 0x33, 0x34, 0x32, 0x37, 0x35, 0x37, 0x37, 0x38, 0x39, 0x36, 0x40400129, 0x33, 0x36, 0x33, 0x37, 0x31, 0x37, 0x38, 0x37, 0x32, 0x31, 0x34, 0x36, 0x38, 0x34, 0x34, 0x30, 0x39, 0x30, 0x31, 0x32, 0x32, 0x34, 0x39, 0x35, 0x33, 0x34, 0x33, 0x30, 0x31, 0x34, 0x36, 0x35, 0x34, 0x39, 0x35, 0x38, 0x35, 0x33, 0x37, 0x31, 0x30, 0x35, 0x30, 0x37, 0x39, 0x404000ca, 0x36, 0x40400153, 0x38, 0x39, 0x32, 0x33, 0x35, 0x34, 0x404001c9, 0x39, 0x35, 0x36, 0x31, 0x31, 0x32, 0x31, 0x32, 0x39, 0x30, 0x32, 0x31, 0x39, 0x36, 0x30, 0x38, 0x36, 0x34, 0x30, 0x33, 0x34, 0x34, 0x31, 0x38, 0x31, 0x35, 0x39, 0x38, 0x31, 0x33, 0x36, 0x32, 0x39, 0x37, 0x37, 0x34, 0x40400074, 0x30, 0x39, 0x39, 0x36, 0x30, 0x35, 0x31, 0x38, 0x37, 0x30, 0x37, 0x32, 0x31, 0x31, 0x33, 0x34, 0x39, 0x40800000, 0x38, 0x33, 0x37, 0x32, 0x39, 0x37, 0x38, 0x30, 0x34, 0x39, 0x39, 0x404002da, 0x39, 0x37, 0x33, 0x31, 0x37, 0x33, 0x32, 0x38, 0x4040018a, 0x36, 0x33, 0x31, 0x38, 0x35, 0x40400301, 0x404002e8, 0x34, 0x35, 0x35, 0x33, 0x34, 0x36, 0x39, 0x30, 0x38, 0x33, 0x30, 0x32, 0x36, 0x34, 0x32, 0x35, 0x32, 0x32, 0x33, 0x30, 0x404002e3, 0x40400267, 0x38, 0x35, 0x30, 0x33, 0x35, 0x32, 0x36, 0x31, 0x39, 0x33, 0x31, 0x31, 0x40400212, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x33, 0x31, 0x33, 0x37, 0x38, 0x33, 0x38, 0x37, 0x35, 0x32, 0x38, 0x38, 0x36, 0x35, 0x38, 0x37, 0x35, 0x33, 0x33, 0x32, 0x30, 0x38, 0x33, 0x38, 0x31, 0x34, 0x32, 0x30, 0x36, 0x40400140, 0x4040012b, 0x31, 0x34, 0x37, 0x33, 0x30, 0x33, 0x35, 0x39, 0x4080032e, 0x39, 0x30, 0x34, 0x32, 0x38, 0x37, 0x35, 0x35, 0x34, 0x36, 0x38, 0x37, 0x33, 0x31, 0x31, 0x35, 0x39, 0x35, 0x40400355, 0x33, 0x38, 0x38, 0x32, 0x33, 0x35, 0x33, 0x37, 0x38, 0x37, 0x35, 0x4080037f, 0x39, 0x4040013a, 0x31, 0x40400148, 0x38, 0x30, 0x35, 0x33, 0x4040018a, 0x32, 0x32, 0x36, 0x38, 0x30, 0x36, 0x36, 0x31, 0x33, 0x30, 0x30, 0x31, 0x39, 0x32, 0x37, 0x38, 0x37, 0x36, 0x36, 0x31, 0x31, 0x31, 0x39, 0x35, 0x39, 0x40400237, 0x36, 0x40800124, 0x38, 0x39, 0x33, 0x38, 0x30, 0x39, 0x35, 0x32, 0x35, 0x37, 0x32, 0x30, 0x31, 0x30, 0x36, 0x35, 0x34, 0x38, 0x35, 0x38, 0x36, 0x33, 0x32, 0x37, 0x4040009a, 0x39, 0x33, 0x36, 0x31, 0x35, 0x33, 0x40400220, 0x4080015c, 0x32, 0x33, 0x30, 0x33, 0x30, 0x31, 0x39, 0x35, 0x32, 0x30, 0x33, 0x35, 0x33, 0x30, 0x31, 0x38, 0x35, 0x32, 0x40400171, 0x40400075, 0x33, 0x36, 0x32, 0x32, 0x35, 0x39, 0x39, 0x34, 0x31, 0x33, 0x40400254, 0x34, 0x39, 0x37, 0x32, 0x31, 0x37, 0x404000de, 0x33, 0x34, 0x37, 0x39, 0x31, 0x33, 0x31, 0x35, 0x31, 0x35, 0x35, 0x37, 0x34, 0x38, 0x35, 0x37, 0x32, 0x34, 0x32, 0x34, 0x35, 0x34, 0x31, 0x35, 0x30, 0x36, 0x39, 0x4040013f, 0x38, 0x32, 0x39, 0x35, 0x33, 0x33, 0x31, 0x31, 0x36, 0x38, 0x36, 0x31, 0x37, 0x32, 0x37, 0x38, 0x40400337, 0x39, 0x30, 0x37, 0x35, 0x30, 0x39, 0x4040010d, 0x37, 0x35, 0x34, 0x36, 0x33, 0x37, 0x34, 0x36, 0x34, 0x39, 0x33, 0x39, 0x33, 0x31, 0x39, 0x32, 0x35, 0x35, 0x30, 0x36, 0x30, 0x34, 0x30, 0x30, 0x39, 0x4040026b, 0x31, 0x36, 0x37, 0x31, 0x31, 0x33, 0x39, 0x30, 0x30, 0x39, 0x38, 0x40400335, 0x34, 0x30, 0x31, 0x32, 0x38, 0x35, 0x38, 0x33, 0x36, 0x31, 0x36, 0x30, 0x33, 0x35, 0x36, 0x33, 0x37, 0x30, 0x37, 0x36, 0x36, 0x30, 0x31, 0x30, 0x34, 0x40400172, 0x38, 0x31, 0x39, 0x34, 0x32, 0x39, 0x4080041e, 0x404000ef, 0x4040028b, 0x37, 0x38, 0x33, 0x37, 0x34, 0x404004a8, 0x38, 0x32, 0x35, 0x35, 0x33, 0x37, 0x40800209, 0x32, 0x36, 0x38, 0x4040002e, 0x34, 0x30, 0x34, 0x37, 0x404001d1, 0x34, 0x404004b5, 0x4040038d, 0x38, 0x34, 0x404003a8, 0x36, 0x40c0031f, 0x33, 0x33, 0x31, 0x33, 0x36, 0x37, 0x37, 0x30, 0x32, 0x38, 0x39, 0x38, 0x39, 0x31, 0x35, 0x32, 0x40400062, 0x35, 0x32, 0x31, 0x36, 0x32, 0x30, 0x35, 0x36, 0x39, 0x36, 0x40400411, 0x30, 0x35, 0x38, 0x40400477, 0x35, 0x40400498, 0x35, 0x31, 0x31, 0x40400209, 0x38, 0x32, 0x34, 0x33, 0x30, 0x30, 0x33, 0x35, 0x35, 0x38, 0x37, 0x36, 0x34, 0x30, 0x32, 0x34, 0x37, 0x34, 0x39, 0x36, 0x34, 0x37, 0x33, 0x32, 0x36, 0x33, 0x4040043e, 0x39, 0x39, 0x32, 0x4040044b, 0x34, 0x32, 0x36, 0x39, 0x40c002c5, 0x37, 0x404001d6, 0x34, 0x4040053d, 0x4040041d, 0x39, 0x33, 0x34, 0x31, 0x37, 0x404001ad, 0x31, 0x32, 0x4040002a, 0x34, 0x4040019e, 0x31, 0x35, 0x30, 0x33, 0x30, 0x32, 0x38, 0x36, 0x31, 0x38, 0x32, 0x39, 0x37, 0x34, 0x35, 0x35, 0x35, 0x37, 0x30, 0x36, 0x37, 0x34, 0x40400135, 0x35, 0x30, 0x35, 0x34, 0x39, 0x34, 0x35, 0x38, 0x404001c5, 0x39, 0x40400051, 0x35, 0x36, 0x404001ec, 0x37, 0x32, 0x31, 0x30, 0x37, 0x39, 0x40400159, 0x33, 0x30, 0x4040010a, 0x33, 0x32, 0x31, 0x31, 0x36, 0x35, 0x33, 0x34, 0x34, 0x39, 0x38, 0x37, 0x32, 0x30, 0x32, 0x37, 0x4040011b, 0x30, 0x32, 0x33, 0x36, 0x34, 0x4040022e, 0x35, 0x34, 0x39, 0x39, 0x31, 0x31, 0x39, 0x38, 0x40400418, 0x34, 0x4040011b, 0x35, 0x33, 0x35, 0x36, 0x36, 0x33, 0x36, 0x39, 0x40400450, 0x32, 0x36, 0x35, 0x404002e4, 0x37, 0x38, 0x36, 0x32, 0x35, 0x35, 0x31, 0x404003da, 0x31, 0x37, 0x35, 0x37, 0x34, 0x36, 0x37, 0x32, 0x38, 0x39, 0x30, 0x39, 0x37, 0x37, 0x37, 0x37, 0x40800453, 0x30, 0x30, 0x30, 0x404005fd, 0x37, 0x30, 0x404004df, 0x36, 0x404003e9, 0x34, 0x39, 0x31, 0x4040041e, 0x40400297, 0x32, 0x31, 0x34, 0x37, 0x37, 0x32, 0x33, 0x35, 0x30, 0x31, 0x34, 0x31, 0x34, 0x40400643, 0x33, 0x35, 0x36, 0x404004af, 0x31, 0x36, 0x31, 0x33, 0x36, 0x31, 0x31, 0x35, 0x37, 0x33, 0x35, 0x32, 0x35, 0x40400504, 0x33, 0x34, 0x4040005b, 0x31, 0x38, 0x4040047b, 0x38, 0x34, 0x404005e7, 0x33, 0x33, 0x32, 0x33, 0x39, 0x30, 0x37, 0x33, 0x39, 0x34, 0x31, 0x34, 0x33, 0x33, 0x33, 0x34, 0x35, 0x34, 0x37, 0x37, 0x36, 0x32, 0x34, 0x40400242, 0x32, 0x35, 0x31, 0x38, 0x39, 0x38, 0x33, 0x35, 0x36, 0x39, 0x34, 0x38, 0x35, 0x35, 0x36, 0x32, 0x30, 0x39, 0x39, 0x32, 0x31, 0x39, 0x32, 0x32, 0x32, 0x31, 0x38, 0x34, 0x32, 0x37, 0x4040023e, 0x32, 0x404000ba, 0x36, 0x38, 0x38, 0x37, 0x36, 0x37, 0x31, 0x37, 0x39, 0x30, 0x40400055, 0x30, 0x40800106, 0x36, 0x36, 0x404003e7, 0x38, 0x38, 0x36, 0x32, 0x37, 0x32, 0x404006dc, 0x31, 0x37, 0x38, 0x36, 0x30, 0x38, 0x35, 0x37, 0x40400073, 0x33, 0x408002fc, 0x37, 0x39, 0x37, 0x36, 0x36, 0x38, 0x31, 0x404002bd, 0x30, 0x30, 0x39, 0x35, 0x33, 0x38, 0x38, 0x40400638, 0x33, 0x404006a5, 0x30, 0x36, 0x38, 0x30, 0x30, 0x36, 0x34, 0x32, 0x32, 0x35, 0x31, 0x32, 0x35, 0x32, 0x4040057b, 0x37, 0x33, 0x39, 0x32, 0x40400297, 0x40400474, 0x34, 0x408006b3, 0x38, 0x36, 0x32, 0x36, 0x39, 0x34, 0x35, 0x404001e5, 0x34, 0x31, 0x39, 0x36, 0x35, 0x32, 0x38, 0x35, 0x30, 0x40400099, 0x4040039c, 0x31, 0x38, 0x36, 0x33, 0x404001be, 0x34, 0x40800154, 0x32, 0x30, 0x33, 0x39, 0x4040058b, 0x34, 0x35, 0x404002bc, 0x32, 0x33, 0x37, 0x4040042c, 0x36, 0x40400510, 0x35, 0x36, 0x40400638, 0x37, 0x31, 0x39, 0x31, 0x37, 0x32, 0x38, 0x40400171, 0x37, 0x36, 0x34, 0x36, 0x35, 0x37, 0x35, 0x37, 0x33, 0x39, 0x40400101, 0x33, 0x38, 0x39, 0x40400748, 0x38, 0x33, 0x32, 0x36, 0x34, 0x35, 0x39, 0x39, 0x35, 0x38, 0x404006a7, 0x30, 0x34, 0x37, 0x38, 0x404001de, 0x40400328, 0x39, 0x4040002d, 0x36, 0x34, 0x30, 0x37, 0x38, 0x39, 0x35, 0x31, 0x4040008e, 0x36, 0x38, 0x33, 0x4040012f, 0x32, 0x35, 0x39, 0x35, 0x37, 0x30, 0x40400468, 0x38, 0x32, 0x32, 0x404002c8, 0x32, 0x4040061b, 0x34, 0x30, 0x37, 0x37, 0x32, 0x36, 0x37, 0x31, 0x39, 0x34, 0x37, 0x38, 0x40400319, 0x38, 0x32, 0x36, 0x30, 0x31, 0x34, 0x37, 0x36, 0x39, 0x39, 0x30, 0x39, 0x404004e8, 0x30, 0x31, 0x33, 0x36, 0x33, 0x39, 0x34, 0x34, 0x33, 0x4040027f, 0x33, 0x30, 0x40400105, 0x32, 0x30, 0x33, 0x34, 0x39, 0x36, 0x32, 0x35, 0x32, 0x34, 0x35, 0x31, 0x37, 0x404003b5, 0x39, 0x36, 0x35, 0x31, 0x34, 0x33, 0x31, 0x34, 0x32, 0x39, 0x38, 0x30, 0x39, 0x31, 0x39, 0x30, 0x36, 0x35, 0x39, 0x32, 0x40400282, 0x37, 0x32, 0x32, 0x31, 0x36, 0x39, 0x36, 0x34, 0x36, 0x40400419, 0x4040007a, 0x35, 0x4040050e, 0x34, 0x40800565, 0x38, 0x40400559, 0x39, 0x37, 0x4040057b, 0x35, 0x34, 0x4040049d, 0x4040023e, 0x37, 0x4040065a, 0x38, 0x34, 0x36, 0x38, 0x31, 0x33, 0x4040008c, 0x36, 0x38, 0x33, 0x38, 0x36, 0x38, 0x39, 0x34, 0x32, 0x37, 0x37, 0x34, 0x31, 0x35, 0x35, 0x39, 0x39, 0x31, 0x38, 0x35, 0x4040005a, 0x32, 0x34, 0x35, 0x39, 0x35, 0x33, 0x39, 0x35, 0x39, 0x34, 0x33, 0x31, 0x404005b7, 0x37, 0x40400012, 0x36, 0x38, 0x30, 0x38, 0x34, 0x35, 0x404002e7, 0x37, 0x33, 0x4040081e, 0x39, 0x35, 0x38, 0x34, 0x38, 0x36, 0x35, 0x33, 0x38, 0x404006e8, 0x36, 0x32, 0x404000f2, 0x36, 0x30, 0x39, 0x404004b6, 0x36, 0x30, 0x38, 0x30, 0x35, 0x31, 0x32, 0x34, 0x33, 0x38, 0x38, 0x34, 0x4040013a, 0x4040000b, 0x34, 0x31, 0x33, 0x4040030f, 0x37, 0x36, 0x32, 0x37, 0x38, 0x40400341, 0x37, 0x31, 0x35, 0x4040059b, 0x33, 0x35, 0x39, 0x39, 0x37, 0x37, 0x30, 0x30, 0x31, 0x32, 0x39, 0x40400472, 0x38, 0x39, 0x34, 0x34, 0x31, 0x40400277, 0x36, 0x38, 0x35, 0x35, 0x4040005f, 0x34, 0x30, 0x36, 0x33, 0x404008e6, 0x32, 0x30, 0x37, 0x32, 0x32, 0x40400158, 0x40800203, 0x34, 0x38, 0x31, 0x35, 0x38, 0x40400205, 0x404001fe, 0x4040027a, 0x40400298, 0x33, 0x39, 0x34, 0x35, 0x32, 0x32, 0x36, 0x37, 0x40c00496, 0x38, 0x4040058a, 0x32, 0x31, 0x404002ea, 0x32, 0x40400387, 0x35, 0x34, 0x36, 0x36, 0x36, 0x4040051b, 0x32, 0x33, 0x39, 0x38, 0x36, 0x34, 0x35, 0x36, 0x404004c4, 0x31, 0x36, 0x33, 0x35, 0x40800253, 0x40400811, 0x37, 0x404008ad, 0x39, 0x38, 0x4040045e, 0x39, 0x33, 0x36, 0x33, 0x34, 0x4040075b, 0x37, 0x34, 0x33, 0x32, 0x34, 0x4040047b, 0x31, 0x35, 0x30, 0x37, 0x36, 0x404004bb, 0x37, 0x39, 0x34, 0x35, 0x31, 0x30, 0x39, 0x4040003e, 0x30, 0x39, 0x34, 0x30, 0x404006a6, 0x38, 0x38, 0x37, 0x39, 0x37, 0x31, 0x30, 0x38, 0x39, 0x33, 0x404008f0, 0x36, 0x39, 0x31, 0x33, 0x36, 0x38, 0x36, 0x37, 0x32, 0x4040025b, 0x404001fe, 0x35, 0x4040053f, 0x40400468, 0x40400801, 0x31, 0x37, 0x39, 0x32, 0x38, 0x36, 0x38, 0x404008cc, 0x38, 0x37, 0x34, 0x37, 0x4080079e, 0x38, 0x32, 0x34, 0x4040097a, 0x38, 0x4040025b, 0x37, 0x31, 0x34, 0x39, 0x30, 0x39, 0x36, 0x37, 0x35, 0x39, 0x38, 0x404006ef, 0x33, 0x36, 0x35, 0x40400134, 0x38, 0x31, 0x4040005c, 0x40400745, 0x40400936, 0x36, 0x38, 0x32, 0x39, 0x4040057e, 0x38, 0x37, 0x32, 0x32, 0x36, 0x35, 0x38, 0x38, 0x30, 0x40400611, 0x35, 0x40400249, 0x34, 0x32, 0x37, 0x30, 0x34, 0x37, 0x37, 0x35, 0x35, 0x4040081e, 0x33, 0x37, 0x39, 0x36, 0x34, 0x31, 0x34, 0x35, 0x31, 0x35, 0x32, 0x404005fd, 0x32, 0x33, 0x34, 0x33, 0x36, 0x34, 0x35, 0x34, 0x404005de, 0x34, 0x34, 0x34, 0x37, 0x39, 0x35, 0x4040003c, 0x40400523, 0x408008e6, 0x34, 0x31, 0x4040052a, 0x33, 0x40400304, 0x35, 0x32, 0x33, 0x31, 0x40800841, 0x31, 0x36, 0x36, 0x31, 0x404008b2, 0x35, 0x39, 0x36, 0x39, 0x35, 0x33, 0x36, 0x32, 0x33, 0x31, 0x34, 0x404005ff, 0x32, 0x34, 0x38, 0x34, 0x39, 0x33, 0x37, 0x31, 0x38, 0x37, 0x31, 0x31, 0x30, 0x31, 0x34, 0x35, 0x37, 0x36, 0x35, 0x34, 0x40400761, 0x30, 0x32, 0x37, 0x39, 0x39, 0x33, 0x34, 0x34, 0x30, 0x33, 0x37, 0x34, 0x32, 0x30, 0x30, 0x37, 0x4040093f, 0x37, 0x38, 0x35, 0x33, 0x39, 0x30, 0x36, 0x32, 0x31, 0x39, 0x40800299, 0x40400345, 0x38, 0x34, 0x37, 0x408003d2, 0x38, 0x33, 0x33, 0x32, 0x31, 0x34, 0x34, 0x35, 0x37, 0x31, 0x40400284, 0x40400776, 0x34, 0x33, 0x35, 0x30, 0x40400928, 0x40400468, 0x35, 0x33, 0x31, 0x39, 0x31, 0x30, 0x34, 0x38, 0x34, 0x38, 0x31, 0x30, 0x30, 0x35, 0x33, 0x37, 0x30, 0x36, 0x404008bc, 0x4080059d, 0x40800781, 0x31, 0x40400559, 0x37, 0x4040031b, 0x35, 0x404007ec, 0x4040040c, 0x36, 0x33, 0x408007dc, 0x34, 0x40400971, 0x4080034e, 0x408003f5, 0x38, 0x4080052d, 0x40800887, 0x39, 0x40400187, 0x39, 0x31, 0x404008ce, 0x38, 0x31, 0x34, 0x36, 0x37, 0x35, 0x31, 0x4040062b, 0x31, 0x32, 0x33, 0x39, 0x40c001a9, 0x39, 0x30, 0x37, 0x31, 0x38, 0x36, 0x34, 0x39, 0x34, 0x32, 0x33, 0x31, 0x39, 0x36, 0x31, 0x35, 0x36, 0x404001ec, 0x404006bc, 0x39, 0x35, 0x40400926, 0x40400469, 0x4040011b, 0x36, 0x30, 0x33, 0x38, 0x40400a25, 0x4040016f, 0x40400384, 0x36, 0x32, 0x4040045a, 0x35, 0x4040084c, 0x36, 0x33, 0x38, 0x39, 0x33, 0x37, 0x37, 0x38, 0x37, 0x404008c5, 0x404000f8, 0x39, 0x37, 0x39, 0x32, 0x30, 0x37, 0x37, 0x33, 0x404005d7, 0x32, 0x31, 0x38, 0x32, 0x35, 0x36, 0x404007df, 0x36, 0x36, 0x404006d6, 0x34, 0x32, 0x4080067e, 0x36, 0x404006e6, 0x34, 0x34, 0x40400024, 0x35, 0x34, 0x39, 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x40400ab3, 0x408003e4, 0x32, 0x30, 0x31, 0x34, 0x39, 0x404004d2, 0x38, 0x35, 0x30, 0x37, 0x33, 0x40400599, 0x36, 0x36, 0x36, 0x30, 0x40400194, 0x32, 0x34, 0x33, 0x34, 0x30, 0x40400087, 0x30, 0x4040076b, 0x38, 0x36, 0x33, 0x40400956, 0x404007e4, 0x4040042b, 0x40400174, 0x35, 0x37, 0x39, 0x36, 0x32, 0x36, 0x38, 0x35, 0x36, 0x40400140, 0x35, 0x30, 0x38, 0x40400523, 0x35, 0x38, 0x37, 0x39, 0x36, 0x39, 0x39, 0x40400711, 0x35, 0x37, 0x34, 0x40400a18, 0x38, 0x34, 0x30, 0x404008b3, 0x31, 0x34, 0x35, 0x39, 0x31, 0x4040078c, 0x37, 0x30, 0x40400234, 0x30, 0x31, 0x40400be7, 0x31, 0x32, 0x40400c74, 0x30, 0x404003c3, 0x33, 0x39, 0x40400b2a, 0x40400112, 0x37, 0x31, 0x35, 0x404003b0, 0x34, 0x32, 0x30, 0x40800bf2, 0x39, 0x40400bc2, 0x30, 0x37, 0x40400341, 0x40400795, 0x40400aaf, 0x40400c62, 0x32, 0x31, 0x40400960, 0x32, 0x35, 0x31, 0x4040057b, 0x40400944, 0x39, 0x32, 0x404001b2, 0x38, 0x32, 0x36, 0x40400b66, 0x32, 0x40400278, 0x33, 0x32, 0x31, 0x35, 0x37, 0x39, 0x31, 0x39, 0x38, 0x34, 0x31, 0x34, 0x4080087b, 0x39, 0x31, 0x36, 0x34, 0x408006e8, 0x39, 0x40800b58, 0x404008db, 0x37, 0x32, 0x32, 0x40400321, 0x35, 0x404008a4, 0x40400141, 0x39, 0x31, 0x30, 0x404000bc, 0x40400c5b, 0x35, 0x32, 0x38, 0x30, 0x31, 0x37, 0x40400231, 0x37, 0x31, 0x32, 0x40400914, 0x38, 0x33, 0x32, 0x40400373, 0x31, 0x40400589, 0x30, 0x39, 0x33, 0x35, 0x33, 0x39, 0x36, 0x35, 0x37, 0x4040064b, 0x31, 0x30, 0x38, 0x33, 0x40400069, 0x35, 0x31, 0x4040077a, 0x40400d5a, 0x31, 0x34, 0x34, 0x34, 0x32, 0x31, 0x30, 0x30, 0x40400202, 0x30, 0x33, 0x4040019c, 0x31, 0x31, 0x30, 0x33, 0x40400c81, 0x40400009, 0x40400026, 0x40c00602, 0x35, 0x31, 0x36, 0x404005d9, 0x40800883, 0x4040092a, 0x35, 0x40800c42, 0x38, 0x35, 0x31, 0x37, 0x31, 0x34, 0x33, 0x37, 0x40400605, 0x4040006d, 0x31, 0x35, 0x35, 0x36, 0x35, 0x30, 0x38, 0x38, 0x404003b9, 0x39, 0x38, 0x39, 0x38, 0x35, 0x39, 0x39, 0x38, 0x32, 0x33, 0x38, 0x404001cf, 0x404009ba, 0x33, 0x4040016c, 0x4040043e, 0x404009c3, 0x38, 0x40800e05, 0x33, 0x32, 0x40400107, 0x35, 0x40400305, 0x33, 0x404001ca, 0x39, 0x4040041b, 0x39, 0x38, 0x4040087d, 0x34, 0x40400cb8, 0x37, 0x4040064b, 0x30, 0x37, 0x404000e5, 0x34, 0x38, 0x31, 0x34, 0x31, 0x40400539, 0x38, 0x35, 0x39, 0x34, 0x36, 0x31, 0x40400bc9, 0x38, 0x30}, + }, + huffTest{ + input: "testdata/huffman-rand-1k.in", + expect: "testdata/huffman-rand-1k.%s.expect", + expectNoInput: "testdata/huffman-rand-1k.%s.expect-noinput", + tokens: []token{0xf8, 0x8b, 0x96, 0x76, 0x48, 0xd, 0x85, 0x94, 0x25, 0x80, 0xaf, 0xc2, 0xfe, 0x8d, 0xe8, 0x20, 0xeb, 0x17, 0x86, 0xc9, 0xb7, 0xc5, 0xde, 0x6, 0xea, 0x7d, 0x18, 0x8b, 0xe7, 0x3e, 0x7, 0xda, 0xdf, 0xff, 0x6c, 0x73, 0xde, 0xcc, 0xe7, 0x6d, 0x8d, 0x4, 0x19, 0x49, 0x7f, 0x47, 0x1f, 0x48, 0x15, 0xb0, 0xe8, 0x9e, 0xf2, 0x31, 0x59, 0xde, 0x34, 0xb4, 0x5b, 0xe5, 0xe0, 0x9, 0x11, 0x30, 0xc2, 0x88, 0x5b, 0x7c, 0x5d, 0x14, 0x13, 0x6f, 0x23, 0xa9, 0xd, 0xbc, 0x2d, 0x23, 0xbe, 0xd9, 0xed, 0x75, 0x4, 0x6c, 0x99, 0xdf, 0xfd, 0x70, 0x66, 0xe6, 0xee, 0xd9, 0xb1, 0x9e, 0x6e, 0x83, 0x59, 0xd5, 0xd4, 0x80, 0x59, 0x98, 0x77, 0x89, 0x43, 0x38, 0xc9, 0xaf, 0x30, 0x32, 0x9a, 0x20, 0x1b, 0x46, 0x3d, 0x67, 0x6e, 0xd7, 0x72, 0x9e, 0x4e, 0x21, 0x4f, 0xc6, 0xe0, 0xd4, 0x7b, 0x4, 0x8d, 0xa5, 0x3, 0xf6, 0x5, 0x9b, 0x6b, 0xdc, 0x2a, 0x93, 0x77, 0x28, 0xfd, 0xb4, 0x62, 0xda, 0x20, 0xe7, 0x1f, 0xab, 0x6b, 0x51, 0x43, 0x39, 0x2f, 0xa0, 0x92, 0x1, 0x6c, 0x75, 0x3e, 0xf4, 0x35, 0xfd, 0x43, 0x2e, 0xf7, 0xa4, 0x75, 0xda, 0xea, 0x9b, 0xa, 0x64, 0xb, 0xe0, 0x23, 0x29, 0xbd, 0xf7, 0xe7, 0x83, 0x3c, 0xfb, 0xdf, 0xb3, 0xae, 0x4f, 0xa4, 0x47, 0x55, 0x99, 0xde, 0x2f, 0x96, 0x6e, 0x1c, 0x43, 0x4c, 0x87, 0xe2, 0x7c, 0xd9, 0x5f, 0x4c, 0x7c, 0xe8, 0x90, 0x3, 0xdb, 0x30, 0x95, 0xd6, 0x22, 0xc, 0x47, 0xb8, 0x4d, 0x6b, 0xbd, 0x24, 0x11, 0xab, 0x2c, 0xd7, 0xbe, 0x6e, 0x7a, 0xd6, 0x8, 0xa3, 0x98, 0xd8, 0xdd, 0x15, 0x6a, 0xfa, 0x93, 0x30, 0x1, 0x25, 0x1d, 0xa2, 0x74, 0x86, 0x4b, 0x6a, 0x95, 0xe8, 0xe1, 0x4e, 0xe, 0x76, 0xb9, 0x49, 0xa9, 0x5f, 0xa0, 0xa6, 0x63, 0x3c, 0x7e, 0x7e, 0x20, 0x13, 0x4f, 0xbb, 0x66, 0x92, 0xb8, 0x2e, 0xa4, 0xfa, 0x48, 0xcb, 0xae, 0xb9, 0x3c, 0xaf, 0xd3, 0x1f, 0xe1, 0xd5, 0x8d, 0x42, 0x6d, 0xf0, 0xfc, 0x8c, 0xc, 0x0, 0xde, 0x40, 0xab, 0x8b, 0x47, 0x97, 0x4e, 0xa8, 0xcf, 0x8e, 0xdb, 0xa6, 0x8b, 0x20, 0x9, 0x84, 0x7a, 0x66, 0xe5, 0x98, 0x29, 0x2, 0x95, 0xe6, 0x38, 0x32, 0x60, 0x3, 0xe3, 0x9a, 0x1e, 0x54, 0xe8, 0x63, 0x80, 0x48, 0x9c, 0xe7, 0x63, 0x33, 0x6e, 0xa0, 0x65, 0x83, 0xfa, 0xc6, 0xba, 0x7a, 0x43, 0x71, 0x5, 0xf5, 0x68, 0x69, 0x85, 0x9c, 0xba, 0x45, 0xcd, 0x6b, 0xb, 0x19, 0xd1, 0xbb, 0x7f, 0x70, 0x85, 0x92, 0xd1, 0xb4, 0x64, 0x82, 0xb1, 0xe4, 0x62, 0xc5, 0x3c, 0x46, 0x1f, 0x92, 0x31, 0x1c, 0x4e, 0x41, 0x77, 0xf7, 0xe7, 0x87, 0xa2, 0xf, 0x6e, 0xe8, 0x92, 0x3, 0x6b, 0xa, 0xe7, 0xa9, 0x3b, 0x11, 0xda, 0x66, 0x8a, 0x29, 0xda, 0x79, 0xe1, 0x64, 0x8d, 0xe3, 0x54, 0xd4, 0xf5, 0xef, 0x64, 0x87, 0x3b, 0xf4, 0xc2, 0xf4, 0x71, 0x13, 0xa9, 0xe9, 0xe0, 0xa2, 0x6, 0x14, 0xab, 0x5d, 0xa7, 0x96, 0x0, 0xd6, 0xc3, 0xcc, 0x57, 0xed, 0x39, 0x6a, 0x25, 0xcd, 0x76, 0xea, 0xba, 0x3a, 0xf2, 0xa1, 0x95, 0x5d, 0xe5, 0x71, 0xcf, 0x9c, 0x62, 0x9e, 0x6a, 0xfa, 0xd5, 0x31, 0xd1, 0xa8, 0x66, 0x30, 0x33, 0xaa, 0x51, 0x17, 0x13, 0x82, 0x99, 0xc8, 0x14, 0x60, 0x9f, 0x4d, 0x32, 0x6d, 0xda, 0x19, 0x26, 0x21, 0xdc, 0x7e, 0x2e, 0x25, 0x67, 0x72, 0xca, 0xf, 0x92, 0xcd, 0xf6, 0xd6, 0xcb, 0x97, 0x8a, 0x33, 0x58, 0x73, 0x70, 0x91, 0x1d, 0xbf, 0x28, 0x23, 0xa3, 0xc, 0xf1, 0x83, 0xc3, 0xc8, 0x56, 0x77, 0x68, 0xe3, 0x82, 0xba, 0xb9, 0x57, 0x56, 0x57, 0x9c, 0xc3, 0xd6, 0x14, 0x5, 0x3c, 0xb1, 0xaf, 0x93, 0xc8, 0x8a, 0x57, 0x7f, 0x53, 0xfa, 0x2f, 0xaa, 0x6e, 0x66, 0x83, 0xfa, 0x33, 0xd1, 0x21, 0xab, 0x1b, 0x71, 0xb4, 0x7c, 0xda, 0xfd, 0xfb, 0x7f, 0x20, 0xab, 0x5e, 0xd5, 0xca, 0xfd, 0xdd, 0xe0, 0xee, 0xda, 0xba, 0xa8, 0x27, 0x99, 0x97, 0x69, 0xc1, 0x3c, 0x82, 0x8c, 0xa, 0x5c, 0x2d, 0x5b, 0x88, 0x3e, 0x34, 0x35, 0x86, 0x37, 0x46, 0x79, 0xe1, 0xaa, 0x19, 0xfb, 0xaa, 0xde, 0x15, 0x9, 0xd, 0x1a, 0x57, 0xff, 0xb5, 0xf, 0xf3, 0x2b, 0x5a, 0x6a, 0x4d, 0x19, 0x77, 0x71, 0x45, 0xdf, 0x4f, 0xb3, 0xec, 0xf1, 0xeb, 0x18, 0x53, 0x3e, 0x3b, 0x47, 0x8, 0x9a, 0x73, 0xa0, 0x5c, 0x8c, 0x5f, 0xeb, 0xf, 0x3a, 0xc2, 0x43, 0x67, 0xb4, 0x66, 0x67, 0x80, 0x58, 0xe, 0xc1, 0xec, 0x40, 0xd4, 0x22, 0x94, 0xca, 0xf9, 0xe8, 0x92, 0xe4, 0x69, 0x38, 0xbe, 0x67, 0x64, 0xca, 0x50, 0xc7, 0x6, 0x67, 0x42, 0x6e, 0xa3, 0xf0, 0xb7, 0x6c, 0xf2, 0xe8, 0x5f, 0xb1, 0xaf, 0xe7, 0xdb, 0xbb, 0x77, 0xb5, 0xf8, 0xcb, 0x8, 0xc4, 0x75, 0x7e, 0xc0, 0xf9, 0x1c, 0x7f, 0x3c, 0x89, 0x2f, 0xd2, 0x58, 0x3a, 0xe2, 0xf8, 0x91, 0xb6, 0x7b, 0x24, 0x27, 0xe9, 0xae, 0x84, 0x8b, 0xde, 0x74, 0xac, 0xfd, 0xd9, 0xb7, 0x69, 0x2a, 0xec, 0x32, 0x6f, 0xf0, 0x92, 0x84, 0xf1, 0x40, 0xc, 0x8a, 0xbc, 0x39, 0x6e, 0x2e, 0x73, 0xd4, 0x6e, 0x8a, 0x74, 0x2a, 0xdc, 0x60, 0x1f, 0xa3, 0x7, 0xde, 0x75, 0x8b, 0x74, 0xc8, 0xfe, 0x63, 0x75, 0xf6, 0x3d, 0x63, 0xac, 0x33, 0x89, 0xc3, 0xf0, 0xf8, 0x2d, 0x6b, 0xb4, 0x9e, 0x74, 0x8b, 0x5c, 0x33, 0xb4, 0xca, 0xa8, 0xe4, 0x99, 0xb6, 0x90, 0xa1, 0xef, 0xf, 0xd3, 0x61, 0xb2, 0xc6, 0x1a, 0x94, 0x7c, 0x44, 0x55, 0xf4, 0x45, 0xff, 0x9e, 0xa5, 0x5a, 0xc6, 0xa0, 0xe8, 0x2a, 0xc1, 0x8d, 0x6f, 0x34, 0x11, 0xb9, 0xbe, 0x4e, 0xd9, 0x87, 0x97, 0x73, 0xcf, 0x3d, 0x23, 0xae, 0xd5, 0x1a, 0x5e, 0xae, 0x5d, 0x6a, 0x3, 0xf9, 0x22, 0xd, 0x10, 0xd9, 0x47, 0x69, 0x15, 0x3f, 0xee, 0x52, 0xa3, 0x8, 0xd2, 0x3c, 0x51, 0xf4, 0xf8, 0x9d, 0xe4, 0x98, 0x89, 0xc8, 0x67, 0x39, 0xd5, 0x5e, 0x35, 0x78, 0x27, 0xe8, 0x3c, 0x80, 0xae, 0x79, 0x71, 0xd2, 0x93, 0xf4, 0xaa, 0x51, 0x12, 0x1c, 0x4b, 0x1b, 0xe5, 0x6e, 0x15, 0x6f, 0xe4, 0xbb, 0x51, 0x9b, 0x45, 0x9f, 0xf9, 0xc4, 0x8c, 0x2a, 0xfb, 0x1a, 0xdf, 0x55, 0xd3, 0x48, 0x93, 0x27, 0x1, 0x26, 0xc2, 0x6b, 0x55, 0x6d, 0xa2, 0xfb, 0x84, 0x8b, 0xc9, 0x9e, 0x28, 0xc2, 0xef, 0x1a, 0x24, 0xec, 0x9b, 0xae, 0xbd, 0x60, 0xe9, 0x15, 0x35, 0xee, 0x42, 0xa4, 0x33, 0x5b, 0xfa, 0xf, 0xb6, 0xf7, 0x1, 0xa6, 0x2, 0x4c, 0xca, 0x90, 0x58, 0x3a, 0x96, 0x41, 0xe7, 0xcb, 0x9, 0x8c, 0xdb, 0x85, 0x4d, 0xa8, 0x89, 0xf3, 0xb5, 0x8e, 0xfd, 0x75, 0x5b, 0x4f, 0xed, 0xde, 0x3f, 0xeb, 0x38, 0xa3, 0xbe, 0xb0, 0x73, 0xfc, 0xb8, 0x54, 0xf7, 0x4c, 0x30, 0x67, 0x2e, 0x38, 0xa2, 0x54, 0x18, 0xba, 0x8, 0xbf, 0xf2, 0x39, 0xd5, 0xfe, 0xa5, 0x41, 0xc6, 0x66, 0x66, 0xba, 0x81, 0xef, 0x67, 0xe4, 0xe6, 0x3c, 0xc, 0xca, 0xa4, 0xa, 0x79, 0xb3, 0x57, 0x8b, 0x8a, 0x75, 0x98, 0x18, 0x42, 0x2f, 0x29, 0xa3, 0x82, 0xef, 0x9f, 0x86, 0x6, 0x23, 0xe1, 0x75, 0xfa, 0x8, 0xb1, 0xde, 0x17, 0x4a}, + }, + huffTest{ + input: "testdata/huffman-rand-limit.in", + expect: "testdata/huffman-rand-limit.%s.expect", + expectNoInput: "testdata/huffman-rand-limit.%s.expect-noinput", + tokens: []token{0x61, 0x51c00000, 0xa, 0xf8, 0x8b, 0x96, 0x76, 0x48, 0xa, 0x85, 0x94, 0x25, 0x80, 0xaf, 0xc2, 0xfe, 0x8d, 0xe8, 0x20, 0xeb, 0x17, 0x86, 0xc9, 0xb7, 0xc5, 0xde, 0x6, 0xea, 0x7d, 0x18, 0x8b, 0xe7, 0x3e, 0x7, 0xda, 0xdf, 0xff, 0x6c, 0x73, 0xde, 0xcc, 0xe7, 0x6d, 0x8d, 0x4, 0x19, 0x49, 0x7f, 0x47, 0x1f, 0x48, 0x15, 0xb0, 0xe8, 0x9e, 0xf2, 0x31, 0x59, 0xde, 0x34, 0xb4, 0x5b, 0xe5, 0xe0, 0x9, 0x11, 0x30, 0xc2, 0x88, 0x5b, 0x7c, 0x5d, 0x14, 0x13, 0x6f, 0x23, 0xa9, 0xa, 0xbc, 0x2d, 0x23, 0xbe, 0xd9, 0xed, 0x75, 0x4, 0x6c, 0x99, 0xdf, 0xfd, 0x70, 0x66, 0xe6, 0xee, 0xd9, 0xb1, 0x9e, 0x6e, 0x83, 0x59, 0xd5, 0xd4, 0x80, 0x59, 0x98, 0x77, 0x89, 0x43, 0x38, 0xc9, 0xaf, 0x30, 0x32, 0x9a, 0x20, 0x1b, 0x46, 0x3d, 0x67, 0x6e, 0xd7, 0x72, 0x9e, 0x4e, 0x21, 0x4f, 0xc6, 0xe0, 0xd4, 0x7b, 0x4, 0x8d, 0xa5, 0x3, 0xf6, 0x5, 0x9b, 0x6b, 0xdc, 0x2a, 0x93, 0x77, 0x28, 0xfd, 0xb4, 0x62, 0xda, 0x20, 0xe7, 0x1f, 0xab, 0x6b, 0x51, 0x43, 0x39, 0x2f, 0xa0, 0x92, 0x1, 0x6c, 0x75, 0x3e, 0xf4, 0x35, 0xfd, 0x43, 0x2e, 0xf7, 0xa4, 0x75, 0xda, 0xea, 0x9b, 0xa}, + }, + huffTest{ + input: "testdata/huffman-shifts.in", + expect: "testdata/huffman-shifts.%s.expect", + expectNoInput: "testdata/huffman-shifts.%s.expect-noinput", + tokens: []token{0x31, 0x30, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x52400001, 0xd, 0xa, 0x32, 0x33, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7f400001}, + }, + huffTest{ + input: "testdata/huffman-text-shift.in", + expect: "testdata/huffman-text-shift.%s.expect", + expectNoInput: "testdata/huffman-text-shift.%s.expect-noinput", + tokens: []token{0x2f, 0x2f, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x32, 0x30, 0x30, 0x39, 0x54, 0x68, 0x47, 0x6f, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x2e, 0x41, 0x6c, 0x6c, 0x40800016, 0x72, 0x72, 0x76, 0x64, 0x2e, 0xd, 0xa, 0x2f, 0x2f, 0x55, 0x6f, 0x66, 0x74, 0x68, 0x69, 0x6f, 0x75, 0x72, 0x63, 0x63, 0x6f, 0x64, 0x69, 0x67, 0x6f, 0x76, 0x72, 0x6e, 0x64, 0x62, 0x79, 0x42, 0x53, 0x44, 0x2d, 0x74, 0x79, 0x6c, 0x40400020, 0x6c, 0x69, 0x63, 0x6e, 0x74, 0x68, 0x74, 0x63, 0x6e, 0x62, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x74, 0x68, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x66, 0x69, 0x6c, 0x2e, 0xd, 0xa, 0xd, 0xa, 0x70, 0x63, 0x6b, 0x67, 0x6d, 0x69, 0x6e, 0x4040000a, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x6f, 0x22, 0x4040000c, 0x66, 0x75, 0x6e, 0x63, 0x6d, 0x69, 0x6e, 0x28, 0x29, 0x7b, 0xd, 0xa, 0x9, 0x76, 0x72, 0x62, 0x3d, 0x6d, 0x6b, 0x28, 0x5b, 0x5d, 0x62, 0x79, 0x74, 0x2c, 0x36, 0x35, 0x35, 0x33, 0x35, 0x29, 0xd, 0xa, 0x9, 0x66, 0x2c, 0x5f, 0x3a, 0x3d, 0x6f, 0x2e, 0x43, 0x72, 0x74, 0x28, 0x22, 0x68, 0x75, 0x66, 0x66, 0x6d, 0x6e, 0x2d, 0x6e, 0x75, 0x6c, 0x6c, 0x2d, 0x6d, 0x78, 0x2e, 0x69, 0x6e, 0x22, 0x40800021, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x28, 0x62, 0x29, 0xd, 0xa, 0x7d, 0xd, 0xa, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x58, 0x78, 0x79, 0x7a, 0x21, 0x22, 0x23, 0xc2, 0xa4, 0x25, 0x26, 0x2f, 0x3f, 0x22}, + }, + huffTest{ + input: "testdata/huffman-text.in", + expect: "testdata/huffman-text.%s.expect", + expectNoInput: "testdata/huffman-text.%s.expect-noinput", + tokens: []token{0x2f, 0x2f, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x54, 0x68, 0x65, 0x20, 0x47, 0x6f, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x4080001e, 0x73, 0x20, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x2e, 0xd, 0xa, 0x2f, 0x2f, 0x20, 0x55, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x73, 0x20, 0x67, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x61, 0x20, 0x42, 0x53, 0x44, 0x2d, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x40800036, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0xd, 0xa, 0xd, 0xa, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x4040000f, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x22, 0x6f, 0x73, 0x22, 0x4040000e, 0x66, 0x75, 0x6e, 0x63, 0x4080001b, 0x28, 0x29, 0x20, 0x7b, 0xd, 0xa, 0x9, 0x76, 0x61, 0x72, 0x20, 0x62, 0x20, 0x3d, 0x20, 0x6d, 0x61, 0x6b, 0x65, 0x28, 0x5b, 0x5d, 0x62, 0x79, 0x74, 0x65, 0x2c, 0x20, 0x36, 0x35, 0x35, 0x33, 0x35, 0x29, 0xd, 0xa, 0x9, 0x66, 0x2c, 0x20, 0x5f, 0x20, 0x3a, 0x3d, 0x20, 0x6f, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x28, 0x22, 0x68, 0x75, 0x66, 0x66, 0x6d, 0x61, 0x6e, 0x2d, 0x6e, 0x75, 0x6c, 0x6c, 0x2d, 0x6d, 0x61, 0x78, 0x2e, 0x69, 0x6e, 0x22, 0x4080002a, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x28, 0x62, 0x29, 0xd, 0xa, 0x7d, 0xd, 0xa}, + }, + huffTest{ + input: "testdata/huffman-zero.in", + expect: "testdata/huffman-zero.%s.expect", + expectNoInput: "testdata/huffman-zero.%s.expect-noinput", + tokens: []token{0x30, 0x7fc00000, 0x4b800000}, + }, + huffTest{ + input: "", + expect: "", + expectNoInput: "testdata/null-long-match.%s.expect-noinput", + tokens: []token{0x0, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x7fc00000, 0x41400000}, + }, +} + +// TestWriteBlock will test that if encoding in writeBlock is changed +// it will become visible. +// To update the reference files use the "-update" parameter on the test. +func TestWriteBlock(t *testing.T) { + for _, test := range writeBlockTests { + testBlock(t, test, "wb") + } +} + +// TestWriteBlock will test that if encoding in writeBlockDynamic is changed +// it will become visible. +// To update the reference files use the "-update" parameter on the test. +func TestWriteBlockDynamic(t *testing.T) { + for _, test := range writeBlockTests { + testBlock(t, test, "dyn") + } +} + +// testBlock will test a block against its references, +// or regenerate the references, if "-update" is set. +func testBlock(t *testing.T, test huffTest, ttype string) { + if test.expect != "" { + test.expect = fmt.Sprintf(test.expect, ttype) + } + test.expectNoInput = fmt.Sprintf(test.expectNoInput, ttype) + if *update { + if test.input != "" { + t.Logf("Updating %q", test.expect) + input, err := ioutil.ReadFile(test.input) + if err != nil { + t.Error(err) + return + } + + f, err := os.Create(test.expect) + if err != nil { + t.Fatal(err) + } + defer f.Close() + bw := newHuffmanBitWriter(f) + writeToType(t, ttype, bw, test.tokens, input) + } + + t.Logf("Updating %q", test.expectNoInput) + f, err := os.Create(test.expectNoInput) + if err != nil { + t.Fatal(err) + } + defer f.Close() + bw := newHuffmanBitWriter(f) + writeToType(t, ttype, bw, test.tokens, nil) + return + } + + if test.input != "" { + t.Logf("Testing %q", test.expect) + input, err := ioutil.ReadFile(test.input) + if err != nil { + t.Error(err) + return + } + expect, err := ioutil.ReadFile(test.expect) + if err != nil { + t.Error(err) + return + } + var buf bytes.Buffer + bw := newHuffmanBitWriter(&buf) + writeToType(t, ttype, bw, test.tokens, input) + + got := buf.Bytes() + if !bytes.Equal(got, expect) { + t.Errorf("writeBlock did not yield expected result for file %q with input. See %q", test.expect, test.expect+".got") + if err := ioutil.WriteFile(test.expect+".got", got, 0666); err != nil { + t.Error(err) + } + } + t.Log("Output ok") + + // Test if the writer produces the same output after reset. + buf.Reset() + bw.reset(&buf) + writeToType(t, ttype, bw, test.tokens, input) + bw.flush() + got = buf.Bytes() + if !bytes.Equal(got, expect) { + t.Errorf("reset: writeBlock did not yield expected result for file %q with input. See %q", test.expect, test.expect+".reset.got") + if err := ioutil.WriteFile(test.expect+".reset.got", got, 0666); err != nil { + t.Error(err) + } + return + } + t.Log("Reset ok") + testWriterEOF(t, "wb", test, true) + } + t.Logf("Testing %q", test.expectNoInput) + expectN, err := ioutil.ReadFile(test.expectNoInput) + if err != nil { + t.Error(err) + return + } + var buf bytes.Buffer + bw := newHuffmanBitWriter(&buf) + writeToType(t, ttype, bw, test.tokens, nil) + + got := buf.Bytes() + if !bytes.Equal(got, expectN) { + t.Errorf("writeBlock did not yield expected result for file %q with input. See %q", test.expectNoInput, test.expectNoInput+".got") + if err := ioutil.WriteFile(test.expect+".got", got, 0666); err != nil { + t.Error(err) + } + } else if got[0]&1 == 1 { + t.Error("got unexpected EOF") + return + } + + t.Log("Output ok") + + // Test if the writer produces the same output after reset. + buf.Reset() + bw.reset(&buf) + writeToType(t, ttype, bw, test.tokens, nil) + bw.flush() + got = buf.Bytes() + if !bytes.Equal(got, expectN) { + t.Errorf("reset: writeBlock did not yield expected result for file %q without input. See %q", test.expect, test.expect+".reset.got") + if err := ioutil.WriteFile(test.expect+".reset.got", got, 0666); err != nil { + t.Error(err) + } + return + } + t.Log("Reset ok") + testWriterEOF(t, "wb", test, false) +} + +func writeToType(t *testing.T, ttype string, bw *huffmanBitWriter, tok []token, input []byte) { + switch ttype { + case "wb": + bw.writeBlock(toTokens(tok), false, input) + case "dyn": + bw.writeBlockDynamic(toTokens(tok), false, input) + default: + panic("unknown test type") + } + + if bw.err != nil { + t.Error(bw.err) + return + } + + bw.flush() + if bw.err != nil { + t.Error(bw.err) + return + } +} + +func toTokens(in []token) tokens { + var t = tokens{n: len(in), tokens: make([]token, maxFlateBlockTokens)} + copy(t.tokens, in) + return t +} + +// testWriterEOF will test if the written block contains an EOF marker. +func testWriterEOF(t *testing.T, ttype string, test huffTest, useInput bool) { + if useInput && test.input == "" { + return + } + var input []byte + if useInput { + var err error + input, err = ioutil.ReadFile(test.input) + if err != nil { + t.Error(err) + return + } + } + var buf bytes.Buffer + bw := newHuffmanBitWriter(&buf) + switch ttype { + case "wb": + bw.writeBlock(toTokens(test.tokens), true, input) + case "dyn": + bw.writeBlockDynamic(toTokens(test.tokens), true, input) + case "huff": + bw.writeBlockHuff(true, input) + default: + panic("unknown test type") + } + if bw.err != nil { + t.Error(bw.err) + return + } + + bw.flush() + if bw.err != nil { + t.Error(bw.err) + return + } + b := buf.Bytes() + if len(b) == 0 { + t.Fatal("no output received") + } + if b[0]&1 != 1 { + t.Errorf("block not marked with EOF for input %q", test.input) + return + } + t.Log("EOF ok") +} diff --git a/vendor/github.com/klauspost/compress/flate/huffman_code.go b/vendor/github.com/klauspost/compress/flate/huffman_code.go new file mode 100644 index 0000000..9dba0fa --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/huffman_code.go @@ -0,0 +1,363 @@ +// Copyright 2009 The Go 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 flate + +import ( + "math" + "sort" +) + +type hcode uint32 + +type huffmanEncoder struct { + codes []hcode + freqcache []literalNode + bitCount [17]int32 + lns literalNodeSorter + lfs literalFreqSorter +} + +type literalNode struct { + literal uint16 + freq int32 +} + +// A levelInfo describes the state of the constructed tree for a given depth. +type levelInfo struct { + // Our level. for better printing + level int32 + + // The frequency of the last node at this level + lastFreq int32 + + // The frequency of the next character to add to this level + nextCharFreq int32 + + // The frequency of the next pair (from level below) to add to this level. + // Only valid if the "needed" value of the next lower level is 0. + nextPairFreq int32 + + // The number of chains remaining to generate for this level before moving + // up to the next level + needed int32 +} + +func (h hcode) codeBits() (code uint16, bits uint8) { + return uint16(h), uint8(h >> 16) +} + +func (h *hcode) set(code uint16, bits uint8) { + *h = hcode(code) | hcode(uint32(bits)<<16) +} + +func (h *hcode) setBits(bits uint8) { + *h = hcode(*h&0xffff) | hcode(uint32(bits)<<16) +} + +func toCode(code uint16, bits uint8) hcode { + return hcode(code) | hcode(uint32(bits)<<16) +} + +func (h hcode) code() (code uint16) { + return uint16(h) +} + +func (h hcode) bits() (bits uint) { + return uint(h >> 16) +} + +func maxNode() literalNode { return literalNode{math.MaxUint16, math.MaxInt32} } + +func newHuffmanEncoder(size int) *huffmanEncoder { + return &huffmanEncoder{codes: make([]hcode, size), freqcache: nil} +} + +// Generates a HuffmanCode corresponding to the fixed literal table +func generateFixedLiteralEncoding() *huffmanEncoder { + h := newHuffmanEncoder(maxNumLit) + codes := h.codes + var ch uint16 + for ch = 0; ch < maxNumLit; ch++ { + var bits uint16 + var size uint8 + switch { + case ch < 144: + // size 8, 000110000 .. 10111111 + bits = ch + 48 + size = 8 + break + case ch < 256: + // size 9, 110010000 .. 111111111 + bits = ch + 400 - 144 + size = 9 + break + case ch < 280: + // size 7, 0000000 .. 0010111 + bits = ch - 256 + size = 7 + break + default: + // size 8, 11000000 .. 11000111 + bits = ch + 192 - 280 + size = 8 + } + codes[ch] = toCode(reverseBits(bits, size), size) + } + return h +} + +func generateFixedOffsetEncoding() *huffmanEncoder { + h := newHuffmanEncoder(30) + codes := h.codes + for ch := uint16(0); ch < 30; ch++ { + codes[ch] = toCode(reverseBits(ch, 5), 5) + } + return h +} + +var fixedLiteralEncoding *huffmanEncoder = generateFixedLiteralEncoding() +var fixedOffsetEncoding *huffmanEncoder = generateFixedOffsetEncoding() + +func (h *huffmanEncoder) bitLength(freq []int32) int64 { + var total int64 + for i, f := range freq { + if f != 0 { + total += int64(f) * int64(h.codes[i].bits()) + } + } + return total +} + +const maxBitsLimit = 16 + +// Return the number of literals assigned to each bit size in the Huffman encoding +// +// This method is only called when list.length >= 3 +// The cases of 0, 1, and 2 literals are handled by special case code. +// +// list An array of the literals with non-zero frequencies +// and their associated frequencies. The array is in order of increasing +// frequency, and has as its last element a special element with frequency +// MaxInt32 +// maxBits The maximum number of bits that should be used to encode any literal. +// Must be less than 16. +// return An integer array in which array[i] indicates the number of literals +// that should be encoded in i bits. +func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 { + if maxBits >= maxBitsLimit { + panic("flate: maxBits too large") + } + n := int32(len(list)) + list = list[0 : n+1] + list[n] = maxNode() + + // The tree can't have greater depth than n - 1, no matter what. This + // saves a little bit of work in some small cases + if maxBits > n-1 { + maxBits = n - 1 + } + + // Create information about each of the levels. + // A bogus "Level 0" whose sole purpose is so that + // level1.prev.needed==0. This makes level1.nextPairFreq + // be a legitimate value that never gets chosen. + var levels [maxBitsLimit]levelInfo + // leafCounts[i] counts the number of literals at the left + // of ancestors of the rightmost node at level i. + // leafCounts[i][j] is the number of literals at the left + // of the level j ancestor. + var leafCounts [maxBitsLimit][maxBitsLimit]int32 + + for level := int32(1); level <= maxBits; level++ { + // For every level, the first two items are the first two characters. + // We initialize the levels as if we had already figured this out. + levels[level] = levelInfo{ + level: level, + lastFreq: list[1].freq, + nextCharFreq: list[2].freq, + nextPairFreq: list[0].freq + list[1].freq, + } + leafCounts[level][level] = 2 + if level == 1 { + levels[level].nextPairFreq = math.MaxInt32 + } + } + + // We need a total of 2*n - 2 items at top level and have already generated 2. + levels[maxBits].needed = 2*n - 4 + + level := maxBits + for { + l := &levels[level] + if l.nextPairFreq == math.MaxInt32 && l.nextCharFreq == math.MaxInt32 { + // We've run out of both leafs and pairs. + // End all calculations for this level. + // To make sure we never come back to this level or any lower level, + // set nextPairFreq impossibly large. + l.needed = 0 + levels[level+1].nextPairFreq = math.MaxInt32 + level++ + continue + } + + prevFreq := l.lastFreq + if l.nextCharFreq < l.nextPairFreq { + // The next item on this row is a leaf node. + n := leafCounts[level][level] + 1 + l.lastFreq = l.nextCharFreq + // Lower leafCounts are the same of the previous node. + leafCounts[level][level] = n + l.nextCharFreq = list[n].freq + } else { + // The next item on this row is a pair from the previous row. + // nextPairFreq isn't valid until we generate two + // more values in the level below + l.lastFreq = l.nextPairFreq + // Take leaf counts from the lower level, except counts[level] remains the same. + copy(leafCounts[level][:level], leafCounts[level-1][:level]) + levels[l.level-1].needed = 2 + } + + if l.needed--; l.needed == 0 { + // We've done everything we need to do for this level. + // Continue calculating one level up. Fill in nextPairFreq + // of that level with the sum of the two nodes we've just calculated on + // this level. + if l.level == maxBits { + // All done! + break + } + levels[l.level+1].nextPairFreq = prevFreq + l.lastFreq + level++ + } else { + // If we stole from below, move down temporarily to replenish it. + for levels[level-1].needed > 0 { + level-- + } + } + } + + // Somethings is wrong if at the end, the top level is null or hasn't used + // all of the leaves. + if leafCounts[maxBits][maxBits] != n { + panic("leafCounts[maxBits][maxBits] != n") + } + + bitCount := h.bitCount[:maxBits+1] + //make([]int32, maxBits+1) + bits := 1 + counts := &leafCounts[maxBits] + for level := maxBits; level > 0; level-- { + // chain.leafCount gives the number of literals requiring at least "bits" + // bits to encode. + bitCount[bits] = counts[level] - counts[level-1] + bits++ + } + return bitCount +} + +// Look at the leaves and assign them a bit count and an encoding as specified +// in RFC 1951 3.2.2 +func (h *huffmanEncoder) assignEncodingAndSize(bitCount []int32, list []literalNode) { + code := uint16(0) + for n, bits := range bitCount { + code <<= 1 + if n == 0 || bits == 0 { + continue + } + // The literals list[len(list)-bits] .. list[len(list)-bits] + // are encoded using "bits" bits, and get the values + // code, code + 1, .... The code values are + // assigned in literal order (not frequency order). + chunk := list[len(list)-int(bits):] + + h.lns.Sort(chunk) + for _, node := range chunk { + h.codes[node.literal] = toCode(reverseBits(code, uint8(n)), uint8(n)) + code++ + } + list = list[0 : len(list)-int(bits)] + } +} + +// Update this Huffman Code object to be the minimum code for the specified frequency count. +// +// freq An array of frequencies, in which frequency[i] gives the frequency of literal i. +// maxBits The maximum number of bits to use for any literal. +func (h *huffmanEncoder) generate(freq []int32, maxBits int32) { + if h.freqcache == nil { + h.freqcache = make([]literalNode, 300) + } + list := h.freqcache[:len(freq)+1] + // Number of non-zero literals + count := 0 + // Set list to be the set of all non-zero literals and their frequencies + for i, f := range freq { + if f != 0 { + list[count] = literalNode{uint16(i), f} + count++ + } else { + list[count] = literalNode{} + //h.codeBits[i] = 0 + h.codes[i].setBits(0) + } + } + list[len(freq)] = literalNode{} + // If freq[] is shorter than codeBits[], fill rest of codeBits[] with zeros + // FIXME: Doesn't do what it says on the tin (klauspost) + //h.codeBits = h.codeBits[0:len(freq)] + + list = list[0:count] + if count <= 2 { + // Handle the small cases here, because they are awkward for the general case code. With + // two or fewer literals, everything has bit length 1. + for i, node := range list { + // "list" is in order of increasing literal value. + h.codes[node.literal].set(uint16(i), 1) + //h.codeBits[node.literal] = 1 + //h.code[node.literal] = uint16(i) + } + return + } + h.lfs.Sort(list) + + // Get the number of literals for each bit count + bitCount := h.bitCounts(list, maxBits) + // And do the assignment + h.assignEncodingAndSize(bitCount, list) +} + +type literalNodeSorter []literalNode + +func (s *literalNodeSorter) Sort(a []literalNode) { + *s = literalNodeSorter(a) + sort.Sort(s) +} + +func (s literalNodeSorter) Len() int { return len(s) } + +func (s literalNodeSorter) Less(i, j int) bool { + return s[i].literal < s[j].literal +} + +func (s literalNodeSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +type literalFreqSorter []literalNode + +func (s *literalFreqSorter) Sort(a []literalNode) { + *s = literalFreqSorter(a) + sort.Sort(s) +} + +func (s literalFreqSorter) Len() int { return len(s) } + +func (s literalFreqSorter) Less(i, j int) bool { + if s[i].freq == s[j].freq { + return s[i].literal < s[j].literal + } + return s[i].freq < s[j].freq +} + +func (s literalFreqSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] } diff --git a/vendor/github.com/klauspost/compress/flate/inflate.go b/vendor/github.com/klauspost/compress/flate/inflate.go new file mode 100644 index 0000000..91e27e7 --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/inflate.go @@ -0,0 +1,846 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:generate go run gen.go -output fixedhuff.go + +// Package flate implements the DEFLATE compressed data format, described in +// RFC 1951. The gzip and zlib packages implement access to DEFLATE-based file +// formats. +package flate + +import ( + "bufio" + "io" + "strconv" +) + +const ( + maxCodeLen = 16 // max length of Huffman code + maxHist = 32768 // max history required + // The next three numbers come from the RFC section 3.2.7, with the + // additional proviso in section 3.2.5 which implies that distance codes + // 30 and 31 should never occur in compressed data. + maxNumLit = 286 + maxNumDist = 30 + numCodes = 19 // number of codes in Huffman meta-code +) + +// A CorruptInputError reports the presence of corrupt input at a given offset. +type CorruptInputError int64 + +func (e CorruptInputError) Error() string { + return "flate: corrupt input before offset " + strconv.FormatInt(int64(e), 10) +} + +// An InternalError reports an error in the flate code itself. +type InternalError string + +func (e InternalError) Error() string { return "flate: internal error: " + string(e) } + +// A ReadError reports an error encountered while reading input. +type ReadError struct { + Offset int64 // byte offset where error occurred + Err error // error returned by underlying Read +} + +func (e *ReadError) Error() string { + return "flate: read error at offset " + strconv.FormatInt(e.Offset, 10) + ": " + e.Err.Error() +} + +// A WriteError reports an error encountered while writing output. +type WriteError struct { + Offset int64 // byte offset where error occurred + Err error // error returned by underlying Write +} + +func (e *WriteError) Error() string { + return "flate: write error at offset " + strconv.FormatInt(e.Offset, 10) + ": " + e.Err.Error() +} + +// Resetter resets a ReadCloser returned by NewReader or NewReaderDict to +// to switch to a new underlying Reader. This permits reusing a ReadCloser +// instead of allocating a new one. +type Resetter interface { + // Reset discards any buffered data and resets the Resetter as if it was + // newly initialized with the given reader. + Reset(r io.Reader, dict []byte) error +} + +// Note that much of the implementation of huffmanDecoder is also copied +// into gen.go (in package main) for the purpose of precomputing the +// fixed huffman tables so they can be included statically. + +// The data structure for decoding Huffman tables is based on that of +// zlib. There is a lookup table of a fixed bit width (huffmanChunkBits), +// For codes smaller than the table width, there are multiple entries +// (each combination of trailing bits has the same value). For codes +// larger than the table width, the table contains a link to an overflow +// table. The width of each entry in the link table is the maximum code +// size minus the chunk width. + +// Note that you can do a lookup in the table even without all bits +// filled. Since the extra bits are zero, and the DEFLATE Huffman codes +// have the property that shorter codes come before longer ones, the +// bit length estimate in the result is a lower bound on the actual +// number of bits. + +// chunk & 15 is number of bits +// chunk >> 4 is value, including table link + +const ( + huffmanChunkBits = 9 + huffmanNumChunks = 1 << huffmanChunkBits + huffmanCountMask = 15 + huffmanValueShift = 4 +) + +type huffmanDecoder struct { + min int // the minimum code length + chunks [huffmanNumChunks]uint32 // chunks as described above + links [][]uint32 // overflow links + linkMask uint32 // mask the width of the link table +} + +// Initialize Huffman decoding tables from array of code lengths. +// Following this function, h is guaranteed to be initialized into a complete +// tree (i.e., neither over-subscribed nor under-subscribed). The exception is a +// degenerate case where the tree has only a single symbol with length 1. Empty +// trees are permitted. +func (h *huffmanDecoder) init(bits []int) bool { + // Sanity enables additional runtime tests during Huffman + // table construction. It's intended to be used during + // development to supplement the currently ad-hoc unit tests. + const sanity = false + + if h.min != 0 { + *h = huffmanDecoder{} + } + + // Count number of codes of each length, + // compute min and max length. + var count [maxCodeLen]int + var min, max int + for _, n := range bits { + if n == 0 { + continue + } + if min == 0 || n < min { + min = n + } + if n > max { + max = n + } + count[n]++ + } + + // Empty tree. The decompressor.huffSym function will fail later if the tree + // is used. Technically, an empty tree is only valid for the HDIST tree and + // not the HCLEN and HLIT tree. However, a stream with an empty HCLEN tree + // is guaranteed to fail since it will attempt to use the tree to decode the + // codes for the HLIT and HDIST trees. Similarly, an empty HLIT tree is + // guaranteed to fail later since the compressed data section must be + // composed of at least one symbol (the end-of-block marker). + if max == 0 { + return true + } + + code := 0 + var nextcode [maxCodeLen]int + for i := min; i <= max; i++ { + code <<= 1 + nextcode[i] = code + code += count[i] + } + + // Check that the coding is complete (i.e., that we've + // assigned all 2-to-the-max possible bit sequences). + // Exception: To be compatible with zlib, we also need to + // accept degenerate single-code codings. See also + // TestDegenerateHuffmanCoding. + if code != 1< huffmanChunkBits { + numLinks := 1 << (uint(max) - huffmanChunkBits) + h.linkMask = uint32(numLinks - 1) + + // create link tables + link := nextcode[huffmanChunkBits+1] >> 1 + h.links = make([][]uint32, huffmanNumChunks-link) + for j := uint(link); j < huffmanNumChunks; j++ { + reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8 + reverse >>= uint(16 - huffmanChunkBits) + off := j - uint(link) + if sanity && h.chunks[reverse] != 0 { + panic("impossible: overwriting existing chunk") + } + h.chunks[reverse] = uint32(off<>8]) | int(reverseByte[code&0xff])<<8 + reverse >>= uint(16 - n) + if n <= huffmanChunkBits { + for off := reverse; off < len(h.chunks); off += 1 << uint(n) { + // We should never need to overwrite + // an existing chunk. Also, 0 is + // never a valid chunk, because the + // lower 4 "count" bits should be + // between 1 and 15. + if sanity && h.chunks[off] != 0 { + panic("impossible: overwriting existing chunk") + } + h.chunks[off] = chunk + } + } else { + j := reverse & (huffmanNumChunks - 1) + if sanity && h.chunks[j]&huffmanCountMask != huffmanChunkBits+1 { + // Longer codes should have been + // associated with a link table above. + panic("impossible: not an indirect chunk") + } + value := h.chunks[j] >> huffmanValueShift + linktab := h.links[value] + reverse >>= huffmanChunkBits + for off := reverse; off < len(linktab); off += 1 << uint(n-huffmanChunkBits) { + if sanity && linktab[off] != 0 { + panic("impossible: overwriting existing chunk") + } + linktab[off] = chunk + } + } + } + + if sanity { + // Above we've sanity checked that we never overwrote + // an existing entry. Here we additionally check that + // we filled the tables completely. + for i, chunk := range h.chunks { + if chunk == 0 { + // As an exception, in the degenerate + // single-code case, we allow odd + // chunks to be missing. + if code == 1 && i%2 == 1 { + continue + } + panic("impossible: missing chunk") + } + } + for _, linktab := range h.links { + for _, chunk := range linktab { + if chunk == 0 { + panic("impossible: missing chunk") + } + } + } + } + + return true +} + +// The actual read interface needed by NewReader. +// If the passed in io.Reader does not also have ReadByte, +// the NewReader will introduce its own buffering. +type Reader interface { + io.Reader + io.ByteReader +} + +// Decompress state. +type decompressor struct { + // Input source. + r Reader + roffset int64 + woffset int64 + + // Input bits, in top of b. + b uint32 + nb uint + + // Huffman decoders for literal/length, distance. + h1, h2 huffmanDecoder + + // Length arrays used to define Huffman codes. + bits *[maxNumLit + maxNumDist]int + codebits *[numCodes]int + + // Output history, buffer. + hist *[maxHist]byte + hp int // current output position in buffer + hw int // have written hist[0:hw] already + hfull bool // buffer has filled at least once + + // Temporary buffer (avoids repeated allocation). + buf [4]byte + + // Next step in the decompression, + // and decompression state. + step func(*decompressor) + final bool + err error + toRead []byte + hl, hd *huffmanDecoder + copyLen int + copyDist int +} + +func (f *decompressor) nextBlock() { + if f.final { + if f.hw != f.hp { + f.flush((*decompressor).nextBlock) + return + } + f.err = io.EOF + return + } + for f.nb < 1+2 { + if f.err = f.moreBits(); f.err != nil { + return + } + } + f.final = f.b&1 == 1 + f.b >>= 1 + typ := f.b & 3 + f.b >>= 2 + f.nb -= 1 + 2 + switch typ { + case 0: + f.dataBlock() + case 1: + // compressed, fixed Huffman tables + f.hl = &fixedHuffmanDecoder + f.hd = nil + f.huffmanBlock() + case 2: + // compressed, dynamic Huffman tables + if f.err = f.readHuffman(); f.err != nil { + break + } + f.hl = &f.h1 + f.hd = &f.h2 + f.huffmanBlock() + default: + // 3 is reserved. + f.err = CorruptInputError(f.roffset) + } +} + +func (f *decompressor) Read(b []byte) (int, error) { + for { + if len(f.toRead) > 0 { + n := copy(b, f.toRead) + f.toRead = f.toRead[n:] + return n, nil + } + if f.err != nil { + return 0, f.err + } + f.step(f) + } +} + +// Support the io.WriteTo interface for io.Copy and friends. +func (f *decompressor) WriteTo(w io.Writer) (int64, error) { + total := int64(0) + for { + if f.err != nil { + if f.err == io.EOF { + return total, nil + } + return total, f.err + } + if len(f.toRead) > 0 { + var n int + n, f.err = w.Write(f.toRead) + if f.err != nil { + return total, f.err + } + if n != len(f.toRead) { + return total, io.ErrShortWrite + } + f.toRead = f.toRead[:0] + total += int64(n) + } + f.step(f) + } +} + +func (f *decompressor) Close() error { + if f.err == io.EOF { + return nil + } + return f.err +} + +// RFC 1951 section 3.2.7. +// Compression with dynamic Huffman codes + +var codeOrder = [...]int{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15} + +func (f *decompressor) readHuffman() error { + // HLIT[5], HDIST[5], HCLEN[4]. + for f.nb < 5+5+4 { + if err := f.moreBits(); err != nil { + return err + } + } + nlit := int(f.b&0x1F) + 257 + if nlit > maxNumLit { + return CorruptInputError(f.roffset) + } + f.b >>= 5 + ndist := int(f.b&0x1F) + 1 + if ndist > maxNumDist { + return CorruptInputError(f.roffset) + } + f.b >>= 5 + nclen := int(f.b&0xF) + 4 + // numCodes is 19, so nclen is always valid. + f.b >>= 4 + f.nb -= 5 + 5 + 4 + + // (HCLEN+4)*3 bits: code lengths in the magic codeOrder order. + for i := 0; i < nclen; i++ { + for f.nb < 3 { + if err := f.moreBits(); err != nil { + return err + } + } + f.codebits[codeOrder[i]] = int(f.b & 0x7) + f.b >>= 3 + f.nb -= 3 + } + for i := nclen; i < len(codeOrder); i++ { + f.codebits[codeOrder[i]] = 0 + } + if !f.h1.init(f.codebits[0:]) { + return CorruptInputError(f.roffset) + } + + // HLIT + 257 code lengths, HDIST + 1 code lengths, + // using the code length Huffman code. + for i, n := 0, nlit+ndist; i < n; { + x, err := f.huffSym(&f.h1) + if err != nil { + return err + } + if x < 16 { + // Actual length. + f.bits[i] = x + i++ + continue + } + // Repeat previous length or zero. + var rep int + var nb uint + var b int + switch x { + default: + return InternalError("unexpected length code") + case 16: + rep = 3 + nb = 2 + if i == 0 { + return CorruptInputError(f.roffset) + } + b = f.bits[i-1] + case 17: + rep = 3 + nb = 3 + b = 0 + case 18: + rep = 11 + nb = 7 + b = 0 + } + for f.nb < nb { + if err := f.moreBits(); err != nil { + return err + } + } + rep += int(f.b & uint32(1<>= nb + f.nb -= nb + if i+rep > n { + return CorruptInputError(f.roffset) + } + for j := 0; j < rep; j++ { + f.bits[i] = b + i++ + } + } + + if !f.h1.init(f.bits[0:nlit]) || !f.h2.init(f.bits[nlit:nlit+ndist]) { + return CorruptInputError(f.roffset) + } + + // In order to preserve the property that we never read any extra bytes + // after the end of the DEFLATE stream, huffSym conservatively reads min + // bits at a time until it decodes the symbol. However, since every block + // must end with an EOB marker, we can use that as the minimum number of + // bits to read and guarantee we never read past the end of the stream. + if f.bits[endBlockMarker] > 0 { + f.h1.min = f.bits[endBlockMarker] // Length of EOB marker + } + + return nil +} + +// Decode a single Huffman block from f. +// hl and hd are the Huffman states for the lit/length values +// and the distance values, respectively. If hd == nil, using the +// fixed distance encoding associated with fixed Huffman blocks. +func (f *decompressor) huffmanBlock() { + for { + v, err := f.huffSym(f.hl) + if err != nil { + f.err = err + return + } + var n uint // number of bits extra + var length int + switch { + case v < 256: + f.hist[f.hp] = byte(v) + f.hp++ + if f.hp == len(f.hist) { + // After the flush, continue this loop. + f.flush((*decompressor).huffmanBlock) + return + } + continue + case v == 256: + // Done with huffman block; read next block. + f.step = (*decompressor).nextBlock + return + // otherwise, reference to older data + case v < 265: + length = v - (257 - 3) + n = 0 + case v < 269: + length = v*2 - (265*2 - 11) + n = 1 + case v < 273: + length = v*4 - (269*4 - 19) + n = 2 + case v < 277: + length = v*8 - (273*8 - 35) + n = 3 + case v < 281: + length = v*16 - (277*16 - 67) + n = 4 + case v < 285: + length = v*32 - (281*32 - 131) + n = 5 + case v < maxNumLit: + length = 258 + n = 0 + default: + f.err = CorruptInputError(f.roffset) + return + } + if n > 0 { + for f.nb < n { + if err = f.moreBits(); err != nil { + f.err = err + return + } + } + length += int(f.b & uint32(1<>= n + f.nb -= n + } + + var dist int + if f.hd == nil { + for f.nb < 5 { + if err = f.moreBits(); err != nil { + f.err = err + return + } + } + dist = int(reverseByte[(f.b&0x1F)<<3]) + f.b >>= 5 + f.nb -= 5 + } else { + if dist, err = f.huffSym(f.hd); err != nil { + f.err = err + return + } + } + + switch { + case dist < 4: + dist++ + case dist < maxNumDist: + nb := uint(dist-2) >> 1 + // have 1 bit in bottom of dist, need nb more. + extra := (dist & 1) << nb + for f.nb < nb { + if err = f.moreBits(); err != nil { + f.err = err + return + } + } + extra |= int(f.b & uint32(1<>= nb + f.nb -= nb + dist = 1<<(nb+1) + 1 + extra + default: + f.err = CorruptInputError(f.roffset) + return + } + + // Copy history[-dist:-dist+length] into output. + if dist > len(f.hist) { + f.err = InternalError("bad history distance") + return + } + + // No check on length; encoding can be prescient. + if !f.hfull && dist > f.hp { + f.err = CorruptInputError(f.roffset) + return + } + + f.copyLen, f.copyDist = length, dist + if f.copyHist() { + return + } + } +} + +// copyHist copies f.copyLen bytes from f.hist (f.copyDist bytes ago) to itself. +// It reports whether the f.hist buffer is full. +func (f *decompressor) copyHist() bool { + p := f.hp - f.copyDist + if p < 0 { + p += len(f.hist) + } + for f.copyLen > 0 { + n := f.copyLen + if x := len(f.hist) - f.hp; n > x { + n = x + } + if x := len(f.hist) - p; n > x { + n = x + } + forwardCopy(f.hist[:], f.hp, p, n) + p += n + f.hp += n + f.copyLen -= n + if f.hp == len(f.hist) { + // After flush continue copying out of history. + f.flush((*decompressor).copyHuff) + return true + } + if p == len(f.hist) { + p = 0 + } + } + return false +} + +func (f *decompressor) copyHuff() { + if f.copyHist() { + return + } + f.huffmanBlock() +} + +// Copy a single uncompressed data block from input to output. +func (f *decompressor) dataBlock() { + // Uncompressed. + // Discard current half-byte. + f.nb = 0 + f.b = 0 + + // Length then ones-complement of length. + nr, err := io.ReadFull(f.r, f.buf[0:4]) + f.roffset += int64(nr) + if err != nil { + f.err = &ReadError{f.roffset, err} + return + } + n := int(f.buf[0]) | int(f.buf[1])<<8 + nn := int(f.buf[2]) | int(f.buf[3])<<8 + if uint16(nn) != uint16(^n) { + f.err = CorruptInputError(f.roffset) + return + } + + if n == 0 { + // 0-length block means sync + f.flush((*decompressor).nextBlock) + return + } + + f.copyLen = n + f.copyData() +} + +// copyData copies f.copyLen bytes from the underlying reader into f.hist. +// It pauses for reads when f.hist is full. +func (f *decompressor) copyData() { + n := f.copyLen + for n > 0 { + m := len(f.hist) - f.hp + if m > n { + m = n + } + m, err := io.ReadFull(f.r, f.hist[f.hp:f.hp+m]) + f.roffset += int64(m) + if err != nil { + f.err = &ReadError{f.roffset, err} + return + } + n -= m + f.hp += m + if f.hp == len(f.hist) { + f.copyLen = n + f.flush((*decompressor).copyData) + return + } + } + f.step = (*decompressor).nextBlock +} + +func (f *decompressor) setDict(dict []byte) { + if len(dict) > len(f.hist) { + // Will only remember the tail. + dict = dict[len(dict)-len(f.hist):] + } + + f.hp = copy(f.hist[:], dict) + if f.hp == len(f.hist) { + f.hp = 0 + f.hfull = true + } + f.hw = f.hp +} + +func (f *decompressor) moreBits() error { + c, err := f.r.ReadByte() + if err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + return err + } + f.roffset++ + f.b |= uint32(c) << f.nb + f.nb += 8 + return nil +} + +// Read the next Huffman-encoded symbol from f according to h. +func (f *decompressor) huffSym(h *huffmanDecoder) (int, error) { + // Since a huffmanDecoder can be empty or be composed of a degenerate tree + // with single element, huffSym must error on these two edge cases. In both + // cases, the chunks slice will be 0 for the invalid sequence, leading it + // satisfy the n == 0 check below. + n := uint(h.min) + for { + for f.nb < n { + if err := f.moreBits(); err != nil { + return 0, err + } + } + chunk := h.chunks[f.b&(huffmanNumChunks-1)] + n = uint(chunk & huffmanCountMask) + if n > huffmanChunkBits { + chunk = h.links[chunk>>huffmanValueShift][(f.b>>huffmanChunkBits)&h.linkMask] + n = uint(chunk & huffmanCountMask) + } + if n <= f.nb { + if n == 0 { + f.err = CorruptInputError(f.roffset) + return 0, f.err + } + f.b >>= n + f.nb -= n + return int(chunk >> huffmanValueShift), nil + } + } +} + +// Flush any buffered output to the underlying writer. +func (f *decompressor) flush(step func(*decompressor)) { + f.toRead = f.hist[f.hw:f.hp] + f.woffset += int64(f.hp - f.hw) + f.hw = f.hp + if f.hp == len(f.hist) { + f.hp = 0 + f.hw = 0 + f.hfull = true + } + f.step = step +} + +func makeReader(r io.Reader) Reader { + if rr, ok := r.(Reader); ok { + return rr + } + return bufio.NewReader(r) +} + +func (f *decompressor) Reset(r io.Reader, dict []byte) error { + *f = decompressor{ + r: makeReader(r), + bits: f.bits, + codebits: f.codebits, + hist: f.hist, + step: (*decompressor).nextBlock, + } + if dict != nil { + f.setDict(dict) + } + return nil +} + +// NewReader returns a new ReadCloser that can be used +// to read the uncompressed version of r. +// If r does not also implement io.ByteReader, +// the decompressor may read more data than necessary from r. +// It is the caller's responsibility to call Close on the ReadCloser +// when finished reading. +// +// The ReadCloser returned by NewReader also implements Resetter. +func NewReader(r io.Reader) io.ReadCloser { + var f decompressor + f.bits = new([maxNumLit + maxNumDist]int) + f.codebits = new([numCodes]int) + f.r = makeReader(r) + f.hist = new([maxHist]byte) + f.step = (*decompressor).nextBlock + return &f +} + +// NewReaderDict is like NewReader but initializes the reader +// with a preset dictionary. The returned Reader behaves as if +// the uncompressed data stream started with the given dictionary, +// which has already been read. NewReaderDict is typically used +// to read data compressed by NewWriterDict. +// +// The ReadCloser returned by NewReader also implements Resetter. +func NewReaderDict(r io.Reader, dict []byte) io.ReadCloser { + var f decompressor + f.r = makeReader(r) + f.hist = new([maxHist]byte) + f.bits = new([maxNumLit + maxNumDist]int) + f.codebits = new([numCodes]int) + f.step = (*decompressor).nextBlock + f.setDict(dict) + return &f +} diff --git a/vendor/github.com/klauspost/compress/flate/inflate_test.go b/vendor/github.com/klauspost/compress/flate/inflate_test.go new file mode 100644 index 0000000..4eea42f --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/inflate_test.go @@ -0,0 +1,225 @@ +// Copyright 2014 The Go 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 flate + +import ( + "bytes" + "crypto/rand" + "io" + "io/ioutil" + "strconv" + "strings" + "testing" +) + +func TestReset(t *testing.T) { + ss := []string{ + "lorem ipsum izzle fo rizzle", + "the quick brown fox jumped over", + } + + deflated := make([]bytes.Buffer, 2) + for i, s := range ss { + w, _ := NewWriter(&deflated[i], 1) + w.Write([]byte(s)) + w.Close() + } + + inflated := make([]bytes.Buffer, 2) + + f := NewReader(&deflated[0]) + io.Copy(&inflated[0], f) + f.(Resetter).Reset(&deflated[1], nil) + io.Copy(&inflated[1], f) + f.Close() + + for i, s := range ss { + if s != inflated[i].String() { + t.Errorf("inflated[%d]:\ngot %q\nwant %q", i, inflated[i], s) + } + } +} + +// Tests ported from zlib/test/infcover.c +type infTest struct { + hex string + id string + n int +} + +var infTests = []infTest{ + infTest{"0 0 0 0 0", "invalid stored block lengths", 1}, + infTest{"3 0", "fixed", 0}, + infTest{"6", "invalid block type", 1}, + infTest{"1 1 0 fe ff 0", "stored", 0}, + infTest{"fc 0 0", "too many length or distance symbols", 1}, + infTest{"4 0 fe ff", "invalid code lengths set", 1}, + infTest{"4 0 24 49 0", "invalid bit length repeat", 1}, + infTest{"4 0 24 e9 ff ff", "invalid bit length repeat", 1}, + infTest{"4 0 24 e9 ff 6d", "invalid code -- missing end-of-block", 1}, + infTest{"4 80 49 92 24 49 92 24 71 ff ff 93 11 0", "invalid literal/lengths set", 1}, + infTest{"4 80 49 92 24 49 92 24 f b4 ff ff c3 84", "invalid distances set", 1}, + infTest{"4 c0 81 8 0 0 0 0 20 7f eb b 0 0", "invalid literal/length code", 1}, + infTest{"2 7e ff ff", "invalid distance code", 1}, + infTest{"c c0 81 0 0 0 0 0 90 ff 6b 4 0", "invalid distance too far back", 1}, + + // also trailer mismatch just in inflate() + infTest{"1f 8b 8 0 0 0 0 0 0 0 3 0 0 0 0 1", "incorrect data check", -1}, + infTest{"1f 8b 8 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 1", "incorrect length check", -1}, + infTest{"5 c0 21 d 0 0 0 80 b0 fe 6d 2f 91 6c", "pull 17", 0}, + infTest{"5 e0 81 91 24 cb b2 2c 49 e2 f 2e 8b 9a 47 56 9f fb fe ec d2 ff 1f", "long code", 0}, + infTest{"ed c0 1 1 0 0 0 40 20 ff 57 1b 42 2c 4f", "length extra", 0}, + infTest{"ed cf c1 b1 2c 47 10 c4 30 fa 6f 35 1d 1 82 59 3d fb be 2e 2a fc f c", "long distance and extra", 0}, + infTest{"ed c0 81 0 0 0 0 80 a0 fd a9 17 a9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6", "window end", 0}, +} + +func TestInflate(t *testing.T) { + for _, test := range infTests { + hex := strings.Split(test.hex, " ") + data := make([]byte, len(hex)) + for i, h := range hex { + b, _ := strconv.ParseInt(h, 16, 32) + data[i] = byte(b) + } + buf := bytes.NewReader(data) + r := NewReader(buf) + + _, err := io.Copy(ioutil.Discard, r) + if (test.n == 0 && err == nil) || (test.n != 0 && err != nil) { + t.Logf("%q: OK:", test.id) + t.Logf(" - got %v", err) + continue + } + + if test.n == 0 && err != nil { + t.Errorf("%q: Expected no error, but got %v", test.id, err) + continue + } + + if test.n != 0 && err == nil { + t.Errorf("%q:Expected an error, but got none", test.id) + continue + } + t.Fatal(test.n, err) + } + + for _, test := range infOutTests { + hex := strings.Split(test.hex, " ") + data := make([]byte, len(hex)) + for i, h := range hex { + b, _ := strconv.ParseInt(h, 16, 32) + data[i] = byte(b) + } + buf := bytes.NewReader(data) + r := NewReader(buf) + + _, err := io.Copy(ioutil.Discard, r) + if test.err == (err != nil) { + t.Logf("%q: OK:", test.id) + t.Logf(" - got %v", err) + continue + } + + if test.err == false && err != nil { + t.Errorf("%q: Expected no error, but got %v", test.id, err) + continue + } + + if test.err && err == nil { + t.Errorf("%q: Expected an error, but got none", test.id) + continue + } + t.Fatal(test.err, err) + } + +} + +// Tests ported from zlib/test/infcover.c +// Since zlib inflate is push (writer) instead of pull (reader) +// some of the window size tests have been removed, since they +// are irrelevant. +type infOutTest struct { + hex string + id string + step int + win int + length int + err bool +} + +var infOutTests = []infOutTest{ + infOutTest{"2 8 20 80 0 3 0", "inflate_fast TYPE return", 0, -15, 258, false}, + infOutTest{"63 18 5 40 c 0", "window wrap", 3, -8, 300, false}, + infOutTest{"e5 e0 81 ad 6d cb b2 2c c9 01 1e 59 63 ae 7d ee fb 4d fd b5 35 41 68 ff 7f 0f 0 0 0", "fast length extra bits", 0, -8, 258, true}, + infOutTest{"25 fd 81 b5 6d 59 b6 6a 49 ea af 35 6 34 eb 8c b9 f6 b9 1e ef 67 49 50 fe ff ff 3f 0 0", "fast distance extra bits", 0, -8, 258, true}, + infOutTest{"3 7e 0 0 0 0 0", "fast invalid distance code", 0, -8, 258, true}, + infOutTest{"1b 7 0 0 0 0 0", "fast invalid literal/length code", 0, -8, 258, true}, + infOutTest{"d c7 1 ae eb 38 c 4 41 a0 87 72 de df fb 1f b8 36 b1 38 5d ff ff 0", "fast 2nd level codes and too far back", 0, -8, 258, true}, + infOutTest{"63 18 5 8c 10 8 0 0 0 0", "very common case", 0, -8, 259, false}, + infOutTest{"63 60 60 18 c9 0 8 18 18 18 26 c0 28 0 29 0 0 0", "contiguous and wrap around window", 6, -8, 259, false}, + infOutTest{"63 0 3 0 0 0 0 0", "copy direct from output", 0, -8, 259, false}, + infOutTest{"1f 8b 0 0", "bad gzip method", 0, 31, 0, true}, + infOutTest{"1f 8b 8 80", "bad gzip flags", 0, 31, 0, true}, + infOutTest{"77 85", "bad zlib method", 0, 15, 0, true}, + infOutTest{"78 9c", "bad zlib window size", 0, 8, 0, true}, + infOutTest{"1f 8b 8 1e 0 0 0 0 0 0 1 0 0 0 0 0 0", "bad header crc", 0, 47, 1, true}, + infOutTest{"1f 8b 8 2 0 0 0 0 0 0 1d 26 3 0 0 0 0 0 0 0 0 0", "check gzip length", 0, 47, 0, true}, + infOutTest{"78 90", "bad zlib header check", 0, 47, 0, true}, + infOutTest{"8 b8 0 0 0 1", "need dictionary", 0, 8, 0, true}, + infOutTest{"63 18 68 30 d0 0 0", "force split window update", 4, -8, 259, false}, + infOutTest{"3 0", "use fixed blocks", 0, -15, 1, false}, + infOutTest{"", "bad window size", 0, 1, 0, true}, +} + +func TestWriteTo(t *testing.T) { + input := make([]byte, 100000) + n, err := rand.Read(input) + if err != nil { + t.Fatal(err) + } + if n != len(input) { + t.Fatal("did not fill buffer") + } + compressed := &bytes.Buffer{} + w, err := NewWriter(compressed, -2) + if err != nil { + t.Fatal(err) + } + n, err = w.Write(input) + if err != nil { + t.Fatal(err) + } + if n != len(input) { + t.Fatal("did not fill buffer") + } + w.Close() + buf := compressed.Bytes() + + dec := NewReader(bytes.NewBuffer(buf)) + // ReadAll does not use WriteTo, but we wrap it in a NopCloser to be sure. + readall, err := ioutil.ReadAll(ioutil.NopCloser(dec)) + if err != nil { + t.Fatal(err) + } + if len(readall) != len(input) { + t.Fatal("did not decompress everything") + } + + dec = NewReader(bytes.NewBuffer(buf)) + wtbuf := &bytes.Buffer{} + written, err := dec.(io.WriterTo).WriteTo(wtbuf) + if err != nil { + t.Fatal(err) + } + if written != int64(len(input)) { + t.Error("Returned length did not match, expected", len(input), "got", written) + } + if wtbuf.Len() != len(input) { + t.Error("Actual Length did not match, expected", len(input), "got", wtbuf.Len()) + } + if bytes.Compare(wtbuf.Bytes(), input) != 0 { + t.Fatal("output did not match input") + } +} diff --git a/vendor/github.com/klauspost/compress/flate/reader_test.go b/vendor/github.com/klauspost/compress/flate/reader_test.go new file mode 100644 index 0000000..e42bd01 --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/reader_test.go @@ -0,0 +1,97 @@ +// Copyright 2012 The Go 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 flate + +import ( + "bytes" + "io" + "io/ioutil" + "runtime" + "strings" + "testing" +) + +func TestNlitOutOfRange(t *testing.T) { + // Trying to decode this bogus flate data, which has a Huffman table + // with nlit=288, should not panic. + io.Copy(ioutil.Discard, NewReader(strings.NewReader( + "\xfc\xfe\x36\xe7\x5e\x1c\xef\xb3\x55\x58\x77\xb6\x56\xb5\x43\xf4"+ + "\x6f\xf2\xd2\xe6\x3d\x99\xa0\x85\x8c\x48\xeb\xf8\xda\x83\x04\x2a"+ + "\x75\xc4\xf8\x0f\x12\x11\xb9\xb4\x4b\x09\xa0\xbe\x8b\x91\x4c"))) +} + +const ( + digits = iota + twain +) + +var testfiles = []string{ + // Digits is the digits of the irrational number e. Its decimal representation + // does not repeat, but there are only 10 possible digits, so it should be + // reasonably compressible. + digits: "../testdata/e.txt", + // Twain is Project Gutenberg's edition of Mark Twain's classic English novel. + twain: "../testdata/Mark.Twain-Tom.Sawyer.txt", +} + +func benchmarkDecode(b *testing.B, testfile, level, n int) { + b.ReportAllocs() + b.StopTimer() + b.SetBytes(int64(n)) + buf0, err := ioutil.ReadFile(testfiles[testfile]) + if err != nil { + b.Fatal(err) + } + if len(buf0) == 0 { + b.Fatalf("test file %q has no data", testfiles[testfile]) + } + compressed := new(bytes.Buffer) + w, err := NewWriter(compressed, level) + if err != nil { + b.Fatal(err) + } + for i := 0; i < n; i += len(buf0) { + if len(buf0) > n-i { + buf0 = buf0[:n-i] + } + io.Copy(w, bytes.NewReader(buf0)) + } + w.Close() + buf1 := compressed.Bytes() + buf0, compressed, w = nil, nil, nil + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1))) + } +} + +// These short names are so that gofmt doesn't break the BenchmarkXxx function +// bodies below over multiple lines. +const ( + constant = ConstantCompression + speed = BestSpeed + default_ = DefaultCompression + compress = BestCompression +) + +func BenchmarkDecodeDigitsSpeed1e4(b *testing.B) { benchmarkDecode(b, digits, speed, 1e4) } +func BenchmarkDecodeDigitsSpeed1e5(b *testing.B) { benchmarkDecode(b, digits, speed, 1e5) } +func BenchmarkDecodeDigitsSpeed1e6(b *testing.B) { benchmarkDecode(b, digits, speed, 1e6) } +func BenchmarkDecodeDigitsDefault1e4(b *testing.B) { benchmarkDecode(b, digits, default_, 1e4) } +func BenchmarkDecodeDigitsDefault1e5(b *testing.B) { benchmarkDecode(b, digits, default_, 1e5) } +func BenchmarkDecodeDigitsDefault1e6(b *testing.B) { benchmarkDecode(b, digits, default_, 1e6) } +func BenchmarkDecodeDigitsCompress1e4(b *testing.B) { benchmarkDecode(b, digits, compress, 1e4) } +func BenchmarkDecodeDigitsCompress1e5(b *testing.B) { benchmarkDecode(b, digits, compress, 1e5) } +func BenchmarkDecodeDigitsCompress1e6(b *testing.B) { benchmarkDecode(b, digits, compress, 1e6) } +func BenchmarkDecodeTwainSpeed1e4(b *testing.B) { benchmarkDecode(b, twain, speed, 1e4) } +func BenchmarkDecodeTwainSpeed1e5(b *testing.B) { benchmarkDecode(b, twain, speed, 1e5) } +func BenchmarkDecodeTwainSpeed1e6(b *testing.B) { benchmarkDecode(b, twain, speed, 1e6) } +func BenchmarkDecodeTwainDefault1e4(b *testing.B) { benchmarkDecode(b, twain, default_, 1e4) } +func BenchmarkDecodeTwainDefault1e5(b *testing.B) { benchmarkDecode(b, twain, default_, 1e5) } +func BenchmarkDecodeTwainDefault1e6(b *testing.B) { benchmarkDecode(b, twain, default_, 1e6) } +func BenchmarkDecodeTwainCompress1e4(b *testing.B) { benchmarkDecode(b, twain, compress, 1e4) } +func BenchmarkDecodeTwainCompress1e5(b *testing.B) { benchmarkDecode(b, twain, compress, 1e5) } +func BenchmarkDecodeTwainCompress1e6(b *testing.B) { benchmarkDecode(b, twain, compress, 1e6) } diff --git a/vendor/github.com/klauspost/compress/flate/reverse_bits.go b/vendor/github.com/klauspost/compress/flate/reverse_bits.go new file mode 100644 index 0000000..c1a0272 --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/reverse_bits.go @@ -0,0 +1,48 @@ +// Copyright 2009 The Go 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 flate + +var reverseByte = [256]byte{ + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, +} + +func reverseUint16(v uint16) uint16 { + return uint16(reverseByte[v>>8]) | uint16(reverseByte[v&0xFF])<<8 +} + +func reverseBits(number uint16, bitLength byte) uint16 { + return reverseUint16(number << uint8(16-bitLength)) +} diff --git a/vendor/github.com/klauspost/compress/flate/snappy.go b/vendor/github.com/klauspost/compress/flate/snappy.go new file mode 100644 index 0000000..a80ebe9 --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/snappy.go @@ -0,0 +1,558 @@ +// Copyright 2011 The Snappy-Go Authors. All rights reserved. +// Modified for deflate by Klaus Post (c) 2015. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flate + +// We limit how far copy back-references can go, the same as the C++ code. +const maxOffset = 1 << 15 + +// emitLiteral writes a literal chunk and returns the number of bytes written. +func emitLiteral(dst *tokens, lit []byte) { + ol := dst.n + for i, v := range lit { + dst.tokens[i+ol] = token(v) + } + dst.n += len(lit) +} + +// emitCopy writes a copy chunk and returns the number of bytes written. +func emitCopy(dst *tokens, offset, length int) { + dst.tokens[dst.n] = matchToken(uint32(length-3), uint32(offset-minOffsetSize)) + dst.n++ +} + +type snappyEnc interface { + Encode(dst *tokens, src []byte) + Reset() +} + +func newSnappy(level int) snappyEnc { + if useSSE42 { + e := &snappySSE4{snappyGen: snappyGen{cur: 1}} + switch level { + case 3: + e.enc = e.encodeL3 + return e + } + } + e := &snappyGen{cur: 1} + switch level { + case 1: + e.enc = e.encodeL1 + case 2: + e.enc = e.encodeL2 + case 3: + e.enc = e.encodeL3 + default: + panic("invalid level specified") + } + return e +} + +const tableBits = 14 // Bits used in the table +const tableSize = 1 << tableBits // Size of the table + +// snappyGen maintains the table for matches, +// and the previous byte block for level 2. +// This is the generic implementation. +type snappyGen struct { + table [tableSize]int64 + block [maxStoreBlockSize]byte + prev []byte + cur int + enc func(dst *tokens, src []byte) +} + +func (e *snappyGen) Encode(dst *tokens, src []byte) { + e.enc(dst, src) +} + +// EncodeL1 uses Snappy-like compression, but stores as Huffman +// blocks. +func (e *snappyGen) encodeL1(dst *tokens, src []byte) { + // Return early if src is short. + if len(src) <= 4 { + if len(src) != 0 { + emitLiteral(dst, src) + } + e.cur += 4 + return + } + + // Ensure that e.cur doesn't wrap, mainly an issue on 32 bits. + if e.cur > 1<<30 { + e.cur = 1 + } + + // Iterate over the source bytes. + var ( + s int // The iterator position. + t int // The last position with the same hash as s. + lit int // The start position of any pending literal bytes. + ) + + for s+3 < len(src) { + // Update the hash table. + b0, b1, b2, b3 := src[s], src[s+1], src[s+2], src[s+3] + h := uint32(b0) | uint32(b1)<<8 | uint32(b2)<<16 | uint32(b3)<<24 + p := &e.table[(h*0x1e35a7bd)>>(32-tableBits)] + // We need to to store values in [-1, inf) in table. + // To save some initialization time, we make sure that + // e.cur is never zero. + t, *p = int(*p)-e.cur, int64(s+e.cur) + + offset := uint(s - t - 1) + + // If t is invalid or src[s:s+4] differs from src[t:t+4], accumulate a literal byte. + if t < 0 || offset >= (maxOffset-1) || b0 != src[t] || b1 != src[t+1] || b2 != src[t+2] || b3 != src[t+3] { + // Skip 1 byte for 16 consecutive missed. + s += 1 + ((s - lit) >> 4) + continue + } + // Otherwise, we have a match. First, emit any pending literal bytes. + if lit != s { + emitLiteral(dst, src[lit:s]) + } + // Extend the match to be as long as possible. + s0 := s + s1 := s + maxMatchLength + if s1 > len(src) { + s1 = len(src) + } + s, t = s+4, t+4 + for s < s1 && src[s] == src[t] { + s++ + t++ + } + // Emit the copied bytes. + // inlined: emitCopy(dst, s-t, s-s0) + + dst.tokens[dst.n] = matchToken(uint32(s-s0-3), uint32(s-t-minOffsetSize)) + dst.n++ + lit = s + } + + // Emit any final pending literal bytes and return. + if lit != len(src) { + emitLiteral(dst, src[lit:]) + } + e.cur += len(src) +} + +// EncodeL2 uses a similar algorithm to level 1, but is capable +// of matching across blocks giving better compression at a small slowdown. +func (e *snappyGen) encodeL2(dst *tokens, src []byte) { + // Return early if src is short. + if len(src) <= 4 { + if len(src) != 0 { + emitLiteral(dst, src) + } + e.prev = nil + e.cur += len(src) + return + } + + // Ensure that e.cur doesn't wrap, mainly an issue on 32 bits. + if e.cur > 1<<30 { + e.cur = 1 + } + + // Iterate over the source bytes. + var ( + s int // The iterator position. + t int // The last position with the same hash as s. + lit int // The start position of any pending literal bytes. + ) + + for s+3 < len(src) { + // Update the hash table. + b0, b1, b2, b3 := src[s], src[s+1], src[s+2], src[s+3] + h := uint32(b0) | uint32(b1)<<8 | uint32(b2)<<16 | uint32(b3)<<24 + p := &e.table[(h*0x1e35a7bd)>>(32-tableBits)] + // We need to to store values in [-1, inf) in table. + // To save some initialization time, we make sure that + // e.cur is never zero. + t, *p = int(*p)-e.cur, int64(s+e.cur) + + // If t is positive, the match starts in the current block + if t >= 0 { + + offset := uint(s - t - 1) + // Check that the offset is valid and that we match at least 4 bytes + if offset >= (maxOffset-1) || b0 != src[t] || b1 != src[t+1] || b2 != src[t+2] || b3 != src[t+3] { + // Skip 1 byte for 32 consecutive missed. + s += 1 + ((s - lit) >> 5) + continue + } + // Otherwise, we have a match. First, emit any pending literal bytes. + if lit != s { + emitLiteral(dst, src[lit:s]) + } + // Extend the match to be as long as possible. + s0 := s + s1 := s + maxMatchLength + if s1 > len(src) { + s1 = len(src) + } + s, t = s+4, t+4 + for s < s1 && src[s] == src[t] { + s++ + t++ + } + // Emit the copied bytes. + // inlined: emitCopy(dst, s-t, s-s0) + dst.tokens[dst.n] = matchToken(uint32(s-s0-3), uint32(s-t-minOffsetSize)) + dst.n++ + lit = s + continue + } + // We found a match in the previous block. + tp := len(e.prev) + t + if tp < 0 || t > -5 || s-t >= maxOffset || b0 != e.prev[tp] || b1 != e.prev[tp+1] || b2 != e.prev[tp+2] || b3 != e.prev[tp+3] { + // Skip 1 byte for 32 consecutive missed. + s += 1 + ((s - lit) >> 5) + continue + } + // Otherwise, we have a match. First, emit any pending literal bytes. + if lit != s { + emitLiteral(dst, src[lit:s]) + } + // Extend the match to be as long as possible. + s0 := s + s1 := s + maxMatchLength + if s1 > len(src) { + s1 = len(src) + } + s, tp = s+4, tp+4 + for s < s1 && src[s] == e.prev[tp] { + s++ + tp++ + if tp == len(e.prev) { + t = 0 + // continue in current buffer + for s < s1 && src[s] == src[t] { + s++ + t++ + } + goto l + } + } + l: + // Emit the copied bytes. + if t < 0 { + t = tp - len(e.prev) + } + dst.tokens[dst.n] = matchToken(uint32(s-s0-3), uint32(s-t-minOffsetSize)) + dst.n++ + lit = s + + } + + // Emit any final pending literal bytes and return. + if lit != len(src) { + emitLiteral(dst, src[lit:]) + } + e.cur += len(src) + // Store this block, if it was full length. + if len(src) == maxStoreBlockSize { + copy(e.block[:], src) + e.prev = e.block[:len(src)] + } else { + e.prev = nil + } +} + +// EncodeL3 uses a similar algorithm to level 2, but is capable +// will keep two matches per hash. +// Both hashes are checked if the first isn't ok, and the longest is selected. +func (e *snappyGen) encodeL3(dst *tokens, src []byte) { + // Return early if src is short. + if len(src) <= 4 { + if len(src) != 0 { + emitLiteral(dst, src) + } + e.prev = nil + e.cur += len(src) + return + } + + // Ensure that e.cur doesn't wrap, mainly an issue on 32 bits. + if e.cur > 1<<30 { + e.cur = 1 + } + + // Iterate over the source bytes. + var ( + s int // The iterator position. + lit int // The start position of any pending literal bytes. + ) + + for s+3 < len(src) { + // Update the hash table. + h := uint32(src[s]) | uint32(src[s+1])<<8 | uint32(src[s+2])<<16 | uint32(src[s+3])<<24 + p := &e.table[(h*0x1e35a7bd)>>(32-tableBits)] + tmp := *p + p1 := int(tmp & 0xffffffff) // Closest match position + p2 := int(tmp >> 32) // Furthest match position + + // We need to to store values in [-1, inf) in table. + // To save some initialization time, we make sure that + // e.cur is never zero. + t1 := p1 - e.cur + + var l2 int + var t2 int + l1 := e.matchlen(s, t1, src) + // If fist match was ok, don't do the second. + if l1 < 16 { + t2 = p2 - e.cur + l2 = e.matchlen(s, t2, src) + + // If both are short, continue + if l1 < 4 && l2 < 4 { + // Update hash table + *p = int64(s+e.cur) | (int64(p1) << 32) + // Skip 1 byte for 32 consecutive missed. + s += 1 + ((s - lit) >> 5) + continue + } + } + + // Otherwise, we have a match. First, emit any pending literal bytes. + if lit != s { + emitLiteral(dst, src[lit:s]) + } + // Update hash table + *p = int64(s+e.cur) | (int64(p1) << 32) + + // Store the longest match l1 will be closest, so we prefer that if equal length + if l1 >= l2 { + dst.tokens[dst.n] = matchToken(uint32(l1-3), uint32(s-t1-minOffsetSize)) + s += l1 + } else { + dst.tokens[dst.n] = matchToken(uint32(l2-3), uint32(s-t2-minOffsetSize)) + s += l2 + } + dst.n++ + lit = s + } + + // Emit any final pending literal bytes and return. + if lit != len(src) { + emitLiteral(dst, src[lit:]) + } + e.cur += len(src) + // Store this block, if it was full length. + if len(src) == maxStoreBlockSize { + copy(e.block[:], src) + e.prev = e.block[:len(src)] + } else { + e.prev = nil + } +} + +func (e *snappyGen) matchlen(s, t int, src []byte) int { + // If t is invalid or src[s:s+4] differs from src[t:t+4], accumulate a literal byte. + offset := uint(s - t - 1) + + // If we are inside the current block + if t >= 0 { + if offset >= (maxOffset-1) || + src[s] != src[t] || src[s+1] != src[t+1] || + src[s+2] != src[t+2] || src[s+3] != src[t+3] { + return 0 + } + // Extend the match to be as long as possible. + s0 := s + s1 := s + maxMatchLength + if s1 > len(src) { + s1 = len(src) + } + s, t = s+4, t+4 + for s < s1 && src[s] == src[t] { + s++ + t++ + } + return s - s0 + } + + // We found a match in the previous block. + tp := len(e.prev) + t + if tp < 0 || offset >= (maxOffset-1) || t > -5 || + src[s] != e.prev[tp] || src[s+1] != e.prev[tp+1] || + src[s+2] != e.prev[tp+2] || src[s+3] != e.prev[tp+3] { + return 0 + } + + // Extend the match to be as long as possible. + s0 := s + s1 := s + maxMatchLength + if s1 > len(src) { + s1 = len(src) + } + s, tp = s+4, tp+4 + for s < s1 && src[s] == e.prev[tp] { + s++ + tp++ + if tp == len(e.prev) { + t = 0 + // continue in current buffer + for s < s1 && src[s] == src[t] { + s++ + t++ + } + return s - s0 + } + } + return s - s0 +} + +// Reset the encoding table. +func (e *snappyGen) Reset() { + e.prev = nil +} + +// snappySSE4 extends snappyGen. +// This implementation can use SSE 4.2 for length matching. +type snappySSE4 struct { + snappyGen +} + +// EncodeL3 uses a similar algorithm to level 2, +// but will keep two matches per hash. +// Both hashes are checked if the first isn't ok, and the longest is selected. +func (e *snappySSE4) encodeL3(dst *tokens, src []byte) { + // Return early if src is short. + if len(src) <= 4 { + if len(src) != 0 { + emitLiteral(dst, src) + } + e.prev = nil + e.cur += len(src) + return + } + + // Ensure that e.cur doesn't wrap, mainly an issue on 32 bits. + if e.cur > 1<<30 { + e.cur = 1 + } + + // Iterate over the source bytes. + var ( + s int // The iterator position. + lit int // The start position of any pending literal bytes. + ) + + for s+3 < len(src) { + // Load potential matches from hash table. + h := uint32(src[s]) | uint32(src[s+1])<<8 | uint32(src[s+2])<<16 | uint32(src[s+3])<<24 + p := &e.table[(h*0x1e35a7bd)>>(32-tableBits)] + tmp := *p + p1 := int(tmp & 0xffffffff) // Closest match position + p2 := int(tmp >> 32) // Furthest match position + + // We need to to store values in [-1, inf) in table. + // To save some initialization time, we make sure that + // e.cur is never zero. + t1 := int(p1) - e.cur + + var l2 int + var t2 int + l1 := e.matchlen(s, t1, src) + // If fist match was ok, don't do the second. + if l1 < 16 { + t2 = int(p2) - e.cur + l2 = e.matchlen(s, t2, src) + + // If both are short, continue + if l1 < 4 && l2 < 4 { + // Update hash table + *p = int64(s+e.cur) | (int64(p1) << 32) + // Skip 1 byte for 32 consecutive missed. + s += 1 + ((s - lit) >> 5) + continue + } + } + + // Otherwise, we have a match. First, emit any pending literal bytes. + if lit != s { + emitLiteral(dst, src[lit:s]) + } + // Update hash table + *p = int64(s+e.cur) | (int64(p1) << 32) + + // Store the longest match l1 will be closest, so we prefer that if equal length + if l1 >= l2 { + dst.tokens[dst.n] = matchToken(uint32(l1-3), uint32(s-t1-minOffsetSize)) + s += l1 + } else { + dst.tokens[dst.n] = matchToken(uint32(l2-3), uint32(s-t2-minOffsetSize)) + s += l2 + } + dst.n++ + lit = s + } + + // Emit any final pending literal bytes and return. + if lit != len(src) { + emitLiteral(dst, src[lit:]) + } + e.cur += len(src) + // Store this block, if it was full length. + if len(src) == maxStoreBlockSize { + copy(e.block[:], src) + e.prev = e.block[:len(src)] + } else { + e.prev = nil + } +} + +func (e *snappySSE4) matchlen(s, t int, src []byte) int { + // If t is invalid or src[s:s+4] differs from src[t:t+4], accumulate a literal byte. + offset := uint(s - t - 1) + + // If we are inside the current block + if t >= 0 { + if offset >= (maxOffset - 1) { + return 0 + } + length := len(src) - s + if length > maxMatchLength { + length = maxMatchLength + } + // Extend the match to be as long as possible. + return matchLenSSE4(src[t:], src[s:], length) + } + + // We found a match in the previous block. + tp := len(e.prev) + t + if tp < 0 || offset >= (maxOffset-1) || t > -5 || + src[s] != e.prev[tp] || src[s+1] != e.prev[tp+1] || + src[s+2] != e.prev[tp+2] || src[s+3] != e.prev[tp+3] { + return 0 + } + + // Extend the match to be as long as possible. + s0 := s + s1 := s + maxMatchLength + if s1 > len(src) { + s1 = len(src) + } + s, tp = s+4, tp+4 + for s < s1 && src[s] == e.prev[tp] { + s++ + tp++ + if tp == len(e.prev) { + t = 0 + // continue in current buffer + for s < s1 && src[s] == src[t] { + s++ + t++ + } + return s - s0 + } + } + return s - s0 +} diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-null-max.dyn.expect b/vendor/github.com/klauspost/compress/flate/testdata/huffman-null-max.dyn.expect new file mode 100644 index 0000000000000000000000000000000000000000..c08165143f2c570013c4916cbac5addfe9622a55 GIT binary patch literal 78 ZcmaEJppgLx8W#LrDZUcKq5v#l0|1+Y23i0B literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-null-max.dyn.expect-noinput b/vendor/github.com/klauspost/compress/flate/testdata/huffman-null-max.dyn.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..c08165143f2c570013c4916cbac5addfe9622a55 GIT binary patch literal 78 ZcmaEJppgLx8W#LrDZUcKq5v#l0|1+Y23i0B literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-null-max.golden b/vendor/github.com/klauspost/compress/flate/testdata/huffman-null-max.golden new file mode 100644 index 0000000000000000000000000000000000000000..db422ca3983d12e71e31979d7b3dddd080dcbca7 GIT binary patch literal 8204 zcmeIuK@9*P3YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ t0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFwg)F00961 literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-null-max.wb.expect b/vendor/github.com/klauspost/compress/flate/testdata/huffman-null-max.wb.expect new file mode 100644 index 0000000000000000000000000000000000000000..c08165143f2c570013c4916cbac5addfe9622a55 GIT binary patch literal 78 ZcmaEJppgLx8W#LrDZUcKq5v#l0|1+Y23i0B literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-null-max.wb.expect-noinput b/vendor/github.com/klauspost/compress/flate/testdata/huffman-null-max.wb.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..c08165143f2c570013c4916cbac5addfe9622a55 GIT binary patch literal 78 ZcmaEJppgLx8W#LrDZUcKq5v#l0|1+Y23i0B literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-pi.dyn.expect b/vendor/github.com/klauspost/compress/flate/testdata/huffman-pi.dyn.expect new file mode 100644 index 0000000000000000000000000000000000000000..e4396ac6fe5e34609ccb7ea0bc359e6adb48c7f4 GIT binary patch literal 1696 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 EAEW(DiU0rr literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-pi.in b/vendor/github.com/klauspost/compress/flate/testdata/huffman-pi.in new file mode 100644 index 0000000..efaed43 --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/testdata/huffman-pi.in @@ -0,0 +1 @@ +3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420198938095257201065485863278865936153381827968230301952035301852968995773622599413891249721775283479131515574857242454150695950829533116861727855889075098381754637464939319255060400927701671139009848824012858361603563707660104710181942955596198946767837449448255379774726847104047534646208046684259069491293313677028989152104752162056966024058038150193511253382430035587640247496473263914199272604269922796782354781636009341721641219924586315030286182974555706749838505494588586926995690927210797509302955321165344987202755960236480665499119881834797753566369807426542527862551818417574672890977772793800081647060016145249192173217214772350141441973568548161361157352552133475741849468438523323907394143334547762416862518983569485562099219222184272550254256887671790494601653466804988627232791786085784383827967976681454100953883786360950680064225125205117392984896084128488626945604241965285022210661186306744278622039194945047123713786960956364371917287467764657573962413890865832645995813390478027590099465764078951269468398352595709825822620522489407726719478268482601476990902640136394437455305068203496252451749399651431429809190659250937221696461515709858387410597885959772975498930161753928468138268683868942774155991855925245953959431049972524680845987273644695848653836736222626099124608051243884390451244136549762780797715691435997700129616089441694868555848406353422072225828488648158456028506016842739452267467678895252138522549954666727823986456596116354886230577456498035593634568174324112515076069479451096596094025228879710893145669136867228748940560101503308617928680920874760917824938589009714909675985261365549781893129784821682998948722658804857564014270477555132379641451523746234364542858444795265867821051141354735739523113427166102135969536231442952484937187110145765403590279934403742007310578539062198387447808478489683321445713868751943506430218453191048481005370614680674919278191197939952061419663428754440643745123718192179998391015919561814675142691239748940907186494231961567945208095146550225231603881930142093762137855956638937787083039069792077346722182562599661501421503068038447734549202605414665925201497442850732518666002132434088190710486331734649651453905796268561005508106658796998163574736384052571459102897064140110971206280439039759515677157700420337869936007230558763176359421873125147120532928191826186125867321579198414848829164470609575270695722091756711672291098169091528017350671274858322287183520935396572512108357915136988209144421006751033467110314126711136990865851639831501970165151168517143765761835155650884909989859982387345528331635507647918535893226185489632132933089857064204675259070915481416549859461637180 \ No newline at end of file diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-pi.wb.expect b/vendor/github.com/klauspost/compress/flate/testdata/huffman-pi.wb.expect new file mode 100644 index 0000000000000000000000000000000000000000..e4396ac6fe5e34609ccb7ea0bc359e6adb48c7f4 GIT binary patch literal 1696 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 Yxt^P)DKm4sCRYuzNKydW#Fu~kAGX;UBLDyZ literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.dyn.expect-noinput b/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.dyn.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..0c24742fde2487e3a454ec3364f15e541693c37c GIT binary patch literal 1054 zcmV+(1mXJxzzaAU2mk=!nayIXbMy_f)7H$mL&SF;F?3`%k8@)&&%@Oe(UOiioadDG zS>BI}35WJ&PF@*1*&LbA=aF5pFj3x*HIFRrKcto>d1~bp8)vlgPG~al`sLh_uD4>f zwcquqQs)bz`O{dU_?0E5ZyfOj3vL$R|;Io1R(-}eKi+pE+?-hv`IeFsDFRE4SU5j~y=5(3C6?qYw^br64(dswwJMG1iwh9bz5{6%{CK{d z?OTrws1RG0;tdgAc^^}S;a;h-Le*Jl$;@?4WVbi2?}j$(yZ8P0lo@^JyA?I@?GEt7oU6m&;AhmaN!WN2o4Ue&a8T%J8g~M#1p4zh)_hxG4z2`Ogny za;mxRW4Md@6TRsPIrIrmbY`0*@-5uMh;C)*<4Qh|=G6i5GP){GL)z@9EkaXFMahfN zv?c%P&)d;?j&h!ypwqm%P^YHL3jM3}%*^0B)TTYwcr0m+>#+B{By^cDULDE6Dg;&& zO=u{r#qY9CX2q~>M2)v~oJjxXwYfA4W6UEykUq9QGg?N01rigUU44BE!qnW&8XUe) zez=s$?Lpl~RS(YSo`<)!77bHS>Gu?tEqHX60yc4tb%nr56)BI?!K^R=U-@BSOT=w5 zsVIvXfM*tHgqR0EakjC|{oW&au|@y5MGR8cGC-Yn06%^E0PC$!Cb-Z0wr}jN>)ms9 zL;@;_wIK!J>p%w{0>eRLG6F9RY`9EcFXkV~=#m(_eoQp~r+?KjZg}QSSL~iFyscF_ z+e_{^90j}~rTuecm=4dkoD6jMc=)XI@ePwzb~aU<_(Cb{iZR=;j^CkY@49GGUfJU< zh|_pVqS;)85%YqWL`@t%i6ZSgMZJLK5AGbA<2Z~&Y6y(OZ<17W7CzqwPW|%tkU??k z4*_!bQ%1vsp<0>Q04?4|yQkkrm{&#|cY?4524U<_tm@Hqt*?a07|`vlpP7J3xS#y+ zPf2l=uqk^9aS%w&GBx^|J3nR zNecGe6yILAWA?u!e(Cl<@PcA2?CSjWxPaGt_JWfJ*C8~T`^Pp$vI5uS*J~uVqo@>8 Yxt^P)DKm4sCRYuzNKydW#Fu~kAGX;UBLDyZ literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.golden b/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.golden new file mode 100644 index 0000000000000000000000000000000000000000..09dc798ee37df82176b8b7c9998c88a14207c1ad GIT binary patch literal 1005 zcmVlcQ}x5eHD>U|iC=ROD8-~ViL-puE1 zjRYA__oQ{&>YEB=3*aLuz4zyXJp13Xu1};#Rhix|mTnwF zOo!rp*PZhF=TqnOy;6>9pEFaaeUqI8B!YL)2W zP7ZdtNvU6;rei#QejpQ1yJnKOE~NTM%dWXRuhSpl)r~@J@cfJn0Ny~Wi$|AEsLzhu zri&m6gnDM>m?;94<~TB71LK+=ROn-XNSxENOU6sujQmH^hn%vbF>Y9-Bf>bg4ep_N_banGD$o@)BlG0~`IFf*!A z7ZZY+$P{3oO)_oT873jzel8_va>@^q&Gy#Imx?o3b8wLzzbGT44Do}*$X0h~ljl$J4Xnb zbD&&|U+WJ#!b4}YW@ms{4#Dg|)FPD1`RJ15X*j-TWXe#-24_NUqwu$E^5|c&ujkvl zceVJ-2*h=M!1)}1Jc%#TSUTePk+ypzC+V()i{5ms{n@u^D(o_E@REe_Kn#k!Ic_d< z)NYD&D%@ZnqX*t~i*(5TV|DgDW2`fY!|?bmYqXwpi(E6b%BbX-wveIk57S|?#u}7- zL{;=f|DL5<#-Qjb!HsV;5xKrj*@u^N&pjiq)f!%|U1|gQA`KAPM`;y5?oy)&(mYZ0 z_?_gKiO6R;)m}AtC+IwYu6c3Nlk}=l5*$k#%8*z(mO5DYDWih#pN0k_;dS~5vECO-S0Dj5 literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.in b/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.in new file mode 100644 index 0000000000000000000000000000000000000000..ce038ebb5bd911cd054b86c044fd26e6003225e2 GIT binary patch literal 1000 zcmV&K%;#;51Q|(x zM;}NPu;`xhFDh+BMJ6ccYFsSUg>Bfi<~bp&jg-~DiA=I+_Co^FF# z)zpAln0JXoILWUtGMXS8Mm=Y4*K(dtAy3BO)O!Str33Z_n`_)ElXocnv|`#I=O3$U zQA0T|pppS>bw2bp{X;JIq;=Zrn+jwL;3Fx$_veE=``@#!Pozgxncgp!ZX82QhvIzM zUrc=HkOSK=mDVB*N4QOEy(AHOADFT(|I5J=Zkm4@Lua&RXMk7^!R$cPB9zMc=#u1VIKF3O%23A!XF_hH@V9L8=wGp~=i9q?wfM^j z#C3ka`5b>di7(PvI^y_|wtFNe>8^x}-gK<}*|%vb>@sigl7#U<42rxtZZ31wZi;j& z++ZK02i|pybjbc=b@n}DtTTzj@c1ojw4QW}Tr;%FsN|WpkfHAn(_ym48kBrQRrE#w zo~2sGpy(>Wjc+s&xxP->hnI8DJtMBw8eXnlY6JNq4G`H!X%#>2QlkjcJW=%co#dE_ z$Y(j#UNv|p=sbX~d2!N{^r}%397`MJZWV9jyHT4(pZUa$D*GDWRnth5CjlnHYgKKc z`-F?ho+!fa8YJwSuDxLC6*cZcq%&Lk54QIKrUFdLkXSmFLFdZ}jN64xsEPBnj{S98 zPwn16>o}vnuyg#lRQF6UXD&FRR2aGlzw$ZN{-r_2W@fs9?`P!ZJPgXD3VE|vi;8ua W7(y>8qk`|Bh6W?yb@~Xg-WN)Vp#LfW literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.wb.expect b/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.wb.expect new file mode 100644 index 0000000000000000000000000000000000000000..09dc798ee37df82176b8b7c9998c88a14207c1ad GIT binary patch literal 1005 zcmVlcQ}x5eHD>U|iC=ROD8-~ViL-puE1 zjRYA__oQ{&>YEB=3*aLuz4zyXJp13Xu1};#Rhix|mTnwF zOo!rp*PZhF=TqnOy;6>9pEFaaeUqI8B!YL)2W zP7ZdtNvU6;rei#QejpQ1yJnKOE~NTM%dWXRuhSpl)r~@J@cfJn0Ny~Wi$|AEsLzhu zri&m6gnDM>m?;94<~TB71LK+=ROn-XNSxENOU6sujQmH^hn%vbF>Y9-Bf>bg4ep_N_banGD$o@)BlG0~`IFf*!A z7ZZY+$P{3oO)_oT873jzel8_va>@^q&Gy#Imx?o3b8wLzzbGT44Do}*$X0h~ljl$J4Xnb zbD&&|U+WJ#!b4}YW@ms{4#Dg|)FPD1`RJ15X*j-TWXe#-24_NUqwu$E^5|c&ujkvl zceVJ-2*h=M!1)}1Jc%#TSUTePk+ypzC+V()i{5ms{n@u^D(o_E@REe_Kn#k!Ic_d< z)NYD&D%@ZnqX*t~i*(5TV|DgDW2`fY!|?bmYqXwpi(E6b%BbX-wveIk57S|?#u}7- zL{;=f|DL5<#-Qjb!HsV;5xKrj*@u^N&pjiq)f!%|U1|gQA`KAPM`;y5?oy)&(mYZ0 z_?_gKiO6R;)m}AtC+IwYu6c3Nlk}=l5*$k#%8*z(mO5DYDWih#pN0k_;dS~5vECO-S0Dj5 literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.wb.expect-noinput b/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.wb.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..0c24742fde2487e3a454ec3364f15e541693c37c GIT binary patch literal 1054 zcmV+(1mXJxzzaAU2mk=!nayIXbMy_f)7H$mL&SF;F?3`%k8@)&&%@Oe(UOiioadDG zS>BI}35WJ&PF@*1*&LbA=aF5pFj3x*HIFRrKcto>d1~bp8)vlgPG~al`sLh_uD4>f zwcquqQs)bz`O{dU_?0E5ZyfOj3vL$R|;Io1R(-}eKi+pE+?-hv`IeFsDFRE4SU5j~y=5(3C6?qYw^br64(dswwJMG1iwh9bz5{6%{CK{d z?OTrws1RG0;tdgAc^^}S;a;h-Le*Jl$;@?4WVbi2?}j$(yZ8P0lo@^JyA?I@?GEt7oU6m&;AhmaN!WN2o4Ue&a8T%J8g~M#1p4zh)_hxG4z2`Ogny za;mxRW4Md@6TRsPIrIrmbY`0*@-5uMh;C)*<4Qh|=G6i5GP){GL)z@9EkaXFMahfN zv?c%P&)d;?j&h!ypwqm%P^YHL3jM3}%*^0B)TTYwcr0m+>#+B{By^cDULDE6Dg;&& zO=u{r#qY9CX2q~>M2)v~oJjxXwYfA4W6UEykUq9QGg?N01rigUU44BE!qnW&8XUe) zez=s$?Lpl~RS(YSo`<)!77bHS>Gu?tEqHX60yc4tb%nr56)BI?!K^R=U-@BSOT=w5 zsVIvXfM*tHgqR0EakjC|{oW&au|@y5MGR8cGC-Yn06%^E0PC$!Cb-Z0wr}jN>)ms9 zL;@;_wIK!J>p%w{0>eRLG6F9RY`9EcFXkV~=#m(_eoQp~r+?KjZg}QSSL~iFyscF_ z+e_{^90j}~rTuecm=4dkoD6jMc=)XI@ePwzb~aU<_(Cb{iZR=;j^CkY@49GGUfJU< zh|_pVqS;)85%YqWL`@t%i6ZSgMZJLK5AGbA<2Z~&Y6y(OZ<17W7CzqwPW|%tkU??k z4*_!bQ%1vsp<0>Q04?4|yQkkrm{&#|cY?4524U<_tm@Hqt*?a07|`vlpP7J3xS#y+ zPf2l=uqk^9aS%w&GBx^|J3nR zNecGe6yILAWA?u!e(Cl<@PcA2?CSjWxPaGt_JWfJ*C8~T`^Pp$vI5uS*J~uVqo@>8 Yxt^P)DKm4sCRYuzNKydW#Fu~kAGX;UBLDyZ literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.dyn.expect b/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.dyn.expect new file mode 100644 index 0000000000000000000000000000000000000000..2d6527934e98300d744c7558a025250f67e0f1c9 GIT binary patch literal 229 zcmVoXRI~IhW&XxGJNu5- o$p8QV literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.in b/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.in new file mode 100644 index 0000000..fb5b1be --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.in @@ -0,0 +1,4 @@ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +vH +% ɷ}>lsmIGH1Y4[ 0ˆ[|]o# +-#ulpfٱnYԀYwC8ɯ02 F=gnrN!O{k*w(b kQC9/lu>5C.u diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.wb.expect b/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.wb.expect new file mode 100644 index 0000000000000000000000000000000000000000..881e59c9ab9bb356c5f1b8f2e188818bd42dbcf0 GIT binary patch literal 186 zcmV;r07d^wq#oe<(LJrqgR6ClYQy?N|9W32ycTaex&7!pwpX+&C|&*fKV2Rd8oFPOxbQ)>6c^slqt_a&vbUd`qL0Dk3ZG5`Po literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.wb.expect-noinput b/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.wb.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..881e59c9ab9bb356c5f1b8f2e188818bd42dbcf0 GIT binary patch literal 186 zcmV;r07d^wq#oe<(LJrqgR6ClYQy?N|9W32ycTaex&7!pwpX+&C|&*fKV2Rd8oFPOxbQ)>6c^slqt_a&vbUd`qL0Dk3ZG5`Po literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-max.golden b/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-max.golden new file mode 100644 index 0000000000000000000000000000000000000000..47d53c89c077d0e62aeaf818154f60921960de5c GIT binary patch literal 65540 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

EX1}=qzy8wF0O3Y(SaC~(L zw;1S%=h`|m*`8^eTcei#g#yS=Nh&;ZBuiR@s{SsC)-2T;<6$q>3Zg1xD3tL~4a2F* zOZWLS;OsyPT+SQ@tOhvEeV(w8+4vr3@B@|MdZTr{(cY-n_pSPhYp1uevWxu0cQ5pM zX=6VH&we=N4jauzyV38=UBx5?K&^o*^cV*hXgaPCRWIXbm@h2qLqzEVU9O5sQO-~F zuQxV3y;a2?K6v%k@<@)=4?nicEWT}V3;>-00XWt|$}FM#3B z(%LBqL>t|pwrYE}=Yu5zKV1bWRH^}5Ca_QN1T58UTBqB2@x)vILrEbLwJtyY=T}cQm@I|woVgIvI~9X6q6KA3+&mw@(OYliwen}Q zI7C1H*m~9x&F)W2;Y!-Xu40HHU`Js70}4j9%6-eTSgZ?3o`ClHNO`y4SDn|yUVG>z z55IU3b9_kBg+vw=ki{>gWl?XQv>Nry-nR z!Aw!1Y`B?%>h5JT+0`^~b4?uP`EsWVaXh&}r}qKJPe?|#b=>HKFq-|@_2C>u6oZJy zf|EFUhgivi-&}(j7G*khsiEtZuIq#t#Mw$@FOqFM-T9{yj8Zes3|&cJ9IU|TA9wog zIp08^w*)edflL4hyf}nfH z0OJ-B#wKka+zzKrQuDv`*!q>|-s6%JpQ(GN-8*SE7NSYR&m=${M)jaB#;MrHFJb9 zZlCnp{q79NnmEQt%|R1D8^AGQ^op{;d(j+(8m?m;Ii}dEB-;bn+kuhD<5L?VSY*G` zR0JzCU4cw@Jf5L|fPBLD9pXZqciA!RqG8*bwqMCtKx>>50cNE*hGiS@`n_w-v*uZ& zd952ZZ#TPh^UniU2MhK1(qrqHI6Q2hOC2m(JrqS7LfoOM0h!j6a5Qpk6TBgX=*fks z!xQiqHDjHJlf_+5scqd0o-3WIf4#xCfBoZ9awjesXtX;Jh|ey4;)4WdCDUy>tFBJY3Ml|5J)O5*S~GXJ4P9 zD2;lfeR9&CQIrLQDTK9y@wf!49YC}P3=69_e9X#YUK?T!<_8QSbC2JgE}qlkE>z=B zH}I3u3>ddMDl1oT4lsh-jiI%D7}O@OT32I50yfY~S&H zH{*j$Tmx8^ol{EknQB~bUTf6Tk;e)%xf6*bVfkNdAn+I&zF8vh=_qh134}pvp@J{( zSFr>LoE}G$3!ylMw1EiFD|%@H-{@bH!g4tfykn7EduX(6tX;=)OxK7L>t~J5M(1(q zj%@Br((?GSXk%0_`wq{b1zjP$H z88}|mVcfQYfSK@9rzNn$Hsvdnw|xy_k&}(I_Z)(`wvf#J?w)= zc8EblGex9qnF# zsz@afF_4uy8%%e-A!Wo;sjUfcM|BQlJdMN+O;?KfLfP8i&*mz7%As1^KRh@9Wcl0` zHxJIF%3b=2&u6scp?fh@%D?XShOxx zOzNBd6}_YouVOes8De$I(mk-na#|5iRr7kYao6l{V!+JD*JJjdglB(06;sbMODtjlVU}u|4$0bA3YtO7q@2y<_i0JZsk)=+mEC>4lwVPl6TlO;)|})F)U1RK@180{vI`vBsV(`J)Yd`?A+vLr`7MA^qaGroi!9UK*#YqhcWL6?>iw9 z5yJCCRaC3Y^BvQ7)Z4q+IlE;A!}9yT{`h*R{>$*}hVQ)3jtgA;FJU~gfsXtPJp1Mpfp66@7@5(; zGzfJ{fWR|bXD$O0MFn%P*oO(l(5dCwp37ZgY|sB(kidUZf}yNvHHPm$Bx!XjR9{2k zS@7OIkC|<9_`!$6?|5AZ%HgLglsX%u^o!JAf5!%m#`x-;sUSp-rTB1K<3qx0;bao= z(QvAo0XB$jeDrFj8h!cuQkhZNZ>tI%qS{28 zjzS)46ZrGKsq7XEEnmrID|VJR6{0%S&UzKwGpVjp-DRoh_ImTIwVoS2C#hQA-o727 zC}|!46L|K4R64HHZua`~l38^X$qkQT`p3hLDmX&ICmu+}^NFuu-K>X6p_`}Ul(|3@ zKw+QbSpC2T9`z-7HrbI&0NQ<^Aide`?eaKj%80|C6*xc)BR#j^>IN z>~6N4C6(O4erfmMK%)m)Yd^1AB}b)HCv#@oXorpK@Yi}+d(OaPDU_ewpzFxtzbBQ) zO89zAZfBCH)e<067i3{lYJ1ot;#i(z+gMEwHVfi&@Z8J`wnyh{LOE9#&rdIevOHUV z1kb*AdA52DAR+B~SK@@LK&BzbG9`|Fn`1df;QK=HtJOdpsp2T8=|0cg^s2D8R_Ad4 zc`kK+W`k7Fvpk!!z_K$04IitMXsV5($rQP+LV1nhG#*9SHL!Fc`Kq~n!NGNf^ghRVbh&VeuTf(i%kIs;zys=f$><;LA& z0xMv*9XEGC5K*^0c6U@q$>^wH?c$maUlfO?tyF(%`n>SO4Vk7bdeGL^c;qq z>ZyHLx|ND`8#rPQ&0=D6Q5Oc$crZn~I~CCwED`k_OS6l+cBNt++O$kP)85sy86&G% z1udI9P*!bjJ6(F*k^9{47*KMj^E-I9s%e7q!VgOo?XyU>gOThkkWGn1RiheOB!dW( zbE^cVsTvfsfy0cd&C3qexOZeb^yY!=xyAA?Bub@T{b22~#7~fVy*G8ome8yl5brAR z|M+;EBAH1<;k8K=e=4NRY(^N(Ixgo51wmyT1)ND-cBeJr%R2GXo&QauCF=bjtX+}hgY@MC zQk}z+s-Vi0<}$+H6G$`pM8hyFAE>!v1;nxEdPXtJNlEAUfhUZ4uImCN1KBiQ)o4H5 zc(7T2I98%fl;svg^5qW=PhSro?9%zBZ+!I}7Shx18GKW%MK=3?T}W!FM}Gs)&UWPT zvv#)!5NDinMNS$S#+5amha3`{Tl^zF`v~FYj6H)IOp$LE8YgFs^&H)~EyBN)Vl363 z$tpQ>7>j*xdWyw7?)v_nnVg=uG&6Nz5TYd_O-xD^Wxtp${%Mr7!u0t1mknymwO~M;jXj%8T+o;#ub6S>0Fqnp? zhGAMD1H;OhrsrxIZh56FD;08Xp`208!a)&pc2^#0oISgl(If^N+pBl(puIX_1An#1 z%P%Q1GK6PRTwi7bs~AQj${o!UM}{ewZDJKOa(v6iv@q6jVi^vfqxc_h&IazVNqiZB z{WZckOtXPkgDl>ia-Pj@v!0|VP({LNIH(1{^SR)|+EAO0u>}UZU<}J6Xq|;;Goxra zHnAupd5_S1eh%f=HWq81tin0G6F8rj?A2;n9on_uNL@0>HcYGvMayOm3%T8LIa@j; zg;K>1m;Os2yf=h5fu)a7#cjor-0bE!#OPQ)*d`lbT}FzuxR_RQALe zx6Tp1V7#?@U-D5o@3Izy%?{LH7!1^K5)Eq{ydf5(`JV1^A3`w~3uc++0Uhws+2BB% zdlQ2t6ca<0)$tq{(!4tjVi~@q#4wnsQ!h(N{!lZNQdT#2b?Ui$8gVeBWQ<#4&*L?kk~6L3XTE5yVBQIOR_)v`ng&Y@OLnb zxaK%^EW3e>Bt36FB7v%*zw!mvww4@f5#>_VZ^VL#E={&WXa!= zt{RXSaTp0P6%!DGP)1s97~aTQPQl&9c}|#}_dOSjY#W0cIqUsWnwLKj0 z6eqwuZ!{`*UJmyaZN_6HUSmdxQg?3L-yJHZq zkB`(9`1Q!6P5ez7A#~DfcRSsAQT!kn)|6=Z;U4lRFFrX;1j`SERe7E6QfecJeNYYM zzRlAq7AQ6%z^1U5zU*Z$fB7q3@$kbBpFZ%C(}y2^@rxHm_9qr{cyOT=_-p|oo_5e` zHcwh7%{c>!zkTV$xIrne;y3`5P~2;u`fv}^5e2~TjrXk?+V(9l49AO3B4dZ>9J+6_#etFKjj&?M}1Pm=FAD!;_Ovt6T5QAGBWZm5pYr z-f!0%ZD}Y->w5Z1bTPQ)(s>5ABuwhxEYxGkq|kKzP|EqqW@@US$Efk)lz_GmYW%cZ z+&y$j0RoN!d=I`)OA6I(1^#%&1f%8gc#4pShtGwL&h`FAJ9XbVjBR44{%C`e|Bhf-{U+?PajGPo#Am z|K+!~Q(GX6S0Knbz8%8i>P?-H(NOR~P#be)3e3<@D>`>ewm9&#d_M2eJ$)CLNG4M( z794l4wC_VCF6nsu@=3V%|9yCUy4PDkBOaGD0)puJ34{mBmx#YU@W0wL8V=C^j)-1S zD>SDn4xz-VRC0Dk%UGJK?wPrYQ_N+o!^5O|vlBMLRKtJ&{B>dQeg4h-wfCP$j>ON# z2YU~Gy?gIXmzUq?tS+qA?=@$&prg@rNVH%WOf{iS12H|Nj$10R!))H=W`$YVJqwPr zLtM+D5Vch-D~=Ja#2Iza?dA(!*gI*}>nE)jv^uD^ofo_iDC0@1*FKp)X>>ukTfl}} zt>pg{=iM6cC8WzpJ1M=m1D(iTTH5BByT zReVNxj#fDnI6v0rZZ!bCjxVQe&gE|bK%cZaU9ev#bL$0Ikc|bN zg>`B06$HFmjl180`Ir2yVeh#wP_Lf8c#(oY=QMLzOOc`zdwVLIB0H=xsZB&QnUHA| zO$S;y9SaCaM4Y@2j(p+yqFNPIY<~rYP{p~lH@gPDz(mK>W##ENJ+WS+_VFjAO5oVk zHS4W*BeB-gF_}zjsxlbI#hc0i8?hK>9I!vpXAVv>#;#t7Qf%t^9x1ZYW*CXJzVL1K zw=G~SPt+%#kP2}?>}{O-)@n88lbfR2V9d3e3J!D{YCI}o?$^V%J{$-vkmci85eyw2 z$H&=kuCw(>U1Xr+0>o=KfcV8Hq>7K&|F^r{dV5}Jw;~8K#*7cnp@E1hh))#uR^xSW z;DW92ufN)opfXCdbAK82E!U5vs+lD#6(1vjfJjEzkWsP< zDy622_t=3I_^$5aF;-RaNUsmVB4oT;&*Or{$1z-baJV8$U3+=t%+h$WABa8&i- z4`6k-^ut|vHpi!>?|!v@2xau~)McqG4>FD>gbNZ)qi`51p)zm<2hSmNYWY^q30zU; zyo!}Wpf7kiq6Z4u3`3U2g)HtbE?_LR0}a>*Qo)LBtX4scOR8<^xf072fXMlVt+@g7 zDK;kiASGdfQ`ug6b0K4u$l~K0WPu)WQBS+({UB_H5PGT&6;07<$^dpiiNBOYmJdb= zTXm~55r}ve75>5r^WaW`^zfs*HViXBw=(4O02l9 zpuX>WE=~gjPwv92V-b!JF0iZZ+afOH{SwFV?>5+}uX{2*8l`s(v3Umw?MyF5k*JL( zkw!)&8W27j+m1mUuv3Px^Lw7473virPPjrr^;z%Lp6;i0?h3gxYcONCt5^GrlL5R3b7s6#!g*oQ-@+o1Hv6zVGeWMEgF8; z4AtLmu(#j+WO_(;=eT{+Zgtyp81bvC(?JwPHEkSe1BSDgak37_tqMoJD~{qE-Qkg8 zgNloiMXqdxaj`mu_+&X%6z^-n&!R(bjdPo_6UbdQ_;UcK9& zXX9%MQ6cIB!6<5N8b+S(l-z>jGmtDo71)6uRWb#^}Qgn=bDW6xiTB{2cZGKu( zgjF3!g?Vf0zED<<6aX<%1-W7x1&4ql=bbz#xMLG%)|O8RXuC}aW!rW9V#<-E9N+)s z`T(c@8=g%i9d91Pch;Xz+Nnj6G9FBnaV;7tVhaAl#oGf9=LKQVS`8|`Uv=VvC^(1_ zTN!M7D~gLW_bgA;uWmR|_doUM?$4%9RHNBwc3blfU2PbRH3fMH!5TrFK4)4L-L~zl zs1de*%$QlFDFd3F92YWxqU+QlU8)@qRk3O-PA zy^tzYO*IR)TguZt0-r)|*EKAn6Pz4k+Xp7qaN=2N67;oZBkXU~@N;#GC8z2?KDkZ~ z-vX!V*_55?wokhK#_UuLqHqK%&IRrmQaKN~!8}K&g+exCn|6jW-S#Y_tm({P70n$61oWTHls8mKo3H9^EgIW;ubaY{f1 z-2;zO>VoTF3h+UiHCR5&O(pB3ath&H$|=YP>;9+KwF8at_oe$TB!epe1_v109LDJM zvQKa*zZWQuZScVMcRi2@a49oh&E>}>0rGH%?)7x5cX#W_x{X%j&q}6g)#`pu*7G%U zHJ-w8n$);91%4QCpjCOIWXjpYL!#w0k|jFbbMR7EwMm&c8nLkMPlD3D)?Ck4U6>pW zo?4%U@GLxgPl_CN+9#b>V_y9uK?t?cs8-`;N&=j96mZv!XV3)YpjtI7hgnV*JWK6X zLzT}t`|s)k#w(v%cOSprVOXx%A;vC8bbsHuH1Df z?jZ3TPZ->{eDLUH;kn$SR<2SxNY8F+U2AT1=NCFwuiGGxPdp`E)xwc(T_`H1UGaBvIm*$V>Qj|W5hM~v8oGTq)deX$*435;*wV0ix+o;{f|yg=7` zt@d?58DZ;H0^Fqurd>IgCfR5Fv`xXgVDYCN~TmlJ0Sj2|+1N zx;BEqGy~t)Oe;sqx~G_1xz$CkoE8Ley5U6q`xRH-22tQm>&ykNVwjY4yf?$iAif{F zydb`M@`1IR9L^bzCcd{fPSFNGjvVFPsVfedkE}o-wNsA<5V6KJ$iUMHAc-sF0v!`Q z@K4;@KHK3!+dzL?@^Y))>*x)CG(BZ??)iQW{@0IR0{M;L_0(D@uuOjfq$Dh5&3v}B zS0>8dWs{JDy-FDfmZRob&NHd)9Z(f?hjdHrJ>97pNt^#0=hajVs6 zbnCOc!Z>+<0>quyhSLyi6i$P7@(Ra$SuQGsyDsCl%RI|=2{7JUG*X^BB2Qra$_846 zuKiu9OAgtMkNAL36=3W_osNd;bj(f5@Eroa&U1^LGv;Gliz*L)))}LYL${B0<^IZjhZi(U@Dg>I<2kB} z*ZjPU^PzDb?oH_S5LK^>mgEXcq9x(03)1sJ; zMmHGdbU-8U_Rq%&zVXs8PXzJ(pBJPf*}Le*7uk^wB>e$!8t+U;8~tt{{+qL#8X3Se zs!cR}X)j)m5b(IeASmEJ%m(Z5>iyo4f3H%9pOj#%4w^!$_?Fb6l4;>83NWs~o*W+= zhal>3c)VvFJEAb3fIw~{iVM-g1jGNcf!cl-h~mGKY*Y(GQST=M1Xcy%8CYsWIipy} z0~XeFeWuU?6)L4gkLF7D;Z_V6T2`Fs#DCd9ZQuBGdNdPQsP;*t+v?4AVy@K?x=tdF z{JaeALcn+K?s=thg)uK1=q90Vi5re;=L>B6Xr{Zu3XwFe`n-=lm0staCQ|U)({VUf zwAxS^32m&9+Wn5r1M2xl@mh+YD!eLaMwR;pP~3QBRw~!l3>&E#<2M^PeCr&Qq~Ole z>#Xq2@a*jpD?B-Fwj1EVTl1ZM2xAz-2uGTxsx}2z!77|;EbeS3oOoC->QdKqOC~i< ztGJbiY#m5AygD4-YDdKahPMI6o1T`oV8<8Z%~r2oZzl=qG>C{0lX{g>*{UcGbqv*T zibX{)<})VzC}vbr+%Ij}n041K#=mw0jDG~rer`vuROp;EAr7DS3c`y=!|8yGYEcLZ z!pFESggY)?=j$HOSrc1|uu0G*F4sNBu=K4JJQrO2mB4u5>2-38CiutGtWfqEqamN- zT~lqM5+x#u{e&Wy;T!zPRmNf|J9(j$#TD|n?rSn@*k*CwEr&`Co zF8np;Qwt%G@fc^xk<)m2pO5vQLA=kw=eQEj=O)M1T0Xb^?Ry$GkWDPQt-L7T2F% zcYmLJTB>`AFE@IPdaKo&6@IRvxM48Qg_n;>2Tojr-yFEM z1a^u|$)l0+Uw@$lbRvy6KD|!Rk)V8UI$V;-ND9VqLbOxI$LeR!VtNaNmd2d}$l7u9 zl)wdr_lArltPmOCDzinV_?@YF1rjS%d zvBE^V-?V{Hp+kQ(Rn;at?^O)7$oHyMeuQNrM?uxctp}KR#+B7oEJ&g_3-ca0?`sb& zFPPrE0S3~mznAXJmZ%ii)+n0rsW#%{Au#o5=(E7Bnh<0QuK3hPQs`B&wU!6Wi}x*h z_iDEDqNRC*k^0!v(rn?_NVOW>PNO{^c9Vh-X%k#(?>a8=Encx)&!<>+#PDi^vRuhB z3nhn~!$>`F`$HGriE7bGgZQuT?CBNP-Rjq8)B9Es)M}>&W(08$7O1hUJD?EM&->IY zi4t{6S=&~&H*KT__T1?VkK{ak@ag5$q2xUMd-s_~cmM7}6j%w} zsGl_Zt=VMZNQ)*lZ3tk9!ug1BVR$yi-Eq~C!7SHz48!paQ!_Je4&n>L&g{$8x81NW z&Adyhp%p1u`ik@L+F#tD;YdxUtJ%&44N2rMo~W8S2A&>K8drAWt(XrUkK+y|6bK**FZd3Qx6T;b6;x`CCD!p4e(cx zVEFW=6d{yDrI{`$9DzU_KADtCMaR_~Vxhlt-GDi6;M)QGa6uTtyJ_Reg$Q8+;tLx< zU?BU(6d_Cnt!Y7Ue#2n}1B9UpaCJV074YsZ=A3=p1dU zqt$EoaNWnO273Aa(PSEi!l1V2V(X|KkF4@5@hEgJsQ8u}1O-zoY@2?5;oi{%#{a$n zMgv^m52QVKuhm|x;D$2+R|WN4;P zvWf?#17$lSyvXj?g)IJjgVV!f_UTkZmVBh*Q>2C3WJ(CvMk9_rCkz*%$9*R>;J%1| z#ndWJjriWZXvmUb{N;iaE=}zR)24QX6wU;I1z;Kw=#z-5zrGZ(Xrc3w|z1K^p=^7dN;rd=oo& zeG6jm3T6?4nfIQp|CkNqy2F8*w}x=GSb}rkGs*0U(oL4&fY$?uF&m?i0)YB)N);YB zS6B{v8dw!x-U+H6L$+>XQ;-23a5jzP4Vew=OI~_sGb55SgzS69$d{^sEd3oRRgf9E ze0o4FhBe&9$0&CQW(}|w1aHNhxK|^dAr=c_{`FtktP1jmj5}iEU!1>k<(c*EY44E( zi0PDgD?aL;V@LS+Gt{%CUuG~ci`*J@<>_25~!v%JUX;*`3R?!3o+c8~^>KpQH`U>X5!!s!B@s9Kuf zuBiH+=HReEEN3eoQHQBEHMgchF4Azagwc3r-Poct{K>SHk{lljf=|U{64eGEAK)aw z2LnzuPh>pH4l1sX%fdxmcI#Ixjd&-3Kl?2(Oy9<< z8P8%&VcXkJ?n-y{*#I62MAIZjsJB}QdW z%UrQDnXFaV&*l#Esmb_ldClvEJ7|)#^>fdx$K+^-e@xQzw9TD~VTM6~qC__iE5(eu zTfCAl=y_V$wLFJ1#VwnrYq_>XXznI4`Gsum?@IP{)fu84e&?6v4uQnxCTB~li5log zM53vpg;Oz|+7dIK(t0(Fk~zT2shGV>7A?wu_P=zHM?HoJIiFtBNfIo^ZD> zs=Yh$;OC!NPcbx~T^*&+Jn1*;?O7f1bW$5C(R4fziWn;q9}*I`hF1u&9LFh@sZnt< z)I2oIV%8{U>_Tq8l)FdW;>o4*Z*P!>3ow3YN4`|oRSfr+)xO0 zxRNQUrnPH;NUV~rd(<^?P={^W4$)*)@5&>QWJhwIQsP7&fA-9J&)sKa^>qn9{=H)_0%*nmT#4;)(ShBPDl+*QWPn*F&Xp8lvs*wn-x3nFzQkpYpX2F zGF;2DT}O8;!x7u3Dcl`)@>dH_xOD939p99KvGjz?m*+|-#>27V2;l%T$6Ar9Ln*W1 zK^eQ8xN8FSg6P-VenGw!#PGq<%@GW)E-%OrpIx_A-}!91k$xIf~`xDM< zoDXf6Vw0loRcsCHtIo?6Mu?$%L?;HfT~np^s=6)F4eQzE_|!zj-}h`f9ojhtdt2|- zdpqBMX(#40BZUuCb)u>RF$u(wN1ozj!OrGvT2@U>XL+lzYqDG}lRG%rzmm=5bGZ_# z1#YvfUu#}(u3Z(Na$LDJbAMoE$IU_>?z8Kb4IclX?kLW*gE3>jG*LE>Blg()L6wKLyWzGNmTHMh`S)KIbBhV;G(q z%yGc$88#!HOGus(jlri_ESavJQ!9JL)G(e+N^;T0*ygkAsVpR2>2W+V!AewP3Pe%W zz#UGgVXKF%VtXnltSW@zKujxiaER4-?<*Lxd$p7^S;YIIh0$6bE_CwmPs5ly^mdYJ z5M(qR1)`=!6LkR5y4cTV^LzQdZ1Ku|Zr91x9kgCmX%`-bH#DA9;42F5=nxrX9H+w9x^t-kg`61oPAV{LUTbXxaxT`J0Qt@hN`l`0M^bqQ*|U#E z!9*Q{me<0FYg27J#ZnBdA_6CHJ?09hYPl#D&&^|*65g(*DoQ%nTX%5~+NUJHp{#6) zLI3ioMBf*_B+i|r#4#e_ja`gGGMs3B0F;;Du;sX+gT)<0IHN!=&|O_Q)ZE5;ZwE!f z7T@>m`mP&fEpJT~G9(OTRv8mUwP;cs4>d&@D#Kdo(6c}_{QU#pCfIw;4NPdcG?*oP zJ)7U6&E}#Pwm-FjE&j!`(!RR*4x!g+_1gXU*bx~3Zb2X0E?%B9i(-E)&sp5!It1;M z3CmzCUpgYzy}CnKhp{xgXuh6L)r`reY8{5<+OCnKIGWLmhi~}??zO?4q8?tuQF?Dm z*QF!%Q<8=+`uXA652TJ%%A2pkxZw&)sZQf1^f+A|i&=wsZ4&0Gv5)Q^6-y_w_|S$U zb?LdZy{#X&PC6itWP+F$YJ)KkwFrQa>3C$>*z9B*9&nKXu-d^3h zT^3hw6_+o2AwIt0Kq0W-P1`65#28RSBQ2T^AhZ=DB|K$lO})6l4IPBQJE?fY6W)G^ zdw8G{5Wl`b5?A0ry=h0jG-x!NC-vTZlg9G(Lmm!P9R7lL=eS)LmoDJ_frxX7j8mIJ zxa+w0=+fZ#<}dsSDV|NV;;WvMn$F_#`);@0YIZxzl|M5aQH%qJvkHxmd$dd zynApt3#{-kS1uf85B97~_As}9xS!l^wy!lB*P3UIYpEN~)&;_-(?wlIjHi05x{P+W zg2F^s1LROx+QYf+`$0MGGy@H14vqk2g{sZ( z-#&)?VpcXuD|~)~ZdYX(vpJ2eem$vCT1X;5NoX}*0?y>R1WROuz-mNalq;Mw$7U8& zEJE$FjG}Q8HZ~XMo+p4!(h9%7A+3Oc#}B3mND^cuX@!(DCW;nm`C`ekEyGeAQZd~_ zt7vCgxy1Zz1$;W?W#B04&F%#6Qt|pf-=HMnbLlCd?c)wE)0`)*7Po;1-BI7iMNR1ro za5tVjfP+|Bymx>D3?PQI;<+YeY>Td6Od12Js&WGi3NWrqB)xy!Yd5-$Mt9!ap($is zi=r`*!*Dp^k$s?nILg4ND6kP1KRDU9a%fw+t%7@`MA=HxFP2_UVEn~~_!SxN+fwyP z=~!b4Ae!Q*O0wmwsRh_88*p9)ukKcZDt6z*3k7k8$DPL-w=lfnaPYuz0Ry@0DvS@U zsCt^;0sw6!aCaYm2AVPs{ObMHqoaTe6W+bbd>{Kda4b*UON0{;xA&*q9e#V|xpiuY zOzR({?$A=KN|FO^9nem(0)t~YWq_>^I5*74Ssg5{SVE?ClcvV=v#P=Jvcq_8-3z`D zo}HwedArj+Y0pRG&IK?G;Rn%_$#BXXPDB}dYH&%pa7_;zOqqw=5PswgGrMJ^`h_o^ zJ}oKp>XAaF|E1Kh3t7QeFlf`UtKWYF%6)`=PP0`Oz@o4r)AnX1`4EZRV+Ci=tw-U= zQ*NX+L*gWBC`QDt7(@Z9>I$3TurS<(R3T>EFT{MXyY}{p1Q*kc1P0$A4P=e)PG18` z3~>!bje6SA{eG2wMK$i;_mAL*FtM2&ORz+hr&l1|i`&fV1_l4TER8j4wF+Wbg0DMX zH-JtLtx~+IE&dC*IW}H<_oQ=cne+TgNx>5kH{jV1?xYLGu*$VJAJZr!m=4JeJC6B) z9O5oByXrru<`dS*r6D9WS?0y>NqWp!NEE`ifk#R4E*I zRX(A)tf5kaXeGySfl}dW5qNpWav1!jx(4&^)fIUH14Gu;^p%?a zi)cI~!6+P!H0)Ukqlky0jZ=Au-JPgo@Z36GfATqLnc=KH^rTZy zW|A)tl+XsM#)o4}sM{`cJr`mpiUWCgy#1HDn2@e`oaozUfZm;=x0i3=R=@t7JmoiT zVCi)0_5Qq&WcmIAeoPgD^SW`cVIX1>f>oaWkhySS{?Q$@W&NZ~MZkUhvUVp+sB9m6(M(_!F1;A2{rvwcI@MJkOK z2kIYg(2GBPPAYec>0!HHZ#0@G^TvL7@rf3UNPLG$#v}NqW2NwBQ>sjwg{VA(b6A*}+f2l-TG#y3L`#Ha#<7`8;tGK-hhffCh z6YXq#Yjcjq{@dEvp1}CW3s1gO?{9ei(cRxjrFgm>U=F?cEb`_1N29R@ZV*+X>R?-% z4|Ym06_?Q~oEe;1wog~BhTy7`-*ToBBXw>*k_h8hH=HTtDBqYGRGjdUm>rIy zVLahp2}iX7=V4@Hh=J4JIR*`3{O0_XKl9vr?IC+!+Ql*3 z#|ZIX564Dd+S&Op@V@{IK7%nHOo!8G>=}+-vYd=tvTP@J=$133Qf}|i$Yis-yV=UY zVYYy^huyG|+VHZ_i%WNYKeNnyZgAdT`MeZ2#oFDh_q(0>dTWhLLv1uxz#2p~Fd{t|e5@;TAaY?V}po7iw`#{NBIX;P+l3>&2S$#v?S06jd7$ zpoUXLIW=6R4BpPRs6!m50*1~v~`dB z?UPPpR-3Sb0GtP-K%Xd%t-+x-F877+#;p)wfAQALbZ$~te0OyFPdAt-^yu$TC3j@+ zEdz*kJOZ;ystym1;uxcf6IpHC;yYu8H#boi@!r?2Eh4`^-w^qszgQGZ#@@T#Z*}_f zsvV5{R)I`3T&Z6>hOYrIMo+s;jzQwjjDSNrjNDJ0&kz zzmrHM`~138zWe#qZ6=nswOc?(mhpHRhKLl!#_Jf@@Eq4OIW=+eWIWtP(H)*8PT5er z(!G*OxXfCWpI_G%l+^F1ZaQSCgyB?zfj&_jRawzL@*$S>%NYhF(RTM~l?7!ZV3ZNh zO6f|fu|t;2>aFJ41GgMqyqx}oUT?L=4ZY)!O7?f@3FGve1R+#HGP+SvvoC`rQ*XWN&E{EWqdz>?aWX!~G;wtwLH zbl+3|xZP~mJFR6c%y_6xAe;@yL8J+d4-^i1t~hziaVr)rQNuiNoT9DUime)|QzUx@ zb6?r6?RPEFK9Fp1q9nike0tt`>lpuY^=5xQ(P{;XXJD>}d*xXW5)^#uSya{C{k(1M zm+XA0ynS-dg@!>TGI{kvCejtub5iMH$}c7b3=2_cDxa-mEnMO1{X7qR#KEz96eC&g z&Q_}9@17Ld-fatfHrV-s1P8;y%aWpCsQ5rC5}AjEh~@^c_}v;7TAqWPue>OZSE8#1pd}&!fg-uaMN(EC+|TN#$SmDp@p%H~EI=*SiWZdOu6q zuOw2(R;Yi0&QVh|9!fZrV#z+dvae(cOy4!kL&w#~mAtK!ebcF^q{67fjJWxxe%3i_ zG&aWSx3wH;^x$Si`Q{CZ^2hM(Ba)&tz%ACh{l-l1!CrAy3B_ztE{T*I26IhnTUfD2 z@&1Fk)W#h=u4`KsFqV?Neb4V*nTql48$f*K`Sb{b?lGL>ey=-gGncd@8k13Nc*F20 z-l#F=xx&UwLqL7k^{LMl=2M5;2dSYLt?LaL#<>fY&LkLb*gzc72EQ_uH)+>f{a$mH zI7!K2I+;dO0|WsOnC*k{Vvc6RA6?h7Sef!%))u8qcFRWA3uku|v-RB@%odW#8!5Au z5XZ!9rNl9cMhe$+I#wYb1zfAfn~SUQHToxj&rVYs zf^#L>o&KWhQI^Um8mr`nfmIn0SyAvNzT;PDAedh9*nwf~ALgu#y}yg*s z0ggYFsjgp3IrWP)q%CdLPi$bmD4kEHrb#4{hz}JRjrgz@@lh125x9_&8!+7qm>C3& z`M!%486xoG9j5W`LTqQg8>MkuD8g`|ck+vlal>a*U{J_uu8$&f|>A;|!z z&0^&@iX&dj8b|INYvP=$&rKvOH;>s5C9OCP7ldN{k>gMYyOK-^EhJ(+cP?#?&CKr{TY6ep2Q?m7%` z6JVNn0Iyt)7gbd;PmP0sy?Ae<2*kY}j`-B`>lX)=kF4Gcc028Er#CBBTE0I1X+YE( z?%Q&0jyL9lDVOnh8AuK*JX6t&tWeGtw;ZawmU92-^GN~w62{&~q?E&K>{zc~2j4M^ z3Q-**R1A%e#Ta}D!|p~*!U=E{_zO-}m7z=oKjK)}cdNAAjwFpBfpHu6I14-V%hI9p zCEbwsE2M*ur4+!UlWC}ySP@mb3}y=d#sRuGTqWL$7B`~ZZ0ptqf)A-Ce}mWfGkEsW z)RAg+vEZsT-x?hYAQ~#1s2X_l2rqHsi{=0cRXmaz%NTHdG!AI4!vA`&CebFc_{;`b zAYJ_7RK=A{4HFS4V;+VYnT}55ZrQj1v^uN0n2p>FW@F%RQ^Y;4xccITY{~aMpH4BP zJvh96IDh@o5LlI}?Zg`#epif4t#HVHovDiiXG`)AH?=v7!)V=m7)t0>^XU51v1tSDySP zTwJzy3mS6Kkm=7h94S=!UrtX2mee~wMey=~K^shm!E|KJ-yLtsaUEbVgW!40W{erw zo_UUI!P`Kwj5Ypt&Zguz92wU4r6+mJ+0SmS&!9TUL^YR#giN)6`OjAOH=4Gyv5yG7IFj%($uvdSt2fO8+fF}Js@B#N>F zaI&{QZg+Xe(08jr`jCB8js(~I`5Ka`=^T&}W_1nS$eV=P2AC_$F;&H3wsS}{7SA9; zC@;CWKSvnV^T5a;jIT<&!gt8*Do*y`bo}OgMf@s=p~8e?3rea%)vCsem;I`#IA8{J zZd7#FHOZnBT-|(eo0-GN0F19XPhS@j!quD=6328UKtd9658@YbW=s%7Ju_aKu?NOif%kNlw*$^HX(rd#5Tq9gLRZ_=*LLW$1y>elI;LSb~9HzBU*RhJ*{; z+B4L6z>YX)*aGZ8WbQ!JVODV+7mnwP1H(8)Vn5P&+uvN?d`~EAM}lK`?KZ^mImv&o zM&;<|zdzm2Ecx^x91gS)0@_e$Vm#n#Y41KS>(Si|_4pxR$$N%pYQ}+QvUm{}@J8h9 z`vBvkm#|;(di#2M_FHFFBzK_bi%Y4OERZY@)~Dgw&!;GFquXdUd-Gs0nrbQ^)HH}= zr=x))Y897xo~e5}?xS-&RnF6c$8*`7O%5Dw6&R#Sl_MjU^|$*EZrogZ(J#+DCZ z`*t9hi&d`zbg;_Mqy|&JlOLMHzeX)@&p@XCt@i|Ca3@?^w9;rT;_M{+868jqJu3f&hCpfYUV? z=F}2_j|l|CfKQp`4s6|^6>xzz*6otAyM^+uy7B5AxpAqG;awXJ*1v{lKbp2u7|%9N zlB@F+h{3>%^%oO}u>|1z$76=+T@f(bKs?YV_iVZs|I9 zet-VbKMpUgG}2`E-+d%C6%meCx7Fy@Wv+86Eu;VtR1kN6x}w?L$H1tC1a)~^EV%nQoC_Zv{?reIrkrP zBw~hS4EzdxIrW4qOxMkbJz;o`>K){KPMKocS0G}KiyAJ2D}2kP%}G&N@69{W`{acE zW5m%-`@t7}^wHfXcjOC$M(3p8Z_G{CP(x~>h9L=RQ&p%TVR>TM8OJ;%x@tM(u&k8x z<;vx9VK19KIM56Ghly0;H5sk2xt4BF<^sV*8Qt?FfBvVBtltZoA5Bj(Xn_sxcW^Of ze8iR*lrWrz;SGaPSGXjuL!scXSK2^xhSx=G~apcEvtfz%Pm6MOFb*|);8 z$;&Ul9Q~Kt?QZMFpw;ZR+x@*J01=+1OoyQ_g{F~_MgqsSG|HLd2!jjPwZ;pTY4tlh-hTq#_4L^{uhVG4ar+wBQw4%>{VFhCB zPbV7j?&x`LQ;S=M#T~&xrzjPsY1#&*loP6}7g$4g7i)-R@ka~aw3Nk1;Mqsh)^IxL zw_0bBES7H{NHq`*si~Fy8n>vK(;Z$gJ=>&)BOI`14&RuA)*hocOv@s+h2k7V>3(H# zc5U{`{|aI3A&j4iU>w5lSJ%Gnk-dbAJ-yNDwcBT{_ROgLNfLt$fw|#*dnhy`tajb~@d5JAO2H>=mtctJgg3 z$B$42dbirAY1e)ltHC30nwjGpFY)2|!_jN^zBrfn{{bJK(n@>8ABSf@lCa12jee)q zZ}w;As3_C%P&9_>R16!Vp`wCIxArR*v1CPYEm^OE?*Ok}7Zx~0`0_j{<|wc8r*XHm17pMd!#POPiLE^KdLu}pXpY{6fvzbFoLeMnfsdpSk zT<&-p=hU+t?plUJy_%@f95XG)IHtr(s`B>mRJspi{J|su(Bi$lk6!{nBb1HCP>dUL zI-Y`2in7kMM{=~R5O98nd8Ja!Gs3gSN5^?pKP;Cr$BL4A-QS-7H~v5T?;2?*@ORvwX{Ig`FPZ9Wc&4DPvXa<0UV~>PhAhJj5aV?iSEa{e>)662J zrF@kTJ8KnmQpte*LZH0$P8aQ?cdO~QZ}o0>H`4h1dn(ulH}i!goPOHhKL>EWH36pw z!Sd|%v^C>ja~xA5N!UPFGv%O2oaa2-22W{Qj%DiHay?+d9+94qply6J|H8ifA4}y8a}`UP`me*YpNZ{cMkAY@eyevH*@=c~=1<8qoQ9zc;75O?sU~B`=wOS75rG5iOoG1 zN@dy@0)x?faK^$1f9xwj9U&8hM8r1XJLDx`DMEnvg6{&11%5l5rLxU?T@FUVR^GQk zD*rRWNJ(YT??&lWEEP2vYT8KA6fG3$Bp8nZYJtb)_?uGQ5R?nk%5$|Mh*L8h^+?yR zv4<#?*cqeaT_yP_l@Fx-Si%`EgfX5f4KfPGH!I~FWe(7MV3JIjj6i~70l_y+X2Ty4 z8Ml-C&MqWBCU`$Mm&rAdNetpY!n0paMU-y$wA%#li6Ca;2$tfwsoFJ2N=&NjSv$ij zU^K@?t5C}1iifOltR5dJ*<^Tc`|b8dKYZ=}rLo{CpIG2n7E=BKp8Z5Zx7s&ao!$Vn zD>9Lp1V%zt1eQ&Lk&j8b6jA(u@1$xORkvER@=P2F`G{g0CM_p`wEKSB@2_!HBf(Ry zWbMx;L=r>Mo_ylq6DghoYSroVW>AK{7zs(lnD|3YG)5Dlvl?d-l&Jt2mdgasVF5+f zfQ*~eWHeK-Y8PAk&Q9y44KU0n6A}S$51Q5McUxyOr=<;5G1Vr4CWdM-R+W)TxS?`` zaLcl&YL#_UKW2K(&K&E?5zShPo>K~2LrG^R7_rm(^@Y<~`d$n#?@3oA=Ai@~78=P? z5}Gen5t30U$Ep@lAZ{2Htt1RvsvhNzVRF_G?0E z-s*HWie=q&JORvvk|4SVqk%s#T3-_DSh5f0W7Uc~#5gOGz($-WvF=^&BvvAJ1R@FMs7SrPM*Y-RkxRvy>|URZ3!UIB;Je!ye~4#1@B8r|vo)cRA55 z!z!1ld7LWH`^~jt>b1+h`*<1K|Kq{~FB2_{_isrNlw@p=UYpEcTP0&zzJ5Jl6ZB9Q zwo?>U#{@D=EZ~lgD5n+%Bf>OdH^ zVPg`gVytRW5tv)ttAk|&=j9xtp}?fX0mm!R``(NG?i>)!4KQ9xn#Ni{T){B*C1Fx$ zwC=i!Y4Eyh*F8wBAkAg6E@d6Kyv4TXRu3j1@+V^pUox$qdNPq)!GEcLqX+5xX@8kp zDgH=?#FyGc47EV@G?l~WE|`#Y_yZJ5TFi7@igdor0A`hwN@;sQ#Q(@PIK%Txz==Jt z^W=I}=;QD#Ouzw$1!~ZP4-k`gOyZMb34J*M#>H)B5b(T4xojvFA%*-=K6g+&yk03D z9vs6@$E7)pcK195q`m0`?!HrZ@5yxr{A2L!IPEPo)8YSO%xv zPOrBOj~d~Tg__`qN1~clz~CK8nM;5Q>%y?Ci&OXA#1q>}dxNcf1fG3w%2xWIWxc^n z%MwNciK6iR5TSs9IA9~fiq078LYR?P{ zD=F`Oa=i%gZ{XP{6CA5|qu=YDwN7UtW$gPxYU80$8{trlw8l*x(-BZC&as^BL5c!j zo(&w!(JEPkWkqFcC8f86H1>XL{=y%4GA`0B1IZsJ)AlCD#rB}p>-6U=MT`Qe$S?pq z83y5WGNKkFAl$~D0YGC?OWL&xIkcS`b(mJlaB5eR;%J|@I!U$aU%i*ZUs}gU7UEcP zc(jJl>(&vFb1 z`=Y!RM*Hf;-vo>w+n`iPS$;UBR4ICrP$vi?W1`k{LJ1^MHnTBLH$baQ*Rj!FxQzjk zS`SC5Ztney`78hATpHICO7&MOO4UUY-)c2y<)A%)(uF@}CLV+!l8HB+0&UEj$EDrosxx#(w^IpJd3|E$HJD3!d`IC)4G+1y6~NtCs*K;bc0QDwOC8cf2cZab z!CdFeHmr;2R)3ew*I)3IKVIZmOBaUW@%ho>UCGbZ?_I9;)#SG;Rh_6MzvE&BvUB58~Tzqn)>4xD%5EF z#y7ud0pu??kob2$^~Aw1BwR5_qdmYrsaar5ff$X&1baBJ{vepZV^HAokSzjBkt~LYEC19wd3-NC`|(r)KWI142Hkn*8|u@@AF3o2G6=*- zv25Fd-;jwoj2R9j0S!O$z`wxa8E`Mkh3!~6F=|OR-#p*qdsjvB=F1f1{~)1AtDywN z^p8><9kFu7zIUi-8koq?n~p<&q>zS|RgSXd96QbxYg#$47Ak7)kwcpkHLojLp-|Fn zX{;WV_^s31t=>j8yV4119OPg1)cPUTXP!#b?4skJvrg}9-Xtu?jWE!BWjY!Anl|<% zF{uWI!B8BO@fsSABMch^W7@i9Rkd2WCcoY!ymSA+tDah#eH=}mfM*|0WWC)R?PjZW z+U?KF^D8jQ4v=?jb#gs$Ti|$IjD*6&3LfAA*3aeEXwuy!>y2ss+cwzA=bu_TtUhga z`n}dXnkdR7)U>H0RH2YbsOSt^f~5ud2>328IZ*nVCu)|kK}42GR6~DAwfUHEy>nqD zOBi2DYZL^uJeno?1UGLDl-9R3k(p60S&NEJJ?cf;Lr| zq2quL1@0(Z8x)LL5K}zia(BCdJRo8GlMTYS0lM|`siI12fD;%pZph}iaQ>bvl94hZ!g)40uXwG_H1}*4Ta-~ zs>Mv|IE?6y&GiapHM8vL+$o7HGxJ>CPvwWVn`?&(iy^oxOiM%%R;DGkLr{F6?OJ21 zDZZQlf0t#ws$`8~Aydnh)uY-YIZY`PONE1sk}u~=M_T4Mr>0)_4-y_^m29J@xtq$Z zW3LjEZP^$KPm_~LBT#@(DC0&ZQ!O54v-w=cR<&%lR>>Xb3kTI2Bb8D$e`Fe@vPvUb zom(9rG+>j9*{L1zOB=NMooN@7phmO$b4nSeVZ&vbB^B>P=7HF`^@yX^@kAEu1rE0D zyW4~CZj>n2>VLV=>JKkq{L7?DL>0~sXvEoIRz^<(@U_NJm9)ZnHOKe~JE4wct99X+ z!jxFe5f*sN8q>CSU-VP$y7vQNl7z5_+V$B>K!`)|cb9n7-QeGAaB8O4an!YkQ_-Sh)0)pl`~=-bLu47W$Wy` zwccrWiu1QqRj?$T2{dgoRK`*pd0In()IL-!$1WZh zi`3A$p=r!k>EU%|Fv=~TCB zMPO8Iq-i7qGs)6?u1sl`7>pbfZc!|}&;zqd9SVtnZE#1APPuNK-D-6X zfn&7=si(&-D7Ea;dA9)Z^-r&-kqGSf((RlH5b?WDNGOzPI3i_(o1i?=KOB_EhE$B& z@XKT-q-7wA3x>*f0ukHBHzkZb2JsX;`@s}5>-Jlxr)RSmwtW8(BJxCSII3Y(EXox| zjVe>XMl{E~{z!oqa~1QroYRh#T*@@go5?nbO-(CTseHY4Lj*w=_UTk{BI&NeX+sI8 z3TXsBAX4O%0PV>OR47cfuzDAb$+@#r6zK@8B=p`OUo#Bq2m> z|Ff5XFd8YEKNaAYd?nO;Wg;p(lOe}EbC}C(nr<=s`eA`;S~Z`u3|gsJ*_x@RUN}~P z@7oZue*fuo%VqyYzuP%&cjt~i`LPA#a4IccRIq$w!H4JMrBhRMM;AB@W;&z>7HhEW zJq=r1U@xJ_%Ob*uo?b5^Agg$Ps%JmRAR1x<2~!BpQ8q@yfcRW6W!3Li>Rf5q{$7bz=JOpH55{M(x%8eyh`O#fmJ0QNs_&csLeeAR1#H zosHKetH`JR2@E(*a$T5>FYGR zr~Uc7LEueEI8=j)41E%+WrtzoF61U0iwDecqb7Ggi&xyke%^~0>Fio8{LItq#X=oG z{9KC4^_zokx7S@{Dk%_JFj5qYmTgL%EFKRy95~ORteHiYGfbsgzFV7c|0g7~XWa3uIKd zE;n@#S2|R|*XA5SJ=gRcrn#xk-3Mmmw-%E4$_7dJfZ@MOIo#f9|16%kO#v7w{*;3Z zh*NbWWc|{1RbgTG0_E6^p=LDedX1GX_O}~B+`5D$V%z@x4Kxnp`VXgilaeufp-0$7 z68IWvm=3Rlt3BcTLYg+jJy6-#+A zk1S(^;M?D7onzAMpKc@~JFNow^QYGjW!?a?_|X)(ZQ;J5&e^;J20ni=ltTjSP}3S? zFa=i!PfIaDb_E6V)^asr3fE+YE19G<0%UR4%xnKJjxx?Q{qp55L{ z9#(dngGG;9LY35p7mkKLmrA8B3ry4uX-E}UGMW2TTFZJ`;XtWYwd+MKwYSJ`KbYd) z%>+r;pIINGN2U6%Q~@I<>5C@gSQ5cVQv)fdL#xDduHsfCGg;X!)f~Hq4U~`p+Csr1 zSyf!P+28?nS^TwU)(!oqo=GI*QFCs))j4a;N7P~fQ>n_Z(ICN{Xe=1sIND3+RBdn8 z7X}njKtg2+TVA0#cX)~H@AC;oS`Fi$f@jlIDWlhfFg`nLi(h>j_)?5VL((7+tSQwk z#bQo{*77YK=Q1^=FC8YPp)G>+tpkg{l=*uToAeiK5e61qqvmfgco%E>IB<*GKRCy8-G{>zV{3o)GwX#nB=YZ0 z4XY$b`-&_Y!?EDZtxDX*fc4@!Zq>w;BW@A%9P5I@+b;2Nw6ONC-w+VL3!c3y6%c_a zo_6}PnVX~(ys$ByjH8SX5+^QgTxH;%V26M_alwz_|2R3x@$KZK`#@T$zJ4K$B{{(~ z{To*{ST9oY(QpOD%}g#+E><#?GGoW(gQ{VdOvAK!wn~|0}&$6h_lv5`fbR$XJ+a>G;?v0*?vS_or9hC6cKbj&P2n z5z0H|TrP7|ELv9Cs+zoH7wrC8J~Fl&@<~BKmPQY^lk<)kuylp z2i-kfjP-exj0=W~39E!NQboNwT{Dl1_Q3wF^X*J) zA%`D*X1z}GXV0wefo->&onCu3h!*<6R1K$%Fpz;VQp50$?qK=T;h4bUNez}tgzdT1 z6r5Os(e$~~CFOAMn$-ftPi;^pB=J9-nx;z<_T>9dgT^Q*8VR0}MRW)CEF>KY^;RawuJ z>aykv1v_y)Q_4E??y)a*=M%s$B8ru>vqzsz9B@RPtDV#4X>-;_Ob8h^d_@6A8^};c6)Ab{kJA6nA6_*#jyrI;C(J)EV(~-|l3qsK* z?7C7v!AklGZds{&by=Cs1x1Yo4)+|9JOFGZSK1}x-j&J=u{8d8Lq6_5o0y=3PYiTw zfQ8WcPP_R1$6+`Ov|w__iB`o&UuX4J}auR3vtnS(=Jto1)ciSXVwQAF@C%! zO{eCuBH|&5_n#o1p&@CuQ8(}!4ct8BdQqP`_N9Y#&@voxkJEvjE#uENWJ?%B(yMBd z@nQu-IB{^+0R@4j5L~c50}!c{gZ~Dk@o@W}{@)D>_3h6lRxd>64UTru>CY4@`Tk-Y zHbT%Rlz_x8m09yK(M5C+Xmj|JyWYc?zD|Pps|_H&13>(ADsn@-zzZbi1-CI#Nf?eA zp{j)tG0IMKrwL;4W-Hq*>=_b{8?~Wf8_{+UJ4qsLM9x1OHzI#vIhXZpqTwdWTYG2y z&RKW44a(QZND<>PF4mSr4FYlP;E3&4-NWJm-N*f*WFOahlr+=B<7B)tN3SFsk)xFL zx05eX$Cvo0mw1V|pfUdpwV)9y8X2pN#(qV2aB;uU$SGOr8l{3I$~>RL;Yu49pIK({ z-YcoD)Y$#GM5t9(PK+>^eIzwFk_f-}-oQjBjgbg(n4S3L;$c-5WvL(wpaD`!ErVOV z-5PwCq*`!*3E_^+^RwHn_IY<>@V$PObcCZag{%O*&dcMbk}_d!S^+1Bs zH5?M0U-tt=A&s$^f+rCSOw^1F(hxPnrP7dA9Vhips3=#6ww2Cp-L>Oirv4hs!hd$1 zSz|c^gBz9B2F9qunYQ@l{;k@a$#w$3oa0bk1hJav_6h16)2)f;->{`H9PMd#TGkuU?mR z$MMiiq+?>C?1HFupI31$59_{tgA!o~eqYL^j9Nb)w-yOcp>Oj`fh(bPVD4XH(s|7vJe%00KC4W2`^|29)=d|Q0kh?a5DF2E$sPUJ zuuMBsD$zsJWXDC*JgOe62i(>Rm8_P}TrXuX6KI~F`7QtKe7!KK%=-xx0HItyKrBFf z|H8E{V;s8MUrgmSN!N-}n1*B~g+Q4E8h(HA+4WP#uRNO=exBXx)$N|PPUn~G0ecRDM&K)$ zp*5x`-5CASyc#uV?w`Q+Cf*>&(hY+==!ZJ;c*3GyC`{u;L_VpSN4~TermFkv7w%n6|fB7~TmuPuf zCj7s?0mgNJ@wZcPuG{K#ny2%XWhw~6p9aAwoB(%{nu1#yc%^JrC^2e`Q9?<<&}*8i z8)hbxRm+8PD$aFow>N6lPOI0x^6Yvk3^ncU%gHwKgjOv8fQ^TdYRQQAgLkdtcxc^I zT`w94^k(b$qtUttuT|%-{hO~{45<9U!r3l)EIQy1rjLOV&UU6t6J-Jh9vON0x=y7q zTv3CUmicS06%|+UP_a@~@MkNTDz`efnz!2P1JKI6S|5Ad`wbg^^6Yv!>>a&}EqX!pkmDw6ME&*fd zZi~;Y2l0<3%{zi|)*N)^ErFo!4fp~W;YcIXDVabThbv56tmX*_knBYc2P}K$@lVLc7?A5ZOQAWXq z!wduWE;%(rSGl9}TCGNp9wEneT)jySVQ(HMzi(pr*ap-1bXph?`v$#Er`2xGCqyPf zP9~w&09vJtgXt9B-1R8h2AGKI)eQ+D&~zZ%1H*SA|8P#WE)?I9QpMi3|J=H_{rTt8 zJ#>Q`?X%P7V16W*LZE65czsLixJS`}SV3`neFdD90iX<_J7wmX7YrXgkedBpe{Q{q z^9#?VHx%@4^gDw=JKiP(D&%Y7xFN)Fs)l1SErJOhqGDNC$gwp_v6zFC z*ZE}XdUm_LIrd$pAthF+H$1mq7er=~Y#B(i5Y(bZFbNyuK#h{{J7P9xEwQNy*D7FX z7;kOyqB^m=a;5qMV8;P58{JOpw0$~DUKcWmN+DztG=MtJM@KY@c`59MzTczAq$!telZzSikdfvX49t z;hTVrrzOWWYd{6*i3u?eY`l&%s>&j2h2{Ty4#MwzM*1@wV&9kH**B*$jqae`IqS@Z z6DHwsA|XxELeWqr*xTd?%eAASXMAJFD?o-}m7QoOZ*cvUY&px+4SNNAn zIu%u$Tc@o-bC$d=B%n@6)E{&wnuc_6X4rLDbRQ;OiwSmtBo~*B%I#=+G5O)t=|z%+q=XQLg50bzjoF3rG0QU3&eRw!(=1qrS*3Wns#PpqP0G{zHp2?)QX4MTsE_>?jLCfs-kE1 z^F~3h7R&K9ez&@QtG$s=-S_hLq(pvcgTKA@{1XQsOHuS*Z!iEdGILW&Vfc+<5SSLH zoY!o@RIm`6SMb(IY2dEcswr(Mn7;LXtOr!}e0~EJv7S#*ktq0~EjG{QnMM+UHk4%U zjBux*hsQ^C!xeQZ>!w??D;03QmZV#j4DOuw#nJC`8|(vFR&rB#no*4wudfAQ=R*?K zvTFG_Z)rMX$7-fPYGy^J7PstU%55aLPO6gL^3!cjSHGJOS0u&q`0@sCg`wmhrf7OH zY$!<#*q?GUTh5W3N=cRqlc^+Q*{W?-RcygzmPM$Mx&^v*p1#L^Cz>8#SoXUZIFxiA z{^;|GI@`?9yZz2tf6>t~l9Qkr7#N7>X=TB9#pGJVR1?K;v%{8?ncAE5?hSh z;s37ry5; zH6(F4=cb5mk=#xicM0wbQ6L>z6$R3kX^J!^Dauj=lSvRZ##qAgEZ2(~1F^*JLLy~j zRT_Pl%dyfcx2!PQnWDr#OMQObXMODX#1@CBGp{{3JMFZV%k)D+$aspkN~sOdFtsr< zO-lpf%N-u&RFar3-iv43R5Hf`smSF#ReZH-?{@OupTRCORm-Jy*7NIR<@qF8S>s%h zC=`jtE(2dxHDVa>;=E?)wF5^NA_smdZ#xXjCJe6&a9C>I0ta}`9-R06t%RptMS>pr zsr1sig!f$oLWGs|RK|d#0P!sYhD?TI!<)lwVLO7`l%|k$Z?{_;eeX_4kenz=+E$Rn zOww*^Mpz;?pTwXDG77KjW5_p^?tD|{>Jm` z5&f5*Pq$iiZ*)3+_-}UR2Oz2vjBzMThU3Q2CwRTEjIMXbDWs?`dzNsy7zrJNunU$5 z>~v-xw;Yb2k6RAQ7qlFLWi$uPng30`e`7LL!<)>ZxZ>o5yC&A!F;lc01DhxD(lY7R z>)T82_t|o|EVI9EL;OPm{JkkZ8U}-G{${cz&Z?pypY#rP1I*?3oeerc(ZMU z4=J~esmSf;*NbqUdp@>+dId;Zu4QD9vEfdmy<#_%XmNUX907a2}vV-z&P#-oIvh({%I5nPw+VF#`| zlYqdLkW_9j>TaJ+zr8)kbnAoVhCwAP1Wvn``!7uO&Y^^XyeL6iA%AV zi&ys5Ey*ACT&{Zuo?v?2)A;s%8oLpy4Jh`uqv*8nC422`{n4=!GB)OD(*beRD zjNTSm?1*An*ZrjpaSr|M2U913N#EMgCL|2U!VjcI#)=5(J9-;*PcwnaR7oC5fV0T=F5~Y&Q+UK;Pq{t zFhX-eaBK>mO@>O~k62x7yu}R*$SozfW{= zx%YQaM5UD~&S%S!Wh;}Re#U8Vl>`_He}8Qus`{?T5t zS*ds0?&8SXESHK!G$zx=SQ!(+J&!t325Vsi@#;>!hJ8NNuvIr_R3IgJ$XDb1$@A+~ z>o)+5pIyWf91ZF>yRA-hc4Uj=_A;1gldv(;8sT^n=nM!H6{L)7{iTI-C|=GJ$CRs{ z>1mEzw6|Phz4M(ivF-ow3rg~u1q^()mx9r5b^yq%Cu1%G&??;TN5G-lCU}W5J(3zkb0n#)l8T zob01dMzqxD=#K+oRq|G*T4jeiWtPEIMwRGBE{jpTT7ZM`ZeQ2^U?N%q#ol%l$%wXw z!Y~NOL2aEzC_pV(%>ophP~36PaYx2OLJ_;mKi^=SZ+{`NNg`5+E_}teW~UI0!bUjM zRmT>Vt%-smrKy+|7b4kVzK|&tGsl^Xc64N<_Ek3h?s;=fuXn!XCkZ8vYySzJy)waB zTQ@rGes?e*Q(A#SaHE8S(|dyP*@cwCwIw`Y5SMGZV^H(>D0S)6`FhXu6$%_UQ?~Fk z|0zLR-2}9Mk?P(~!axV9g+pyT!5yMNzOj-4gd2~&Mbu~HM2$ySUv`}t8^6M0-N)}a z`F3k@Hg@pBdg%Jj7t)(IAq|2Y=yWh2Y)HJn48tiI3kY1EYs%<0W?rVAbDd$<#<-0e zc3J8AwG?aZoVOobwQ135y8*}tUPxrq@#!(HLY=LxOn}hFji51BWzKOVlh`PX>w(Mk zL{=feu7jevC(_jF52>^~T;$W07cP@ex6V#a0m!@)FNI;El`ZKKk5im##gz;$)@7q@ z1{^B|K+Ww3Ho~_|M8ym1iRdR@NLMp@;AOGgH(#(4zc87OC!>j9jutRr_U1+r*Yu)v z4kf|e=pIcew!Zh)Pyg}P-1G95z5gviKar9q6H%n8Kax5qjwxxx;~D{3B2a}tba`3P z+(&Gw+3duXmZ?h1sY{7tp-vSKl7y0=+^r^X?oO-Q>9hx}$2$F(bN6qx&o&a(YYC!y z-_&UI!g|T+xfc@mH%09(-F|;CXwS4uYM@@jsWw$c!wK=jp@aMJDac6LQ7<>30t+eI zHuf7rvJL#m*ea#LgD4lg;f3{b0aDlROHHt+XzKFyr7EQ|ni$mKB9EhF!gg)E5v2~U z*z#~GpMl32j(j**A1(_}Z+v0BiiwHDH>DaRlS#uG3dJ&YOR*u^*#_Rcu9!$uq{FHj zb(pYiW?j&=^I(#OH*fH}|Kx@Apho*fyWKl$&O4xmHfksV39y|-Xk!I5%)b)SJ}-;r4Tv-Ad;1F6s|# z5DT)$55Bz8XBaWXSS(A;l7a+Ys7-UlLOD|=Mx|1)R7F*C74?|ptCVuXQmIiRnYAP1 z^mf_@b8-2{H#p!we<9tZH^7@Z``!7#-$EFTaR}*@0*Io(=Q*zKRV_S5+81@|n5I`L zFcA(APfmH#5kqw6^_b!b{CO*U|x_H~ZQ2Ri6pZh1X+~kZ78s_~Q_AlA*jVY|U{g z4lm+y2FRwuJv-`cnPrDY%!7|tH>xFl7vd-;eAnZb0rJ%ZD_kw0BYS-R%gM&*BvV|& zaZ@!&fl%8psZAZ#!C3)tSQK(}E2^LyTC(`u8a(!jR(H@o?YCM{@wxRi_aKn>TX|kw z0ltBGA&p6nrlcv$Wa9ha%fgU^BVZ=usb>-cCmJ;km=mL5 zbnM4Izwl#A!*9I!#6g%a{QiyB;H=Z>Eeq%=6k-HPub2&7N4jOIB8The37(r3C9maJ zon)@9UI3lmslVHzh#1cAZGh8!G2KK78aDu9-(OZdQ%IB{9$Mo3zJ=wKsJYDo??vr; z{jgx#wm7mfD$8BCV{5xV8=c>WlKoqR(@t}kn=d9N17}SNonH5>H#^kCmzSED2IF9e z^>l4WEgW73{c>>oAfELjrC}TwzeX3#GJX5Th^R@Skbu#?AF2H7L?kJ%^jCeyi|O0d zAmlgCnr91{q(L;ik&p91crYOJO2sBjckQBUYZl8mc~avVMA3Xc;R*(iy%N0qX}jNR z#wl?usg~baV+2<`iAoeCH#h_gtI3|LbO>F6C`NvsTUAk09je=c5?vQnRwm#S(C;~n z2%B9%Y<3Hw|7HHl{{dmBX(sS>FDABFMd#?Pe!J6~U#>_Rqj1!i2EIR%Qw@)BsEPK2 zBp=7hJx2$wAndB+x+)N~vZv`H-nDWaBz5}OE6)1;PVcPOjU?6jn%3E4ujri)THvft z=Z|`iy|Q)I9`u^0t@)EJNAU4tI~6_w_44gaOCR#`3-Jia@)LO9i>VG~%&8&#_WH|P z%Tph~q#=T_h}uvbow=^bFc)}^zMi7DZF#zp1x)h&K|(QL!dWa zR-nH&fA#$rXNN#|U#gpUmMjK>K%2cYNFnCejLfug7>4SUi~_%Gv#6`I>=MsY^onOn zR-@QKE0J=07LN)Yj{uVT<_hxy#pMy~{oo1!ye;+K094^ALnTy5qY*Yj__~wNR`XiE zlCwx9qZ!xDDBhZOg;h<9F={Zbr(QR%b7fy#j%6>_J;Sr%Ua~8u)9akJPiI|8=}%1? z`(8pp%O<>N@+zV5?zU8IjT4n=8R0O~65J^zQm(l&pWSM2j__By zJ^l*`3CwESOHPTB`sb;BhNM({Ef{H&kvElOBtZ6~vRQNT72BqkVGEm9ZAxmd|5F^>C~-dxC~xj`C zd#O?w&4ZVd9dOCWo&4yB4IKQhnubO-U|EoHsji`eWt6H^x;Eu1=e$PEk~#PE`xl4b zy?OY(bi9h)?ze7myMOp%`goypqu(BM&ic){x00HihM|Jgx6u&Z9f#w>p=hkxj@+)4 zM7V~d3$8Mzt_rx~aQ1>je8-FNuHPl&{pyQ}>p*7a-S4!zr^`GfjUrGQ0<7Cs zxI?q7S`(%%4WrD6bV`Kel$z<7MyAB>ormltNa1~rntyf$&c#;IYMq|q{a6v4RVd(% zY`nU`<2c(PoH}>v5+}8Joe?IfXF1zta^DAvUr4-od9{}PLi)~> zHgNp~URLBe)B(@r;DvEjoKlJA%##J773Z4DEv{Ui`|cOl%X7a5&px!5Y;)^0PtSV2 zdHcx<4Bv-33QhOU{0TgJ zcR~(bTr%4}>&`E8o=jC`qyi#kD8fmA7c4orN0V`ga*hQKSGR=Vyy|eub=@>+OrZ`o z_qFEdAj$xO-iJuOlu-ZGbQ{g&6RBhNq)7~=s;Uhs8bd{d5c7mM&gZpUF`LgGEBSI+ z$&`zSx?0i;`HDt4rDaB)jjbN&!xxvE z7h(_?%io_O=5gG{TZ*0sKcJ#o&2T7)!@qf4$*cRBqkKMpXcbMO88%g@O*0S!tunI= z>fm1ZR_}JJwJ~g8yZ@aFiy5u2E(GzWRH5p7(yV+Qwxh~>Bmf0o+z$c8NL8J>CFni` zG)d_-PgIqv1#!Zz8>S!-O=^@L<2v)sn_)kT8)skpFt~ z8Sa&97oSTwrJ18zcE_Rf`g^Gk{Dh-gfiRiXI~gvhb9J2IV9XYnNjUSHS@0^Xxm^@5 zc2xQMa#YKvfd9Nf67P8_QBI0Z3R@j4RL<&Ys#H`D9Ilw6U4+4y3(0KT;2tF1Rp8=v zpy*ulm|;odIDcejRjsf!bnmv@?Y9%|2rc7!!n)CI{c@^LF?LZuIJfSoFs1~<5%DEy zpwA6QLAjhiJggiZW)HFjC6~=t3W}O9W(&s!)wWovbX>I2!XYiX)#@geVkaHdeJ{m+ z_40Tv|I&JW?*lI-?jnm$ZaM%2$2$H1U?7~OG{z$_3WJFf-N1=OK42t5dZex?1+7xe zQzB{Z+9NDe%x0ETzMZwRn=3l2C6K~P>n*VFfM*|E3FF<) zZuwn*vsA9May{mX>IN`AJbU9_^2}z?9-N-_mzzlzy44ts#)=sE9xxCrwK=ZK1cS80 z&g)X@CB1Zzv$CpEJ1*poV=!$1(>(9rYOfVU*nBMI%3FxMm)28{PrtqX!=h;-nFgBE^YkcevRc$019)xD>U-b%vb>%1@t5MH_QMMp_-t=4nVYv-y=G@H z@77oWF&a~Fy%5;xc&t~`YdM0;JQq`lQN~KJab3)O}FK%Vt z;AnpJrNl*JvmgLLxjP@=O?`x;X(Nnw|9RN!g1YQ6{PgN|kvqz}LIJw>sKbmcpW}`V z6^}1lSrb7yhVfB&_BT^>uiXS!(419aS1>e2lGGUC7Og1d!z!(n==H);Rz1$us9wvG zYPOuq6>=Bzy`3AvzHNgvKKD{$q+@n*$Y~c>>CHF5d!t}1!>J60jbJnxha6cpQJF&^ z7R$Pbt}-%fc%PACRE1Y|oGty)7j1yQL@%qqaFp*@z*r^_NSl6QC4pE{q@*0e(O3)b z2xe>GJF&SKc%F2Onv3z+!U>y7w0`v-%X~N0&CYM#1IN%`#4gMhl$D)^m{ol5%gJ8D zc?Pk#H*P8?LmA0IO0_YRq);qobA?j=pj1?9*RSvA%zZ7JRSRmNq8wEVplh7WV^;qh zFQoB1{`&USD-()E=j2OItZisSO8$YDlZ{g`{f^xR$o{>at70`9i|BSG%Rr2YfaqoTR;jPE8@c20~05%21nx zf@)3`@;g0GOkp|91pX?`8djX8S;u=s6~p-H4Z#>``P-YWIbBB;o_@%LfWomm~jIN&hK#<$`z%tyaViKHxMJ^ZeoafX7Au$ zTK)OGp(`M!ckq4+$FqT#Vk^GwNg>N74%2Crx*nfU0)f5%g1)Kfud|6vm`B>;wF!AwrnnuyKnT-PlQZmh`<(-`C z7$#(_xTIV)Evsx?v90h@aN?5GlP|5$snqT!_MJt1uMhe)h*P>GifK5VVoDdyI08?t zBOXW8PvlA6gXqrcC&HbnX%$7Pp&iFm>eg?@dRL1b<&B zQy?HOoq{-O8llpJIL;W5T#noNxujg;c5kF!4)}nFysr3j8(<(A{%FEurHSt<2oVsY zdTfxYmSdJxQLB_XCdEz6OsP^0bc#K^8}mLlf8{T~v_47Oznfm^)Vx=L@ZJY0IMY&@ zb*p(BO#E~$g6zeC@G8;cKP;lh(%lY07Vk|(kM>!+c{*6GmkfqtfdYT>wb{8v)KhC& zNJ}Ke3CFr^o8F1zRk*R3>3A5?BZl*z7jTwT5d&nfa!57{hB1L(!6Fri>$r&Ap^9nN zJXWSIcLb4wiRf~$h=pkn5l(FI$gEZgJTkBkrYeI;wlxO&K9y4yG7@Dd)L=X&jx7W> z+fn$#qr$CIK0|@qWw8}$Tc-QK#vMy{*Aw>l+)eFZ7&LFRdcAIEK6W0EU>aq7iLbW>Qh{Wp$QVj|Tl7+f7 z8jm5Ek8l@5W7;^*WwXUh?r6V~)oHF=s;YX`vMg#9l&VQIlPE^A+2! zYWtlBcghr7h`GT+2Jq}_Q+yGE$!T+*;zqWekjHq|(~oTy7Dw~0>v`R&)bTPT4|hmE zYB|>S0^`bT;sUx2Fn;cCqP1{#5ka$e+MhSRBqR|`RZRvOci{E$TpV|Q)OZr?w&4BlG7kaFr5%E zX_bK`SX{GAS}v6dtx|Ga;~IcJR8+hQ0aq6LZ=X);H6Nwb(yI(7`h5;rULjU3tE-1OEmO^wvJa^Q6!#mxb_0yN$!bHi0IqY^X${)*Td!w2MIvFS&08s>Z|_ux&ur9l*zQ0i?9aBRC2>p;#~ll3yJLvxJ_|XU&vIQnJI2C0 zZeVff)*!M=C|nrGdp4LlviXmunv0XnefjoNoH(1R0X20@4Qn|5gQGtn0FyJUpJ3q! z8;c*>C5JJLPj29e805b%5lPYkeM$oP|B!J+7JWq(jhl+1+h(R}9TVGRq-HZ_GZWsO zT4v3vS*DfZiNJUJ8$2Q4qDVCet676*$`zC8 zHf5AsD#uNgoN1O-)tN;hI&QE3>{c9&vyWf68+RQp^C)C1-<^UnXD0K-KJSfyTb0YdoQg_ z1drd^;IJ^Dd^pvxo(vufIfxOktkFcdW80;wVVh=|b82&&@gjF@YCF`%TTM;Vw6|B? zcM2Xc@%_EK>)nQrel~qcAQ0cPUS|Lx;uK_tA{@!lcoZsO7*0)0J}ijim5hCKU}$R5 zVA-0Y)viJCxL$qaNPDCZ&yTimHT{m?UTvRTH0K^%B_a9!`OAN0LrT^DY5X2m z-9H=b{VTxpF2sYn6_TmuhvNy3eM_rk@&Z$Y#hsG3HvJn(MJ-@@f2LxX|prGX=G_8 p4Q(m|00s%W#MVjIB$l8y*h$?2)3*f^?ulX$yqsriMA_}8kr*g~?<4>K literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/gzip/testdata/test.json b/vendor/github.com/klauspost/compress/gzip/testdata/test.json new file mode 100644 index 0000000..3b7b678 --- /dev/null +++ b/vendor/github.com/klauspost/compress/gzip/testdata/test.json @@ -0,0 +1,5902 @@ +[ + { + "_id": "543fa821aeca0fed7f182f01", + "index": 0, + "guid": "3526d142-6d2b-4266-9855-e6ec1589a265", + "isActive": false, + "balance": "$2,156.72", + "picture": "http://placehold.it/32x32", + "age": 29, + "eyeColor": "brown", + "name": { + "first": "Rosella", + "last": "Hale" + }, + "company": "SKINSERVE", + "email": "rosella.hale@skinserve.net", + "phone": "+1 (920) 528-2959", + "address": "324 Imlay Street, Sehili, Guam, 3022", + "about": "Est consectetur ut incididunt commodo elit cillum incididunt consectetur id officia pariatur pariatur cillum. Ipsum non incididunt tempor non. Cillum aliquip aliquip non minim ipsum voluptate incididunt adipisicing aute pariatur laborum minim deserunt laborum. Do do consequat enim adipisicing dolor incididunt reprehenderit sint. Veniam dolor consequat sint ullamco id enim occaecat.\r\n", + "registered": "Wednesday, August 27, 2014 9:12 PM", + "latitude": 43.44586, + "longitude": -65.480986, + "tags": [ + "Lorem", + "ex", + "magna", + "aliqua", + "id", + "sint", + "elit" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Etta Stanton" + }, + { + "id": 1, + "name": "Cora Velazquez" + }, + { + "id": 2, + "name": "Deann Guy" + } + ], + "greeting": "Hello, Rosella! You have 6 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa8218066e8499ef38bcc", + "index": 1, + "guid": "991a35b5-91db-49e8-8a1e-13688b5ed88d", + "isActive": true, + "balance": "$1,762.71", + "picture": "http://placehold.it/32x32", + "age": 28, + "eyeColor": "green", + "name": { + "first": "Rose", + "last": "Lynn" + }, + "company": "NITRACYR", + "email": "rose.lynn@nitracyr.com", + "phone": "+1 (912) 564-2131", + "address": "485 Pulaski Street, Logan, Mississippi, 7453", + "about": "Minim proident enim eiusmod reprehenderit excepteur laboris. Adipisicing culpa cupidatat eiusmod exercitation reprehenderit anim. Nostrud mollit reprehenderit reprehenderit id magna et id esse cillum et proident. Incididunt eu nisi excepteur est est irure voluptate id nulla. Laboris consectetur aliqua cupidatat ex elit proident officia ex quis. Minim officia eu eiusmod velit. Ullamco dolor non quis aliqua cupidatat amet laborum laborum ad ex proident qui eiusmod ea.\r\n", + "registered": "Sunday, October 5, 2014 10:36 PM", + "latitude": -3.548698, + "longitude": 79.421107, + "tags": [ + "exercitation", + "adipisicing", + "aliqua", + "do", + "id", + "veniam", + "est" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Ada Little" + }, + { + "id": 1, + "name": "Lopez Osborne" + }, + { + "id": 2, + "name": "Tami Leach" + } + ], + "greeting": "Hello, Rose! You have 5 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa821255974bb9f89e5ea", + "index": 2, + "guid": "e5727238-63a4-4e1e-88cc-67300826259c", + "isActive": false, + "balance": "$2,131.97", + "picture": "http://placehold.it/32x32", + "age": 21, + "eyeColor": "green", + "name": { + "first": "Gloria", + "last": "Richards" + }, + "company": "SPHERIX", + "email": "gloria.richards@spherix.biz", + "phone": "+1 (884) 536-3434", + "address": "493 Judge Street, Cetronia, Rhode Island, 4439", + "about": "Lorem cupidatat ea et laboris tempor enim non. Sit consequat culpa et qui aute cillum ut ullamco. Nulla duis sit Lorem incididunt mollit nostrud dolor veniam ullamco. Sunt magna id velit in laborum nisi labore. Id deserunt labore dolore dolor aliqua culpa est id duis.\r\n", + "registered": "Saturday, March 29, 2014 8:18 AM", + "latitude": 60.328012, + "longitude": 126.657357, + "tags": [ + "dolore", + "laboris", + "proident", + "cillum", + "in", + "fugiat", + "incididunt" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Bowen Cote" + }, + { + "id": 1, + "name": "Olga Gardner" + }, + { + "id": 2, + "name": "Evangeline Howard" + } + ], + "greeting": "Hello, Gloria! You have 9 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa8212b7e1e8201a38702", + "index": 3, + "guid": "bab757bd-2ebd-4c2c-86b7-0d4d8b059d35", + "isActive": true, + "balance": "$2,509.81", + "picture": "http://placehold.it/32x32", + "age": 39, + "eyeColor": "green", + "name": { + "first": "Casey", + "last": "Hayes" + }, + "company": "SURELOGIC", + "email": "casey.hayes@surelogic.co.uk", + "phone": "+1 (993) 573-3937", + "address": "330 Tapscott Avenue, Eastvale, New Mexico, 928", + "about": "Eu elit sint sunt labore dolor cillum esse ad voluptate commodo. Dolor aliqua do dolore ex tempor sint consequat culpa et consectetur nisi voluptate reprehenderit. Dolor velit eu cillum tempor anim anim. Nostrud laboris eiusmod elit enim duis in consectetur esse anim qui. Et eiusmod culpa nulla anim et officia pariatur reprehenderit eiusmod veniam. Ullamco nisi ea incididunt velit. Ullamco cillum mollit ea aliqua ea eu et enim.\r\n", + "registered": "Sunday, September 14, 2014 8:35 AM", + "latitude": -43.494604, + "longitude": 95.217518, + "tags": [ + "officia", + "sunt", + "dolore", + "qui", + "elit", + "irure", + "cillum" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Serrano Wise" + }, + { + "id": 1, + "name": "Lorene Macias" + }, + { + "id": 2, + "name": "Kristen Lott" + } + ], + "greeting": "Hello, Casey! You have 7 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa821bfefa43403d5d054", + "index": 4, + "guid": "675d1598-8c45-4d67-a4df-d38a270de371", + "isActive": false, + "balance": "$3,887.07", + "picture": "http://placehold.it/32x32", + "age": 35, + "eyeColor": "blue", + "name": { + "first": "Price", + "last": "Oconnor" + }, + "company": "ANOCHA", + "email": "price.oconnor@anocha.tv", + "phone": "+1 (855) 410-3197", + "address": "447 Stockholm Street, Templeton, Wisconsin, 2216", + "about": "Cillum veniam esse duis tempor incididunt do dolor officia elit eu. Excepteur velit reprehenderit minim Lorem commodo est. Duis Lorem nisi elit aliquip est deserunt fugiat ut. Nisi tempor ex est pariatur laborum eiusmod anim eu nulla. Nisi enim id aute id ex id nostrud.\r\n", + "registered": "Wednesday, May 14, 2014 5:19 PM", + "latitude": 26.083477, + "longitude": 122.61114, + "tags": [ + "in", + "ad", + "aliqua", + "minim", + "nisi", + "cupidatat", + "id" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Montgomery Mccray" + }, + { + "id": 1, + "name": "Lucia Ferrell" + }, + { + "id": 2, + "name": "Glover Brock" + } + ], + "greeting": "Hello, Price! You have 5 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa821a699260d8ed4439a", + "index": 5, + "guid": "5e271270-fef3-48a7-b389-346251b46abc", + "isActive": false, + "balance": "$1,046.50", + "picture": "http://placehold.it/32x32", + "age": 38, + "eyeColor": "blue", + "name": { + "first": "Rita", + "last": "Huber" + }, + "company": "VURBO", + "email": "rita.huber@vurbo.name", + "phone": "+1 (803) 589-3948", + "address": "838 River Street, Gadsden, American Samoa, 2602", + "about": "Culpa quis qui exercitation velit officia eu id qui consequat qui. Ea fugiat quis fugiat proident velit. Velit et reprehenderit quis irure adipisicing duis dolor id cupidatat ea aliqua elit.\r\n", + "registered": "Friday, April 11, 2014 11:56 AM", + "latitude": 30.717665, + "longitude": -29.687902, + "tags": [ + "veniam", + "ex", + "deserunt", + "cillum", + "sint", + "eu", + "proident" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Oliver Terrell" + }, + { + "id": 1, + "name": "Lora Shepherd" + }, + { + "id": 2, + "name": "Guzman Holman" + } + ], + "greeting": "Hello, Rita! You have 7 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa821b888230e87ce950e", + "index": 6, + "guid": "7e4efd9a-4923-42ae-8924-d6d5fae80ec0", + "isActive": false, + "balance": "$1,205.59", + "picture": "http://placehold.it/32x32", + "age": 30, + "eyeColor": "green", + "name": { + "first": "Peterson", + "last": "Oliver" + }, + "company": "ZENTIX", + "email": "peterson.oliver@zentix.me", + "phone": "+1 (924) 564-2815", + "address": "596 Middleton Street, Walker, Louisiana, 3358", + "about": "Exercitation cillum sit exercitation voluptate duis nostrud incididunt cillum sint minim labore tempor minim ad. Esse ad id pariatur cillum id exercitation ullamco elit. Quis nisi excepteur mollit consectetur id et. Ea voluptate nulla duis minim exercitation aliqua aute nisi enim enim excepteur dolor ad non. Aliquip elit eu enim officia minim enim Lorem tempor. Cillum anim aute sunt cupidatat deserunt consequat.\r\n", + "registered": "Friday, March 28, 2014 2:28 PM", + "latitude": 45.092029, + "longitude": 56.730029, + "tags": [ + "in", + "voluptate", + "sit", + "sit", + "Lorem", + "reprehenderit", + "esse" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Wiley Henry" + }, + { + "id": 1, + "name": "Downs Rowland" + }, + { + "id": 2, + "name": "White Guerra" + } + ], + "greeting": "Hello, Peterson! You have 8 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa8210f8589ab846b3d88", + "index": 7, + "guid": "afc25e30-7e70-4a87-bdd3-519e1837969a", + "isActive": false, + "balance": "$3,928.85", + "picture": "http://placehold.it/32x32", + "age": 39, + "eyeColor": "green", + "name": { + "first": "Shauna", + "last": "Morse" + }, + "company": "CENTICE", + "email": "shauna.morse@centice.us", + "phone": "+1 (926) 517-3679", + "address": "752 Dunne Place, Ebro, Kansas, 3215", + "about": "Cupidatat incididunt sit duis tempor labore dolore aute qui magna in. Consequat aute ut veniam laborum aliqua Lorem esse. Cillum in qui sint excepteur eiusmod eiusmod eu anim adipisicing et.\r\n", + "registered": "Saturday, September 6, 2014 2:32 PM", + "latitude": 36.341849, + "longitude": 108.378341, + "tags": [ + "in", + "nulla", + "labore", + "qui", + "id", + "enim", + "fugiat" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Lizzie Carson" + }, + { + "id": 1, + "name": "Eliza Hall" + }, + { + "id": 2, + "name": "Baxter Burton" + } + ], + "greeting": "Hello, Shauna! You have 6 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa8213c997bd81d4a7fa5", + "index": 8, + "guid": "1337ad27-17e3-459f-90a3-a43b54b88184", + "isActive": true, + "balance": "$2,096.67", + "picture": "http://placehold.it/32x32", + "age": 24, + "eyeColor": "blue", + "name": { + "first": "Glenn", + "last": "Brooks" + }, + "company": "MANGLO", + "email": "glenn.brooks@manglo.ca", + "phone": "+1 (895) 595-2669", + "address": "605 McDonald Avenue, Nicholson, Indiana, 2302", + "about": "Deserunt incididunt ullamco dolore nostrud cupidatat sit consequat adipisicing incididunt sunt. Laboris fugiat et laboris est eu laborum culpa. Labore ad aliquip ut enim aute nulla quis cillum dolor aliqua. Culpa labore occaecat et sunt qui. Velit consequat ad proident non voluptate non mollit eu et cillum tempor. Velit quis deserunt Lorem cupidatat enim ut.\r\n", + "registered": "Friday, March 21, 2014 9:06 AM", + "latitude": -40.51084, + "longitude": -137.771438, + "tags": [ + "enim", + "laboris", + "culpa", + "do", + "nulla", + "anim", + "cillum" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Shelly Cardenas" + }, + { + "id": 1, + "name": "Kristine Mendoza" + }, + { + "id": 2, + "name": "Hall Hendrix" + } + ], + "greeting": "Hello, Glenn! You have 10 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa821054bcf388259b272", + "index": 9, + "guid": "cd9601fc-7ca7-4d54-830b-145ff5c5c147", + "isActive": true, + "balance": "$1,816.14", + "picture": "http://placehold.it/32x32", + "age": 33, + "eyeColor": "green", + "name": { + "first": "Maribel", + "last": "Small" + }, + "company": "FUTURITY", + "email": "maribel.small@futurity.org", + "phone": "+1 (825) 532-2134", + "address": "424 Rockaway Parkway, Vale, Alaska, 1834", + "about": "Aliqua irure culpa exercitation nostrud qui exercitation deserunt ullamco culpa aliquip irure. Proident officia in consequat laborum ex adipisicing exercitation proident anim cupidatat excepteur anim. Labore irure pariatur laboris reprehenderit.\r\n", + "registered": "Tuesday, July 29, 2014 9:59 PM", + "latitude": 53.843872, + "longitude": 85.292318, + "tags": [ + "dolore", + "laborum", + "aute", + "aliqua", + "nostrud", + "commodo", + "commodo" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Anthony Bray" + }, + { + "id": 1, + "name": "Vicki Kelly" + }, + { + "id": 2, + "name": "Baird Wagner" + } + ], + "greeting": "Hello, Maribel! You have 5 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821f14efb6f7f1210b9", + "index": 10, + "guid": "c9400d51-ea8d-4748-9a10-fa0e3a037b23", + "isActive": false, + "balance": "$1,395.15", + "picture": "http://placehold.it/32x32", + "age": 31, + "eyeColor": "green", + "name": { + "first": "Kendra", + "last": "Knapp" + }, + "company": "UNCORP", + "email": "kendra.knapp@uncorp.biz", + "phone": "+1 (830) 509-3054", + "address": "765 Cameron Court, Ferney, Florida, 1963", + "about": "Duis irure ea qui ut velit nostrud. Lorem laborum excepteur do qui ad sit culpa. Labore mollit mollit deserunt sint aute officia qui laboris dolor aliqua magna in officia.\r\n", + "registered": "Sunday, April 27, 2014 11:55 AM", + "latitude": 84.200593, + "longitude": -155.377179, + "tags": [ + "laborum", + "labore", + "aliquip", + "ex", + "voluptate", + "dolor", + "Lorem" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Marva Cash" + }, + { + "id": 1, + "name": "Aimee Velez" + }, + { + "id": 2, + "name": "Eaton Delgado" + } + ], + "greeting": "Hello, Kendra! You have 7 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa82119105322ba52b407", + "index": 11, + "guid": "b6862230-95da-43d5-97ba-13ed4bcc0744", + "isActive": false, + "balance": "$1,442.51", + "picture": "http://placehold.it/32x32", + "age": 21, + "eyeColor": "brown", + "name": { + "first": "Katrina", + "last": "Ferguson" + }, + "company": "MANTRIX", + "email": "katrina.ferguson@mantrix.io", + "phone": "+1 (938) 541-3037", + "address": "447 Putnam Avenue, Collins, Georgia, 8421", + "about": "Minim aliquip Lorem fugiat et fugiat esse aliqua consectetur non officia esse. Fugiat irure eu ut irure cillum mollit nisi consequat do cillum. Est exercitation deserunt proident ex cupidatat. Elit aliquip pariatur ad minim adipisicing qui. Quis enim laborum incididunt eiusmod deserunt cillum amet enim. Proident et do voluptate esse laboris nisi. Duis cupidatat fugiat adipisicing aute velit et ullamco anim velit velit et excepteur laboris.\r\n", + "registered": "Tuesday, February 4, 2014 5:01 PM", + "latitude": 43.287084, + "longitude": 133.518964, + "tags": [ + "magna", + "officia", + "reprehenderit", + "excepteur", + "cillum", + "veniam", + "officia" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Tameka Mccullough" + }, + { + "id": 1, + "name": "Madden Vincent" + }, + { + "id": 2, + "name": "Jewel Mccarthy" + } + ], + "greeting": "Hello, Katrina! You have 7 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa821ee55902ac207b17a", + "index": 12, + "guid": "50161207-4477-47b9-8aa7-a845c3c2e96f", + "isActive": false, + "balance": "$1,937.64", + "picture": "http://placehold.it/32x32", + "age": 38, + "eyeColor": "brown", + "name": { + "first": "Gilliam", + "last": "Flowers" + }, + "company": "INTERLOO", + "email": "gilliam.flowers@interloo.net", + "phone": "+1 (930) 564-2474", + "address": "986 Elton Street, Bagtown, Alabama, 9115", + "about": "Velit incididunt ut nulla adipisicing ad qui sint dolor cillum cupidatat in. Commodo aliqua deserunt ea eu irure irure nisi ullamco culpa nostrud. Adipisicing exercitation excepteur et id cupidatat. Ullamco ut incididunt proident est ad deserunt duis id ut. Excepteur cupidatat irure reprehenderit et excepteur minim cillum occaecat adipisicing. Commodo fugiat ad ex consectetur commodo dolore id nisi deserunt commodo aliquip. Veniam amet mollit nulla adipisicing eu minim sit magna incididunt adipisicing.\r\n", + "registered": "Tuesday, April 1, 2014 12:42 AM", + "latitude": -55.19047, + "longitude": 177.975351, + "tags": [ + "sint", + "pariatur", + "incididunt", + "exercitation", + "quis", + "ad", + "sint" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Patsy Hunter" + }, + { + "id": 1, + "name": "Cecilia Green" + }, + { + "id": 2, + "name": "Meyer Jones" + } + ], + "greeting": "Hello, Gilliam! You have 9 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821658f3962ce822678", + "index": 13, + "guid": "7017674f-79b3-43ed-8832-2b787c51f59d", + "isActive": false, + "balance": "$2,291.31", + "picture": "http://placehold.it/32x32", + "age": 38, + "eyeColor": "blue", + "name": { + "first": "Roberts", + "last": "Floyd" + }, + "company": "OVOLO", + "email": "roberts.floyd@ovolo.com", + "phone": "+1 (935) 401-2916", + "address": "723 Amherst Street, Brady, District Of Columbia, 4241", + "about": "Occaecat incididunt eu do quis est. Est mollit incididunt sint aute sunt. Consectetur incididunt officia eu fugiat quis officia pariatur excepteur sint. In enim nostrud nisi culpa. Ex incididunt exercitation id voluptate.\r\n", + "registered": "Thursday, June 19, 2014 4:16 PM", + "latitude": 72.321258, + "longitude": 28.548926, + "tags": [ + "et", + "ipsum", + "anim", + "dolor", + "commodo", + "do", + "exercitation" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Tracey Vasquez" + }, + { + "id": 1, + "name": "Castro Harrell" + }, + { + "id": 2, + "name": "Sanders Barr" + } + ], + "greeting": "Hello, Roberts! You have 10 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa821f95ca5383b9eb53d", + "index": 14, + "guid": "a6532d9a-d291-4a51-92e7-33c50ceecc12", + "isActive": true, + "balance": "$3,310.31", + "picture": "http://placehold.it/32x32", + "age": 33, + "eyeColor": "green", + "name": { + "first": "Miles", + "last": "Valdez" + }, + "company": "DENTREX", + "email": "miles.valdez@dentrex.biz", + "phone": "+1 (960) 513-3228", + "address": "726 Stillwell Place, Soham, Pennsylvania, 3510", + "about": "Sit labore ex commodo duis tempor labore officia et et est qui ullamco. Aute elit in labore laboris magna duis ipsum excepteur anim laboris ipsum magna magna non. Sint mollit eiusmod in est sint ipsum excepteur do anim cillum cillum.\r\n", + "registered": "Thursday, May 1, 2014 6:08 PM", + "latitude": 88.123309, + "longitude": -121.226418, + "tags": [ + "voluptate", + "sunt", + "anim", + "laboris", + "exercitation", + "deserunt", + "culpa" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Bradford Horn" + }, + { + "id": 1, + "name": "Hanson Dillon" + }, + { + "id": 2, + "name": "Whitley Stanley" + } + ], + "greeting": "Hello, Miles! You have 8 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821c52f80cda8ff36b3", + "index": 15, + "guid": "63820e33-a8c7-410e-afa9-32b7f7017a32", + "isActive": true, + "balance": "$2,616.09", + "picture": "http://placehold.it/32x32", + "age": 38, + "eyeColor": "brown", + "name": { + "first": "Floyd", + "last": "Barker" + }, + "company": "TALAE", + "email": "floyd.barker@talae.co.uk", + "phone": "+1 (843) 435-2898", + "address": "501 Sullivan Place, Cotopaxi, Nevada, 5498", + "about": "Non deserunt voluptate occaecat est mollit dolor aliqua. Qui elit aute qui aliquip ipsum et labore est aliquip pariatur. Sint deserunt tempor dolore excepteur elit est sint in est ex anim. Nostrud culpa amet eiusmod incididunt. Ea exercitation amet labore cillum culpa duis aute incididunt dolore sunt. Cillum velit laboris quis eiusmod fugiat consectetur sit fugiat irure labore.\r\n", + "registered": "Monday, March 10, 2014 7:48 AM", + "latitude": -86.397923, + "longitude": 171.646534, + "tags": [ + "dolore", + "sit", + "qui", + "id", + "aliquip", + "mollit", + "laborum" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Eileen Daniels" + }, + { + "id": 1, + "name": "Genevieve Wood" + }, + { + "id": 2, + "name": "Carver Fields" + } + ], + "greeting": "Hello, Floyd! You have 6 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa8219eb621c418384935", + "index": 16, + "guid": "ed67eac2-cfdf-4d28-a734-bc973cba8613", + "isActive": false, + "balance": "$1,917.58", + "picture": "http://placehold.it/32x32", + "age": 38, + "eyeColor": "green", + "name": { + "first": "Carrillo", + "last": "Cox" + }, + "company": "ARCHITAX", + "email": "carrillo.cox@architax.tv", + "phone": "+1 (818) 444-3875", + "address": "309 Randolph Street, Avoca, Illinois, 770", + "about": "Labore consequat et nostrud officia ad. Sint ipsum ipsum sint laboris adipisicing minim voluptate aliqua proident est commodo nulla. Officia sint ipsum laborum aliquip adipisicing adipisicing ea et reprehenderit dolore. Et deserunt sint incididunt velit dolore voluptate deserunt anim nisi sit est officia fugiat. Velit dolore ea do enim veniam ut do. Duis adipisicing fugiat magna Lorem ullamco quis sint ut cupidatat laborum aute laboris sint aliqua.\r\n", + "registered": "Friday, January 17, 2014 12:19 AM", + "latitude": -31.228015, + "longitude": -82.248255, + "tags": [ + "occaecat", + "nostrud", + "ex", + "dolor", + "magna", + "minim", + "pariatur" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Douglas Mayer" + }, + { + "id": 1, + "name": "Dorothy Riddle" + }, + { + "id": 2, + "name": "Melanie Thompson" + } + ], + "greeting": "Hello, Carrillo! You have 7 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821e152869356625777", + "index": 17, + "guid": "1dc17af3-a194-42e8-add8-a73853f16da2", + "isActive": true, + "balance": "$1,703.08", + "picture": "http://placehold.it/32x32", + "age": 36, + "eyeColor": "green", + "name": { + "first": "Ana", + "last": "Reese" + }, + "company": "FORTEAN", + "email": "ana.reese@fortean.name", + "phone": "+1 (876) 419-2128", + "address": "451 Brevoort Place, Leola, Tennessee, 3725", + "about": "Consectetur officia irure proident nulla. Anim veniam mollit sit id aliqua. Do reprehenderit culpa magna magna aute est pariatur consequat ut occaecat cillum adipisicing consectetur. Sint qui pariatur id velit deserunt laborum. Minim consequat ut sunt qui. Ex occaecat tempor fugiat sit anim veniam incididunt mollit mollit. Non id anim cillum culpa tempor voluptate aute consequat proident reprehenderit.\r\n", + "registered": "Saturday, June 28, 2014 4:53 AM", + "latitude": 80.18306, + "longitude": 70.818006, + "tags": [ + "mollit", + "voluptate", + "est", + "magna", + "ad", + "duis", + "est" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Mclaughlin Johns" + }, + { + "id": 1, + "name": "Leanne Hanson" + }, + { + "id": 2, + "name": "Isabel Leon" + } + ], + "greeting": "Hello, Ana! You have 7 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa82168ed66f19f510aea", + "index": 18, + "guid": "87be73dd-bf5e-48c4-8168-f8f76cda905d", + "isActive": true, + "balance": "$1,307.88", + "picture": "http://placehold.it/32x32", + "age": 31, + "eyeColor": "green", + "name": { + "first": "Daugherty", + "last": "Ware" + }, + "company": "TYPHONICA", + "email": "daugherty.ware@typhonica.me", + "phone": "+1 (936) 470-3445", + "address": "919 Oriental Boulevard, Westboro, Iowa, 2587", + "about": "Occaecat in nisi et consequat. Laboris minim consequat qui proident id aute occaecat pariatur. Sint esse anim id ex voluptate fugiat culpa anim commodo incididunt.\r\n", + "registered": "Tuesday, March 4, 2014 11:53 PM", + "latitude": -15.007384, + "longitude": -86.496257, + "tags": [ + "consequat", + "nisi", + "duis", + "cupidatat", + "anim", + "eu", + "culpa" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Maddox Wells" + }, + { + "id": 1, + "name": "Maura May" + }, + { + "id": 2, + "name": "Terry Calhoun" + } + ], + "greeting": "Hello, Daugherty! You have 10 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa8210abc44da895c5591", + "index": 19, + "guid": "32c4c5d0-b54c-4ea4-999a-f4fa517ac5ce", + "isActive": true, + "balance": "$2,706.98", + "picture": "http://placehold.it/32x32", + "age": 34, + "eyeColor": "green", + "name": { + "first": "Sonja", + "last": "Craft" + }, + "company": "KOZGENE", + "email": "sonja.craft@kozgene.us", + "phone": "+1 (808) 410-3427", + "address": "808 Lawn Court, Blodgett, Massachusetts, 560", + "about": "Eu occaecat reprehenderit ea ad ullamco ea sint cupidatat ex. Deserunt eu est veniam consectetur do anim in. Dolore minim veniam dolore elit sunt labore id eiusmod.\r\n", + "registered": "Sunday, August 31, 2014 12:09 AM", + "latitude": -47.101894, + "longitude": -130.294589, + "tags": [ + "sint", + "cillum", + "magna", + "sit", + "fugiat", + "nisi", + "reprehenderit" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Loretta Mcgee" + }, + { + "id": 1, + "name": "Wilson Merritt" + }, + { + "id": 2, + "name": "Susanne Lloyd" + } + ], + "greeting": "Hello, Sonja! You have 8 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa82134480e13e931193a", + "index": 20, + "guid": "c4a7ded5-aa3e-411f-9956-f4b938ce93dc", + "isActive": false, + "balance": "$3,216.50", + "picture": "http://placehold.it/32x32", + "age": 23, + "eyeColor": "green", + "name": { + "first": "Powers", + "last": "Mathews" + }, + "company": "ANDRYX", + "email": "powers.mathews@andryx.ca", + "phone": "+1 (914) 559-2596", + "address": "545 Nolans Lane, Brenton, Arkansas, 7607", + "about": "In irure et tempor ad commodo culpa reprehenderit excepteur tempor ex. Exercitation eiusmod consequat anim incididunt veniam duis sunt velit sunt aliquip esse adipisicing do. Elit ea incididunt id amet mollit ea in ad ea cupidatat duis minim consectetur incididunt.\r\n", + "registered": "Friday, July 11, 2014 11:27 AM", + "latitude": 64.259332, + "longitude": 111.604942, + "tags": [ + "ut", + "ex", + "cillum", + "commodo", + "pariatur", + "ex", + "reprehenderit" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Woodward Witt" + }, + { + "id": 1, + "name": "Hazel Mcfadden" + }, + { + "id": 2, + "name": "Desiree Mclean" + } + ], + "greeting": "Hello, Powers! You have 5 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa821117e0b8bd3f6e566", + "index": 21, + "guid": "fae9ba5c-948b-429c-b1e6-a0a6835f0694", + "isActive": false, + "balance": "$1,046.41", + "picture": "http://placehold.it/32x32", + "age": 31, + "eyeColor": "brown", + "name": { + "first": "Lola", + "last": "Roy" + }, + "company": "EURON", + "email": "lola.roy@euron.org", + "phone": "+1 (920) 413-2000", + "address": "237 Tabor Court, Berwind, Hawaii, 2276", + "about": "Aute voluptate proident occaecat exercitation aute proident ullamco veniam aute magna velit cupidatat. Occaecat dolor aliquip adipisicing dolor do elit eu elit laboris officia magna dolore. Velit tempor sit ad et occaecat nisi elit excepteur. Non velit sint deserunt culpa magna irure.\r\n", + "registered": "Thursday, February 27, 2014 1:20 AM", + "latitude": 12.90929, + "longitude": 68.693395, + "tags": [ + "ad", + "officia", + "non", + "aute", + "magna", + "minim", + "sint" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Lee Tate" + }, + { + "id": 1, + "name": "Miranda Payne" + }, + { + "id": 2, + "name": "Jocelyn Cantrell" + } + ], + "greeting": "Hello, Lola! You have 9 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa8211cf627425d947100", + "index": 22, + "guid": "590c913b-2457-47a5-ad5c-8a5fc3c249f9", + "isActive": true, + "balance": "$2,144.16", + "picture": "http://placehold.it/32x32", + "age": 22, + "eyeColor": "green", + "name": { + "first": "Marci", + "last": "Mcpherson" + }, + "company": "VIAGREAT", + "email": "marci.mcpherson@viagreat.biz", + "phone": "+1 (916) 417-2166", + "address": "527 Kenilworth Place, Bartonsville, Puerto Rico, 4739", + "about": "Duis velit irure sit sit aliquip sit culpa velit labore velit ipsum amet. Pariatur labore ex et sunt proident ad minim. Aliquip qui adipisicing elit do sunt mollit irure adipisicing in labore cillum. Ut velit dolor cillum irure voluptate ad incididunt consequat cillum esse laborum consequat do.\r\n", + "registered": "Wednesday, August 27, 2014 6:55 AM", + "latitude": 23.135493, + "longitude": -133.213153, + "tags": [ + "ut", + "ex", + "deserunt", + "mollit", + "cillum", + "aliquip", + "excepteur" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Latisha Ortiz" + }, + { + "id": 1, + "name": "Ila Marshall" + }, + { + "id": 2, + "name": "Kathie Strong" + } + ], + "greeting": "Hello, Marci! You have 5 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa82113ff45aaf64d6b75", + "index": 23, + "guid": "a074b7d2-92de-4728-9032-ac711cc8ca1b", + "isActive": true, + "balance": "$1,927.67", + "picture": "http://placehold.it/32x32", + "age": 26, + "eyeColor": "green", + "name": { + "first": "Lorie", + "last": "Haynes" + }, + "company": "CUBIX", + "email": "lorie.haynes@cubix.io", + "phone": "+1 (914) 479-2574", + "address": "209 Stoddard Place, Grahamtown, New Hampshire, 3422", + "about": "Commodo eu reprehenderit aute veniam occaecat eiusmod ex enim mollit elit. Officia fugiat proident cillum sint sint. In anim occaecat in dolore pariatur occaecat dolore eu duis sint veniam labore tempor id.\r\n", + "registered": "Thursday, June 19, 2014 3:03 AM", + "latitude": -80.694066, + "longitude": 98.315178, + "tags": [ + "proident", + "est", + "nulla", + "minim", + "aute", + "duis", + "ea" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Shana Jensen" + }, + { + "id": 1, + "name": "Audra Hays" + }, + { + "id": 2, + "name": "Shannon Stewart" + } + ], + "greeting": "Hello, Lorie! You have 5 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa8216788a07fe633c5a6", + "index": 24, + "guid": "ff361134-2ce3-4cce-b043-d571e87a041d", + "isActive": false, + "balance": "$1,274.62", + "picture": "http://placehold.it/32x32", + "age": 34, + "eyeColor": "green", + "name": { + "first": "Parker", + "last": "Higgins" + }, + "company": "ISOSTREAM", + "email": "parker.higgins@isostream.net", + "phone": "+1 (965) 467-3975", + "address": "908 Division Place, Homeland, South Carolina, 2577", + "about": "Laborum minim consectetur ipsum incididunt cupidatat ex ad labore eu non est consequat. Tempor eiusmod commodo Lorem enim aliquip ad non sint ipsum culpa amet. Eu sit amet velit est sit cupidatat aliquip magna proident id veniam Lorem dolore. Eiusmod ex amet proident enim ipsum proident mollit adipisicing ut.\r\n", + "registered": "Monday, August 25, 2014 4:51 AM", + "latitude": -28.784274, + "longitude": -151.224185, + "tags": [ + "ea", + "cupidatat", + "do", + "culpa", + "ea", + "ullamco", + "nulla" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Bridgette Tyler" + }, + { + "id": 1, + "name": "Harris Pollard" + }, + { + "id": 2, + "name": "Davenport Skinner" + } + ], + "greeting": "Hello, Parker! You have 6 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821ff898d23056717a4", + "index": 25, + "guid": "f5e85a0d-f46e-427e-86a7-657eaaadb169", + "isActive": true, + "balance": "$3,413.58", + "picture": "http://placehold.it/32x32", + "age": 36, + "eyeColor": "brown", + "name": { + "first": "Rios", + "last": "Reilly" + }, + "company": "QUILTIGEN", + "email": "rios.reilly@quiltigen.com", + "phone": "+1 (982) 565-3930", + "address": "789 Beekman Place, Wiscon, Texas, 8745", + "about": "Consectetur qui do sint deserunt voluptate sunt dolor in officia aliquip. Eu irure sit veniam nostrud culpa laboris. Commodo nostrud cillum nulla nostrud.\r\n", + "registered": "Thursday, September 4, 2014 1:54 PM", + "latitude": 6.093115, + "longitude": 145.037939, + "tags": [ + "eu", + "consectetur", + "veniam", + "pariatur", + "laboris", + "ad", + "cupidatat" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Sweet Conley" + }, + { + "id": 1, + "name": "Key Grant" + }, + { + "id": 2, + "name": "Guthrie Moss" + } + ], + "greeting": "Hello, Rios! You have 10 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa82125f7c765fcbb1743", + "index": 26, + "guid": "e5f12323-5c7c-4103-b20c-1a633845a28c", + "isActive": true, + "balance": "$1,645.61", + "picture": "http://placehold.it/32x32", + "age": 26, + "eyeColor": "green", + "name": { + "first": "Hurley", + "last": "Cooke" + }, + "company": "QUORDATE", + "email": "hurley.cooke@quordate.biz", + "phone": "+1 (841) 404-3894", + "address": "369 Denton Place, Curtice, South Dakota, 2613", + "about": "Nulla non in aliqua sit mollit pariatur do mollit. Ut pariatur ut velit minim. Fugiat deserunt velit duis consequat labore culpa voluptate sint voluptate consectetur officia voluptate et laborum. Et exercitation ut eu pariatur minim velit elit. Dolore amet officia ipsum voluptate occaecat eiusmod cupidatat do dolore consequat esse consectetur aliquip.\r\n", + "registered": "Sunday, April 13, 2014 11:42 AM", + "latitude": -78.463811, + "longitude": 36.580914, + "tags": [ + "deserunt", + "nisi", + "do", + "enim", + "nisi", + "qui", + "ipsum" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Harvey Norman" + }, + { + "id": 1, + "name": "Porter Shannon" + }, + { + "id": 2, + "name": "Reyes Goodman" + } + ], + "greeting": "Hello, Hurley! You have 10 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa821f375b9cabd418303", + "index": 27, + "guid": "452fe001-7fff-4f69-9336-00e3e80e9792", + "isActive": true, + "balance": "$2,608.67", + "picture": "http://placehold.it/32x32", + "age": 38, + "eyeColor": "green", + "name": { + "first": "Jill", + "last": "Blair" + }, + "company": "ORBALIX", + "email": "jill.blair@orbalix.co.uk", + "phone": "+1 (863) 519-2778", + "address": "680 Cleveland Street, Kohatk, Ohio, 1688", + "about": "Do labore sint cupidatat dolor. Mollit nulla voluptate nostrud tempor ad cillum in mollit officia reprehenderit duis commodo veniam ad. Adipisicing enim adipisicing consequat sint minim ut. Cupidatat non ullamco sunt mollit proident. Aliquip dolore dolor excepteur cupidatat. Consectetur duis adipisicing qui enim aute quis veniam deserunt occaecat. Duis elit exercitation ullamco voluptate aliqua.\r\n", + "registered": "Tuesday, September 30, 2014 11:23 PM", + "latitude": -33.279869, + "longitude": 6.221211, + "tags": [ + "nostrud", + "elit", + "adipisicing", + "esse", + "in", + "commodo", + "ea" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Tania Flores" + }, + { + "id": 1, + "name": "Nina Blackburn" + }, + { + "id": 2, + "name": "Mathews Fischer" + } + ], + "greeting": "Hello, Jill! You have 10 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821304372a99199671f", + "index": 28, + "guid": "d160ded3-911c-4ce2-a314-9ed9a8e6fa9b", + "isActive": true, + "balance": "$3,005.54", + "picture": "http://placehold.it/32x32", + "age": 35, + "eyeColor": "brown", + "name": { + "first": "Estela", + "last": "Dalton" + }, + "company": "POWERNET", + "email": "estela.dalton@powernet.tv", + "phone": "+1 (959) 527-2607", + "address": "820 Montauk Avenue, Whitmer, Maine, 3867", + "about": "Commodo est ullamco sit eu irure tempor veniam deserunt in aute cillum tempor. Occaecat velit et deserunt incididunt sint do eu consectetur enim ullamco consectetur esse ipsum pariatur. Tempor exercitation dolore tempor enim. Dolor esse est magna occaecat. Elit culpa sint non ea exercitation. Aliquip nostrud aliquip culpa Lorem cillum incididunt do sit sunt velit id. Proident sit proident est velit consequat cillum officia in et.\r\n", + "registered": "Sunday, April 13, 2014 5:53 AM", + "latitude": 32.713335, + "longitude": 174.505048, + "tags": [ + "aliquip", + "dolore", + "proident", + "pariatur", + "elit", + "cillum", + "id" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Gibson Durham" + }, + { + "id": 1, + "name": "Carolina Cooley" + }, + { + "id": 2, + "name": "Rosa Mcintyre" + } + ], + "greeting": "Hello, Estela! You have 8 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa82187c6143c96c5ce1f", + "index": 29, + "guid": "f62ae8de-8905-4ac0-9b5c-ce12dad96a86", + "isActive": false, + "balance": "$1,859.49", + "picture": "http://placehold.it/32x32", + "age": 34, + "eyeColor": "brown", + "name": { + "first": "Martina", + "last": "Jacobson" + }, + "company": "CUIZINE", + "email": "martina.jacobson@cuizine.name", + "phone": "+1 (927) 493-2997", + "address": "234 Utica Avenue, Hinsdale, Vermont, 459", + "about": "Pariatur nulla ad sint tempor qui in id aliqua ex et ut. Qui occaecat quis veniam mollit officia duis ad ea. Est consectetur sit sint proident sit do. Id ut incididunt tempor id irure. Qui commodo cillum labore anim eiusmod exercitation ea qui nulla qui amet.\r\n", + "registered": "Sunday, February 9, 2014 3:54 AM", + "latitude": -36.70558, + "longitude": -140.397297, + "tags": [ + "voluptate", + "adipisicing", + "do", + "deserunt", + "aliquip", + "est", + "minim" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Griffith Martinez" + }, + { + "id": 1, + "name": "Richard Chavez" + }, + { + "id": 2, + "name": "Mckinney Butler" + } + ], + "greeting": "Hello, Martina! You have 5 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821392ebf56130b6eaa", + "index": 30, + "guid": "91c5f9c9-d3c7-435a-98cc-06e360c12e1d", + "isActive": true, + "balance": "$3,693.79", + "picture": "http://placehold.it/32x32", + "age": 21, + "eyeColor": "brown", + "name": { + "first": "Althea", + "last": "Valencia" + }, + "company": "BLANET", + "email": "althea.valencia@blanet.me", + "phone": "+1 (887) 501-3212", + "address": "911 Adams Street, Brambleton, Delaware, 5831", + "about": "Quis culpa exercitation dolor anim. Id labore ea aute aliqua. Dolor dolore sit duis anim cillum nostrud officia dolor sit. Laborum tempor dolore id consequat.\r\n", + "registered": "Saturday, January 11, 2014 6:27 PM", + "latitude": -39.101471, + "longitude": -22.991091, + "tags": [ + "eu", + "anim", + "elit", + "pariatur", + "cupidatat", + "cupidatat", + "enim" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Dawson Foreman" + }, + { + "id": 1, + "name": "Sanford Meyer" + }, + { + "id": 2, + "name": "Ruth Barron" + } + ], + "greeting": "Hello, Althea! You have 8 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa82111b129b44454e349", + "index": 31, + "guid": "184ea3dd-af3f-400a-aa64-429b6cac091f", + "isActive": true, + "balance": "$1,351.78", + "picture": "http://placehold.it/32x32", + "age": 20, + "eyeColor": "blue", + "name": { + "first": "Morrison", + "last": "Chan" + }, + "company": "TALKALOT", + "email": "morrison.chan@talkalot.us", + "phone": "+1 (822) 448-3384", + "address": "599 Olive Street, Franklin, Palau, 3303", + "about": "Ex deserunt nulla velit dolore. Sunt sit ea irure incididunt aute sint do veniam. Sit ut ad ipsum est velit ea duis exercitation aliquip consectetur Lorem fugiat eu.\r\n", + "registered": "Sunday, February 16, 2014 2:04 PM", + "latitude": 61.099205, + "longitude": -37.736061, + "tags": [ + "eu", + "deserunt", + "pariatur", + "labore", + "reprehenderit", + "magna", + "consectetur" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Norma Montoya" + }, + { + "id": 1, + "name": "Bailey Gillespie" + }, + { + "id": 2, + "name": "Candace Kent" + } + ], + "greeting": "Hello, Morrison! You have 7 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821aec56cb0ce50b54b", + "index": 32, + "guid": "b211ab76-8674-4ed0-9a40-2087930468ad", + "isActive": false, + "balance": "$1,492.99", + "picture": "http://placehold.it/32x32", + "age": 34, + "eyeColor": "green", + "name": { + "first": "Walters", + "last": "Potts" + }, + "company": "FLUMBO", + "email": "walters.potts@flumbo.ca", + "phone": "+1 (871) 461-3958", + "address": "438 Highland Avenue, Elwood, Arizona, 9669", + "about": "Lorem do Lorem aliquip ipsum. Elit labore reprehenderit tempor do. Incididunt labore ad eu occaecat enim laborum irure elit nulla Lorem anim sit exercitation velit. Proident ullamco voluptate aute ex et aute mollit nostrud. Adipisicing labore sit irure amet dolore nostrud. Tempor nulla aliqua culpa commodo aliqua ut esse velit mollit ad. Aliqua nulla enim non nisi laboris sint aute duis proident qui officia.\r\n", + "registered": "Saturday, September 6, 2014 11:47 AM", + "latitude": 64.732922, + "longitude": -168.513014, + "tags": [ + "tempor", + "amet", + "dolore", + "proident", + "reprehenderit", + "non", + "tempor" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Freida Bailey" + }, + { + "id": 1, + "name": "Bernice Curry" + }, + { + "id": 2, + "name": "Ochoa Jefferson" + } + ], + "greeting": "Hello, Walters! You have 6 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa82137be18ee6b852a45", + "index": 33, + "guid": "e8c67cca-c977-4668-9aff-46bfde1cd3de", + "isActive": true, + "balance": "$3,747.65", + "picture": "http://placehold.it/32x32", + "age": 24, + "eyeColor": "blue", + "name": { + "first": "Meredith", + "last": "Santana" + }, + "company": "GADTRON", + "email": "meredith.santana@gadtron.org", + "phone": "+1 (836) 438-3637", + "address": "999 Centre Street, Chaparrito, Colorado, 4540", + "about": "Magna nisi laboris sit quis duis anim et ullamco nostrud exercitation. Tempor enim nisi non culpa sit ex elit labore proident veniam dolore anim ex. Nostrud est qui do magna proident et. Nulla ea laboris incididunt elit labore id mollit reprehenderit. Amet in Lorem exercitation tempor voluptate labore anim adipisicing labore in dolor proident labore. Lorem labore duis ex Lorem nulla. Veniam in fugiat ex ullamco officia elit eiusmod enim.\r\n", + "registered": "Sunday, March 2, 2014 1:38 PM", + "latitude": 80.220732, + "longitude": 79.102966, + "tags": [ + "culpa", + "esse", + "velit", + "consectetur", + "incididunt", + "dolore", + "aliqua" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Bernadine Manning" + }, + { + "id": 1, + "name": "Daphne Wyatt" + }, + { + "id": 2, + "name": "Keri Harrison" + } + ], + "greeting": "Hello, Meredith! You have 7 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821ecdd700bb0b77dc2", + "index": 34, + "guid": "b93f3a6f-f05b-4d7e-93b8-4502d9c76cd2", + "isActive": true, + "balance": "$3,059.56", + "picture": "http://placehold.it/32x32", + "age": 25, + "eyeColor": "brown", + "name": { + "first": "Samantha", + "last": "Finley" + }, + "company": "XYQAG", + "email": "samantha.finley@xyqag.biz", + "phone": "+1 (879) 568-2419", + "address": "349 Truxton Street, Haring, Missouri, 8383", + "about": "Consequat do id et quis eiusmod eu irure sunt qui. Mollit minim nulla magna duis nostrud cillum ullamco sunt adipisicing elit ex. Minim fugiat deserunt nostrud esse laboris ullamco sit sit magna. Tempor occaecat Lorem qui ad ut tempor excepteur. Et sunt ullamco officia et Lorem est. Ipsum dolor ut ut elit do nisi in aute consequat. Enim esse ex aliqua anim aliquip cupidatat do Lorem voluptate quis ea culpa incididunt reprehenderit.\r\n", + "registered": "Saturday, March 29, 2014 1:38 PM", + "latitude": 79.209401, + "longitude": -139.211605, + "tags": [ + "irure", + "eiusmod", + "nulla", + "officia", + "eu", + "elit", + "nisi" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Mayer Justice" + }, + { + "id": 1, + "name": "Mae Hancock" + }, + { + "id": 2, + "name": "Sherri Bradshaw" + } + ], + "greeting": "Hello, Samantha! You have 8 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa8218ac5365ad300d1bd", + "index": 35, + "guid": "f3b50cb9-da35-47fe-b0fa-fec9fc84cf8e", + "isActive": false, + "balance": "$2,819.28", + "picture": "http://placehold.it/32x32", + "age": 29, + "eyeColor": "blue", + "name": { + "first": "Cohen", + "last": "Finch" + }, + "company": "SYNTAC", + "email": "cohen.finch@syntac.io", + "phone": "+1 (950) 459-2729", + "address": "436 Pineapple Street, Deercroft, Minnesota, 3218", + "about": "Sint velit officia quis esse. Nulla aute laborum veniam dolore tempor adipisicing proident. Duis irure esse nostrud veniam est mollit mollit voluptate eiusmod anim veniam eiusmod. Ullamco sunt sit sint minim ea reprehenderit qui consequat ipsum. Sint id voluptate reprehenderit irure nulla veniam eu Lorem enim nulla. Cupidatat amet pariatur dolor amet ex nostrud dolor ipsum tempor enim nulla aliquip tempor Lorem.\r\n", + "registered": "Wednesday, October 8, 2014 10:04 PM", + "latitude": -84.299718, + "longitude": 52.573184, + "tags": [ + "deserunt", + "eu", + "consectetur", + "ea", + "non", + "officia", + "reprehenderit" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Stevenson Mcintosh" + }, + { + "id": 1, + "name": "Chrystal Oneill" + }, + { + "id": 2, + "name": "Janine Rowe" + } + ], + "greeting": "Hello, Cohen! You have 10 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa82161d5c66d4bd0996e", + "index": 36, + "guid": "6dfc2232-f3c6-4818-956a-e8c683fd69fe", + "isActive": true, + "balance": "$3,262.20", + "picture": "http://placehold.it/32x32", + "age": 33, + "eyeColor": "blue", + "name": { + "first": "Joy", + "last": "Moran" + }, + "company": "UPDAT", + "email": "joy.moran@updat.net", + "phone": "+1 (968) 581-3365", + "address": "279 Kosciusko Street, Smock, Northern Mariana Islands, 5007", + "about": "Quis elit pariatur eu enim magna magna sunt dolore duis commodo. Pariatur sint duis ex aute eu est deserunt culpa fugiat minim non. Tempor consequat consectetur consequat sit incididunt officia id. Incididunt ex eiusmod excepteur aute mollit veniam quis excepteur occaecat excepteur deserunt reprehenderit. Est sit laboris eu dolor. Sunt voluptate quis aliquip nulla ex irure velit in. Aliqua sit id eiusmod amet commodo pariatur deserunt voluptate qui minim ex incididunt voluptate.\r\n", + "registered": "Saturday, February 8, 2014 9:55 PM", + "latitude": 53.735731, + "longitude": 46.00211, + "tags": [ + "exercitation", + "dolor", + "minim", + "incididunt", + "laborum", + "qui", + "sit" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Joyce Mckay" + }, + { + "id": 1, + "name": "Turner Murray" + }, + { + "id": 2, + "name": "Jackson Jackson" + } + ], + "greeting": "Hello, Joy! You have 7 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa821a9817ca1a9be6517", + "index": 37, + "guid": "84fe8707-cfbc-4434-98bb-faf9cb97471a", + "isActive": true, + "balance": "$3,224.80", + "picture": "http://placehold.it/32x32", + "age": 27, + "eyeColor": "blue", + "name": { + "first": "Brennan", + "last": "Stafford" + }, + "company": "LOVEPAD", + "email": "brennan.stafford@lovepad.com", + "phone": "+1 (873) 405-3600", + "address": "471 Ryder Avenue, Succasunna, Marshall Islands, 2595", + "about": "Et officia quis magna laborum et proident labore elit do Lorem reprehenderit irure. Laborum culpa culpa voluptate commodo consequat non et amet. Mollit cupidatat irure magna sint commodo ipsum proident tempor est. Laboris exercitation aliqua aute deserunt do in aliqua minim ex excepteur. Consequat in minim officia labore laboris laboris occaecat occaecat. Ex qui aliquip sint consectetur elit excepteur incididunt eu non laborum do eu excepteur.\r\n", + "registered": "Saturday, May 31, 2014 3:28 PM", + "latitude": -69.429728, + "longitude": 46.837644, + "tags": [ + "proident", + "ad", + "non", + "duis", + "occaecat", + "proident", + "non" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Jones Kirk" + }, + { + "id": 1, + "name": "Howe Drake" + }, + { + "id": 2, + "name": "Kimberly Jennings" + } + ], + "greeting": "Hello, Brennan! You have 6 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa8219251dc49e1cb846a", + "index": 38, + "guid": "c260bce1-46ac-4e84-9490-13eb8202904e", + "isActive": true, + "balance": "$1,330.69", + "picture": "http://placehold.it/32x32", + "age": 27, + "eyeColor": "brown", + "name": { + "first": "Neal", + "last": "Mooney" + }, + "company": "SOFTMICRO", + "email": "neal.mooney@softmicro.biz", + "phone": "+1 (883) 463-3623", + "address": "818 Lancaster Avenue, Chelsea, New Jersey, 3590", + "about": "Reprehenderit anim nostrud adipisicing non minim ea. Elit deserunt id in mollit nisi. Pariatur in consequat irure aliqua laboris ipsum.\r\n", + "registered": "Wednesday, May 21, 2014 4:33 PM", + "latitude": -57.826881, + "longitude": 154.840249, + "tags": [ + "consequat", + "aliquip", + "pariatur", + "nulla", + "dolore", + "deserunt", + "ipsum" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Beach Roman" + }, + { + "id": 1, + "name": "Nash Young" + }, + { + "id": 2, + "name": "Carey Dale" + } + ], + "greeting": "Hello, Neal! You have 10 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa821cedc96e4f2209487", + "index": 39, + "guid": "ed7bbe27-811c-44e4-896e-cdf6ef62e048", + "isActive": false, + "balance": "$3,148.21", + "picture": "http://placehold.it/32x32", + "age": 35, + "eyeColor": "green", + "name": { + "first": "Roy", + "last": "Becker" + }, + "company": "KONGENE", + "email": "roy.becker@kongene.co.uk", + "phone": "+1 (895) 426-2172", + "address": "414 Seagate Avenue, Watrous, Virgin Islands, 3905", + "about": "Commodo mollit do minim dolor magna occaecat labore Lorem eiusmod. Occaecat mollit occaecat ex anim est amet irure non minim. Tempor laborum cupidatat tempor ex Lorem cupidatat incididunt ullamco fugiat Lorem consequat labore Lorem non.\r\n", + "registered": "Sunday, August 17, 2014 3:16 PM", + "latitude": -2.609533, + "longitude": -143.844769, + "tags": [ + "do", + "culpa", + "sint", + "ea", + "duis", + "aliqua", + "anim" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Lowery Hull" + }, + { + "id": 1, + "name": "Abbott Oneal" + }, + { + "id": 2, + "name": "Nellie Hammond" + } + ], + "greeting": "Hello, Roy! You have 9 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821668031e7f50e30e9", + "index": 40, + "guid": "14dc3a87-0acf-4edd-93e4-ddcbeeecf96b", + "isActive": false, + "balance": "$2,617.16", + "picture": "http://placehold.it/32x32", + "age": 31, + "eyeColor": "brown", + "name": { + "first": "Courtney", + "last": "Watson" + }, + "company": "ISOSWITCH", + "email": "courtney.watson@isoswitch.tv", + "phone": "+1 (882) 468-2163", + "address": "385 Douglass Street, Iberia, Oregon, 7802", + "about": "Culpa sunt amet eu magna id quis quis irure velit. Culpa nostrud do enim proident officia. Laboris laborum laborum esse irure proident laborum amet sunt ipsum dolor nulla non ipsum sint. Amet deserunt in esse aliquip laboris proident fugiat nisi cillum ullamco occaecat est. Reprehenderit laborum enim labore ex. Velit do adipisicing irure dolor pariatur duis magna velit. Laborum sint laborum eu anim aliquip adipisicing labore.\r\n", + "registered": "Tuesday, July 22, 2014 6:03 PM", + "latitude": -75.831312, + "longitude": -172.468604, + "tags": [ + "dolor", + "velit", + "et", + "id", + "cupidatat", + "exercitation", + "laborum" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Mccray Gomez" + }, + { + "id": 1, + "name": "Hoover Rasmussen" + }, + { + "id": 2, + "name": "Hillary Castillo" + } + ], + "greeting": "Hello, Courtney! You have 5 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa8213c480453670f0428", + "index": 41, + "guid": "e7b97ea6-a13f-42ab-a998-e48614000aca", + "isActive": true, + "balance": "$1,499.72", + "picture": "http://placehold.it/32x32", + "age": 35, + "eyeColor": "blue", + "name": { + "first": "Dale", + "last": "Love" + }, + "company": "BULLJUICE", + "email": "dale.love@bulljuice.name", + "phone": "+1 (933) 588-3310", + "address": "603 Myrtle Avenue, Allentown, Utah, 793", + "about": "Ad quis anim commodo nulla et anim minim commodo irure excepteur. Pariatur ut anim aliquip id ex ipsum exercitation irure qui in nisi quis. Cillum deserunt duis dolore quis nostrud incididunt ipsum ea ipsum id fugiat eu voluptate nisi. Exercitation laborum fugiat irure anim. Ex nostrud aliqua deserunt amet.\r\n", + "registered": "Tuesday, July 22, 2014 1:19 PM", + "latitude": 55.335017, + "longitude": 101.730023, + "tags": [ + "ea", + "non", + "fugiat", + "Lorem", + "tempor", + "ut", + "do" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Spears Diaz" + }, + { + "id": 1, + "name": "Nora Dominguez" + }, + { + "id": 2, + "name": "Tamra Paul" + } + ], + "greeting": "Hello, Dale! You have 9 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa821c82bf70ca08206a9", + "index": 42, + "guid": "4367142d-e2b7-475c-b430-ac617295fbfc", + "isActive": false, + "balance": "$2,698.29", + "picture": "http://placehold.it/32x32", + "age": 37, + "eyeColor": "blue", + "name": { + "first": "Gibbs", + "last": "Hunt" + }, + "company": "COWTOWN", + "email": "gibbs.hunt@cowtown.me", + "phone": "+1 (960) 424-3404", + "address": "758 Suydam Place, Adamstown, North Carolina, 2800", + "about": "Veniam qui incididunt officia amet commodo nostrud. Magna consectetur consectetur officia Lorem amet sit officia excepteur minim consectetur pariatur dolore. Mollit fugiat aliqua consectetur qui non elit in aliquip culpa Lorem consectetur velit ad.\r\n", + "registered": "Monday, February 10, 2014 4:10 PM", + "latitude": 62.263652, + "longitude": 64.978136, + "tags": [ + "et", + "dolor", + "aute", + "minim", + "sunt", + "veniam", + "do" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Henry Schmidt" + }, + { + "id": 1, + "name": "Herman Wynn" + }, + { + "id": 2, + "name": "Wilda Grimes" + } + ], + "greeting": "Hello, Gibbs! You have 5 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa8210b1096c8a2f821c4", + "index": 43, + "guid": "5184508c-47f7-48b5-85ac-d15ed747ed07", + "isActive": true, + "balance": "$3,460.45", + "picture": "http://placehold.it/32x32", + "age": 30, + "eyeColor": "green", + "name": { + "first": "Francis", + "last": "Barton" + }, + "company": "COMTRAIL", + "email": "francis.barton@comtrail.us", + "phone": "+1 (881) 419-2936", + "address": "562 Ferris Street, Ola, Maryland, 3838", + "about": "Duis minim laboris in reprehenderit id ut laborum esse consequat. In dolore sunt consequat non fugiat do duis duis. Officia ipsum eiusmod laboris do aliqua aute velit minim nulla nisi. Dolor incididunt enim est eu cupidatat. Dolor commodo sit consectetur irure aliqua ea enim esse reprehenderit ullamco.\r\n", + "registered": "Thursday, April 10, 2014 2:48 PM", + "latitude": -35.457713, + "longitude": 141.805123, + "tags": [ + "tempor", + "officia", + "quis", + "tempor", + "ex", + "mollit", + "amet" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Mayra Walters" + }, + { + "id": 1, + "name": "Casey Gross" + }, + { + "id": 2, + "name": "Aisha Santos" + } + ], + "greeting": "Hello, Francis! You have 7 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821890ad48b2eaabcfb", + "index": 44, + "guid": "07497907-7e6f-471d-af9d-1dcbcf056a56", + "isActive": true, + "balance": "$2,166.79", + "picture": "http://placehold.it/32x32", + "age": 33, + "eyeColor": "blue", + "name": { + "first": "Dina", + "last": "Travis" + }, + "company": "VENOFLEX", + "email": "dina.travis@venoflex.ca", + "phone": "+1 (921) 485-3865", + "address": "366 Tillary Street, Century, New York, 6335", + "about": "Dolor sunt culpa enim sint officia sint id do ut anim ex in. Dolore est irure aliquip nulla laborum aliqua tempor id ea mollit in ad deserunt. Qui ullamco duis qui elit excepteur. Aute proident duis veniam enim commodo non minim id. Consequat anim eiusmod consectetur ut et labore officia ex ad cillum occaecat. Sit irure officia veniam sint et consequat reprehenderit officia qui. Aute esse nulla ad quis reprehenderit duis.\r\n", + "registered": "Friday, September 12, 2014 5:53 AM", + "latitude": 24.764352, + "longitude": 148.493552, + "tags": [ + "qui", + "officia", + "dolor", + "velit", + "ex", + "veniam", + "ullamco" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Sharpe Foster" + }, + { + "id": 1, + "name": "Kathrine Ayers" + }, + { + "id": 2, + "name": "Cox Acosta" + } + ], + "greeting": "Hello, Dina! You have 8 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa82101996fc944f7f215", + "index": 45, + "guid": "46b331f8-78d3-403f-8c93-cbaac9438998", + "isActive": false, + "balance": "$2,193.84", + "picture": "http://placehold.it/32x32", + "age": 33, + "eyeColor": "blue", + "name": { + "first": "Haney", + "last": "Garrett" + }, + "company": "EZENTIA", + "email": "haney.garrett@ezentia.org", + "phone": "+1 (965) 596-2629", + "address": "162 Village Road, Southmont, Virginia, 6673", + "about": "Laboris do veniam exercitation officia id eu minim irure Lorem laborum. Sint magna aliquip ad elit eiusmod cillum laborum. Adipisicing aliquip nulla mollit ipsum cupidatat nisi duis irure ullamco. Et elit nulla nisi culpa mollit esse in. Dolore non nulla anim magna enim aliquip quis amet non tempor incididunt dolor.\r\n", + "registered": "Monday, August 18, 2014 3:42 PM", + "latitude": 6.549909, + "longitude": 32.226887, + "tags": [ + "laboris", + "duis", + "culpa", + "qui", + "dolor", + "esse", + "reprehenderit" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Mariana Sharp" + }, + { + "id": 1, + "name": "Sue Baldwin" + }, + { + "id": 2, + "name": "Ross Arnold" + } + ], + "greeting": "Hello, Haney! You have 10 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa821453cc33bd1abd21d", + "index": 46, + "guid": "313f0c45-6eaf-46d9-a28d-ca31e79d2c1c", + "isActive": false, + "balance": "$2,303.36", + "picture": "http://placehold.it/32x32", + "age": 28, + "eyeColor": "blue", + "name": { + "first": "Gale", + "last": "Robles" + }, + "company": "NEWCUBE", + "email": "gale.robles@newcube.biz", + "phone": "+1 (996) 558-2811", + "address": "597 Java Street, Sanborn, North Dakota, 1789", + "about": "Anim fugiat do nisi dolor sunt consequat irure quis laborum. Nisi cupidatat dolore excepteur irure ea minim proident excepteur exercitation ut voluptate deserunt. Ad do amet id voluptate enim commodo ex. Sunt sint quis sint aute do ea aliqua. Enim ullamco dolore proident qui mollit irure consequat. Nostrud sunt adipisicing elit incididunt do laboris ad officia ea amet id reprehenderit nulla.\r\n", + "registered": "Tuesday, July 15, 2014 2:25 PM", + "latitude": -21.549196, + "longitude": -97.373962, + "tags": [ + "ullamco", + "amet", + "sint", + "elit", + "tempor", + "ex", + "pariatur" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Bell Gould" + }, + { + "id": 1, + "name": "Denise Kirby" + }, + { + "id": 2, + "name": "Hess Hinton" + } + ], + "greeting": "Hello, Gale! You have 5 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa821ed643a410e2d79dc", + "index": 47, + "guid": "2620cb2b-df00-4303-a5ff-768ffb1697c5", + "isActive": true, + "balance": "$2,890.73", + "picture": "http://placehold.it/32x32", + "age": 39, + "eyeColor": "blue", + "name": { + "first": "Alisha", + "last": "Hamilton" + }, + "company": "FITCORE", + "email": "alisha.hamilton@fitcore.io", + "phone": "+1 (853) 468-3192", + "address": "257 Bayard Street, Coldiron, Oklahoma, 9228", + "about": "Sunt nostrud sunt magna amet excepteur est tempor veniam aliqua. Laboris id aliquip fugiat exercitation dolore veniam et anim duis sit esse ex elit ullamco. Lorem commodo exercitation in sit cillum ipsum do dolor.\r\n", + "registered": "Tuesday, March 11, 2014 12:29 PM", + "latitude": 85.840017, + "longitude": -57.093095, + "tags": [ + "consectetur", + "commodo", + "est", + "ut", + "incididunt", + "elit", + "ipsum" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Steele Ellis" + }, + { + "id": 1, + "name": "Serena Emerson" + }, + { + "id": 2, + "name": "Betty Langley" + } + ], + "greeting": "Hello, Alisha! You have 8 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa8215c6db03112e3e13d", + "index": 48, + "guid": "28b59ead-0fd8-480b-8eb8-2d75290934f6", + "isActive": false, + "balance": "$3,497.68", + "picture": "http://placehold.it/32x32", + "age": 25, + "eyeColor": "blue", + "name": { + "first": "Kaufman", + "last": "Williams" + }, + "company": "COMBOGENE", + "email": "kaufman.williams@combogene.net", + "phone": "+1 (820) 465-3213", + "address": "353 Clarendon Road, Wilmington, Michigan, 3811", + "about": "Irure id sint elit mollit occaecat occaecat veniam elit reprehenderit esse officia cillum. Aute aute occaecat ipsum commodo laborum adipisicing fugiat aliquip dolore. Deserunt id excepteur enim eu adipisicing nulla ut non est dolore est. Culpa magna et sit et non ex.\r\n", + "registered": "Sunday, September 7, 2014 5:57 AM", + "latitude": 10.667631, + "longitude": 157.707911, + "tags": [ + "consequat", + "dolor", + "deserunt", + "amet", + "Lorem", + "aliqua", + "minim" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Horn Franco" + }, + { + "id": 1, + "name": "Kathleen Hickman" + }, + { + "id": 2, + "name": "Rosario Scott" + } + ], + "greeting": "Hello, Kaufman! You have 7 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821045c82593b79538d", + "index": 49, + "guid": "cef964ed-4208-41eb-a8d8-916d95d18f8a", + "isActive": true, + "balance": "$3,808.37", + "picture": "http://placehold.it/32x32", + "age": 28, + "eyeColor": "blue", + "name": { + "first": "Tran", + "last": "Gallegos" + }, + "company": "CONCILITY", + "email": "tran.gallegos@concility.com", + "phone": "+1 (925) 487-2143", + "address": "969 Schermerhorn Street, Watchtower, Idaho, 413", + "about": "Velit ut enim cupidatat adipisicing culpa in non incididunt exercitation dolor pariatur. Deserunt dolor occaecat dolor officia ipsum occaecat tempor nisi. Culpa et culpa aute incididunt et labore sunt cillum nulla. Reprehenderit culpa enim laborum nostrud consectetur velit nulla consequat aliqua non exercitation sunt nulla aliqua. Labore incididunt aliqua aliqua anim duis culpa elit labore. Aliqua ipsum mollit ut sint aliquip in aute do qui amet.\r\n", + "registered": "Friday, May 9, 2014 9:24 AM", + "latitude": -49.148583, + "longitude": 4.911715, + "tags": [ + "labore", + "duis", + "proident", + "adipisicing", + "nisi", + "tempor", + "nisi" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Nicole Holloway" + }, + { + "id": 1, + "name": "Minerva Beasley" + }, + { + "id": 2, + "name": "Bowers Suarez" + } + ], + "greeting": "Hello, Tran! You have 7 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821fbd8e9836595f96d", + "index": 50, + "guid": "966b2f5e-5686-4381-9ab7-87bc9ac9968b", + "isActive": true, + "balance": "$1,351.67", + "picture": "http://placehold.it/32x32", + "age": 23, + "eyeColor": "green", + "name": { + "first": "Mable", + "last": "Lambert" + }, + "company": "ZENSUS", + "email": "mable.lambert@zensus.biz", + "phone": "+1 (917) 404-3441", + "address": "174 Concord Street, Somerset, Nebraska, 7318", + "about": "Ad minim esse ipsum incididunt incididunt enim Lorem nulla excepteur velit fugiat ullamco amet reprehenderit. Labore velit fugiat proident enim Lorem mollit ex. Tempor voluptate cupidatat officia nostrud qui. Veniam duis voluptate deserunt commodo consectetur eiusmod qui excepteur aliquip. Exercitation laborum Lorem excepteur ipsum aliqua fugiat reprehenderit ea dolore deserunt commodo cillum ipsum eu. Ullamco quis voluptate eiusmod ea aute et pariatur consequat duis occaecat nulla aliquip.\r\n", + "registered": "Sunday, May 25, 2014 4:54 PM", + "latitude": 79.811908, + "longitude": -62.629133, + "tags": [ + "sit", + "non", + "reprehenderit", + "exercitation", + "dolor", + "labore", + "irure" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Rosie Gill" + }, + { + "id": 1, + "name": "Parrish Dean" + }, + { + "id": 2, + "name": "Annmarie Delacruz" + } + ], + "greeting": "Hello, Mable! You have 10 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa821c85822cf149b785f", + "index": 51, + "guid": "1afd0e8f-b518-4bca-a4df-29e9b6a961d6", + "isActive": true, + "balance": "$2,628.22", + "picture": "http://placehold.it/32x32", + "age": 22, + "eyeColor": "brown", + "name": { + "first": "Sadie", + "last": "Clarke" + }, + "company": "UNISURE", + "email": "sadie.clarke@unisure.co.uk", + "phone": "+1 (905) 480-2930", + "address": "326 Gilmore Court, Hamilton, Montana, 9217", + "about": "Dolore do nisi reprehenderit consectetur in. In esse sit proident enim duis veniam quis laboris nulla cillum adipisicing veniam aute. Culpa sunt ex exercitation sit esse exercitation dolor ea enim ad est aute consequat qui. Esse esse nulla eiusmod eiusmod ullamco esse cillum aute ea id ex quis. Pariatur officia Lorem aute officia anim velit velit elit sint voluptate. Aliquip ad velit velit laboris et culpa. Do consectetur aliqua sit sunt eu anim culpa ut incididunt et.\r\n", + "registered": "Sunday, April 27, 2014 10:37 AM", + "latitude": -71.828101, + "longitude": -138.908359, + "tags": [ + "nostrud", + "amet", + "minim", + "occaecat", + "proident", + "sint", + "nostrud" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Christa Estes" + }, + { + "id": 1, + "name": "Alana Schneider" + }, + { + "id": 2, + "name": "Frank Spears" + } + ], + "greeting": "Hello, Sadie! You have 6 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa821aa6b44e8d20db81c", + "index": 52, + "guid": "e0220e02-565c-424a-8834-f955ccb72f7d", + "isActive": false, + "balance": "$2,918.63", + "picture": "http://placehold.it/32x32", + "age": 30, + "eyeColor": "brown", + "name": { + "first": "Deana", + "last": "Fletcher" + }, + "company": "VISALIA", + "email": "deana.fletcher@visalia.tv", + "phone": "+1 (815) 430-2641", + "address": "347 Tehama Street, Hollins, Washington, 5953", + "about": "Est consequat id ad Lorem consequat quis ullamco minim pariatur ipsum cillum. Enim exercitation qui duis cillum ea amet ea sint proident officia dolor non. Irure culpa cillum minim officia est culpa sit.\r\n", + "registered": "Monday, May 5, 2014 1:51 AM", + "latitude": 51.516197, + "longitude": 80.400628, + "tags": [ + "ut", + "tempor", + "pariatur", + "ex", + "dolore", + "deserunt", + "culpa" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Hansen Estrada" + }, + { + "id": 1, + "name": "Regina Munoz" + }, + { + "id": 2, + "name": "Bethany Cabrera" + } + ], + "greeting": "Hello, Deana! You have 5 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa82120c61930bc25e2ff", + "index": 53, + "guid": "99c62c99-ef16-4eb7-a41d-80feafca740a", + "isActive": false, + "balance": "$1,836.96", + "picture": "http://placehold.it/32x32", + "age": 27, + "eyeColor": "brown", + "name": { + "first": "Long", + "last": "Sandoval" + }, + "company": "GINKLE", + "email": "long.sandoval@ginkle.name", + "phone": "+1 (989) 541-2327", + "address": "161 Crown Street, Omar, Kentucky, 8615", + "about": "Et ea eiusmod ex consequat culpa proident. Reprehenderit proident ullamco ullamco aliquip incididunt ullamco sit proident dolore nulla fugiat sit laboris. Adipisicing ullamco laborum nulla exercitation reprehenderit irure ex.\r\n", + "registered": "Tuesday, July 29, 2014 12:14 AM", + "latitude": -20.766582, + "longitude": 74.616145, + "tags": [ + "et", + "consequat", + "duis", + "excepteur", + "sint", + "sunt", + "aliqua" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Aline Rosa" + }, + { + "id": 1, + "name": "Olivia Quinn" + }, + { + "id": 2, + "name": "Fowler Carter" + } + ], + "greeting": "Hello, Long! You have 5 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821cc7ceb7da88472ed", + "index": 54, + "guid": "3a965f51-48f9-4d10-8a9b-a0b529749c93", + "isActive": true, + "balance": "$2,950.94", + "picture": "http://placehold.it/32x32", + "age": 25, + "eyeColor": "green", + "name": { + "first": "Rush", + "last": "Thornton" + }, + "company": "AQUASSEUR", + "email": "rush.thornton@aquasseur.me", + "phone": "+1 (916) 493-2777", + "address": "344 Sunnyside Avenue, Brethren, California, 9529", + "about": "Duis ut consequat eu laborum voluptate eu Lorem cillum ad in commodo adipisicing. Excepteur aliquip sint dolor voluptate cillum nisi mollit mollit laborum ex culpa adipisicing voluptate. Cupidatat do sit fugiat amet irure. Cupidatat ex ut commodo reprehenderit veniam sit est officia ad pariatur aliquip.\r\n", + "registered": "Thursday, September 25, 2014 11:09 AM", + "latitude": -61.409359, + "longitude": -87.414208, + "tags": [ + "adipisicing", + "consequat", + "magna", + "Lorem", + "consequat", + "voluptate", + "eu" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Hill Good" + }, + { + "id": 1, + "name": "Hartman Rice" + }, + { + "id": 2, + "name": "Petersen Hogan" + } + ], + "greeting": "Hello, Rush! You have 7 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa821e221eb5b7ed845c0", + "index": 55, + "guid": "ab0f1517-8c25-46ff-a281-0dcc932e2f9a", + "isActive": false, + "balance": "$2,070.82", + "picture": "http://placehold.it/32x32", + "age": 39, + "eyeColor": "green", + "name": { + "first": "Alyce", + "last": "Perez" + }, + "company": "CAPSCREEN", + "email": "alyce.perez@capscreen.us", + "phone": "+1 (955) 432-2025", + "address": "896 Troutman Street, Williamson, West Virginia, 6491", + "about": "In consequat quis ex sint nisi proident esse excepteur quis nostrud. Enim incididunt ullamco sint quis eiusmod qui tempor ad laboris eiusmod nulla in aliquip sit. Nostrud fugiat fugiat Lorem laboris pariatur eiusmod amet ea do irure et. Excepteur pariatur consequat exercitation amet occaecat do aliqua non deserunt nulla cupidatat tempor id. Mollit ex incididunt et nulla culpa mollit veniam qui amet in excepteur pariatur. Commodo reprehenderit tempor laborum nisi anim minim deserunt eiusmod adipisicing deserunt ut eiusmod excepteur.\r\n", + "registered": "Monday, June 23, 2014 7:37 AM", + "latitude": -4.180393, + "longitude": 21.4789, + "tags": [ + "dolore", + "officia", + "laborum", + "aliquip", + "ex", + "eu", + "sint" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Rosalind Lang" + }, + { + "id": 1, + "name": "Ina Pratt" + }, + { + "id": 2, + "name": "Tamika Mercer" + } + ], + "greeting": "Hello, Alyce! You have 5 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa8215e315c720e186460", + "index": 56, + "guid": "10727900-9be7-46d5-8f2c-7c6834d95a25", + "isActive": false, + "balance": "$1,907.19", + "picture": "http://placehold.it/32x32", + "age": 37, + "eyeColor": "brown", + "name": { + "first": "Snider", + "last": "Johnson" + }, + "company": "IPLAX", + "email": "snider.johnson@iplax.ca", + "phone": "+1 (883) 539-3127", + "address": "424 Hancock Street, Springdale, Wyoming, 7054", + "about": "Incididunt proident amet consectetur cupidatat ex officia labore cupidatat laborum. Tempor proident officia nisi Lorem. Lorem commodo commodo ea voluptate excepteur consequat anim quis excepteur sunt officia.\r\n", + "registered": "Saturday, March 8, 2014 9:23 PM", + "latitude": 16.66716, + "longitude": 17.844641, + "tags": [ + "esse", + "est", + "eu", + "dolor", + "ea", + "voluptate", + "nostrud" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Bauer Burt" + }, + { + "id": 1, + "name": "Lowe Boyd" + }, + { + "id": 2, + "name": "Moon Garcia" + } + ], + "greeting": "Hello, Snider! You have 9 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa82130f82b9ee9265e5f", + "index": 57, + "guid": "ba427ee5-5013-498f-a1a2-97a71b249a6e", + "isActive": true, + "balance": "$2,070.53", + "picture": "http://placehold.it/32x32", + "age": 38, + "eyeColor": "brown", + "name": { + "first": "Berry", + "last": "Carver" + }, + "company": "EVENTIX", + "email": "berry.carver@eventix.org", + "phone": "+1 (907) 508-2463", + "address": "415 Havens Place, Nile, Connecticut, 6089", + "about": "Quis dolor aute consequat sunt esse dolore Lorem pariatur reprehenderit incididunt aliqua. Officia sunt aute fugiat consectetur id exercitation aliquip velit do fugiat culpa. Et ad amet exercitation veniam ipsum duis qui sunt incididunt. Eiusmod commodo esse aliquip exercitation pariatur consequat nulla nulla quis eiusmod dolor. Ut consectetur qui culpa id veniam dolore pariatur quis est cillum voluptate esse. Sunt eiusmod adipisicing mollit est tempor ipsum dolore tempor. Velit consequat dolore cillum adipisicing id nulla veniam nisi velit in magna id anim.\r\n", + "registered": "Monday, January 13, 2014 10:45 PM", + "latitude": -60.884888, + "longitude": 139.360489, + "tags": [ + "eu", + "deserunt", + "minim", + "quis", + "eiusmod", + "sint", + "dolor" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Tanisha Dudley" + }, + { + "id": 1, + "name": "Dale Mcgowan" + }, + { + "id": 2, + "name": "Torres Pennington" + } + ], + "greeting": "Hello, Berry! You have 7 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa821bc354233d50ef914", + "index": 58, + "guid": "6ab626f8-6b71-4f17-ba39-4cc97fdf4855", + "isActive": false, + "balance": "$2,822.25", + "picture": "http://placehold.it/32x32", + "age": 38, + "eyeColor": "green", + "name": { + "first": "Kramer", + "last": "Berg" + }, + "company": "INTRADISK", + "email": "kramer.berg@intradisk.biz", + "phone": "+1 (901) 534-3326", + "address": "455 Bath Avenue, Hoagland, Guam, 2206", + "about": "Labore ullamco aliquip id incididunt cupidatat pariatur. In magna et aliquip consectetur dolor ullamco aliqua reprehenderit. Ad velit nisi ex culpa consequat. Culpa eiusmod incididunt pariatur esse tempor officia mollit.\r\n", + "registered": "Friday, June 13, 2014 8:45 AM", + "latitude": -43.442578, + "longitude": 69.627031, + "tags": [ + "exercitation", + "dolor", + "quis", + "laboris", + "exercitation", + "sunt", + "ipsum" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Love Hutchinson" + }, + { + "id": 1, + "name": "Hayden Marquez" + }, + { + "id": 2, + "name": "Macdonald Hahn" + } + ], + "greeting": "Hello, Kramer! You have 5 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa821cf5d51b48b4bd07a", + "index": 59, + "guid": "7b339d1e-d759-4fed-9e58-fd2608cdb0f2", + "isActive": false, + "balance": "$3,836.86", + "picture": "http://placehold.it/32x32", + "age": 20, + "eyeColor": "brown", + "name": { + "first": "Joann", + "last": "Elliott" + }, + "company": "ATOMICA", + "email": "joann.elliott@atomica.io", + "phone": "+1 (992) 429-2667", + "address": "788 Willow Place, Lindisfarne, Mississippi, 3656", + "about": "Ut consequat sunt ipsum minim velit. Lorem eiusmod dolor voluptate est deserunt cupidatat ut ipsum. Et et irure Lorem laborum sint mollit pariatur elit et enim eu eu sunt. Nisi do quis proident enim irure dolore ut Lorem fugiat quis voluptate non reprehenderit dolore.\r\n", + "registered": "Monday, May 12, 2014 6:04 PM", + "latitude": 14.309335, + "longitude": 32.596666, + "tags": [ + "nulla", + "magna", + "dolore", + "incididunt", + "fugiat", + "elit", + "veniam" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Mason Hurst" + }, + { + "id": 1, + "name": "Castaneda Davidson" + }, + { + "id": 2, + "name": "Rasmussen Adkins" + } + ], + "greeting": "Hello, Joann! You have 5 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821876778d3d011eb7b", + "index": 60, + "guid": "a016ab64-b6dd-42bc-8b5f-dbbab7a01d2a", + "isActive": true, + "balance": "$2,795.00", + "picture": "http://placehold.it/32x32", + "age": 31, + "eyeColor": "green", + "name": { + "first": "Barbara", + "last": "Nolan" + }, + "company": "FURNAFIX", + "email": "barbara.nolan@furnafix.net", + "phone": "+1 (892) 600-2820", + "address": "540 Dennett Place, Mammoth, Rhode Island, 6151", + "about": "In velit officia quis Lorem. Ex quis cillum esse deserunt consectetur et nulla tempor. Lorem reprehenderit cillum excepteur ea veniam commodo et ad ullamco. Ex elit nisi non ipsum aliqua laborum sint aliqua. Reprehenderit consectetur dolore occaecat irure incididunt sunt.\r\n", + "registered": "Monday, April 21, 2014 11:59 AM", + "latitude": 71.103088, + "longitude": -78.48592, + "tags": [ + "eu", + "ullamco", + "cillum", + "est", + "commodo", + "nisi", + "tempor" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Cynthia Aguilar" + }, + { + "id": 1, + "name": "Deanna Graves" + }, + { + "id": 2, + "name": "Bertha Caldwell" + } + ], + "greeting": "Hello, Barbara! You have 9 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa821d6e2aaf18a0b184f", + "index": 61, + "guid": "89ca6bc0-19c2-4d13-a37c-90d02005a6bc", + "isActive": false, + "balance": "$3,134.62", + "picture": "http://placehold.it/32x32", + "age": 39, + "eyeColor": "blue", + "name": { + "first": "Penelope", + "last": "William" + }, + "company": "UTARA", + "email": "penelope.william@utara.com", + "phone": "+1 (968) 575-2395", + "address": "276 Ralph Avenue, Ezel, New Mexico, 2656", + "about": "Pariatur officia anim dolore commodo ipsum labore sint officia. Lorem culpa ea sunt non. Voluptate irure voluptate ut cupidatat nulla nostrud.\r\n", + "registered": "Monday, July 7, 2014 11:29 PM", + "latitude": -83.184502, + "longitude": -91.222471, + "tags": [ + "anim", + "incididunt", + "aliqua", + "id", + "reprehenderit", + "laboris", + "consequat" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Maxwell Rocha" + }, + { + "id": 1, + "name": "Roach Bryan" + }, + { + "id": 2, + "name": "Woods Daugherty" + } + ], + "greeting": "Hello, Penelope! You have 5 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa8217abc85acd32fb42a", + "index": 62, + "guid": "cc58e868-7934-40a2-a350-13ad47e86a56", + "isActive": true, + "balance": "$3,734.05", + "picture": "http://placehold.it/32x32", + "age": 33, + "eyeColor": "green", + "name": { + "first": "Kris", + "last": "Cotton" + }, + "company": "CORPORANA", + "email": "kris.cotton@corporana.biz", + "phone": "+1 (873) 412-2513", + "address": "650 Bushwick Court, Malott, Wisconsin, 9739", + "about": "Aliquip cupidatat exercitation exercitation consectetur. Sit id excepteur ea ut laborum irure ullamco laborum irure reprehenderit nisi aute eu. Ipsum do anim ea veniam do amet pariatur. Lorem consectetur labore deserunt anim deserunt aute.\r\n", + "registered": "Thursday, February 20, 2014 7:18 AM", + "latitude": 41.787092, + "longitude": -44.032192, + "tags": [ + "ex", + "incididunt", + "ut", + "cupidatat", + "commodo", + "commodo", + "occaecat" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Angela Middleton" + }, + { + "id": 1, + "name": "Hicks Douglas" + }, + { + "id": 2, + "name": "Shaffer West" + } + ], + "greeting": "Hello, Kris! You have 8 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821c20dda84da819450", + "index": 63, + "guid": "6ecab19a-0268-4d43-ad43-af2e4941b2e7", + "isActive": false, + "balance": "$2,748.00", + "picture": "http://placehold.it/32x32", + "age": 33, + "eyeColor": "green", + "name": { + "first": "William", + "last": "Haney" + }, + "company": "PROSURE", + "email": "william.haney@prosure.co.uk", + "phone": "+1 (890) 508-3193", + "address": "930 Hopkins Street, Bluetown, American Samoa, 9860", + "about": "Ad aute aliquip eiusmod tempor ullamco. Et ipsum consequat consequat magna do fugiat sint proident nostrud ad fugiat commodo dolor. Est anim do laboris id esse minim do voluptate occaecat nulla esse. Veniam sit dolore aliqua pariatur quis commodo enim nisi sint excepteur pariatur.\r\n", + "registered": "Friday, January 10, 2014 2:42 PM", + "latitude": 70.057151, + "longitude": -46.509685, + "tags": [ + "pariatur", + "est", + "adipisicing", + "aute", + "in", + "ex", + "eu" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Aida Lindsey" + }, + { + "id": 1, + "name": "Harper Roberson" + }, + { + "id": 2, + "name": "Flora Woods" + } + ], + "greeting": "Hello, William! You have 5 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa8219387ab6d8ebd8c1d", + "index": 64, + "guid": "732dfcb2-f8ab-44bf-a11b-d98f5b589993", + "isActive": true, + "balance": "$1,010.25", + "picture": "http://placehold.it/32x32", + "age": 26, + "eyeColor": "green", + "name": { + "first": "Barrera", + "last": "Sellers" + }, + "company": "KLUGGER", + "email": "barrera.sellers@klugger.tv", + "phone": "+1 (968) 510-3228", + "address": "954 Verona Place, Homeworth, Louisiana, 6862", + "about": "Lorem ex voluptate cupidatat minim officia voluptate enim proident qui mollit dolore ipsum. Non consectetur adipisicing quis consectetur. Non est Lorem ad qui nostrud aute aliqua labore exercitation ea aliquip irure dolor nisi. Excepteur anim ex exercitation velit adipisicing qui excepteur enim culpa consequat sint. Velit consectetur velit culpa eu sint irure culpa consequat anim incididunt ad amet excepteur. Non est anim id sint ipsum id officia dolor commodo dolore labore consectetur.\r\n", + "registered": "Sunday, September 14, 2014 1:44 AM", + "latitude": -88.561319, + "longitude": -44.881241, + "tags": [ + "aliquip", + "eiusmod", + "nisi", + "aliquip", + "minim", + "ullamco", + "commodo" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Bond Goff" + }, + { + "id": 1, + "name": "Cathleen Hatfield" + }, + { + "id": 2, + "name": "Pansy Burke" + } + ], + "greeting": "Hello, Barrera! You have 8 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa821ab4d9564c853db57", + "index": 65, + "guid": "bba298e6-ebca-4334-afe9-91807ed1b672", + "isActive": true, + "balance": "$2,345.80", + "picture": "http://placehold.it/32x32", + "age": 38, + "eyeColor": "brown", + "name": { + "first": "Mullen", + "last": "Stephenson" + }, + "company": "POLARIUM", + "email": "mullen.stephenson@polarium.name", + "phone": "+1 (935) 461-2692", + "address": "228 Court Square, Beaulieu, Kansas, 9445", + "about": "Ex magna proident do dolore nostrud aliqua aute dolore enim mollit consectetur sunt pariatur. Ex id duis enim duis laborum do tempor proident exercitation duis. Aute dolor cillum anim incididunt voluptate. Qui proident consectetur sit laboris ex enim excepteur qui.\r\n", + "registered": "Thursday, May 1, 2014 7:57 PM", + "latitude": 34.294733, + "longitude": 138.270754, + "tags": [ + "minim", + "veniam", + "do", + "consequat", + "esse", + "sit", + "do" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Bobbi Pate" + }, + { + "id": 1, + "name": "Moran Griffith" + }, + { + "id": 2, + "name": "Marian Hopkins" + } + ], + "greeting": "Hello, Mullen! You have 7 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa8218eb53a92791a3185", + "index": 66, + "guid": "d297bed2-0986-4d22-b120-0e04c253fb34", + "isActive": false, + "balance": "$2,586.70", + "picture": "http://placehold.it/32x32", + "age": 22, + "eyeColor": "brown", + "name": { + "first": "Leigh", + "last": "Kidd" + }, + "company": "SUNCLIPSE", + "email": "leigh.kidd@sunclipse.me", + "phone": "+1 (870) 427-3520", + "address": "156 Keen Court, Chamizal, Indiana, 4250", + "about": "Ut sunt elit irure eiusmod aliquip consectetur in. Dolore id exercitation irure consectetur. Pariatur occaecat cillum nulla cillum esse deserunt minim consectetur aliqua duis eiusmod. Ea proident aliquip cillum ullamco duis elit Lorem dolore aliqua. Do fugiat culpa reprehenderit ea eu non enim.\r\n", + "registered": "Wednesday, January 15, 2014 1:57 AM", + "latitude": 61.842523, + "longitude": -56.422447, + "tags": [ + "non", + "non", + "incididunt", + "elit", + "aliqua", + "proident", + "nostrud" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Jean Burns" + }, + { + "id": 1, + "name": "Patel Wilkinson" + }, + { + "id": 2, + "name": "Lillie Lane" + } + ], + "greeting": "Hello, Leigh! You have 5 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa8211c12bb8d837e265b", + "index": 67, + "guid": "6560e2f0-6bd2-4e19-bcd1-35297f162890", + "isActive": false, + "balance": "$2,040.59", + "picture": "http://placehold.it/32x32", + "age": 29, + "eyeColor": "green", + "name": { + "first": "Perry", + "last": "Leonard" + }, + "company": "CANDECOR", + "email": "perry.leonard@candecor.us", + "phone": "+1 (945) 556-2907", + "address": "359 Barbey Street, Grandview, Alaska, 9082", + "about": "Dolor fugiat consequat reprehenderit duis duis ex consectetur ea non ut. Irure et elit et mollit consequat dolor exercitation exercitation deserunt culpa mollit nulla. Est sunt deserunt incididunt exercitation eu aliqua qui elit labore id in eu ex.\r\n", + "registered": "Tuesday, August 26, 2014 11:34 PM", + "latitude": -67.974417, + "longitude": 97.189082, + "tags": [ + "sit", + "ex", + "ullamco", + "exercitation", + "adipisicing", + "non", + "laboris" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Alissa Ramsey" + }, + { + "id": 1, + "name": "Adela Bell" + }, + { + "id": 2, + "name": "Pearl Henderson" + } + ], + "greeting": "Hello, Perry! You have 9 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa8219a0b8e44380bd954", + "index": 68, + "guid": "4aa2bec3-3eaa-464f-9577-27f6c65e64b7", + "isActive": false, + "balance": "$3,911.59", + "picture": "http://placehold.it/32x32", + "age": 22, + "eyeColor": "blue", + "name": { + "first": "Barbra", + "last": "Mejia" + }, + "company": "ANIXANG", + "email": "barbra.mejia@anixang.ca", + "phone": "+1 (987) 517-2550", + "address": "635 Franklin Street, Allensworth, Florida, 1895", + "about": "Aliqua tempor excepteur velit do exercitation laborum commodo laboris aliqua nostrud. Aute aliquip nisi nulla labore id veniam ad voluptate non eiusmod minim mollit. Minim incididunt nostrud sint ex.\r\n", + "registered": "Thursday, January 16, 2014 11:04 PM", + "latitude": 44.320545, + "longitude": -61.392889, + "tags": [ + "cupidatat", + "excepteur", + "eu", + "consectetur", + "fugiat", + "aliquip", + "deserunt" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Potts Church" + }, + { + "id": 1, + "name": "Dianna Valentine" + }, + { + "id": 2, + "name": "Valeria Whitney" + } + ], + "greeting": "Hello, Barbra! You have 9 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa821b618d050a076972c", + "index": 69, + "guid": "ef47a627-c517-4f5a-931b-d67c8a18614b", + "isActive": false, + "balance": "$1,771.53", + "picture": "http://placehold.it/32x32", + "age": 32, + "eyeColor": "brown", + "name": { + "first": "Gonzales", + "last": "Walker" + }, + "company": "EVIDENDS", + "email": "gonzales.walker@evidends.org", + "phone": "+1 (984) 510-3347", + "address": "336 Pershing Loop, Croom, Georgia, 9128", + "about": "Quis reprehenderit consectetur ad aliqua ad amet incididunt aute irure Lorem veniam. Consequat consequat ut reprehenderit officia cupidatat irure aliqua nostrud veniam velit aliquip magna elit. Ullamco amet nostrud est cupidatat adipisicing fugiat magna anim eu occaecat incididunt. Ut ex ut quis veniam nulla ad ea magna elit incididunt Lorem anim ipsum elit. Aliqua laborum officia magna aliqua. Est quis adipisicing cillum cupidatat sunt velit fugiat mollit exercitation cupidatat sit.\r\n", + "registered": "Saturday, June 21, 2014 9:02 PM", + "latitude": -64.407501, + "longitude": -157.742045, + "tags": [ + "pariatur", + "minim", + "consectetur", + "consequat", + "ad", + "aliqua", + "ut" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Tina Patterson" + }, + { + "id": 1, + "name": "Gabriela Nielsen" + }, + { + "id": 2, + "name": "Amalia Mueller" + } + ], + "greeting": "Hello, Gonzales! You have 8 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa8210426ced41d67a58b", + "index": 70, + "guid": "5d045ae8-c32c-43f6-b404-30a943205f5e", + "isActive": true, + "balance": "$2,054.02", + "picture": "http://placehold.it/32x32", + "age": 36, + "eyeColor": "green", + "name": { + "first": "Clarissa", + "last": "Madden" + }, + "company": "NIQUENT", + "email": "clarissa.madden@niquent.biz", + "phone": "+1 (910) 480-3769", + "address": "637 Scholes Street, Needmore, Alabama, 9344", + "about": "Sunt nulla ad aliquip incididunt ullamco culpa laboris. Consectetur non enim in officia incididunt deserunt. Quis est consequat ipsum ad. Pariatur nostrud voluptate magna occaecat minim irure sint nostrud voluptate ea labore ullamco quis. Mollit veniam consequat commodo sunt.\r\n", + "registered": "Wednesday, January 8, 2014 4:02 AM", + "latitude": 46.115788, + "longitude": 79.731859, + "tags": [ + "reprehenderit", + "nisi", + "id", + "consectetur", + "sunt", + "nostrud", + "laboris" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Mandy Buckner" + }, + { + "id": 1, + "name": "Hickman Brown" + }, + { + "id": 2, + "name": "Kemp Mclaughlin" + } + ], + "greeting": "Hello, Clarissa! You have 8 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa8211049b550404f3ce5", + "index": 71, + "guid": "2f9a6201-6728-4509-8d88-c0a614649311", + "isActive": true, + "balance": "$1,324.10", + "picture": "http://placehold.it/32x32", + "age": 22, + "eyeColor": "blue", + "name": { + "first": "Joyce", + "last": "Callahan" + }, + "company": "OPTYK", + "email": "joyce.callahan@optyk.io", + "phone": "+1 (893) 544-2327", + "address": "567 Crystal Street, Freetown, District Of Columbia, 8319", + "about": "Deserunt in nisi id consequat qui. Sunt velit proident id culpa incididunt velit aute dolore labore. Deserunt qui ea adipisicing cillum irure sit sunt excepteur quis et quis nulla dolore pariatur. Consequat ut et veniam dolor velit nulla veniam fugiat commodo velit fugiat ad veniam ad. Anim consequat labore deserunt eiusmod esse. Laborum labore eu et incididunt commodo dolore eiusmod occaecat. Nisi elit duis mollit cillum id enim.\r\n", + "registered": "Tuesday, February 4, 2014 2:38 AM", + "latitude": -76.437449, + "longitude": -169.66079, + "tags": [ + "ullamco", + "non", + "officia", + "eiusmod", + "duis", + "cupidatat", + "mollit" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Hendricks Logan" + }, + { + "id": 1, + "name": "Dolly Baird" + }, + { + "id": 2, + "name": "Wendi Wallace" + } + ], + "greeting": "Hello, Joyce! You have 6 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa82176dab97e42086b90", + "index": 72, + "guid": "9680920d-9303-471b-849e-c30e38e06d45", + "isActive": false, + "balance": "$2,696.40", + "picture": "http://placehold.it/32x32", + "age": 38, + "eyeColor": "blue", + "name": { + "first": "Felecia", + "last": "Gonzalez" + }, + "company": "CORIANDER", + "email": "felecia.gonzalez@coriander.net", + "phone": "+1 (923) 575-3582", + "address": "315 Borinquen Pl, Rosburg, Pennsylvania, 9619", + "about": "Laboris officia exercitation duis aliqua in sint consectetur. Ad ut labore ipsum ipsum ut culpa labore irure aute. Et exercitation tempor do dolor culpa ad ipsum pariatur adipisicing fugiat. Incididunt amet incididunt minim quis cupidatat pariatur enim fugiat reprehenderit est ipsum labore.\r\n", + "registered": "Monday, January 20, 2014 11:59 PM", + "latitude": -36.201421, + "longitude": 162.994705, + "tags": [ + "cillum", + "reprehenderit", + "non", + "est", + "tempor", + "exercitation", + "fugiat" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Gould Waters" + }, + { + "id": 1, + "name": "Ramona Coffey" + }, + { + "id": 2, + "name": "Taylor Byers" + } + ], + "greeting": "Hello, Felecia! You have 10 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821df55849ccd4ca74c", + "index": 73, + "guid": "01b7c49a-6dac-4b65-906b-4483de07a5e8", + "isActive": true, + "balance": "$2,037.32", + "picture": "http://placehold.it/32x32", + "age": 27, + "eyeColor": "blue", + "name": { + "first": "Stanton", + "last": "Rutledge" + }, + "company": "EXOBLUE", + "email": "stanton.rutledge@exoblue.com", + "phone": "+1 (817) 408-2566", + "address": "741 Crooke Avenue, Newry, Nevada, 8555", + "about": "Commodo adipisicing ea ipsum non irure quis excepteur. Qui laborum qui sit cupidatat dolore consectetur tempor esse occaecat cillum qui. Dolore in amet ea ex proident do nulla.\r\n", + "registered": "Thursday, August 28, 2014 8:35 PM", + "latitude": 87.299409, + "longitude": 22.167535, + "tags": [ + "commodo", + "aliqua", + "irure", + "ea", + "dolor", + "aute", + "non" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Best Klein" + }, + { + "id": 1, + "name": "Dickerson Mcknight" + }, + { + "id": 2, + "name": "Gayle Washington" + } + ], + "greeting": "Hello, Stanton! You have 6 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa821f3516c63c6fa05e8", + "index": 74, + "guid": "c299ecf4-0528-4280-b6b4-909801b1e9dd", + "isActive": true, + "balance": "$1,695.83", + "picture": "http://placehold.it/32x32", + "age": 27, + "eyeColor": "green", + "name": { + "first": "Thelma", + "last": "Barnett" + }, + "company": "DUOFLEX", + "email": "thelma.barnett@duoflex.biz", + "phone": "+1 (947) 416-2234", + "address": "325 Tampa Court, Zortman, Illinois, 3609", + "about": "Exercitation esse culpa enim anim. Cillum voluptate quis tempor excepteur elit aliquip consequat officia cupidatat laborum ad cupidatat. Mollit exercitation esse fugiat do do id irure tempor et duis. Ut sit reprehenderit velit sit eiusmod in officia nisi commodo magna id in. Lorem sint velit adipisicing aute.\r\n", + "registered": "Tuesday, April 22, 2014 5:11 AM", + "latitude": 20.61329, + "longitude": 48.592063, + "tags": [ + "et", + "excepteur", + "nostrud", + "ullamco", + "quis", + "occaecat", + "in" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Amy Parks" + }, + { + "id": 1, + "name": "Greene Nunez" + }, + { + "id": 2, + "name": "Janna Roth" + } + ], + "greeting": "Hello, Thelma! You have 6 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821637950981c0fa4c8", + "index": 75, + "guid": "bc58930c-58d8-4223-8a98-20295ac61c4e", + "isActive": true, + "balance": "$1,836.33", + "picture": "http://placehold.it/32x32", + "age": 23, + "eyeColor": "green", + "name": { + "first": "Nunez", + "last": "Freeman" + }, + "company": "ZILCH", + "email": "nunez.freeman@zilch.co.uk", + "phone": "+1 (959) 439-2497", + "address": "729 Varick Street, Marne, Tennessee, 1687", + "about": "Sunt nulla ipsum non in nulla. Dolore in fugiat in laborum veniam enim dolore cupidatat. Elit tempor ullamco id in minim excepteur et aute ut mollit aliquip qui consequat. Duis esse magna culpa aliqua ad ipsum deserunt laborum amet sint. Quis voluptate quis quis aute.\r\n", + "registered": "Monday, August 11, 2014 5:27 PM", + "latitude": 85.57657, + "longitude": -145.772132, + "tags": [ + "ullamco", + "tempor", + "et", + "non", + "magna", + "non", + "ex" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Latasha Randolph" + }, + { + "id": 1, + "name": "Neva Porter" + }, + { + "id": 2, + "name": "Drake Nicholson" + } + ], + "greeting": "Hello, Nunez! You have 10 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821ed9d29afc180b718", + "index": 76, + "guid": "45fb73c9-30e9-4e61-b78d-41c8f79a282e", + "isActive": false, + "balance": "$1,298.91", + "picture": "http://placehold.it/32x32", + "age": 25, + "eyeColor": "green", + "name": { + "first": "Bentley", + "last": "Reyes" + }, + "company": "ZYPLE", + "email": "bentley.reyes@zyple.tv", + "phone": "+1 (919) 510-3585", + "address": "227 Oakland Place, Farmers, Iowa, 9827", + "about": "Cillum proident eiusmod id amet anim laboris elit sint ea et non. Aliqua et reprehenderit amet est ea fugiat aute. Minim aute aliquip nulla elit. Duis ad exercitation excepteur laborum anim occaecat nulla sunt. Quis pariatur nulla Lorem consectetur proident sunt amet est et elit eu sunt. Ut irure voluptate consequat amet sint deserunt quis. Incididunt ea culpa commodo fugiat qui veniam quis Lorem incididunt dolor.\r\n", + "registered": "Wednesday, April 9, 2014 1:19 AM", + "latitude": -82.587336, + "longitude": -74.931056, + "tags": [ + "dolore", + "nisi", + "exercitation", + "ullamco", + "excepteur", + "qui", + "ut" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Nadia Pearson" + }, + { + "id": 1, + "name": "Reba Frost" + }, + { + "id": 2, + "name": "Lilia Mcbride" + } + ], + "greeting": "Hello, Bentley! You have 7 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821a936a115315db0b9", + "index": 77, + "guid": "a1b82517-f6a6-437a-9f2d-2c0043591cfa", + "isActive": false, + "balance": "$1,016.00", + "picture": "http://placehold.it/32x32", + "age": 22, + "eyeColor": "blue", + "name": { + "first": "Morales", + "last": "Shields" + }, + "company": "CORECOM", + "email": "morales.shields@corecom.name", + "phone": "+1 (814) 407-2079", + "address": "472 Coleridge Street, Shasta, Massachusetts, 501", + "about": "Ipsum elit adipisicing nostrud quis ut nisi ullamco consectetur ex laborum reprehenderit anim magna fugiat. In nulla dolor esse exercitation elit exercitation. Laborum sit esse velit magna ea irure est ut velit id nisi sint qui. Laborum voluptate amet cupidatat laborum aute in id duis irure. Enim aliqua enim magna ut consequat. Tempor est commodo elit eu et ut occaecat culpa ex ex. Ullamco cillum sint ipsum tempor anim ullamco sit pariatur excepteur dolor mollit ad quis.\r\n", + "registered": "Saturday, July 5, 2014 5:10 AM", + "latitude": -20.583102, + "longitude": -23.34973, + "tags": [ + "nulla", + "proident", + "enim", + "dolor", + "elit", + "excepteur", + "dolore" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Lacey Perry" + }, + { + "id": 1, + "name": "Stokes Foley" + }, + { + "id": 2, + "name": "Trisha Morales" + } + ], + "greeting": "Hello, Morales! You have 6 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa8214ceb22176ac554f9", + "index": 78, + "guid": "1aa9258a-f508-4e73-adb9-5d2cce0dff79", + "isActive": true, + "balance": "$1,100.42", + "picture": "http://placehold.it/32x32", + "age": 21, + "eyeColor": "blue", + "name": { + "first": "Chandra", + "last": "Patel" + }, + "company": "PROVIDCO", + "email": "chandra.patel@providco.me", + "phone": "+1 (875) 430-3869", + "address": "543 Bainbridge Street, Kidder, Arkansas, 3624", + "about": "Magna ad tempor commodo esse labore mollit sit. Duis laborum excepteur dolor officia exercitation. Elit sunt ex voluptate anim consectetur in ullamco mollit qui non. Cupidatat ipsum et cupidatat cupidatat consequat nulla Lorem culpa minim dolore cupidatat ipsum sint.\r\n", + "registered": "Sunday, June 29, 2014 1:41 AM", + "latitude": 55.150075, + "longitude": -26.185265, + "tags": [ + "amet", + "consectetur", + "occaecat", + "cillum", + "enim", + "ut", + "occaecat" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Geneva Snider" + }, + { + "id": 1, + "name": "Rose Michael" + }, + { + "id": 2, + "name": "Kirkland Mason" + } + ], + "greeting": "Hello, Chandra! You have 5 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821050884ba49ad868d", + "index": 79, + "guid": "88a0d238-e3c9-4b1a-8d19-08c622f9eaae", + "isActive": false, + "balance": "$1,263.98", + "picture": "http://placehold.it/32x32", + "age": 30, + "eyeColor": "green", + "name": { + "first": "Elsa", + "last": "Chambers" + }, + "company": "VICON", + "email": "elsa.chambers@vicon.us", + "phone": "+1 (940) 436-3956", + "address": "190 Albemarle Terrace, Sheatown, Hawaii, 2654", + "about": "Est do esse elit consectetur elit. Aliqua esse duis est sint non. Enim minim laborum ad duis. Proident laboris quis ea amet nulla occaecat ex laboris duis ut velit.\r\n", + "registered": "Saturday, April 19, 2014 3:28 AM", + "latitude": 62.679122, + "longitude": 95.229313, + "tags": [ + "magna", + "ipsum", + "Lorem", + "ut", + "duis", + "elit", + "sit" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Laurie Fuentes" + }, + { + "id": 1, + "name": "Juana Blevins" + }, + { + "id": 2, + "name": "Virginia Hester" + } + ], + "greeting": "Hello, Elsa! You have 6 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821eb0dd28cfdc525a9", + "index": 80, + "guid": "e1574006-8d49-4399-8b59-92eaa0ed2be1", + "isActive": true, + "balance": "$2,395.40", + "picture": "http://placehold.it/32x32", + "age": 23, + "eyeColor": "brown", + "name": { + "first": "Morris", + "last": "Trujillo" + }, + "company": "ZOGAK", + "email": "morris.trujillo@zogak.ca", + "phone": "+1 (919) 553-3453", + "address": "127 Clove Road, Keyport, Puerto Rico, 5969", + "about": "Minim do veniam non elit excepteur enim sunt excepteur non amet. Duis eu consequat adipisicing nostrud ad cupidatat tempor occaecat. Ea id consectetur non anim. Irure dolor qui excepteur anim excepteur adipisicing ea sint id aliquip consequat eu id. Ea exercitation officia nostrud ipsum. Voluptate sunt irure aliqua tempor pariatur irure labore ea amet. Quis reprehenderit aliqua pariatur esse id anim laborum ullamco amet.\r\n", + "registered": "Sunday, February 2, 2014 12:52 PM", + "latitude": -86.963921, + "longitude": -157.636932, + "tags": [ + "occaecat", + "amet", + "ex", + "ea", + "exercitation", + "aliqua", + "elit" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Lester Watkins" + }, + { + "id": 1, + "name": "Kellie Clayton" + }, + { + "id": 2, + "name": "Valencia Edwards" + } + ], + "greeting": "Hello, Morris! You have 6 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821f5f0ae13a893ce36", + "index": 81, + "guid": "9dd75e1e-8f3c-473e-800e-518254719ca1", + "isActive": true, + "balance": "$1,956.52", + "picture": "http://placehold.it/32x32", + "age": 36, + "eyeColor": "brown", + "name": { + "first": "Gwen", + "last": "Park" + }, + "company": "INTERGEEK", + "email": "gwen.park@intergeek.org", + "phone": "+1 (830) 581-3561", + "address": "514 Beayer Place, Maxville, New Hampshire, 4162", + "about": "Consequat labore commodo nulla veniam aliqua. Tempor ipsum officia exercitation amet elit dolor labore eu voluptate cillum reprehenderit exercitation proident. Id cillum laborum cupidatat reprehenderit anim cillum exercitation culpa aliqua deserunt cupidatat. In proident ea eu nisi est enim. Quis dolor sit aliquip reprehenderit in id ipsum proident duis. Sit eu sint nisi velit. Minim elit nostrud aliquip anim.\r\n", + "registered": "Wednesday, September 17, 2014 9:38 AM", + "latitude": -66.199245, + "longitude": -52.824656, + "tags": [ + "ex", + "magna", + "incididunt", + "veniam", + "mollit", + "eu", + "sunt" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Nieves Potter" + }, + { + "id": 1, + "name": "Welch Reeves" + }, + { + "id": 2, + "name": "Hardy Forbes" + } + ], + "greeting": "Hello, Gwen! You have 8 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa821a20d620a7ec793ac", + "index": 82, + "guid": "1ae142ff-8d6a-4e72-a3f1-3ac4349ad0b7", + "isActive": false, + "balance": "$2,560.11", + "picture": "http://placehold.it/32x32", + "age": 31, + "eyeColor": "green", + "name": { + "first": "Erickson", + "last": "Lancaster" + }, + "company": "SCENTRIC", + "email": "erickson.lancaster@scentric.biz", + "phone": "+1 (980) 465-3465", + "address": "412 Jackson Street, Chumuckla, South Carolina, 3216", + "about": "Id laborum consectetur pariatur non nulla incididunt labore magna minim duis. Ipsum laboris deserunt velit sunt voluptate. Laboris ipsum duis aliquip non aliqua. Commodo veniam mollit voluptate elit nisi nostrud laboris dolor tempor pariatur duis laborum.\r\n", + "registered": "Wednesday, May 7, 2014 8:50 PM", + "latitude": -57.590749, + "longitude": 117.31662, + "tags": [ + "ad", + "elit", + "non", + "fugiat", + "laborum", + "incididunt", + "enim" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Reeves Nguyen" + }, + { + "id": 1, + "name": "Jo Christian" + }, + { + "id": 2, + "name": "Myers Lowe" + } + ], + "greeting": "Hello, Erickson! You have 10 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa8213747fd3443999762", + "index": 83, + "guid": "ec870637-4e65-49c4-abfb-7b99c2d2f094", + "isActive": true, + "balance": "$2,079.21", + "picture": "http://placehold.it/32x32", + "age": 21, + "eyeColor": "blue", + "name": { + "first": "Saundra", + "last": "Kemp" + }, + "company": "LUNCHPOD", + "email": "saundra.kemp@lunchpod.io", + "phone": "+1 (950) 433-2550", + "address": "593 Stuart Street, Edenburg, Texas, 6251", + "about": "Ipsum proident et duis reprehenderit in minim in sint dolore enim aute excepteur cillum eiusmod. Do nulla deserunt quis adipisicing sunt reprehenderit. Dolor pariatur tempor sint ullamco.\r\n", + "registered": "Tuesday, June 24, 2014 6:44 AM", + "latitude": 81.565149, + "longitude": -92.061448, + "tags": [ + "magna", + "commodo", + "esse", + "ad", + "labore", + "amet", + "mollit" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Tommie Mays" + }, + { + "id": 1, + "name": "Lou Hubbard" + }, + { + "id": 2, + "name": "Jenna Gentry" + } + ], + "greeting": "Hello, Saundra! You have 9 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa821524a5fd2a5f037a2", + "index": 84, + "guid": "e7894fe9-efd4-44ae-afd5-49bfde09b000", + "isActive": true, + "balance": "$2,320.08", + "picture": "http://placehold.it/32x32", + "age": 37, + "eyeColor": "green", + "name": { + "first": "Christensen", + "last": "Wolf" + }, + "company": "GLUKGLUK", + "email": "christensen.wolf@glukgluk.net", + "phone": "+1 (937) 519-3107", + "address": "460 Porter Avenue, Irwin, South Dakota, 2498", + "about": "Ullamco reprehenderit non aliquip amet do deserunt nostrud ea deserunt fugiat. Commodo pariatur est officia dolor dolore in excepteur pariatur laborum ut. Occaecat cillum ullamco nulla eu esse non nisi pariatur ipsum amet do ea ad culpa. Excepteur esse elit laborum deserunt ad consequat. Culpa esse esse nostrud commodo laborum officia sint ea mollit. Dolor culpa pariatur fugiat cillum quis proident non enim esse pariatur duis adipisicing amet. Consequat minim aliqua enim excepteur.\r\n", + "registered": "Saturday, February 8, 2014 10:20 PM", + "latitude": 22.478522, + "longitude": 30.070646, + "tags": [ + "quis", + "ad", + "adipisicing", + "exercitation", + "non", + "eu", + "anim" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Bright Moon" + }, + { + "id": 1, + "name": "Stephenson Sears" + }, + { + "id": 2, + "name": "Fletcher Swanson" + } + ], + "greeting": "Hello, Christensen! You have 9 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa82160fa0826e90b747b", + "index": 85, + "guid": "af08cc83-e8c9-4bcd-84b3-2f3251cf9a02", + "isActive": true, + "balance": "$2,575.60", + "picture": "http://placehold.it/32x32", + "age": 29, + "eyeColor": "brown", + "name": { + "first": "Weaver", + "last": "Parker" + }, + "company": "RETROTEX", + "email": "weaver.parker@retrotex.com", + "phone": "+1 (951) 411-2545", + "address": "560 Madison Place, Sidman, Ohio, 5153", + "about": "Reprehenderit esse dolor tempor consectetur occaecat exercitation consectetur irure commodo. Et eiusmod aute ipsum eu commodo qui id anim proident. Excepteur labore laboris aliqua incididunt ut nisi consequat deserunt dolore officia velit sint consectetur. Laboris sint minim mollit duis. Excepteur nostrud incididunt aute consequat ad magna eu quis. Id dolor eu aliqua deserunt cillum sint ea et nostrud. Lorem amet cillum nulla tempor commodo mollit aliquip do est enim enim.\r\n", + "registered": "Thursday, February 6, 2014 12:55 PM", + "latitude": 87.778566, + "longitude": -122.687026, + "tags": [ + "eu", + "voluptate", + "commodo", + "magna", + "ullamco", + "nulla", + "ea" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Ratliff Mckinney" + }, + { + "id": 1, + "name": "Walker Frye" + }, + { + "id": 2, + "name": "Mcgowan Daniel" + } + ], + "greeting": "Hello, Weaver! You have 5 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa8217a543d20bd4b10c1", + "index": 86, + "guid": "5b670ab7-4ee6-4b8e-b379-4e1849b6e329", + "isActive": false, + "balance": "$3,114.39", + "picture": "http://placehold.it/32x32", + "age": 38, + "eyeColor": "green", + "name": { + "first": "Annabelle", + "last": "Sanders" + }, + "company": "PHORMULA", + "email": "annabelle.sanders@phormula.biz", + "phone": "+1 (982) 489-2678", + "address": "970 Llama Court, Moraida, Maine, 8694", + "about": "Nostrud adipisicing magna nulla magna voluptate duis eu voluptate cupidatat ut dolore excepteur esse dolor. Aliquip exercitation occaecat amet excepteur sit. Velit adipisicing esse labore veniam duis ullamco in ea. Adipisicing eiusmod cillum veniam nostrud sint laboris sit id officia. Esse esse anim sint do ea id. Esse ipsum mollit sit laborum nostrud mollit nulla id.\r\n", + "registered": "Tuesday, January 7, 2014 7:34 AM", + "latitude": 9.515348, + "longitude": -99.138606, + "tags": [ + "ipsum", + "sint", + "dolor", + "laborum", + "est", + "consequat", + "magna" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Juliet Clements" + }, + { + "id": 1, + "name": "Jeannine Pruitt" + }, + { + "id": 2, + "name": "Chambers Warren" + } + ], + "greeting": "Hello, Annabelle! You have 7 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa82179c1fe89e1ccec4d", + "index": 87, + "guid": "31ecaae4-6443-4c00-a20d-82100c49b488", + "isActive": true, + "balance": "$3,803.83", + "picture": "http://placehold.it/32x32", + "age": 40, + "eyeColor": "blue", + "name": { + "first": "Kelley", + "last": "Miles" + }, + "company": "AQUASURE", + "email": "kelley.miles@aquasure.co.uk", + "phone": "+1 (819) 529-2967", + "address": "680 Monument Walk, Wakulla, Vermont, 8903", + "about": "Ea sint dolor nostrud dolor id commodo esse nisi. Reprehenderit minim dolore nostrud sint incididunt excepteur reprehenderit enim velit velit. Proident officia velit Lorem dolore ullamco occaecat.\r\n", + "registered": "Saturday, May 3, 2014 12:23 AM", + "latitude": 73.767872, + "longitude": -118.631186, + "tags": [ + "consectetur", + "irure", + "nostrud", + "nostrud", + "aliquip", + "quis", + "reprehenderit" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Maynard Townsend" + }, + { + "id": 1, + "name": "Carlene Molina" + }, + { + "id": 2, + "name": "Mai Bentley" + } + ], + "greeting": "Hello, Kelley! You have 7 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa8218de20c1f1e1e93fa", + "index": 88, + "guid": "8f6b0aac-f2ba-45aa-a7c8-76c413bdeb7a", + "isActive": true, + "balance": "$1,898.86", + "picture": "http://placehold.it/32x32", + "age": 38, + "eyeColor": "brown", + "name": { + "first": "Mckay", + "last": "Velasquez" + }, + "company": "NORALEX", + "email": "mckay.velasquez@noralex.tv", + "phone": "+1 (973) 599-3463", + "address": "152 Roebling Street, Mathews, Delaware, 7958", + "about": "Nostrud esse dolor excepteur cillum aliqua. Ea nulla elit minim sint non culpa id. Et ullamco aute laborum incididunt sint quis. Tempor tempor aliqua in sunt. Minim elit dolor quis excepteur exercitation adipisicing. Pariatur incididunt tempor irure proident exercitation deserunt sint.\r\n", + "registered": "Monday, August 4, 2014 5:00 AM", + "latitude": 81.463276, + "longitude": -66.291508, + "tags": [ + "nisi", + "anim", + "qui", + "est", + "qui", + "ipsum", + "ullamco" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Myrna Rollins" + }, + { + "id": 1, + "name": "Tricia Gilliam" + }, + { + "id": 2, + "name": "Collins Obrien" + } + ], + "greeting": "Hello, Mckay! You have 10 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821b3490524365bc954", + "index": 89, + "guid": "43825015-fed6-40c8-bd80-8aaf228067f9", + "isActive": false, + "balance": "$3,035.21", + "picture": "http://placehold.it/32x32", + "age": 40, + "eyeColor": "blue", + "name": { + "first": "Brandy", + "last": "Hayden" + }, + "company": "OMNIGOG", + "email": "brandy.hayden@omnigog.name", + "phone": "+1 (827) 481-2334", + "address": "537 Pioneer Street, Saticoy, Palau, 803", + "about": "Ea velit consectetur ipsum ut elit pariatur id labore sunt eu incididunt est aliqua. Veniam esse officia do non officia cupidatat proident id officia esse tempor non mollit dolore. Elit voluptate nulla exercitation laboris ex ad irure est do enim aute velit aute. Cillum adipisicing nisi dolor velit duis ad fugiat deserunt non commodo Lorem fugiat sint qui. Aute consectetur magna incididunt tempor in esse consectetur magna qui sit. Culpa consequat laborum duis adipisicing dolor in deserunt ut velit ea ex dolore ullamco esse.\r\n", + "registered": "Wednesday, February 12, 2014 7:32 PM", + "latitude": 4.319892, + "longitude": 81.048442, + "tags": [ + "labore", + "ullamco", + "commodo", + "quis", + "aute", + "nulla", + "do" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Riggs Flynn" + }, + { + "id": 1, + "name": "Kidd Guerrero" + }, + { + "id": 2, + "name": "Rosario Wade" + } + ], + "greeting": "Hello, Brandy! You have 10 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa8211b737d086264c9a9", + "index": 90, + "guid": "ec5fe190-d16f-4728-bce1-c5140852c583", + "isActive": true, + "balance": "$2,932.98", + "picture": "http://placehold.it/32x32", + "age": 28, + "eyeColor": "green", + "name": { + "first": "Sonia", + "last": "Orr" + }, + "company": "MUSANPOLY", + "email": "sonia.orr@musanpoly.me", + "phone": "+1 (822) 422-2010", + "address": "908 Dekalb Avenue, Elfrida, Arizona, 6925", + "about": "Ut cillum ex irure amet aliquip voluptate Lorem fugiat reprehenderit sunt reprehenderit quis. Nulla laborum sunt elit ad labore ut cupidatat cillum eiusmod est. Ea irure amet excepteur mollit eu ipsum id adipisicing occaecat. Cupidatat sunt do veniam esse enim sint qui voluptate sint. Qui officia ad cupidatat mollit laboris. Duis tempor fugiat ea mollit cupidatat exercitation sunt incididunt.\r\n", + "registered": "Thursday, September 25, 2014 8:21 PM", + "latitude": 71.876999, + "longitude": 79.322401, + "tags": [ + "pariatur", + "sit", + "culpa", + "dolore", + "cupidatat", + "minim", + "cillum" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Morgan Pittman" + }, + { + "id": 1, + "name": "Bullock Cannon" + }, + { + "id": 2, + "name": "Lakeisha Lynch" + } + ], + "greeting": "Hello, Sonia! You have 9 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821b271c92236e5e9b0", + "index": 91, + "guid": "57cff12c-2a18-48c2-b15a-3c393de707b6", + "isActive": false, + "balance": "$1,874.97", + "picture": "http://placehold.it/32x32", + "age": 40, + "eyeColor": "green", + "name": { + "first": "Stephens", + "last": "Whitaker" + }, + "company": "EARTHPLEX", + "email": "stephens.whitaker@earthplex.us", + "phone": "+1 (960) 419-2183", + "address": "368 Division Avenue, Fivepointville, Colorado, 8609", + "about": "Do aliquip laboris irure consectetur esse reprehenderit. Cillum ex deserunt fugiat ut dolore excepteur culpa eiusmod sit ullamco velit consequat consequat aliquip. Nostrud officia est enim velit fugiat laboris.\r\n", + "registered": "Monday, May 26, 2014 8:04 PM", + "latitude": 7.153481, + "longitude": 100.823578, + "tags": [ + "laborum", + "irure", + "dolore", + "enim", + "nisi", + "cillum", + "deserunt" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Perkins Campos" + }, + { + "id": 1, + "name": "Murray Randall" + }, + { + "id": 2, + "name": "Wallace Blackwell" + } + ], + "greeting": "Hello, Stephens! You have 7 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa821c115ee94a728efa4", + "index": 92, + "guid": "7bbe7ace-73f9-4d25-8f20-b50f4b9d4e60", + "isActive": true, + "balance": "$1,168.18", + "picture": "http://placehold.it/32x32", + "age": 33, + "eyeColor": "green", + "name": { + "first": "Shepard", + "last": "Sanchez" + }, + "company": "YOGASM", + "email": "shepard.sanchez@yogasm.ca", + "phone": "+1 (959) 436-3299", + "address": "154 Seeley Street, Witmer, Missouri, 994", + "about": "Adipisicing ut id nulla occaecat enim officia reprehenderit non magna dolor Lorem. Culpa ad proident duis cupidatat nostrud occaecat esse elit pariatur quis Lorem. Velit exercitation anim dolore nisi labore consequat cupidatat magna nostrud sint ut deserunt enim.\r\n", + "registered": "Saturday, February 22, 2014 10:23 PM", + "latitude": -81.429217, + "longitude": -27.374426, + "tags": [ + "aliqua", + "minim", + "consequat", + "aliqua", + "qui", + "proident", + "consequat" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Sara Bruce" + }, + { + "id": 1, + "name": "Kimberley Mcdaniel" + }, + { + "id": 2, + "name": "Tammi England" + } + ], + "greeting": "Hello, Shepard! You have 7 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa821a094fdd2592addbd", + "index": 93, + "guid": "69bc8858-bd55-4fa0-95f9-d2cb680a390c", + "isActive": false, + "balance": "$1,746.96", + "picture": "http://placehold.it/32x32", + "age": 35, + "eyeColor": "blue", + "name": { + "first": "Kristy", + "last": "Johnston" + }, + "company": "KONGLE", + "email": "kristy.johnston@kongle.org", + "phone": "+1 (823) 558-3033", + "address": "122 Cadman Plaza, Suitland, Minnesota, 3918", + "about": "Laboris excepteur ea nostrud incididunt est laborum dolor. Consequat ad duis aute proident incididunt commodo adipisicing. Enim voluptate sunt et est excepteur eiusmod commodo. Mollit fugiat reprehenderit ex ullamco magna laboris commodo mollit. Cupidatat tempor tempor minim dolore. Excepteur ipsum esse ipsum nulla.\r\n", + "registered": "Wednesday, January 29, 2014 11:15 PM", + "latitude": 15.335329, + "longitude": -78.001472, + "tags": [ + "veniam", + "consequat", + "ex", + "anim", + "culpa", + "ullamco", + "ex" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Johns Cochran" + }, + { + "id": 1, + "name": "Sheppard Hicks" + }, + { + "id": 2, + "name": "Cervantes Donovan" + } + ], + "greeting": "Hello, Kristy! You have 10 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821311b6242dc75f718", + "index": 94, + "guid": "9de76ab8-2ef7-4b46-a478-5dea8732650a", + "isActive": false, + "balance": "$2,549.05", + "picture": "http://placehold.it/32x32", + "age": 40, + "eyeColor": "blue", + "name": { + "first": "Melendez", + "last": "Golden" + }, + "company": "GRONK", + "email": "melendez.golden@gronk.biz", + "phone": "+1 (986) 553-2124", + "address": "647 Broadway , Reno, Northern Mariana Islands, 9487", + "about": "Aliquip pariatur deserunt culpa eu nostrud eu amet. Adipisicing elit occaecat aliqua ipsum ut. Cillum magna consectetur elit esse sint laboris duis. In ea enim aute eiusmod culpa. Labore quis sunt aliquip excepteur tempor irure amet consequat eu excepteur et occaecat.\r\n", + "registered": "Monday, April 14, 2014 9:41 AM", + "latitude": 55.489443, + "longitude": 3.620039, + "tags": [ + "pariatur", + "magna", + "quis", + "in", + "irure", + "amet", + "esse" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Hilary Dennis" + }, + { + "id": 1, + "name": "Tyler Burgess" + }, + { + "id": 2, + "name": "Eugenia Donaldson" + } + ], + "greeting": "Hello, Melendez! You have 9 unread messages.", + "favoriteFruit": "strawberry" + }, + { + "_id": "543fa821c394a9871527c834", + "index": 95, + "guid": "ec0f31d4-7264-4649-9af9-2716082915d3", + "isActive": true, + "balance": "$2,810.24", + "picture": "http://placehold.it/32x32", + "age": 34, + "eyeColor": "brown", + "name": { + "first": "Eleanor", + "last": "Curtis" + }, + "company": "ZAPPIX", + "email": "eleanor.curtis@zappix.io", + "phone": "+1 (824) 461-3776", + "address": "981 Lyme Avenue, Oneida, Marshall Islands, 6015", + "about": "Commodo labore do pariatur exercitation voluptate ea velit velit qui ex duis. Commodo est excepteur ad labore aute enim eu. Adipisicing irure exercitation sint consectetur exercitation occaecat aute exercitation commodo.\r\n", + "registered": "Monday, May 5, 2014 7:51 AM", + "latitude": -5.604007, + "longitude": -125.532894, + "tags": [ + "aliqua", + "commodo", + "non", + "magna", + "quis", + "velit", + "irure" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Monica Carr" + }, + { + "id": 1, + "name": "Coleman Simpson" + }, + { + "id": 2, + "name": "Wilma Fisher" + } + ], + "greeting": "Hello, Eleanor! You have 7 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa821a5b5e35d24f265b3", + "index": 96, + "guid": "c865c0ff-8505-4d02-af0a-c5a275d03fd5", + "isActive": true, + "balance": "$3,192.24", + "picture": "http://placehold.it/32x32", + "age": 22, + "eyeColor": "blue", + "name": { + "first": "Terrell", + "last": "Greene" + }, + "company": "AUTOGRATE", + "email": "terrell.greene@autograte.net", + "phone": "+1 (933) 557-3825", + "address": "435 Bridgewater Street, Fresno, New Jersey, 8124", + "about": "Elit sit ut anim reprehenderit anim ipsum esse tempor aliqua id ullamco. Exercitation est velit aliquip est elit mollit magna velit. Elit eiusmod esse voluptate consectetur enim id exercitation adipisicing et laborum. Irure fugiat ut sint exercitation dolor nostrud qui mollit eiusmod cupidatat. Commodo ad dolore incididunt ex quis nostrud veniam pariatur aliquip ea reprehenderit reprehenderit.\r\n", + "registered": "Sunday, September 21, 2014 3:31 AM", + "latitude": 76.638623, + "longitude": 147.966829, + "tags": [ + "aliquip", + "qui", + "nisi", + "ut", + "non", + "proident", + "et" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Lucile Jordan" + }, + { + "id": 1, + "name": "Bender Sheppard" + }, + { + "id": 2, + "name": "Milagros Francis" + } + ], + "greeting": "Hello, Terrell! You have 8 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa8216cc444257e522ec0", + "index": 97, + "guid": "90c19881-6521-4012-aba7-f4d143953965", + "isActive": false, + "balance": "$1,509.96", + "picture": "http://placehold.it/32x32", + "age": 31, + "eyeColor": "green", + "name": { + "first": "Holman", + "last": "Hines" + }, + "company": "NORSUP", + "email": "holman.hines@norsup.com", + "phone": "+1 (925) 565-2825", + "address": "902 Monroe Street, Marienthal, Virgin Islands, 2354", + "about": "Eu cupidatat consectetur labore voluptate nulla non amet incididunt labore non magna tempor. Veniam et sint qui reprehenderit reprehenderit sint ut laboris elit. Pariatur in eu dolore culpa nisi laboris officia magna do velit. Cupidatat proident excepteur officia labore irure sunt elit velit dolor commodo. Minim quis sint minim non incididunt Lorem elit cupidatat adipisicing quis esse non sint et. Laborum culpa incididunt incididunt fugiat minim ex deserunt et.\r\n", + "registered": "Sunday, April 27, 2014 8:05 PM", + "latitude": 61.825518, + "longitude": -28.393161, + "tags": [ + "voluptate", + "veniam", + "Lorem", + "ex", + "in", + "est", + "exercitation" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Cecelia Chapman" + }, + { + "id": 1, + "name": "Isabella Castaneda" + }, + { + "id": 2, + "name": "Montoya Chen" + } + ], + "greeting": "Hello, Holman! You have 9 unread messages.", + "favoriteFruit": "apple" + }, + { + "_id": "543fa8210659aa5cdca41f7e", + "index": 98, + "guid": "81adf15d-24b6-454c-a75f-f5be12f6ac75", + "isActive": false, + "balance": "$2,564.95", + "picture": "http://placehold.it/32x32", + "age": 39, + "eyeColor": "green", + "name": { + "first": "Horton", + "last": "Poole" + }, + "company": "GROK", + "email": "horton.poole@grok.biz", + "phone": "+1 (908) 520-3683", + "address": "141 Gatling Place, Hackneyville, Oregon, 2976", + "about": "Consequat nisi reprehenderit incididunt id minim cillum. Lorem reprehenderit fugiat irure dolor excepteur velit. Est nostrud culpa ut reprehenderit in duis id voluptate pariatur voluptate. Exercitation Lorem esse exercitation Lorem esse. Excepteur mollit sit ut voluptate ipsum pariatur anim sint sunt cillum sit consequat.\r\n", + "registered": "Thursday, September 18, 2014 6:11 AM", + "latitude": -3.525694, + "longitude": -103.351985, + "tags": [ + "deserunt", + "voluptate", + "cillum", + "id", + "magna", + "deserunt", + "incididunt" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Hope Lara" + }, + { + "id": 1, + "name": "French Garner" + }, + { + "id": 2, + "name": "Stein Sykes" + } + ], + "greeting": "Hello, Horton! You have 5 unread messages.", + "favoriteFruit": "banana" + }, + { + "_id": "543fa821cf1b15f13d8c3938", + "index": 99, + "guid": "44533089-c11a-4656-b2d1-9ab6be887f30", + "isActive": false, + "balance": "$3,192.31", + "picture": "http://placehold.it/32x32", + "age": 37, + "eyeColor": "green", + "name": { + "first": "Wanda", + "last": "Wiggins" + }, + "company": "ZEPITOPE", + "email": "wanda.wiggins@zepitope.co.uk", + "phone": "+1 (998) 461-3780", + "address": "427 Canton Court, Heil, Utah, 8283", + "about": "Do officia et exercitation dolor esse. Ut nisi eiusmod dolore laborum ad ex mollit minim. Pariatur qui culpa ullamco ex eiusmod.\r\n", + "registered": "Tuesday, August 26, 2014 6:59 PM", + "latitude": 44.770809, + "longitude": 150.936963, + "tags": [ + "consectetur", + "mollit", + "laborum", + "ipsum", + "quis", + "cupidatat", + "in" + ], + "range": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "friends": [ + { + "id": 0, + "name": "Kristie Cain" + }, + { + "id": 1, + "name": "Geraldine Zimmerman" + }, + { + "id": 2, + "name": "Ingrid Harper" + } + ], + "greeting": "Hello, Wanda! You have 5 unread messages.", + "favoriteFruit": "strawberry" + } +] \ No newline at end of file diff --git a/vendor/github.com/klauspost/compress/testdata/Mark.Twain-Tom.Sawyer.txt b/vendor/github.com/klauspost/compress/testdata/Mark.Twain-Tom.Sawyer.txt new file mode 100644 index 0000000..565627a --- /dev/null +++ b/vendor/github.com/klauspost/compress/testdata/Mark.Twain-Tom.Sawyer.txt @@ -0,0 +1,8472 @@ +Produced by David Widger. The previous edition was updated by Jose +Menendez. + + + + + + THE ADVENTURES OF TOM SAWYER + BY + MARK TWAIN + (Samuel Langhorne Clemens) + + + + + P R E F A C E + +MOST of the adventures recorded in this book really occurred; one or +two were experiences of my own, the rest those of boys who were +schoolmates of mine. Huck Finn is drawn from life; Tom Sawyer also, but +not from an individual--he is a combination of the characteristics of +three boys whom I knew, and therefore belongs to the composite order of +architecture. + +The odd superstitions touched upon were all prevalent among children +and slaves in the West at the period of this story--that is to say, +thirty or forty years ago. + +Although my book is intended mainly for the entertainment of boys and +girls, I hope it will not be shunned by men and women on that account, +for part of my plan has been to try to pleasantly remind adults of what +they once were themselves, and of how they felt and thought and talked, +and what queer enterprises they sometimes engaged in. + + THE AUTHOR. + +HARTFORD, 1876. + + + + T O M S A W Y E R + + + +CHAPTER I + +"TOM!" + +No answer. + +"TOM!" + +No answer. + +"What's gone with that boy, I wonder? You TOM!" + +No answer. + +The old lady pulled her spectacles down and looked over them about the +room; then she put them up and looked out under them. She seldom or +never looked THROUGH them for so small a thing as a boy; they were her +state pair, the pride of her heart, and were built for "style," not +service--she could have seen through a pair of stove-lids just as well. +She looked perplexed for a moment, and then said, not fiercely, but +still loud enough for the furniture to hear: + +"Well, I lay if I get hold of you I'll--" + +She did not finish, for by this time she was bending down and punching +under the bed with the broom, and so she needed breath to punctuate the +punches with. She resurrected nothing but the cat. + +"I never did see the beat of that boy!" + +She went to the open door and stood in it and looked out among the +tomato vines and "jimpson" weeds that constituted the garden. No Tom. +So she lifted up her voice at an angle calculated for distance and +shouted: + +"Y-o-u-u TOM!" + +There was a slight noise behind her and she turned just in time to +seize a small boy by the slack of his roundabout and arrest his flight. + +"There! I might 'a' thought of that closet. What you been doing in +there?" + +"Nothing." + +"Nothing! Look at your hands. And look at your mouth. What IS that +truck?" + +"I don't know, aunt." + +"Well, I know. It's jam--that's what it is. Forty times I've said if +you didn't let that jam alone I'd skin you. Hand me that switch." + +The switch hovered in the air--the peril was desperate-- + +"My! Look behind you, aunt!" + +The old lady whirled round, and snatched her skirts out of danger. The +lad fled on the instant, scrambled up the high board-fence, and +disappeared over it. + +His aunt Polly stood surprised a moment, and then broke into a gentle +laugh. + +"Hang the boy, can't I never learn anything? Ain't he played me tricks +enough like that for me to be looking out for him by this time? But old +fools is the biggest fools there is. Can't learn an old dog new tricks, +as the saying is. But my goodness, he never plays them alike, two days, +and how is a body to know what's coming? He 'pears to know just how +long he can torment me before I get my dander up, and he knows if he +can make out to put me off for a minute or make me laugh, it's all down +again and I can't hit him a lick. I ain't doing my duty by that boy, +and that's the Lord's truth, goodness knows. Spare the rod and spile +the child, as the Good Book says. I'm a laying up sin and suffering for +us both, I know. He's full of the Old Scratch, but laws-a-me! he's my +own dead sister's boy, poor thing, and I ain't got the heart to lash +him, somehow. Every time I let him off, my conscience does hurt me so, +and every time I hit him my old heart most breaks. Well-a-well, man +that is born of woman is of few days and full of trouble, as the +Scripture says, and I reckon it's so. He'll play hookey this evening, * +and [* Southwestern for "afternoon"] I'll just be obleeged to make him +work, to-morrow, to punish him. It's mighty hard to make him work +Saturdays, when all the boys is having holiday, but he hates work more +than he hates anything else, and I've GOT to do some of my duty by him, +or I'll be the ruination of the child." + +Tom did play hookey, and he had a very good time. He got back home +barely in season to help Jim, the small colored boy, saw next-day's +wood and split the kindlings before supper--at least he was there in +time to tell his adventures to Jim while Jim did three-fourths of the +work. Tom's younger brother (or rather half-brother) Sid was already +through with his part of the work (picking up chips), for he was a +quiet boy, and had no adventurous, troublesome ways. + +While Tom was eating his supper, and stealing sugar as opportunity +offered, Aunt Polly asked him questions that were full of guile, and +very deep--for she wanted to trap him into damaging revealments. Like +many other simple-hearted souls, it was her pet vanity to believe she +was endowed with a talent for dark and mysterious diplomacy, and she +loved to contemplate her most transparent devices as marvels of low +cunning. Said she: + +"Tom, it was middling warm in school, warn't it?" + +"Yes'm." + +"Powerful warm, warn't it?" + +"Yes'm." + +"Didn't you want to go in a-swimming, Tom?" + +A bit of a scare shot through Tom--a touch of uncomfortable suspicion. +He searched Aunt Polly's face, but it told him nothing. So he said: + +"No'm--well, not very much." + +The old lady reached out her hand and felt Tom's shirt, and said: + +"But you ain't too warm now, though." And it flattered her to reflect +that she had discovered that the shirt was dry without anybody knowing +that that was what she had in her mind. But in spite of her, Tom knew +where the wind lay, now. So he forestalled what might be the next move: + +"Some of us pumped on our heads--mine's damp yet. See?" + +Aunt Polly was vexed to think she had overlooked that bit of +circumstantial evidence, and missed a trick. Then she had a new +inspiration: + +"Tom, you didn't have to undo your shirt collar where I sewed it, to +pump on your head, did you? Unbutton your jacket!" + +The trouble vanished out of Tom's face. He opened his jacket. His +shirt collar was securely sewed. + +"Bother! Well, go 'long with you. I'd made sure you'd played hookey +and been a-swimming. But I forgive ye, Tom. I reckon you're a kind of a +singed cat, as the saying is--better'n you look. THIS time." + +She was half sorry her sagacity had miscarried, and half glad that Tom +had stumbled into obedient conduct for once. + +But Sidney said: + +"Well, now, if I didn't think you sewed his collar with white thread, +but it's black." + +"Why, I did sew it with white! Tom!" + +But Tom did not wait for the rest. As he went out at the door he said: + +"Siddy, I'll lick you for that." + +In a safe place Tom examined two large needles which were thrust into +the lapels of his jacket, and had thread bound about them--one needle +carried white thread and the other black. He said: + +"She'd never noticed if it hadn't been for Sid. Confound it! sometimes +she sews it with white, and sometimes she sews it with black. I wish to +geeminy she'd stick to one or t'other--I can't keep the run of 'em. But +I bet you I'll lam Sid for that. I'll learn him!" + +He was not the Model Boy of the village. He knew the model boy very +well though--and loathed him. + +Within two minutes, or even less, he had forgotten all his troubles. +Not because his troubles were one whit less heavy and bitter to him +than a man's are to a man, but because a new and powerful interest bore +them down and drove them out of his mind for the time--just as men's +misfortunes are forgotten in the excitement of new enterprises. This +new interest was a valued novelty in whistling, which he had just +acquired from a negro, and he was suffering to practise it undisturbed. +It consisted in a peculiar bird-like turn, a sort of liquid warble, +produced by touching the tongue to the roof of the mouth at short +intervals in the midst of the music--the reader probably remembers how +to do it, if he has ever been a boy. Diligence and attention soon gave +him the knack of it, and he strode down the street with his mouth full +of harmony and his soul full of gratitude. He felt much as an +astronomer feels who has discovered a new planet--no doubt, as far as +strong, deep, unalloyed pleasure is concerned, the advantage was with +the boy, not the astronomer. + +The summer evenings were long. It was not dark, yet. Presently Tom +checked his whistle. A stranger was before him--a boy a shade larger +than himself. A new-comer of any age or either sex was an impressive +curiosity in the poor little shabby village of St. Petersburg. This boy +was well dressed, too--well dressed on a week-day. This was simply +astounding. His cap was a dainty thing, his close-buttoned blue cloth +roundabout was new and natty, and so were his pantaloons. He had shoes +on--and it was only Friday. He even wore a necktie, a bright bit of +ribbon. He had a citified air about him that ate into Tom's vitals. The +more Tom stared at the splendid marvel, the higher he turned up his +nose at his finery and the shabbier and shabbier his own outfit seemed +to him to grow. Neither boy spoke. If one moved, the other moved--but +only sidewise, in a circle; they kept face to face and eye to eye all +the time. Finally Tom said: + +"I can lick you!" + +"I'd like to see you try it." + +"Well, I can do it." + +"No you can't, either." + +"Yes I can." + +"No you can't." + +"I can." + +"You can't." + +"Can!" + +"Can't!" + +An uncomfortable pause. Then Tom said: + +"What's your name?" + +"'Tisn't any of your business, maybe." + +"Well I 'low I'll MAKE it my business." + +"Well why don't you?" + +"If you say much, I will." + +"Much--much--MUCH. There now." + +"Oh, you think you're mighty smart, DON'T you? I could lick you with +one hand tied behind me, if I wanted to." + +"Well why don't you DO it? You SAY you can do it." + +"Well I WILL, if you fool with me." + +"Oh yes--I've seen whole families in the same fix." + +"Smarty! You think you're SOME, now, DON'T you? Oh, what a hat!" + +"You can lump that hat if you don't like it. I dare you to knock it +off--and anybody that'll take a dare will suck eggs." + +"You're a liar!" + +"You're another." + +"You're a fighting liar and dasn't take it up." + +"Aw--take a walk!" + +"Say--if you give me much more of your sass I'll take and bounce a +rock off'n your head." + +"Oh, of COURSE you will." + +"Well I WILL." + +"Well why don't you DO it then? What do you keep SAYING you will for? +Why don't you DO it? It's because you're afraid." + +"I AIN'T afraid." + +"You are." + +"I ain't." + +"You are." + +Another pause, and more eying and sidling around each other. Presently +they were shoulder to shoulder. Tom said: + +"Get away from here!" + +"Go away yourself!" + +"I won't." + +"I won't either." + +So they stood, each with a foot placed at an angle as a brace, and +both shoving with might and main, and glowering at each other with +hate. But neither could get an advantage. After struggling till both +were hot and flushed, each relaxed his strain with watchful caution, +and Tom said: + +"You're a coward and a pup. I'll tell my big brother on you, and he +can thrash you with his little finger, and I'll make him do it, too." + +"What do I care for your big brother? I've got a brother that's bigger +than he is--and what's more, he can throw him over that fence, too." +[Both brothers were imaginary.] + +"That's a lie." + +"YOUR saying so don't make it so." + +Tom drew a line in the dust with his big toe, and said: + +"I dare you to step over that, and I'll lick you till you can't stand +up. Anybody that'll take a dare will steal sheep." + +The new boy stepped over promptly, and said: + +"Now you said you'd do it, now let's see you do it." + +"Don't you crowd me now; you better look out." + +"Well, you SAID you'd do it--why don't you do it?" + +"By jingo! for two cents I WILL do it." + +The new boy took two broad coppers out of his pocket and held them out +with derision. Tom struck them to the ground. In an instant both boys +were rolling and tumbling in the dirt, gripped together like cats; and +for the space of a minute they tugged and tore at each other's hair and +clothes, punched and scratched each other's nose, and covered +themselves with dust and glory. Presently the confusion took form, and +through the fog of battle Tom appeared, seated astride the new boy, and +pounding him with his fists. "Holler 'nuff!" said he. + +The boy only struggled to free himself. He was crying--mainly from rage. + +"Holler 'nuff!"--and the pounding went on. + +At last the stranger got out a smothered "'Nuff!" and Tom let him up +and said: + +"Now that'll learn you. Better look out who you're fooling with next +time." + +The new boy went off brushing the dust from his clothes, sobbing, +snuffling, and occasionally looking back and shaking his head and +threatening what he would do to Tom the "next time he caught him out." +To which Tom responded with jeers, and started off in high feather, and +as soon as his back was turned the new boy snatched up a stone, threw +it and hit him between the shoulders and then turned tail and ran like +an antelope. Tom chased the traitor home, and thus found out where he +lived. He then held a position at the gate for some time, daring the +enemy to come outside, but the enemy only made faces at him through the +window and declined. At last the enemy's mother appeared, and called +Tom a bad, vicious, vulgar child, and ordered him away. So he went +away; but he said he "'lowed" to "lay" for that boy. + +He got home pretty late that night, and when he climbed cautiously in +at the window, he uncovered an ambuscade, in the person of his aunt; +and when she saw the state his clothes were in her resolution to turn +his Saturday holiday into captivity at hard labor became adamantine in +its firmness. + + + +CHAPTER II + +SATURDAY morning was come, and all the summer world was bright and +fresh, and brimming with life. There was a song in every heart; and if +the heart was young the music issued at the lips. There was cheer in +every face and a spring in every step. The locust-trees were in bloom +and the fragrance of the blossoms filled the air. Cardiff Hill, beyond +the village and above it, was green with vegetation and it lay just far +enough away to seem a Delectable Land, dreamy, reposeful, and inviting. + +Tom appeared on the sidewalk with a bucket of whitewash and a +long-handled brush. He surveyed the fence, and all gladness left him and +a deep melancholy settled down upon his spirit. Thirty yards of board +fence nine feet high. Life to him seemed hollow, and existence but a +burden. Sighing, he dipped his brush and passed it along the topmost +plank; repeated the operation; did it again; compared the insignificant +whitewashed streak with the far-reaching continent of unwhitewashed +fence, and sat down on a tree-box discouraged. Jim came skipping out at +the gate with a tin pail, and singing Buffalo Gals. Bringing water from +the town pump had always been hateful work in Tom's eyes, before, but +now it did not strike him so. He remembered that there was company at +the pump. White, mulatto, and negro boys and girls were always there +waiting their turns, resting, trading playthings, quarrelling, +fighting, skylarking. And he remembered that although the pump was only +a hundred and fifty yards off, Jim never got back with a bucket of +water under an hour--and even then somebody generally had to go after +him. Tom said: + +"Say, Jim, I'll fetch the water if you'll whitewash some." + +Jim shook his head and said: + +"Can't, Mars Tom. Ole missis, she tole me I got to go an' git dis +water an' not stop foolin' roun' wid anybody. She say she spec' Mars +Tom gwine to ax me to whitewash, an' so she tole me go 'long an' 'tend +to my own business--she 'lowed SHE'D 'tend to de whitewashin'." + +"Oh, never you mind what she said, Jim. That's the way she always +talks. Gimme the bucket--I won't be gone only a a minute. SHE won't +ever know." + +"Oh, I dasn't, Mars Tom. Ole missis she'd take an' tar de head off'n +me. 'Deed she would." + +"SHE! She never licks anybody--whacks 'em over the head with her +thimble--and who cares for that, I'd like to know. She talks awful, but +talk don't hurt--anyways it don't if she don't cry. Jim, I'll give you +a marvel. I'll give you a white alley!" + +Jim began to waver. + +"White alley, Jim! And it's a bully taw." + +"My! Dat's a mighty gay marvel, I tell you! But Mars Tom I's powerful +'fraid ole missis--" + +"And besides, if you will I'll show you my sore toe." + +Jim was only human--this attraction was too much for him. He put down +his pail, took the white alley, and bent over the toe with absorbing +interest while the bandage was being unwound. In another moment he was +flying down the street with his pail and a tingling rear, Tom was +whitewashing with vigor, and Aunt Polly was retiring from the field +with a slipper in her hand and triumph in her eye. + +But Tom's energy did not last. He began to think of the fun he had +planned for this day, and his sorrows multiplied. Soon the free boys +would come tripping along on all sorts of delicious expeditions, and +they would make a world of fun of him for having to work--the very +thought of it burnt him like fire. He got out his worldly wealth and +examined it--bits of toys, marbles, and trash; enough to buy an +exchange of WORK, maybe, but not half enough to buy so much as half an +hour of pure freedom. So he returned his straitened means to his +pocket, and gave up the idea of trying to buy the boys. At this dark +and hopeless moment an inspiration burst upon him! Nothing less than a +great, magnificent inspiration. + +He took up his brush and went tranquilly to work. Ben Rogers hove in +sight presently--the very boy, of all boys, whose ridicule he had been +dreading. Ben's gait was the hop-skip-and-jump--proof enough that his +heart was light and his anticipations high. He was eating an apple, and +giving a long, melodious whoop, at intervals, followed by a deep-toned +ding-dong-dong, ding-dong-dong, for he was personating a steamboat. As +he drew near, he slackened speed, took the middle of the street, leaned +far over to starboard and rounded to ponderously and with laborious +pomp and circumstance--for he was personating the Big Missouri, and +considered himself to be drawing nine feet of water. He was boat and +captain and engine-bells combined, so he had to imagine himself +standing on his own hurricane-deck giving the orders and executing them: + +"Stop her, sir! Ting-a-ling-ling!" The headway ran almost out, and he +drew up slowly toward the sidewalk. + +"Ship up to back! Ting-a-ling-ling!" His arms straightened and +stiffened down his sides. + +"Set her back on the stabboard! Ting-a-ling-ling! Chow! ch-chow-wow! +Chow!" His right hand, meantime, describing stately circles--for it was +representing a forty-foot wheel. + +"Let her go back on the labboard! Ting-a-lingling! Chow-ch-chow-chow!" +The left hand began to describe circles. + +"Stop the stabboard! Ting-a-ling-ling! Stop the labboard! Come ahead +on the stabboard! Stop her! Let your outside turn over slow! +Ting-a-ling-ling! Chow-ow-ow! Get out that head-line! LIVELY now! +Come--out with your spring-line--what're you about there! Take a turn +round that stump with the bight of it! Stand by that stage, now--let her +go! Done with the engines, sir! Ting-a-ling-ling! SH'T! S'H'T! SH'T!" +(trying the gauge-cocks). + +Tom went on whitewashing--paid no attention to the steamboat. Ben +stared a moment and then said: "Hi-YI! YOU'RE up a stump, ain't you!" + +No answer. Tom surveyed his last touch with the eye of an artist, then +he gave his brush another gentle sweep and surveyed the result, as +before. Ben ranged up alongside of him. Tom's mouth watered for the +apple, but he stuck to his work. Ben said: + +"Hello, old chap, you got to work, hey?" + +Tom wheeled suddenly and said: + +"Why, it's you, Ben! I warn't noticing." + +"Say--I'm going in a-swimming, I am. Don't you wish you could? But of +course you'd druther WORK--wouldn't you? Course you would!" + +Tom contemplated the boy a bit, and said: + +"What do you call work?" + +"Why, ain't THAT work?" + +Tom resumed his whitewashing, and answered carelessly: + +"Well, maybe it is, and maybe it ain't. All I know, is, it suits Tom +Sawyer." + +"Oh come, now, you don't mean to let on that you LIKE it?" + +The brush continued to move. + +"Like it? Well, I don't see why I oughtn't to like it. Does a boy get +a chance to whitewash a fence every day?" + +That put the thing in a new light. Ben stopped nibbling his apple. Tom +swept his brush daintily back and forth--stepped back to note the +effect--added a touch here and there--criticised the effect again--Ben +watching every move and getting more and more interested, more and more +absorbed. Presently he said: + +"Say, Tom, let ME whitewash a little." + +Tom considered, was about to consent; but he altered his mind: + +"No--no--I reckon it wouldn't hardly do, Ben. You see, Aunt Polly's +awful particular about this fence--right here on the street, you know +--but if it was the back fence I wouldn't mind and SHE wouldn't. Yes, +she's awful particular about this fence; it's got to be done very +careful; I reckon there ain't one boy in a thousand, maybe two +thousand, that can do it the way it's got to be done." + +"No--is that so? Oh come, now--lemme just try. Only just a little--I'd +let YOU, if you was me, Tom." + +"Ben, I'd like to, honest injun; but Aunt Polly--well, Jim wanted to +do it, but she wouldn't let him; Sid wanted to do it, and she wouldn't +let Sid. Now don't you see how I'm fixed? If you was to tackle this +fence and anything was to happen to it--" + +"Oh, shucks, I'll be just as careful. Now lemme try. Say--I'll give +you the core of my apple." + +"Well, here--No, Ben, now don't. I'm afeard--" + +"I'll give you ALL of it!" + +Tom gave up the brush with reluctance in his face, but alacrity in his +heart. And while the late steamer Big Missouri worked and sweated in +the sun, the retired artist sat on a barrel in the shade close by, +dangled his legs, munched his apple, and planned the slaughter of more +innocents. There was no lack of material; boys happened along every +little while; they came to jeer, but remained to whitewash. By the time +Ben was fagged out, Tom had traded the next chance to Billy Fisher for +a kite, in good repair; and when he played out, Johnny Miller bought in +for a dead rat and a string to swing it with--and so on, and so on, +hour after hour. And when the middle of the afternoon came, from being +a poor poverty-stricken boy in the morning, Tom was literally rolling +in wealth. He had besides the things before mentioned, twelve marbles, +part of a jews-harp, a piece of blue bottle-glass to look through, a +spool cannon, a key that wouldn't unlock anything, a fragment of chalk, +a glass stopper of a decanter, a tin soldier, a couple of tadpoles, six +fire-crackers, a kitten with only one eye, a brass doorknob, a +dog-collar--but no dog--the handle of a knife, four pieces of +orange-peel, and a dilapidated old window sash. + +He had had a nice, good, idle time all the while--plenty of company +--and the fence had three coats of whitewash on it! If he hadn't run out +of whitewash he would have bankrupted every boy in the village. + +Tom said to himself that it was not such a hollow world, after all. He +had discovered a great law of human action, without knowing it--namely, +that in order to make a man or a boy covet a thing, it is only +necessary to make the thing difficult to attain. If he had been a great +and wise philosopher, like the writer of this book, he would now have +comprehended that Work consists of whatever a body is OBLIGED to do, +and that Play consists of whatever a body is not obliged to do. And +this would help him to understand why constructing artificial flowers +or performing on a tread-mill is work, while rolling ten-pins or +climbing Mont Blanc is only amusement. There are wealthy gentlemen in +England who drive four-horse passenger-coaches twenty or thirty miles +on a daily line, in the summer, because the privilege costs them +considerable money; but if they were offered wages for the service, +that would turn it into work and then they would resign. + +The boy mused awhile over the substantial change which had taken place +in his worldly circumstances, and then wended toward headquarters to +report. + + + +CHAPTER III + +TOM presented himself before Aunt Polly, who was sitting by an open +window in a pleasant rearward apartment, which was bedroom, +breakfast-room, dining-room, and library, combined. The balmy summer +air, the restful quiet, the odor of the flowers, and the drowsing murmur +of the bees had had their effect, and she was nodding over her knitting +--for she had no company but the cat, and it was asleep in her lap. Her +spectacles were propped up on her gray head for safety. She had thought +that of course Tom had deserted long ago, and she wondered at seeing him +place himself in her power again in this intrepid way. He said: "Mayn't +I go and play now, aunt?" + +"What, a'ready? How much have you done?" + +"It's all done, aunt." + +"Tom, don't lie to me--I can't bear it." + +"I ain't, aunt; it IS all done." + +Aunt Polly placed small trust in such evidence. She went out to see +for herself; and she would have been content to find twenty per cent. +of Tom's statement true. When she found the entire fence whitewashed, +and not only whitewashed but elaborately coated and recoated, and even +a streak added to the ground, her astonishment was almost unspeakable. +She said: + +"Well, I never! There's no getting round it, you can work when you're +a mind to, Tom." And then she diluted the compliment by adding, "But +it's powerful seldom you're a mind to, I'm bound to say. Well, go 'long +and play; but mind you get back some time in a week, or I'll tan you." + +She was so overcome by the splendor of his achievement that she took +him into the closet and selected a choice apple and delivered it to +him, along with an improving lecture upon the added value and flavor a +treat took to itself when it came without sin through virtuous effort. +And while she closed with a happy Scriptural flourish, he "hooked" a +doughnut. + +Then he skipped out, and saw Sid just starting up the outside stairway +that led to the back rooms on the second floor. Clods were handy and +the air was full of them in a twinkling. They raged around Sid like a +hail-storm; and before Aunt Polly could collect her surprised faculties +and sally to the rescue, six or seven clods had taken personal effect, +and Tom was over the fence and gone. There was a gate, but as a general +thing he was too crowded for time to make use of it. His soul was at +peace, now that he had settled with Sid for calling attention to his +black thread and getting him into trouble. + +Tom skirted the block, and came round into a muddy alley that led by +the back of his aunt's cow-stable. He presently got safely beyond the +reach of capture and punishment, and hastened toward the public square +of the village, where two "military" companies of boys had met for +conflict, according to previous appointment. Tom was General of one of +these armies, Joe Harper (a bosom friend) General of the other. These +two great commanders did not condescend to fight in person--that being +better suited to the still smaller fry--but sat together on an eminence +and conducted the field operations by orders delivered through +aides-de-camp. Tom's army won a great victory, after a long and +hard-fought battle. Then the dead were counted, prisoners exchanged, +the terms of the next disagreement agreed upon, and the day for the +necessary battle appointed; after which the armies fell into line and +marched away, and Tom turned homeward alone. + +As he was passing by the house where Jeff Thatcher lived, he saw a new +girl in the garden--a lovely little blue-eyed creature with yellow hair +plaited into two long-tails, white summer frock and embroidered +pantalettes. The fresh-crowned hero fell without firing a shot. A +certain Amy Lawrence vanished out of his heart and left not even a +memory of herself behind. He had thought he loved her to distraction; +he had regarded his passion as adoration; and behold it was only a poor +little evanescent partiality. He had been months winning her; she had +confessed hardly a week ago; he had been the happiest and the proudest +boy in the world only seven short days, and here in one instant of time +she had gone out of his heart like a casual stranger whose visit is +done. + +He worshipped this new angel with furtive eye, till he saw that she +had discovered him; then he pretended he did not know she was present, +and began to "show off" in all sorts of absurd boyish ways, in order to +win her admiration. He kept up this grotesque foolishness for some +time; but by-and-by, while he was in the midst of some dangerous +gymnastic performances, he glanced aside and saw that the little girl +was wending her way toward the house. Tom came up to the fence and +leaned on it, grieving, and hoping she would tarry yet awhile longer. +She halted a moment on the steps and then moved toward the door. Tom +heaved a great sigh as she put her foot on the threshold. But his face +lit up, right away, for she tossed a pansy over the fence a moment +before she disappeared. + +The boy ran around and stopped within a foot or two of the flower, and +then shaded his eyes with his hand and began to look down street as if +he had discovered something of interest going on in that direction. +Presently he picked up a straw and began trying to balance it on his +nose, with his head tilted far back; and as he moved from side to side, +in his efforts, he edged nearer and nearer toward the pansy; finally +his bare foot rested upon it, his pliant toes closed upon it, and he +hopped away with the treasure and disappeared round the corner. But +only for a minute--only while he could button the flower inside his +jacket, next his heart--or next his stomach, possibly, for he was not +much posted in anatomy, and not hypercritical, anyway. + +He returned, now, and hung about the fence till nightfall, "showing +off," as before; but the girl never exhibited herself again, though Tom +comforted himself a little with the hope that she had been near some +window, meantime, and been aware of his attentions. Finally he strode +home reluctantly, with his poor head full of visions. + +All through supper his spirits were so high that his aunt wondered +"what had got into the child." He took a good scolding about clodding +Sid, and did not seem to mind it in the least. He tried to steal sugar +under his aunt's very nose, and got his knuckles rapped for it. He said: + +"Aunt, you don't whack Sid when he takes it." + +"Well, Sid don't torment a body the way you do. You'd be always into +that sugar if I warn't watching you." + +Presently she stepped into the kitchen, and Sid, happy in his +immunity, reached for the sugar-bowl--a sort of glorying over Tom which +was wellnigh unbearable. But Sid's fingers slipped and the bowl dropped +and broke. Tom was in ecstasies. In such ecstasies that he even +controlled his tongue and was silent. He said to himself that he would +not speak a word, even when his aunt came in, but would sit perfectly +still till she asked who did the mischief; and then he would tell, and +there would be nothing so good in the world as to see that pet model +"catch it." He was so brimful of exultation that he could hardly hold +himself when the old lady came back and stood above the wreck +discharging lightnings of wrath from over her spectacles. He said to +himself, "Now it's coming!" And the next instant he was sprawling on +the floor! The potent palm was uplifted to strike again when Tom cried +out: + +"Hold on, now, what 'er you belting ME for?--Sid broke it!" + +Aunt Polly paused, perplexed, and Tom looked for healing pity. But +when she got her tongue again, she only said: + +"Umf! Well, you didn't get a lick amiss, I reckon. You been into some +other audacious mischief when I wasn't around, like enough." + +Then her conscience reproached her, and she yearned to say something +kind and loving; but she judged that this would be construed into a +confession that she had been in the wrong, and discipline forbade that. +So she kept silence, and went about her affairs with a troubled heart. +Tom sulked in a corner and exalted his woes. He knew that in her heart +his aunt was on her knees to him, and he was morosely gratified by the +consciousness of it. He would hang out no signals, he would take notice +of none. He knew that a yearning glance fell upon him, now and then, +through a film of tears, but he refused recognition of it. He pictured +himself lying sick unto death and his aunt bending over him beseeching +one little forgiving word, but he would turn his face to the wall, and +die with that word unsaid. Ah, how would she feel then? And he pictured +himself brought home from the river, dead, with his curls all wet, and +his sore heart at rest. How she would throw herself upon him, and how +her tears would fall like rain, and her lips pray God to give her back +her boy and she would never, never abuse him any more! But he would lie +there cold and white and make no sign--a poor little sufferer, whose +griefs were at an end. He so worked upon his feelings with the pathos +of these dreams, that he had to keep swallowing, he was so like to +choke; and his eyes swam in a blur of water, which overflowed when he +winked, and ran down and trickled from the end of his nose. And such a +luxury to him was this petting of his sorrows, that he could not bear +to have any worldly cheeriness or any grating delight intrude upon it; +it was too sacred for such contact; and so, presently, when his cousin +Mary danced in, all alive with the joy of seeing home again after an +age-long visit of one week to the country, he got up and moved in +clouds and darkness out at one door as she brought song and sunshine in +at the other. + +He wandered far from the accustomed haunts of boys, and sought +desolate places that were in harmony with his spirit. A log raft in the +river invited him, and he seated himself on its outer edge and +contemplated the dreary vastness of the stream, wishing, the while, +that he could only be drowned, all at once and unconsciously, without +undergoing the uncomfortable routine devised by nature. Then he thought +of his flower. He got it out, rumpled and wilted, and it mightily +increased his dismal felicity. He wondered if she would pity him if she +knew? Would she cry, and wish that she had a right to put her arms +around his neck and comfort him? Or would she turn coldly away like all +the hollow world? This picture brought such an agony of pleasurable +suffering that he worked it over and over again in his mind and set it +up in new and varied lights, till he wore it threadbare. At last he +rose up sighing and departed in the darkness. + +About half-past nine or ten o'clock he came along the deserted street +to where the Adored Unknown lived; he paused a moment; no sound fell +upon his listening ear; a candle was casting a dull glow upon the +curtain of a second-story window. Was the sacred presence there? He +climbed the fence, threaded his stealthy way through the plants, till +he stood under that window; he looked up at it long, and with emotion; +then he laid him down on the ground under it, disposing himself upon +his back, with his hands clasped upon his breast and holding his poor +wilted flower. And thus he would die--out in the cold world, with no +shelter over his homeless head, no friendly hand to wipe the +death-damps from his brow, no loving face to bend pityingly over him +when the great agony came. And thus SHE would see him when she looked +out upon the glad morning, and oh! would she drop one little tear upon +his poor, lifeless form, would she heave one little sigh to see a bright +young life so rudely blighted, so untimely cut down? + +The window went up, a maid-servant's discordant voice profaned the +holy calm, and a deluge of water drenched the prone martyr's remains! + +The strangling hero sprang up with a relieving snort. There was a whiz +as of a missile in the air, mingled with the murmur of a curse, a sound +as of shivering glass followed, and a small, vague form went over the +fence and shot away in the gloom. + +Not long after, as Tom, all undressed for bed, was surveying his +drenched garments by the light of a tallow dip, Sid woke up; but if he +had any dim idea of making any "references to allusions," he thought +better of it and held his peace, for there was danger in Tom's eye. + +Tom turned in without the added vexation of prayers, and Sid made +mental note of the omission. + + + +CHAPTER IV + +THE sun rose upon a tranquil world, and beamed down upon the peaceful +village like a benediction. Breakfast over, Aunt Polly had family +worship: it began with a prayer built from the ground up of solid +courses of Scriptural quotations, welded together with a thin mortar of +originality; and from the summit of this she delivered a grim chapter +of the Mosaic Law, as from Sinai. + +Then Tom girded up his loins, so to speak, and went to work to "get +his verses." Sid had learned his lesson days before. Tom bent all his +energies to the memorizing of five verses, and he chose part of the +Sermon on the Mount, because he could find no verses that were shorter. +At the end of half an hour Tom had a vague general idea of his lesson, +but no more, for his mind was traversing the whole field of human +thought, and his hands were busy with distracting recreations. Mary +took his book to hear him recite, and he tried to find his way through +the fog: + +"Blessed are the--a--a--" + +"Poor"-- + +"Yes--poor; blessed are the poor--a--a--" + +"In spirit--" + +"In spirit; blessed are the poor in spirit, for they--they--" + +"THEIRS--" + +"For THEIRS. Blessed are the poor in spirit, for theirs is the kingdom +of heaven. Blessed are they that mourn, for they--they--" + +"Sh--" + +"For they--a--" + +"S, H, A--" + +"For they S, H--Oh, I don't know what it is!" + +"SHALL!" + +"Oh, SHALL! for they shall--for they shall--a--a--shall mourn--a--a-- +blessed are they that shall--they that--a--they that shall mourn, for +they shall--a--shall WHAT? Why don't you tell me, Mary?--what do you +want to be so mean for?" + +"Oh, Tom, you poor thick-headed thing, I'm not teasing you. I wouldn't +do that. You must go and learn it again. Don't you be discouraged, Tom, +you'll manage it--and if you do, I'll give you something ever so nice. +There, now, that's a good boy." + +"All right! What is it, Mary, tell me what it is." + +"Never you mind, Tom. You know if I say it's nice, it is nice." + +"You bet you that's so, Mary. All right, I'll tackle it again." + +And he did "tackle it again"--and under the double pressure of +curiosity and prospective gain he did it with such spirit that he +accomplished a shining success. Mary gave him a brand-new "Barlow" +knife worth twelve and a half cents; and the convulsion of delight that +swept his system shook him to his foundations. True, the knife would +not cut anything, but it was a "sure-enough" Barlow, and there was +inconceivable grandeur in that--though where the Western boys ever got +the idea that such a weapon could possibly be counterfeited to its +injury is an imposing mystery and will always remain so, perhaps. Tom +contrived to scarify the cupboard with it, and was arranging to begin +on the bureau, when he was called off to dress for Sunday-school. + +Mary gave him a tin basin of water and a piece of soap, and he went +outside the door and set the basin on a little bench there; then he +dipped the soap in the water and laid it down; turned up his sleeves; +poured out the water on the ground, gently, and then entered the +kitchen and began to wipe his face diligently on the towel behind the +door. But Mary removed the towel and said: + +"Now ain't you ashamed, Tom. You mustn't be so bad. Water won't hurt +you." + +Tom was a trifle disconcerted. The basin was refilled, and this time +he stood over it a little while, gathering resolution; took in a big +breath and began. When he entered the kitchen presently, with both eyes +shut and groping for the towel with his hands, an honorable testimony +of suds and water was dripping from his face. But when he emerged from +the towel, he was not yet satisfactory, for the clean territory stopped +short at his chin and his jaws, like a mask; below and beyond this line +there was a dark expanse of unirrigated soil that spread downward in +front and backward around his neck. Mary took him in hand, and when she +was done with him he was a man and a brother, without distinction of +color, and his saturated hair was neatly brushed, and its short curls +wrought into a dainty and symmetrical general effect. [He privately +smoothed out the curls, with labor and difficulty, and plastered his +hair close down to his head; for he held curls to be effeminate, and +his own filled his life with bitterness.] Then Mary got out a suit of +his clothing that had been used only on Sundays during two years--they +were simply called his "other clothes"--and so by that we know the +size of his wardrobe. The girl "put him to rights" after he had dressed +himself; she buttoned his neat roundabout up to his chin, turned his +vast shirt collar down over his shoulders, brushed him off and crowned +him with his speckled straw hat. He now looked exceedingly improved and +uncomfortable. He was fully as uncomfortable as he looked; for there +was a restraint about whole clothes and cleanliness that galled him. He +hoped that Mary would forget his shoes, but the hope was blighted; she +coated them thoroughly with tallow, as was the custom, and brought them +out. He lost his temper and said he was always being made to do +everything he didn't want to do. But Mary said, persuasively: + +"Please, Tom--that's a good boy." + +So he got into the shoes snarling. Mary was soon ready, and the three +children set out for Sunday-school--a place that Tom hated with his +whole heart; but Sid and Mary were fond of it. + +Sabbath-school hours were from nine to half-past ten; and then church +service. Two of the children always remained for the sermon +voluntarily, and the other always remained too--for stronger reasons. +The church's high-backed, uncushioned pews would seat about three +hundred persons; the edifice was but a small, plain affair, with a sort +of pine board tree-box on top of it for a steeple. At the door Tom +dropped back a step and accosted a Sunday-dressed comrade: + +"Say, Billy, got a yaller ticket?" + +"Yes." + +"What'll you take for her?" + +"What'll you give?" + +"Piece of lickrish and a fish-hook." + +"Less see 'em." + +Tom exhibited. They were satisfactory, and the property changed hands. +Then Tom traded a couple of white alleys for three red tickets, and +some small trifle or other for a couple of blue ones. He waylaid other +boys as they came, and went on buying tickets of various colors ten or +fifteen minutes longer. He entered the church, now, with a swarm of +clean and noisy boys and girls, proceeded to his seat and started a +quarrel with the first boy that came handy. The teacher, a grave, +elderly man, interfered; then turned his back a moment and Tom pulled a +boy's hair in the next bench, and was absorbed in his book when the boy +turned around; stuck a pin in another boy, presently, in order to hear +him say "Ouch!" and got a new reprimand from his teacher. Tom's whole +class were of a pattern--restless, noisy, and troublesome. When they +came to recite their lessons, not one of them knew his verses +perfectly, but had to be prompted all along. However, they worried +through, and each got his reward--in small blue tickets, each with a +passage of Scripture on it; each blue ticket was pay for two verses of +the recitation. Ten blue tickets equalled a red one, and could be +exchanged for it; ten red tickets equalled a yellow one; for ten yellow +tickets the superintendent gave a very plainly bound Bible (worth forty +cents in those easy times) to the pupil. How many of my readers would +have the industry and application to memorize two thousand verses, even +for a Dore Bible? And yet Mary had acquired two Bibles in this way--it +was the patient work of two years--and a boy of German parentage had +won four or five. He once recited three thousand verses without +stopping; but the strain upon his mental faculties was too great, and +he was little better than an idiot from that day forth--a grievous +misfortune for the school, for on great occasions, before company, the +superintendent (as Tom expressed it) had always made this boy come out +and "spread himself." Only the older pupils managed to keep their +tickets and stick to their tedious work long enough to get a Bible, and +so the delivery of one of these prizes was a rare and noteworthy +circumstance; the successful pupil was so great and conspicuous for +that day that on the spot every scholar's heart was fired with a fresh +ambition that often lasted a couple of weeks. It is possible that Tom's +mental stomach had never really hungered for one of those prizes, but +unquestionably his entire being had for many a day longed for the glory +and the eclat that came with it. + +In due course the superintendent stood up in front of the pulpit, with +a closed hymn-book in his hand and his forefinger inserted between its +leaves, and commanded attention. When a Sunday-school superintendent +makes his customary little speech, a hymn-book in the hand is as +necessary as is the inevitable sheet of music in the hand of a singer +who stands forward on the platform and sings a solo at a concert +--though why, is a mystery: for neither the hymn-book nor the sheet of +music is ever referred to by the sufferer. This superintendent was a +slim creature of thirty-five, with a sandy goatee and short sandy hair; +he wore a stiff standing-collar whose upper edge almost reached his +ears and whose sharp points curved forward abreast the corners of his +mouth--a fence that compelled a straight lookout ahead, and a turning +of the whole body when a side view was required; his chin was propped +on a spreading cravat which was as broad and as long as a bank-note, +and had fringed ends; his boot toes were turned sharply up, in the +fashion of the day, like sleigh-runners--an effect patiently and +laboriously produced by the young men by sitting with their toes +pressed against a wall for hours together. Mr. Walters was very earnest +of mien, and very sincere and honest at heart; and he held sacred +things and places in such reverence, and so separated them from worldly +matters, that unconsciously to himself his Sunday-school voice had +acquired a peculiar intonation which was wholly absent on week-days. He +began after this fashion: + +"Now, children, I want you all to sit up just as straight and pretty +as you can and give me all your attention for a minute or two. There +--that is it. That is the way good little boys and girls should do. I see +one little girl who is looking out of the window--I am afraid she +thinks I am out there somewhere--perhaps up in one of the trees making +a speech to the little birds. [Applausive titter.] I want to tell you +how good it makes me feel to see so many bright, clean little faces +assembled in a place like this, learning to do right and be good." And +so forth and so on. It is not necessary to set down the rest of the +oration. It was of a pattern which does not vary, and so it is familiar +to us all. + +The latter third of the speech was marred by the resumption of fights +and other recreations among certain of the bad boys, and by fidgetings +and whisperings that extended far and wide, washing even to the bases +of isolated and incorruptible rocks like Sid and Mary. But now every +sound ceased suddenly, with the subsidence of Mr. Walters' voice, and +the conclusion of the speech was received with a burst of silent +gratitude. + +A good part of the whispering had been occasioned by an event which +was more or less rare--the entrance of visitors: lawyer Thatcher, +accompanied by a very feeble and aged man; a fine, portly, middle-aged +gentleman with iron-gray hair; and a dignified lady who was doubtless +the latter's wife. The lady was leading a child. Tom had been restless +and full of chafings and repinings; conscience-smitten, too--he could +not meet Amy Lawrence's eye, he could not brook her loving gaze. But +when he saw this small new-comer his soul was all ablaze with bliss in +a moment. The next moment he was "showing off" with all his might +--cuffing boys, pulling hair, making faces--in a word, using every art +that seemed likely to fascinate a girl and win her applause. His +exaltation had but one alloy--the memory of his humiliation in this +angel's garden--and that record in sand was fast washing out, under +the waves of happiness that were sweeping over it now. + +The visitors were given the highest seat of honor, and as soon as Mr. +Walters' speech was finished, he introduced them to the school. The +middle-aged man turned out to be a prodigious personage--no less a one +than the county judge--altogether the most august creation these +children had ever looked upon--and they wondered what kind of material +he was made of--and they half wanted to hear him roar, and were half +afraid he might, too. He was from Constantinople, twelve miles away--so +he had travelled, and seen the world--these very eyes had looked upon +the county court-house--which was said to have a tin roof. The awe +which these reflections inspired was attested by the impressive silence +and the ranks of staring eyes. This was the great Judge Thatcher, +brother of their own lawyer. Jeff Thatcher immediately went forward, to +be familiar with the great man and be envied by the school. It would +have been music to his soul to hear the whisperings: + +"Look at him, Jim! He's a going up there. Say--look! he's a going to +shake hands with him--he IS shaking hands with him! By jings, don't you +wish you was Jeff?" + +Mr. Walters fell to "showing off," with all sorts of official +bustlings and activities, giving orders, delivering judgments, +discharging directions here, there, everywhere that he could find a +target. The librarian "showed off"--running hither and thither with his +arms full of books and making a deal of the splutter and fuss that +insect authority delights in. The young lady teachers "showed off" +--bending sweetly over pupils that were lately being boxed, lifting +pretty warning fingers at bad little boys and patting good ones +lovingly. The young gentlemen teachers "showed off" with small +scoldings and other little displays of authority and fine attention to +discipline--and most of the teachers, of both sexes, found business up +at the library, by the pulpit; and it was business that frequently had +to be done over again two or three times (with much seeming vexation). +The little girls "showed off" in various ways, and the little boys +"showed off" with such diligence that the air was thick with paper wads +and the murmur of scufflings. And above it all the great man sat and +beamed a majestic judicial smile upon all the house, and warmed himself +in the sun of his own grandeur--for he was "showing off," too. + +There was only one thing wanting to make Mr. Walters' ecstasy +complete, and that was a chance to deliver a Bible-prize and exhibit a +prodigy. Several pupils had a few yellow tickets, but none had enough +--he had been around among the star pupils inquiring. He would have given +worlds, now, to have that German lad back again with a sound mind. + +And now at this moment, when hope was dead, Tom Sawyer came forward +with nine yellow tickets, nine red tickets, and ten blue ones, and +demanded a Bible. This was a thunderbolt out of a clear sky. Walters +was not expecting an application from this source for the next ten +years. But there was no getting around it--here were the certified +checks, and they were good for their face. Tom was therefore elevated +to a place with the Judge and the other elect, and the great news was +announced from headquarters. It was the most stunning surprise of the +decade, and so profound was the sensation that it lifted the new hero +up to the judicial one's altitude, and the school had two marvels to +gaze upon in place of one. The boys were all eaten up with envy--but +those that suffered the bitterest pangs were those who perceived too +late that they themselves had contributed to this hated splendor by +trading tickets to Tom for the wealth he had amassed in selling +whitewashing privileges. These despised themselves, as being the dupes +of a wily fraud, a guileful snake in the grass. + +The prize was delivered to Tom with as much effusion as the +superintendent could pump up under the circumstances; but it lacked +somewhat of the true gush, for the poor fellow's instinct taught him +that there was a mystery here that could not well bear the light, +perhaps; it was simply preposterous that this boy had warehoused two +thousand sheaves of Scriptural wisdom on his premises--a dozen would +strain his capacity, without a doubt. + +Amy Lawrence was proud and glad, and she tried to make Tom see it in +her face--but he wouldn't look. She wondered; then she was just a grain +troubled; next a dim suspicion came and went--came again; she watched; +a furtive glance told her worlds--and then her heart broke, and she was +jealous, and angry, and the tears came and she hated everybody. Tom +most of all (she thought). + +Tom was introduced to the Judge; but his tongue was tied, his breath +would hardly come, his heart quaked--partly because of the awful +greatness of the man, but mainly because he was her parent. He would +have liked to fall down and worship him, if it were in the dark. The +Judge put his hand on Tom's head and called him a fine little man, and +asked him what his name was. The boy stammered, gasped, and got it out: + +"Tom." + +"Oh, no, not Tom--it is--" + +"Thomas." + +"Ah, that's it. I thought there was more to it, maybe. That's very +well. But you've another one I daresay, and you'll tell it to me, won't +you?" + +"Tell the gentleman your other name, Thomas," said Walters, "and say +sir. You mustn't forget your manners." + +"Thomas Sawyer--sir." + +"That's it! That's a good boy. Fine boy. Fine, manly little fellow. +Two thousand verses is a great many--very, very great many. And you +never can be sorry for the trouble you took to learn them; for +knowledge is worth more than anything there is in the world; it's what +makes great men and good men; you'll be a great man and a good man +yourself, some day, Thomas, and then you'll look back and say, It's all +owing to the precious Sunday-school privileges of my boyhood--it's all +owing to my dear teachers that taught me to learn--it's all owing to +the good superintendent, who encouraged me, and watched over me, and +gave me a beautiful Bible--a splendid elegant Bible--to keep and have +it all for my own, always--it's all owing to right bringing up! That is +what you will say, Thomas--and you wouldn't take any money for those +two thousand verses--no indeed you wouldn't. And now you wouldn't mind +telling me and this lady some of the things you've learned--no, I know +you wouldn't--for we are proud of little boys that learn. Now, no +doubt you know the names of all the twelve disciples. Won't you tell us +the names of the first two that were appointed?" + +Tom was tugging at a button-hole and looking sheepish. He blushed, +now, and his eyes fell. Mr. Walters' heart sank within him. He said to +himself, it is not possible that the boy can answer the simplest +question--why DID the Judge ask him? Yet he felt obliged to speak up +and say: + +"Answer the gentleman, Thomas--don't be afraid." + +Tom still hung fire. + +"Now I know you'll tell me," said the lady. "The names of the first +two disciples were--" + +"DAVID AND GOLIAH!" + +Let us draw the curtain of charity over the rest of the scene. + + + +CHAPTER V + +ABOUT half-past ten the cracked bell of the small church began to +ring, and presently the people began to gather for the morning sermon. +The Sunday-school children distributed themselves about the house and +occupied pews with their parents, so as to be under supervision. Aunt +Polly came, and Tom and Sid and Mary sat with her--Tom being placed +next the aisle, in order that he might be as far away from the open +window and the seductive outside summer scenes as possible. The crowd +filed up the aisles: the aged and needy postmaster, who had seen better +days; the mayor and his wife--for they had a mayor there, among other +unnecessaries; the justice of the peace; the widow Douglass, fair, +smart, and forty, a generous, good-hearted soul and well-to-do, her +hill mansion the only palace in the town, and the most hospitable and +much the most lavish in the matter of festivities that St. Petersburg +could boast; the bent and venerable Major and Mrs. Ward; lawyer +Riverson, the new notable from a distance; next the belle of the +village, followed by a troop of lawn-clad and ribbon-decked young +heart-breakers; then all the young clerks in town in a body--for they +had stood in the vestibule sucking their cane-heads, a circling wall of +oiled and simpering admirers, till the last girl had run their gantlet; +and last of all came the Model Boy, Willie Mufferson, taking as heedful +care of his mother as if she were cut glass. He always brought his +mother to church, and was the pride of all the matrons. The boys all +hated him, he was so good. And besides, he had been "thrown up to them" +so much. His white handkerchief was hanging out of his pocket behind, as +usual on Sundays--accidentally. Tom had no handkerchief, and he looked +upon boys who had as snobs. + +The congregation being fully assembled, now, the bell rang once more, +to warn laggards and stragglers, and then a solemn hush fell upon the +church which was only broken by the tittering and whispering of the +choir in the gallery. The choir always tittered and whispered all +through service. There was once a church choir that was not ill-bred, +but I have forgotten where it was, now. It was a great many years ago, +and I can scarcely remember anything about it, but I think it was in +some foreign country. + +The minister gave out the hymn, and read it through with a relish, in +a peculiar style which was much admired in that part of the country. +His voice began on a medium key and climbed steadily up till it reached +a certain point, where it bore with strong emphasis upon the topmost +word and then plunged down as if from a spring-board: + + Shall I be car-ri-ed toe the skies, on flow'ry BEDS of ease, + + Whilst others fight to win the prize, and sail thro' BLOODY seas? + +He was regarded as a wonderful reader. At church "sociables" he was +always called upon to read poetry; and when he was through, the ladies +would lift up their hands and let them fall helplessly in their laps, +and "wall" their eyes, and shake their heads, as much as to say, "Words +cannot express it; it is too beautiful, TOO beautiful for this mortal +earth." + +After the hymn had been sung, the Rev. Mr. Sprague turned himself into +a bulletin-board, and read off "notices" of meetings and societies and +things till it seemed that the list would stretch out to the crack of +doom--a queer custom which is still kept up in America, even in cities, +away here in this age of abundant newspapers. Often, the less there is +to justify a traditional custom, the harder it is to get rid of it. + +And now the minister prayed. A good, generous prayer it was, and went +into details: it pleaded for the church, and the little children of the +church; for the other churches of the village; for the village itself; +for the county; for the State; for the State officers; for the United +States; for the churches of the United States; for Congress; for the +President; for the officers of the Government; for poor sailors, tossed +by stormy seas; for the oppressed millions groaning under the heel of +European monarchies and Oriental despotisms; for such as have the light +and the good tidings, and yet have not eyes to see nor ears to hear +withal; for the heathen in the far islands of the sea; and closed with +a supplication that the words he was about to speak might find grace +and favor, and be as seed sown in fertile ground, yielding in time a +grateful harvest of good. Amen. + +There was a rustling of dresses, and the standing congregation sat +down. The boy whose history this book relates did not enjoy the prayer, +he only endured it--if he even did that much. He was restive all +through it; he kept tally of the details of the prayer, unconsciously +--for he was not listening, but he knew the ground of old, and the +clergyman's regular route over it--and when a little trifle of new +matter was interlarded, his ear detected it and his whole nature +resented it; he considered additions unfair, and scoundrelly. In the +midst of the prayer a fly had lit on the back of the pew in front of +him and tortured his spirit by calmly rubbing its hands together, +embracing its head with its arms, and polishing it so vigorously that +it seemed to almost part company with the body, and the slender thread +of a neck was exposed to view; scraping its wings with its hind legs +and smoothing them to its body as if they had been coat-tails; going +through its whole toilet as tranquilly as if it knew it was perfectly +safe. As indeed it was; for as sorely as Tom's hands itched to grab for +it they did not dare--he believed his soul would be instantly destroyed +if he did such a thing while the prayer was going on. But with the +closing sentence his hand began to curve and steal forward; and the +instant the "Amen" was out the fly was a prisoner of war. His aunt +detected the act and made him let it go. + +The minister gave out his text and droned along monotonously through +an argument that was so prosy that many a head by and by began to nod +--and yet it was an argument that dealt in limitless fire and brimstone +and thinned the predestined elect down to a company so small as to be +hardly worth the saving. Tom counted the pages of the sermon; after +church he always knew how many pages there had been, but he seldom knew +anything else about the discourse. However, this time he was really +interested for a little while. The minister made a grand and moving +picture of the assembling together of the world's hosts at the +millennium when the lion and the lamb should lie down together and a +little child should lead them. But the pathos, the lesson, the moral of +the great spectacle were lost upon the boy; he only thought of the +conspicuousness of the principal character before the on-looking +nations; his face lit with the thought, and he said to himself that he +wished he could be that child, if it was a tame lion. + +Now he lapsed into suffering again, as the dry argument was resumed. +Presently he bethought him of a treasure he had and got it out. It was +a large black beetle with formidable jaws--a "pinchbug," he called it. +It was in a percussion-cap box. The first thing the beetle did was to +take him by the finger. A natural fillip followed, the beetle went +floundering into the aisle and lit on its back, and the hurt finger +went into the boy's mouth. The beetle lay there working its helpless +legs, unable to turn over. Tom eyed it, and longed for it; but it was +safe out of his reach. Other people uninterested in the sermon found +relief in the beetle, and they eyed it too. Presently a vagrant poodle +dog came idling along, sad at heart, lazy with the summer softness and +the quiet, weary of captivity, sighing for change. He spied the beetle; +the drooping tail lifted and wagged. He surveyed the prize; walked +around it; smelt at it from a safe distance; walked around it again; +grew bolder, and took a closer smell; then lifted his lip and made a +gingerly snatch at it, just missing it; made another, and another; +began to enjoy the diversion; subsided to his stomach with the beetle +between his paws, and continued his experiments; grew weary at last, +and then indifferent and absent-minded. His head nodded, and little by +little his chin descended and touched the enemy, who seized it. There +was a sharp yelp, a flirt of the poodle's head, and the beetle fell a +couple of yards away, and lit on its back once more. The neighboring +spectators shook with a gentle inward joy, several faces went behind +fans and handkerchiefs, and Tom was entirely happy. The dog looked +foolish, and probably felt so; but there was resentment in his heart, +too, and a craving for revenge. So he went to the beetle and began a +wary attack on it again; jumping at it from every point of a circle, +lighting with his fore-paws within an inch of the creature, making even +closer snatches at it with his teeth, and jerking his head till his +ears flapped again. But he grew tired once more, after a while; tried +to amuse himself with a fly but found no relief; followed an ant +around, with his nose close to the floor, and quickly wearied of that; +yawned, sighed, forgot the beetle entirely, and sat down on it. Then +there was a wild yelp of agony and the poodle went sailing up the +aisle; the yelps continued, and so did the dog; he crossed the house in +front of the altar; he flew down the other aisle; he crossed before the +doors; he clamored up the home-stretch; his anguish grew with his +progress, till presently he was but a woolly comet moving in its orbit +with the gleam and the speed of light. At last the frantic sufferer +sheered from its course, and sprang into its master's lap; he flung it +out of the window, and the voice of distress quickly thinned away and +died in the distance. + +By this time the whole church was red-faced and suffocating with +suppressed laughter, and the sermon had come to a dead standstill. The +discourse was resumed presently, but it went lame and halting, all +possibility of impressiveness being at an end; for even the gravest +sentiments were constantly being received with a smothered burst of +unholy mirth, under cover of some remote pew-back, as if the poor +parson had said a rarely facetious thing. It was a genuine relief to +the whole congregation when the ordeal was over and the benediction +pronounced. + +Tom Sawyer went home quite cheerful, thinking to himself that there +was some satisfaction about divine service when there was a bit of +variety in it. He had but one marring thought; he was willing that the +dog should play with his pinchbug, but he did not think it was upright +in him to carry it off. + + + +CHAPTER VI + +MONDAY morning found Tom Sawyer miserable. Monday morning always found +him so--because it began another week's slow suffering in school. He +generally began that day with wishing he had had no intervening +holiday, it made the going into captivity and fetters again so much +more odious. + +Tom lay thinking. Presently it occurred to him that he wished he was +sick; then he could stay home from school. Here was a vague +possibility. He canvassed his system. No ailment was found, and he +investigated again. This time he thought he could detect colicky +symptoms, and he began to encourage them with considerable hope. But +they soon grew feeble, and presently died wholly away. He reflected +further. Suddenly he discovered something. One of his upper front teeth +was loose. This was lucky; he was about to begin to groan, as a +"starter," as he called it, when it occurred to him that if he came +into court with that argument, his aunt would pull it out, and that +would hurt. So he thought he would hold the tooth in reserve for the +present, and seek further. Nothing offered for some little time, and +then he remembered hearing the doctor tell about a certain thing that +laid up a patient for two or three weeks and threatened to make him +lose a finger. So the boy eagerly drew his sore toe from under the +sheet and held it up for inspection. But now he did not know the +necessary symptoms. However, it seemed well worth while to chance it, +so he fell to groaning with considerable spirit. + +But Sid slept on unconscious. + +Tom groaned louder, and fancied that he began to feel pain in the toe. + +No result from Sid. + +Tom was panting with his exertions by this time. He took a rest and +then swelled himself up and fetched a succession of admirable groans. + +Sid snored on. + +Tom was aggravated. He said, "Sid, Sid!" and shook him. This course +worked well, and Tom began to groan again. Sid yawned, stretched, then +brought himself up on his elbow with a snort, and began to stare at +Tom. Tom went on groaning. Sid said: + +"Tom! Say, Tom!" [No response.] "Here, Tom! TOM! What is the matter, +Tom?" And he shook him and looked in his face anxiously. + +Tom moaned out: + +"Oh, don't, Sid. Don't joggle me." + +"Why, what's the matter, Tom? I must call auntie." + +"No--never mind. It'll be over by and by, maybe. Don't call anybody." + +"But I must! DON'T groan so, Tom, it's awful. How long you been this +way?" + +"Hours. Ouch! Oh, don't stir so, Sid, you'll kill me." + +"Tom, why didn't you wake me sooner? Oh, Tom, DON'T! It makes my +flesh crawl to hear you. Tom, what is the matter?" + +"I forgive you everything, Sid. [Groan.] Everything you've ever done +to me. When I'm gone--" + +"Oh, Tom, you ain't dying, are you? Don't, Tom--oh, don't. Maybe--" + +"I forgive everybody, Sid. [Groan.] Tell 'em so, Sid. And Sid, you +give my window-sash and my cat with one eye to that new girl that's +come to town, and tell her--" + +But Sid had snatched his clothes and gone. Tom was suffering in +reality, now, so handsomely was his imagination working, and so his +groans had gathered quite a genuine tone. + +Sid flew down-stairs and said: + +"Oh, Aunt Polly, come! Tom's dying!" + +"Dying!" + +"Yes'm. Don't wait--come quick!" + +"Rubbage! I don't believe it!" + +But she fled up-stairs, nevertheless, with Sid and Mary at her heels. +And her face grew white, too, and her lip trembled. When she reached +the bedside she gasped out: + +"You, Tom! Tom, what's the matter with you?" + +"Oh, auntie, I'm--" + +"What's the matter with you--what is the matter with you, child?" + +"Oh, auntie, my sore toe's mortified!" + +The old lady sank down into a chair and laughed a little, then cried a +little, then did both together. This restored her and she said: + +"Tom, what a turn you did give me. Now you shut up that nonsense and +climb out of this." + +The groans ceased and the pain vanished from the toe. The boy felt a +little foolish, and he said: + +"Aunt Polly, it SEEMED mortified, and it hurt so I never minded my +tooth at all." + +"Your tooth, indeed! What's the matter with your tooth?" + +"One of them's loose, and it aches perfectly awful." + +"There, there, now, don't begin that groaning again. Open your mouth. +Well--your tooth IS loose, but you're not going to die about that. +Mary, get me a silk thread, and a chunk of fire out of the kitchen." + +Tom said: + +"Oh, please, auntie, don't pull it out. It don't hurt any more. I wish +I may never stir if it does. Please don't, auntie. I don't want to stay +home from school." + +"Oh, you don't, don't you? So all this row was because you thought +you'd get to stay home from school and go a-fishing? Tom, Tom, I love +you so, and you seem to try every way you can to break my old heart +with your outrageousness." By this time the dental instruments were +ready. The old lady made one end of the silk thread fast to Tom's tooth +with a loop and tied the other to the bedpost. Then she seized the +chunk of fire and suddenly thrust it almost into the boy's face. The +tooth hung dangling by the bedpost, now. + +But all trials bring their compensations. As Tom wended to school +after breakfast, he was the envy of every boy he met because the gap in +his upper row of teeth enabled him to expectorate in a new and +admirable way. He gathered quite a following of lads interested in the +exhibition; and one that had cut his finger and had been a centre of +fascination and homage up to this time, now found himself suddenly +without an adherent, and shorn of his glory. His heart was heavy, and +he said with a disdain which he did not feel that it wasn't anything to +spit like Tom Sawyer; but another boy said, "Sour grapes!" and he +wandered away a dismantled hero. + +Shortly Tom came upon the juvenile pariah of the village, Huckleberry +Finn, son of the town drunkard. Huckleberry was cordially hated and +dreaded by all the mothers of the town, because he was idle and lawless +and vulgar and bad--and because all their children admired him so, and +delighted in his forbidden society, and wished they dared to be like +him. Tom was like the rest of the respectable boys, in that he envied +Huckleberry his gaudy outcast condition, and was under strict orders +not to play with him. So he played with him every time he got a chance. +Huckleberry was always dressed in the cast-off clothes of full-grown +men, and they were in perennial bloom and fluttering with rags. His hat +was a vast ruin with a wide crescent lopped out of its brim; his coat, +when he wore one, hung nearly to his heels and had the rearward buttons +far down the back; but one suspender supported his trousers; the seat +of the trousers bagged low and contained nothing, the fringed legs +dragged in the dirt when not rolled up. + +Huckleberry came and went, at his own free will. He slept on doorsteps +in fine weather and in empty hogsheads in wet; he did not have to go to +school or to church, or call any being master or obey anybody; he could +go fishing or swimming when and where he chose, and stay as long as it +suited him; nobody forbade him to fight; he could sit up as late as he +pleased; he was always the first boy that went barefoot in the spring +and the last to resume leather in the fall; he never had to wash, nor +put on clean clothes; he could swear wonderfully. In a word, everything +that goes to make life precious that boy had. So thought every +harassed, hampered, respectable boy in St. Petersburg. + +Tom hailed the romantic outcast: + +"Hello, Huckleberry!" + +"Hello yourself, and see how you like it." + +"What's that you got?" + +"Dead cat." + +"Lemme see him, Huck. My, he's pretty stiff. Where'd you get him?" + +"Bought him off'n a boy." + +"What did you give?" + +"I give a blue ticket and a bladder that I got at the slaughter-house." + +"Where'd you get the blue ticket?" + +"Bought it off'n Ben Rogers two weeks ago for a hoop-stick." + +"Say--what is dead cats good for, Huck?" + +"Good for? Cure warts with." + +"No! Is that so? I know something that's better." + +"I bet you don't. What is it?" + +"Why, spunk-water." + +"Spunk-water! I wouldn't give a dern for spunk-water." + +"You wouldn't, wouldn't you? D'you ever try it?" + +"No, I hain't. But Bob Tanner did." + +"Who told you so!" + +"Why, he told Jeff Thatcher, and Jeff told Johnny Baker, and Johnny +told Jim Hollis, and Jim told Ben Rogers, and Ben told a nigger, and +the nigger told me. There now!" + +"Well, what of it? They'll all lie. Leastways all but the nigger. I +don't know HIM. But I never see a nigger that WOULDN'T lie. Shucks! Now +you tell me how Bob Tanner done it, Huck." + +"Why, he took and dipped his hand in a rotten stump where the +rain-water was." + +"In the daytime?" + +"Certainly." + +"With his face to the stump?" + +"Yes. Least I reckon so." + +"Did he say anything?" + +"I don't reckon he did. I don't know." + +"Aha! Talk about trying to cure warts with spunk-water such a blame +fool way as that! Why, that ain't a-going to do any good. You got to go +all by yourself, to the middle of the woods, where you know there's a +spunk-water stump, and just as it's midnight you back up against the +stump and jam your hand in and say: + + 'Barley-corn, barley-corn, injun-meal shorts, + Spunk-water, spunk-water, swaller these warts,' + +and then walk away quick, eleven steps, with your eyes shut, and then +turn around three times and walk home without speaking to anybody. +Because if you speak the charm's busted." + +"Well, that sounds like a good way; but that ain't the way Bob Tanner +done." + +"No, sir, you can bet he didn't, becuz he's the wartiest boy in this +town; and he wouldn't have a wart on him if he'd knowed how to work +spunk-water. I've took off thousands of warts off of my hands that way, +Huck. I play with frogs so much that I've always got considerable many +warts. Sometimes I take 'em off with a bean." + +"Yes, bean's good. I've done that." + +"Have you? What's your way?" + +"You take and split the bean, and cut the wart so as to get some +blood, and then you put the blood on one piece of the bean and take and +dig a hole and bury it 'bout midnight at the crossroads in the dark of +the moon, and then you burn up the rest of the bean. You see that piece +that's got the blood on it will keep drawing and drawing, trying to +fetch the other piece to it, and so that helps the blood to draw the +wart, and pretty soon off she comes." + +"Yes, that's it, Huck--that's it; though when you're burying it if you +say 'Down bean; off wart; come no more to bother me!' it's better. +That's the way Joe Harper does, and he's been nearly to Coonville and +most everywheres. But say--how do you cure 'em with dead cats?" + +"Why, you take your cat and go and get in the graveyard 'long about +midnight when somebody that was wicked has been buried; and when it's +midnight a devil will come, or maybe two or three, but you can't see +'em, you can only hear something like the wind, or maybe hear 'em talk; +and when they're taking that feller away, you heave your cat after 'em +and say, 'Devil follow corpse, cat follow devil, warts follow cat, I'm +done with ye!' That'll fetch ANY wart." + +"Sounds right. D'you ever try it, Huck?" + +"No, but old Mother Hopkins told me." + +"Well, I reckon it's so, then. Becuz they say she's a witch." + +"Say! Why, Tom, I KNOW she is. She witched pap. Pap says so his own +self. He come along one day, and he see she was a-witching him, so he +took up a rock, and if she hadn't dodged, he'd a got her. Well, that +very night he rolled off'n a shed wher' he was a layin drunk, and broke +his arm." + +"Why, that's awful. How did he know she was a-witching him?" + +"Lord, pap can tell, easy. Pap says when they keep looking at you +right stiddy, they're a-witching you. Specially if they mumble. Becuz +when they mumble they're saying the Lord's Prayer backards." + +"Say, Hucky, when you going to try the cat?" + +"To-night. I reckon they'll come after old Hoss Williams to-night." + +"But they buried him Saturday. Didn't they get him Saturday night?" + +"Why, how you talk! How could their charms work till midnight?--and +THEN it's Sunday. Devils don't slosh around much of a Sunday, I don't +reckon." + +"I never thought of that. That's so. Lemme go with you?" + +"Of course--if you ain't afeard." + +"Afeard! 'Tain't likely. Will you meow?" + +"Yes--and you meow back, if you get a chance. Last time, you kep' me +a-meowing around till old Hays went to throwing rocks at me and says +'Dern that cat!' and so I hove a brick through his window--but don't +you tell." + +"I won't. I couldn't meow that night, becuz auntie was watching me, +but I'll meow this time. Say--what's that?" + +"Nothing but a tick." + +"Where'd you get him?" + +"Out in the woods." + +"What'll you take for him?" + +"I don't know. I don't want to sell him." + +"All right. It's a mighty small tick, anyway." + +"Oh, anybody can run a tick down that don't belong to them. I'm +satisfied with it. It's a good enough tick for me." + +"Sho, there's ticks a plenty. I could have a thousand of 'em if I +wanted to." + +"Well, why don't you? Becuz you know mighty well you can't. This is a +pretty early tick, I reckon. It's the first one I've seen this year." + +"Say, Huck--I'll give you my tooth for him." + +"Less see it." + +Tom got out a bit of paper and carefully unrolled it. Huckleberry +viewed it wistfully. The temptation was very strong. At last he said: + +"Is it genuwyne?" + +Tom lifted his lip and showed the vacancy. + +"Well, all right," said Huckleberry, "it's a trade." + +Tom enclosed the tick in the percussion-cap box that had lately been +the pinchbug's prison, and the boys separated, each feeling wealthier +than before. + +When Tom reached the little isolated frame schoolhouse, he strode in +briskly, with the manner of one who had come with all honest speed. +He hung his hat on a peg and flung himself into his seat with +business-like alacrity. The master, throned on high in his great +splint-bottom arm-chair, was dozing, lulled by the drowsy hum of study. +The interruption roused him. + +"Thomas Sawyer!" + +Tom knew that when his name was pronounced in full, it meant trouble. + +"Sir!" + +"Come up here. Now, sir, why are you late again, as usual?" + +Tom was about to take refuge in a lie, when he saw two long tails of +yellow hair hanging down a back that he recognized by the electric +sympathy of love; and by that form was THE ONLY VACANT PLACE on the +girls' side of the schoolhouse. He instantly said: + +"I STOPPED TO TALK WITH HUCKLEBERRY FINN!" + +The master's pulse stood still, and he stared helplessly. The buzz of +study ceased. The pupils wondered if this foolhardy boy had lost his +mind. The master said: + +"You--you did what?" + +"Stopped to talk with Huckleberry Finn." + +There was no mistaking the words. + +"Thomas Sawyer, this is the most astounding confession I have ever +listened to. No mere ferule will answer for this offence. Take off your +jacket." + +The master's arm performed until it was tired and the stock of +switches notably diminished. Then the order followed: + +"Now, sir, go and sit with the girls! And let this be a warning to you." + +The titter that rippled around the room appeared to abash the boy, but +in reality that result was caused rather more by his worshipful awe of +his unknown idol and the dread pleasure that lay in his high good +fortune. He sat down upon the end of the pine bench and the girl +hitched herself away from him with a toss of her head. Nudges and winks +and whispers traversed the room, but Tom sat still, with his arms upon +the long, low desk before him, and seemed to study his book. + +By and by attention ceased from him, and the accustomed school murmur +rose upon the dull air once more. Presently the boy began to steal +furtive glances at the girl. She observed it, "made a mouth" at him and +gave him the back of her head for the space of a minute. When she +cautiously faced around again, a peach lay before her. She thrust it +away. Tom gently put it back. She thrust it away again, but with less +animosity. Tom patiently returned it to its place. Then she let it +remain. Tom scrawled on his slate, "Please take it--I got more." The +girl glanced at the words, but made no sign. Now the boy began to draw +something on the slate, hiding his work with his left hand. For a time +the girl refused to notice; but her human curiosity presently began to +manifest itself by hardly perceptible signs. The boy worked on, +apparently unconscious. The girl made a sort of noncommittal attempt to +see, but the boy did not betray that he was aware of it. At last she +gave in and hesitatingly whispered: + +"Let me see it." + +Tom partly uncovered a dismal caricature of a house with two gable +ends to it and a corkscrew of smoke issuing from the chimney. Then the +girl's interest began to fasten itself upon the work and she forgot +everything else. When it was finished, she gazed a moment, then +whispered: + +"It's nice--make a man." + +The artist erected a man in the front yard, that resembled a derrick. +He could have stepped over the house; but the girl was not +hypercritical; she was satisfied with the monster, and whispered: + +"It's a beautiful man--now make me coming along." + +Tom drew an hour-glass with a full moon and straw limbs to it and +armed the spreading fingers with a portentous fan. The girl said: + +"It's ever so nice--I wish I could draw." + +"It's easy," whispered Tom, "I'll learn you." + +"Oh, will you? When?" + +"At noon. Do you go home to dinner?" + +"I'll stay if you will." + +"Good--that's a whack. What's your name?" + +"Becky Thatcher. What's yours? Oh, I know. It's Thomas Sawyer." + +"That's the name they lick me by. I'm Tom when I'm good. You call me +Tom, will you?" + +"Yes." + +Now Tom began to scrawl something on the slate, hiding the words from +the girl. But she was not backward this time. She begged to see. Tom +said: + +"Oh, it ain't anything." + +"Yes it is." + +"No it ain't. You don't want to see." + +"Yes I do, indeed I do. Please let me." + +"You'll tell." + +"No I won't--deed and deed and double deed won't." + +"You won't tell anybody at all? Ever, as long as you live?" + +"No, I won't ever tell ANYbody. Now let me." + +"Oh, YOU don't want to see!" + +"Now that you treat me so, I WILL see." And she put her small hand +upon his and a little scuffle ensued, Tom pretending to resist in +earnest but letting his hand slip by degrees till these words were +revealed: "I LOVE YOU." + +"Oh, you bad thing!" And she hit his hand a smart rap, but reddened +and looked pleased, nevertheless. + +Just at this juncture the boy felt a slow, fateful grip closing on his +ear, and a steady lifting impulse. In that wise he was borne across the +house and deposited in his own seat, under a peppering fire of giggles +from the whole school. Then the master stood over him during a few +awful moments, and finally moved away to his throne without saying a +word. But although Tom's ear tingled, his heart was jubilant. + +As the school quieted down Tom made an honest effort to study, but the +turmoil within him was too great. In turn he took his place in the +reading class and made a botch of it; then in the geography class and +turned lakes into mountains, mountains into rivers, and rivers into +continents, till chaos was come again; then in the spelling class, and +got "turned down," by a succession of mere baby words, till he brought +up at the foot and yielded up the pewter medal which he had worn with +ostentation for months. + + + +CHAPTER VII + +THE harder Tom tried to fasten his mind on his book, the more his +ideas wandered. So at last, with a sigh and a yawn, he gave it up. It +seemed to him that the noon recess would never come. The air was +utterly dead. There was not a breath stirring. It was the sleepiest of +sleepy days. The drowsing murmur of the five and twenty studying +scholars soothed the soul like the spell that is in the murmur of bees. +Away off in the flaming sunshine, Cardiff Hill lifted its soft green +sides through a shimmering veil of heat, tinted with the purple of +distance; a few birds floated on lazy wing high in the air; no other +living thing was visible but some cows, and they were asleep. Tom's +heart ached to be free, or else to have something of interest to do to +pass the dreary time. His hand wandered into his pocket and his face +lit up with a glow of gratitude that was prayer, though he did not know +it. Then furtively the percussion-cap box came out. He released the +tick and put him on the long flat desk. The creature probably glowed +with a gratitude that amounted to prayer, too, at this moment, but it +was premature: for when he started thankfully to travel off, Tom turned +him aside with a pin and made him take a new direction. + +Tom's bosom friend sat next him, suffering just as Tom had been, and +now he was deeply and gratefully interested in this entertainment in an +instant. This bosom friend was Joe Harper. The two boys were sworn +friends all the week, and embattled enemies on Saturdays. Joe took a +pin out of his lapel and began to assist in exercising the prisoner. +The sport grew in interest momently. Soon Tom said that they were +interfering with each other, and neither getting the fullest benefit of +the tick. So he put Joe's slate on the desk and drew a line down the +middle of it from top to bottom. + +"Now," said he, "as long as he is on your side you can stir him up and +I'll let him alone; but if you let him get away and get on my side, +you're to leave him alone as long as I can keep him from crossing over." + +"All right, go ahead; start him up." + +The tick escaped from Tom, presently, and crossed the equator. Joe +harassed him awhile, and then he got away and crossed back again. This +change of base occurred often. While one boy was worrying the tick with +absorbing interest, the other would look on with interest as strong, +the two heads bowed together over the slate, and the two souls dead to +all things else. At last luck seemed to settle and abide with Joe. The +tick tried this, that, and the other course, and got as excited and as +anxious as the boys themselves, but time and again just as he would +have victory in his very grasp, so to speak, and Tom's fingers would be +twitching to begin, Joe's pin would deftly head him off, and keep +possession. At last Tom could stand it no longer. The temptation was +too strong. So he reached out and lent a hand with his pin. Joe was +angry in a moment. Said he: + +"Tom, you let him alone." + +"I only just want to stir him up a little, Joe." + +"No, sir, it ain't fair; you just let him alone." + +"Blame it, I ain't going to stir him much." + +"Let him alone, I tell you." + +"I won't!" + +"You shall--he's on my side of the line." + +"Look here, Joe Harper, whose is that tick?" + +"I don't care whose tick he is--he's on my side of the line, and you +sha'n't touch him." + +"Well, I'll just bet I will, though. He's my tick and I'll do what I +blame please with him, or die!" + +A tremendous whack came down on Tom's shoulders, and its duplicate on +Joe's; and for the space of two minutes the dust continued to fly from +the two jackets and the whole school to enjoy it. The boys had been too +absorbed to notice the hush that had stolen upon the school awhile +before when the master came tiptoeing down the room and stood over +them. He had contemplated a good part of the performance before he +contributed his bit of variety to it. + +When school broke up at noon, Tom flew to Becky Thatcher, and +whispered in her ear: + +"Put on your bonnet and let on you're going home; and when you get to +the corner, give the rest of 'em the slip, and turn down through the +lane and come back. I'll go the other way and come it over 'em the same +way." + +So the one went off with one group of scholars, and the other with +another. In a little while the two met at the bottom of the lane, and +when they reached the school they had it all to themselves. Then they +sat together, with a slate before them, and Tom gave Becky the pencil +and held her hand in his, guiding it, and so created another surprising +house. When the interest in art began to wane, the two fell to talking. +Tom was swimming in bliss. He said: + +"Do you love rats?" + +"No! I hate them!" + +"Well, I do, too--LIVE ones. But I mean dead ones, to swing round your +head with a string." + +"No, I don't care for rats much, anyway. What I like is chewing-gum." + +"Oh, I should say so! I wish I had some now." + +"Do you? I've got some. I'll let you chew it awhile, but you must give +it back to me." + +That was agreeable, so they chewed it turn about, and dangled their +legs against the bench in excess of contentment. + +"Was you ever at a circus?" said Tom. + +"Yes, and my pa's going to take me again some time, if I'm good." + +"I been to the circus three or four times--lots of times. Church ain't +shucks to a circus. There's things going on at a circus all the time. +I'm going to be a clown in a circus when I grow up." + +"Oh, are you! That will be nice. They're so lovely, all spotted up." + +"Yes, that's so. And they get slathers of money--most a dollar a day, +Ben Rogers says. Say, Becky, was you ever engaged?" + +"What's that?" + +"Why, engaged to be married." + +"No." + +"Would you like to?" + +"I reckon so. I don't know. What is it like?" + +"Like? Why it ain't like anything. You only just tell a boy you won't +ever have anybody but him, ever ever ever, and then you kiss and that's +all. Anybody can do it." + +"Kiss? What do you kiss for?" + +"Why, that, you know, is to--well, they always do that." + +"Everybody?" + +"Why, yes, everybody that's in love with each other. Do you remember +what I wrote on the slate?" + +"Ye--yes." + +"What was it?" + +"I sha'n't tell you." + +"Shall I tell YOU?" + +"Ye--yes--but some other time." + +"No, now." + +"No, not now--to-morrow." + +"Oh, no, NOW. Please, Becky--I'll whisper it, I'll whisper it ever so +easy." + +Becky hesitating, Tom took silence for consent, and passed his arm +about her waist and whispered the tale ever so softly, with his mouth +close to her ear. And then he added: + +"Now you whisper it to me--just the same." + +She resisted, for a while, and then said: + +"You turn your face away so you can't see, and then I will. But you +mustn't ever tell anybody--WILL you, Tom? Now you won't, WILL you?" + +"No, indeed, indeed I won't. Now, Becky." + +He turned his face away. She bent timidly around till her breath +stirred his curls and whispered, "I--love--you!" + +Then she sprang away and ran around and around the desks and benches, +with Tom after her, and took refuge in a corner at last, with her +little white apron to her face. Tom clasped her about her neck and +pleaded: + +"Now, Becky, it's all done--all over but the kiss. Don't you be afraid +of that--it ain't anything at all. Please, Becky." And he tugged at her +apron and the hands. + +By and by she gave up, and let her hands drop; her face, all glowing +with the struggle, came up and submitted. Tom kissed the red lips and +said: + +"Now it's all done, Becky. And always after this, you know, you ain't +ever to love anybody but me, and you ain't ever to marry anybody but +me, ever never and forever. Will you?" + +"No, I'll never love anybody but you, Tom, and I'll never marry +anybody but you--and you ain't to ever marry anybody but me, either." + +"Certainly. Of course. That's PART of it. And always coming to school +or when we're going home, you're to walk with me, when there ain't +anybody looking--and you choose me and I choose you at parties, because +that's the way you do when you're engaged." + +"It's so nice. I never heard of it before." + +"Oh, it's ever so gay! Why, me and Amy Lawrence--" + +The big eyes told Tom his blunder and he stopped, confused. + +"Oh, Tom! Then I ain't the first you've ever been engaged to!" + +The child began to cry. Tom said: + +"Oh, don't cry, Becky, I don't care for her any more." + +"Yes, you do, Tom--you know you do." + +Tom tried to put his arm about her neck, but she pushed him away and +turned her face to the wall, and went on crying. Tom tried again, with +soothing words in his mouth, and was repulsed again. Then his pride was +up, and he strode away and went outside. He stood about, restless and +uneasy, for a while, glancing at the door, every now and then, hoping +she would repent and come to find him. But she did not. Then he began +to feel badly and fear that he was in the wrong. It was a hard struggle +with him to make new advances, now, but he nerved himself to it and +entered. She was still standing back there in the corner, sobbing, with +her face to the wall. Tom's heart smote him. He went to her and stood a +moment, not knowing exactly how to proceed. Then he said hesitatingly: + +"Becky, I--I don't care for anybody but you." + +No reply--but sobs. + +"Becky"--pleadingly. "Becky, won't you say something?" + +More sobs. + +Tom got out his chiefest jewel, a brass knob from the top of an +andiron, and passed it around her so that she could see it, and said: + +"Please, Becky, won't you take it?" + +She struck it to the floor. Then Tom marched out of the house and over +the hills and far away, to return to school no more that day. Presently +Becky began to suspect. She ran to the door; he was not in sight; she +flew around to the play-yard; he was not there. Then she called: + +"Tom! Come back, Tom!" + +She listened intently, but there was no answer. She had no companions +but silence and loneliness. So she sat down to cry again and upbraid +herself; and by this time the scholars began to gather again, and she +had to hide her griefs and still her broken heart and take up the cross +of a long, dreary, aching afternoon, with none among the strangers +about her to exchange sorrows with. + + + +CHAPTER VIII + +TOM dodged hither and thither through lanes until he was well out of +the track of returning scholars, and then fell into a moody jog. He +crossed a small "branch" two or three times, because of a prevailing +juvenile superstition that to cross water baffled pursuit. Half an hour +later he was disappearing behind the Douglas mansion on the summit of +Cardiff Hill, and the schoolhouse was hardly distinguishable away off +in the valley behind him. He entered a dense wood, picked his pathless +way to the centre of it, and sat down on a mossy spot under a spreading +oak. There was not even a zephyr stirring; the dead noonday heat had +even stilled the songs of the birds; nature lay in a trance that was +broken by no sound but the occasional far-off hammering of a +woodpecker, and this seemed to render the pervading silence and sense +of loneliness the more profound. The boy's soul was steeped in +melancholy; his feelings were in happy accord with his surroundings. He +sat long with his elbows on his knees and his chin in his hands, +meditating. It seemed to him that life was but a trouble, at best, and +he more than half envied Jimmy Hodges, so lately released; it must be +very peaceful, he thought, to lie and slumber and dream forever and +ever, with the wind whispering through the trees and caressing the +grass and the flowers over the grave, and nothing to bother and grieve +about, ever any more. If he only had a clean Sunday-school record he +could be willing to go, and be done with it all. Now as to this girl. +What had he done? Nothing. He had meant the best in the world, and been +treated like a dog--like a very dog. She would be sorry some day--maybe +when it was too late. Ah, if he could only die TEMPORARILY! + +But the elastic heart of youth cannot be compressed into one +constrained shape long at a time. Tom presently began to drift +insensibly back into the concerns of this life again. What if he turned +his back, now, and disappeared mysteriously? What if he went away--ever +so far away, into unknown countries beyond the seas--and never came +back any more! How would she feel then! The idea of being a clown +recurred to him now, only to fill him with disgust. For frivolity and +jokes and spotted tights were an offense, when they intruded themselves +upon a spirit that was exalted into the vague august realm of the +romantic. No, he would be a soldier, and return after long years, all +war-worn and illustrious. No--better still, he would join the Indians, +and hunt buffaloes and go on the warpath in the mountain ranges and the +trackless great plains of the Far West, and away in the future come +back a great chief, bristling with feathers, hideous with paint, and +prance into Sunday-school, some drowsy summer morning, with a +bloodcurdling war-whoop, and sear the eyeballs of all his companions +with unappeasable envy. But no, there was something gaudier even than +this. He would be a pirate! That was it! NOW his future lay plain +before him, and glowing with unimaginable splendor. How his name would +fill the world, and make people shudder! How gloriously he would go +plowing the dancing seas, in his long, low, black-hulled racer, the +Spirit of the Storm, with his grisly flag flying at the fore! And at +the zenith of his fame, how he would suddenly appear at the old village +and stalk into church, brown and weather-beaten, in his black velvet +doublet and trunks, his great jack-boots, his crimson sash, his belt +bristling with horse-pistols, his crime-rusted cutlass at his side, his +slouch hat with waving plumes, his black flag unfurled, with the skull +and crossbones on it, and hear with swelling ecstasy the whisperings, +"It's Tom Sawyer the Pirate!--the Black Avenger of the Spanish Main!" + +Yes, it was settled; his career was determined. He would run away from +home and enter upon it. He would start the very next morning. Therefore +he must now begin to get ready. He would collect his resources +together. He went to a rotten log near at hand and began to dig under +one end of it with his Barlow knife. He soon struck wood that sounded +hollow. He put his hand there and uttered this incantation impressively: + +"What hasn't come here, come! What's here, stay here!" + +Then he scraped away the dirt, and exposed a pine shingle. He took it +up and disclosed a shapely little treasure-house whose bottom and sides +were of shingles. In it lay a marble. Tom's astonishment was boundless! +He scratched his head with a perplexed air, and said: + +"Well, that beats anything!" + +Then he tossed the marble away pettishly, and stood cogitating. The +truth was, that a superstition of his had failed, here, which he and +all his comrades had always looked upon as infallible. If you buried a +marble with certain necessary incantations, and left it alone a +fortnight, and then opened the place with the incantation he had just +used, you would find that all the marbles you had ever lost had +gathered themselves together there, meantime, no matter how widely they +had been separated. But now, this thing had actually and unquestionably +failed. Tom's whole structure of faith was shaken to its foundations. +He had many a time heard of this thing succeeding but never of its +failing before. It did not occur to him that he had tried it several +times before, himself, but could never find the hiding-places +afterward. He puzzled over the matter some time, and finally decided +that some witch had interfered and broken the charm. He thought he +would satisfy himself on that point; so he searched around till he +found a small sandy spot with a little funnel-shaped depression in it. +He laid himself down and put his mouth close to this depression and +called-- + +"Doodle-bug, doodle-bug, tell me what I want to know! Doodle-bug, +doodle-bug, tell me what I want to know!" + +The sand began to work, and presently a small black bug appeared for a +second and then darted under again in a fright. + +"He dasn't tell! So it WAS a witch that done it. I just knowed it." + +He well knew the futility of trying to contend against witches, so he +gave up discouraged. But it occurred to him that he might as well have +the marble he had just thrown away, and therefore he went and made a +patient search for it. But he could not find it. Now he went back to +his treasure-house and carefully placed himself just as he had been +standing when he tossed the marble away; then he took another marble +from his pocket and tossed it in the same way, saying: + +"Brother, go find your brother!" + +He watched where it stopped, and went there and looked. But it must +have fallen short or gone too far; so he tried twice more. The last +repetition was successful. The two marbles lay within a foot of each +other. + +Just here the blast of a toy tin trumpet came faintly down the green +aisles of the forest. Tom flung off his jacket and trousers, turned a +suspender into a belt, raked away some brush behind the rotten log, +disclosing a rude bow and arrow, a lath sword and a tin trumpet, and in +a moment had seized these things and bounded away, barelegged, with +fluttering shirt. He presently halted under a great elm, blew an +answering blast, and then began to tiptoe and look warily out, this way +and that. He said cautiously--to an imaginary company: + +"Hold, my merry men! Keep hid till I blow." + +Now appeared Joe Harper, as airily clad and elaborately armed as Tom. +Tom called: + +"Hold! Who comes here into Sherwood Forest without my pass?" + +"Guy of Guisborne wants no man's pass. Who art thou that--that--" + +"Dares to hold such language," said Tom, prompting--for they talked +"by the book," from memory. + +"Who art thou that dares to hold such language?" + +"I, indeed! I am Robin Hood, as thy caitiff carcase soon shall know." + +"Then art thou indeed that famous outlaw? Right gladly will I dispute +with thee the passes of the merry wood. Have at thee!" + +They took their lath swords, dumped their other traps on the ground, +struck a fencing attitude, foot to foot, and began a grave, careful +combat, "two up and two down." Presently Tom said: + +"Now, if you've got the hang, go it lively!" + +So they "went it lively," panting and perspiring with the work. By and +by Tom shouted: + +"Fall! fall! Why don't you fall?" + +"I sha'n't! Why don't you fall yourself? You're getting the worst of +it." + +"Why, that ain't anything. I can't fall; that ain't the way it is in +the book. The book says, 'Then with one back-handed stroke he slew poor +Guy of Guisborne.' You're to turn around and let me hit you in the +back." + +There was no getting around the authorities, so Joe turned, received +the whack and fell. + +"Now," said Joe, getting up, "you got to let me kill YOU. That's fair." + +"Why, I can't do that, it ain't in the book." + +"Well, it's blamed mean--that's all." + +"Well, say, Joe, you can be Friar Tuck or Much the miller's son, and +lam me with a quarter-staff; or I'll be the Sheriff of Nottingham and +you be Robin Hood a little while and kill me." + +This was satisfactory, and so these adventures were carried out. Then +Tom became Robin Hood again, and was allowed by the treacherous nun to +bleed his strength away through his neglected wound. And at last Joe, +representing a whole tribe of weeping outlaws, dragged him sadly forth, +gave his bow into his feeble hands, and Tom said, "Where this arrow +falls, there bury poor Robin Hood under the greenwood tree." Then he +shot the arrow and fell back and would have died, but he lit on a +nettle and sprang up too gaily for a corpse. + +The boys dressed themselves, hid their accoutrements, and went off +grieving that there were no outlaws any more, and wondering what modern +civilization could claim to have done to compensate for their loss. +They said they would rather be outlaws a year in Sherwood Forest than +President of the United States forever. + + + +CHAPTER IX + +AT half-past nine, that night, Tom and Sid were sent to bed, as usual. +They said their prayers, and Sid was soon asleep. Tom lay awake and +waited, in restless impatience. When it seemed to him that it must be +nearly daylight, he heard the clock strike ten! This was despair. He +would have tossed and fidgeted, as his nerves demanded, but he was +afraid he might wake Sid. So he lay still, and stared up into the dark. +Everything was dismally still. By and by, out of the stillness, little, +scarcely perceptible noises began to emphasize themselves. The ticking +of the clock began to bring itself into notice. Old beams began to +crack mysteriously. The stairs creaked faintly. Evidently spirits were +abroad. A measured, muffled snore issued from Aunt Polly's chamber. And +now the tiresome chirping of a cricket that no human ingenuity could +locate, began. Next the ghastly ticking of a deathwatch in the wall at +the bed's head made Tom shudder--it meant that somebody's days were +numbered. Then the howl of a far-off dog rose on the night air, and was +answered by a fainter howl from a remoter distance. Tom was in an +agony. At last he was satisfied that time had ceased and eternity +begun; he began to doze, in spite of himself; the clock chimed eleven, +but he did not hear it. And then there came, mingling with his +half-formed dreams, a most melancholy caterwauling. The raising of a +neighboring window disturbed him. A cry of "Scat! you devil!" and the +crash of an empty bottle against the back of his aunt's woodshed +brought him wide awake, and a single minute later he was dressed and +out of the window and creeping along the roof of the "ell" on all +fours. He "meow'd" with caution once or twice, as he went; then jumped +to the roof of the woodshed and thence to the ground. Huckleberry Finn +was there, with his dead cat. The boys moved off and disappeared in the +gloom. At the end of half an hour they were wading through the tall +grass of the graveyard. + +It was a graveyard of the old-fashioned Western kind. It was on a +hill, about a mile and a half from the village. It had a crazy board +fence around it, which leaned inward in places, and outward the rest of +the time, but stood upright nowhere. Grass and weeds grew rank over the +whole cemetery. All the old graves were sunken in, there was not a +tombstone on the place; round-topped, worm-eaten boards staggered over +the graves, leaning for support and finding none. "Sacred to the memory +of" So-and-So had been painted on them once, but it could no longer +have been read, on the most of them, now, even if there had been light. + +A faint wind moaned through the trees, and Tom feared it might be the +spirits of the dead, complaining at being disturbed. The boys talked +little, and only under their breath, for the time and the place and the +pervading solemnity and silence oppressed their spirits. They found the +sharp new heap they were seeking, and ensconced themselves within the +protection of three great elms that grew in a bunch within a few feet +of the grave. + +Then they waited in silence for what seemed a long time. The hooting +of a distant owl was all the sound that troubled the dead stillness. +Tom's reflections grew oppressive. He must force some talk. So he said +in a whisper: + +"Hucky, do you believe the dead people like it for us to be here?" + +Huckleberry whispered: + +"I wisht I knowed. It's awful solemn like, AIN'T it?" + +"I bet it is." + +There was a considerable pause, while the boys canvassed this matter +inwardly. Then Tom whispered: + +"Say, Hucky--do you reckon Hoss Williams hears us talking?" + +"O' course he does. Least his sperrit does." + +Tom, after a pause: + +"I wish I'd said Mister Williams. But I never meant any harm. +Everybody calls him Hoss." + +"A body can't be too partic'lar how they talk 'bout these-yer dead +people, Tom." + +This was a damper, and conversation died again. + +Presently Tom seized his comrade's arm and said: + +"Sh!" + +"What is it, Tom?" And the two clung together with beating hearts. + +"Sh! There 'tis again! Didn't you hear it?" + +"I--" + +"There! Now you hear it." + +"Lord, Tom, they're coming! They're coming, sure. What'll we do?" + +"I dono. Think they'll see us?" + +"Oh, Tom, they can see in the dark, same as cats. I wisht I hadn't +come." + +"Oh, don't be afeard. I don't believe they'll bother us. We ain't +doing any harm. If we keep perfectly still, maybe they won't notice us +at all." + +"I'll try to, Tom, but, Lord, I'm all of a shiver." + +"Listen!" + +The boys bent their heads together and scarcely breathed. A muffled +sound of voices floated up from the far end of the graveyard. + +"Look! See there!" whispered Tom. "What is it?" + +"It's devil-fire. Oh, Tom, this is awful." + +Some vague figures approached through the gloom, swinging an +old-fashioned tin lantern that freckled the ground with innumerable +little spangles of light. Presently Huckleberry whispered with a +shudder: + +"It's the devils sure enough. Three of 'em! Lordy, Tom, we're goners! +Can you pray?" + +"I'll try, but don't you be afeard. They ain't going to hurt us. 'Now +I lay me down to sleep, I--'" + +"Sh!" + +"What is it, Huck?" + +"They're HUMANS! One of 'em is, anyway. One of 'em's old Muff Potter's +voice." + +"No--'tain't so, is it?" + +"I bet I know it. Don't you stir nor budge. He ain't sharp enough to +notice us. Drunk, the same as usual, likely--blamed old rip!" + +"All right, I'll keep still. Now they're stuck. Can't find it. Here +they come again. Now they're hot. Cold again. Hot again. Red hot! +They're p'inted right, this time. Say, Huck, I know another o' them +voices; it's Injun Joe." + +"That's so--that murderin' half-breed! I'd druther they was devils a +dern sight. What kin they be up to?" + +The whisper died wholly out, now, for the three men had reached the +grave and stood within a few feet of the boys' hiding-place. + +"Here it is," said the third voice; and the owner of it held the +lantern up and revealed the face of young Doctor Robinson. + +Potter and Injun Joe were carrying a handbarrow with a rope and a +couple of shovels on it. They cast down their load and began to open +the grave. The doctor put the lantern at the head of the grave and came +and sat down with his back against one of the elm trees. He was so +close the boys could have touched him. + +"Hurry, men!" he said, in a low voice; "the moon might come out at any +moment." + +They growled a response and went on digging. For some time there was +no noise but the grating sound of the spades discharging their freight +of mould and gravel. It was very monotonous. Finally a spade struck +upon the coffin with a dull woody accent, and within another minute or +two the men had hoisted it out on the ground. They pried off the lid +with their shovels, got out the body and dumped it rudely on the +ground. The moon drifted from behind the clouds and exposed the pallid +face. The barrow was got ready and the corpse placed on it, covered +with a blanket, and bound to its place with the rope. Potter took out a +large spring-knife and cut off the dangling end of the rope and then +said: + +"Now the cussed thing's ready, Sawbones, and you'll just out with +another five, or here she stays." + +"That's the talk!" said Injun Joe. + +"Look here, what does this mean?" said the doctor. "You required your +pay in advance, and I've paid you." + +"Yes, and you done more than that," said Injun Joe, approaching the +doctor, who was now standing. "Five years ago you drove me away from +your father's kitchen one night, when I come to ask for something to +eat, and you said I warn't there for any good; and when I swore I'd get +even with you if it took a hundred years, your father had me jailed for +a vagrant. Did you think I'd forget? The Injun blood ain't in me for +nothing. And now I've GOT you, and you got to SETTLE, you know!" + +He was threatening the doctor, with his fist in his face, by this +time. The doctor struck out suddenly and stretched the ruffian on the +ground. Potter dropped his knife, and exclaimed: + +"Here, now, don't you hit my pard!" and the next moment he had +grappled with the doctor and the two were struggling with might and +main, trampling the grass and tearing the ground with their heels. +Injun Joe sprang to his feet, his eyes flaming with passion, snatched +up Potter's knife, and went creeping, catlike and stooping, round and +round about the combatants, seeking an opportunity. All at once the +doctor flung himself free, seized the heavy headboard of Williams' +grave and felled Potter to the earth with it--and in the same instant +the half-breed saw his chance and drove the knife to the hilt in the +young man's breast. He reeled and fell partly upon Potter, flooding him +with his blood, and in the same moment the clouds blotted out the +dreadful spectacle and the two frightened boys went speeding away in +the dark. + +Presently, when the moon emerged again, Injun Joe was standing over +the two forms, contemplating them. The doctor murmured inarticulately, +gave a long gasp or two and was still. The half-breed muttered: + +"THAT score is settled--damn you." + +Then he robbed the body. After which he put the fatal knife in +Potter's open right hand, and sat down on the dismantled coffin. Three +--four--five minutes passed, and then Potter began to stir and moan. His +hand closed upon the knife; he raised it, glanced at it, and let it +fall, with a shudder. Then he sat up, pushing the body from him, and +gazed at it, and then around him, confusedly. His eyes met Joe's. + +"Lord, how is this, Joe?" he said. + +"It's a dirty business," said Joe, without moving. + +"What did you do it for?" + +"I! I never done it!" + +"Look here! That kind of talk won't wash." + +Potter trembled and grew white. + +"I thought I'd got sober. I'd no business to drink to-night. But it's +in my head yet--worse'n when we started here. I'm all in a muddle; +can't recollect anything of it, hardly. Tell me, Joe--HONEST, now, old +feller--did I do it? Joe, I never meant to--'pon my soul and honor, I +never meant to, Joe. Tell me how it was, Joe. Oh, it's awful--and him +so young and promising." + +"Why, you two was scuffling, and he fetched you one with the headboard +and you fell flat; and then up you come, all reeling and staggering +like, and snatched the knife and jammed it into him, just as he fetched +you another awful clip--and here you've laid, as dead as a wedge til +now." + +"Oh, I didn't know what I was a-doing. I wish I may die this minute if +I did. It was all on account of the whiskey and the excitement, I +reckon. I never used a weepon in my life before, Joe. I've fought, but +never with weepons. They'll all say that. Joe, don't tell! Say you +won't tell, Joe--that's a good feller. I always liked you, Joe, and +stood up for you, too. Don't you remember? You WON'T tell, WILL you, +Joe?" And the poor creature dropped on his knees before the stolid +murderer, and clasped his appealing hands. + +"No, you've always been fair and square with me, Muff Potter, and I +won't go back on you. There, now, that's as fair as a man can say." + +"Oh, Joe, you're an angel. I'll bless you for this the longest day I +live." And Potter began to cry. + +"Come, now, that's enough of that. This ain't any time for blubbering. +You be off yonder way and I'll go this. Move, now, and don't leave any +tracks behind you." + +Potter started on a trot that quickly increased to a run. The +half-breed stood looking after him. He muttered: + +"If he's as much stunned with the lick and fuddled with the rum as he +had the look of being, he won't think of the knife till he's gone so +far he'll be afraid to come back after it to such a place by himself +--chicken-heart!" + +Two or three minutes later the murdered man, the blanketed corpse, the +lidless coffin, and the open grave were under no inspection but the +moon's. The stillness was complete again, too. + + + +CHAPTER X + +THE two boys flew on and on, toward the village, speechless with +horror. They glanced backward over their shoulders from time to time, +apprehensively, as if they feared they might be followed. Every stump +that started up in their path seemed a man and an enemy, and made them +catch their breath; and as they sped by some outlying cottages that lay +near the village, the barking of the aroused watch-dogs seemed to give +wings to their feet. + +"If we can only get to the old tannery before we break down!" +whispered Tom, in short catches between breaths. "I can't stand it much +longer." + +Huckleberry's hard pantings were his only reply, and the boys fixed +their eyes on the goal of their hopes and bent to their work to win it. +They gained steadily on it, and at last, breast to breast, they burst +through the open door and fell grateful and exhausted in the sheltering +shadows beyond. By and by their pulses slowed down, and Tom whispered: + +"Huckleberry, what do you reckon'll come of this?" + +"If Doctor Robinson dies, I reckon hanging'll come of it." + +"Do you though?" + +"Why, I KNOW it, Tom." + +Tom thought a while, then he said: + +"Who'll tell? We?" + +"What are you talking about? S'pose something happened and Injun Joe +DIDN'T hang? Why, he'd kill us some time or other, just as dead sure as +we're a laying here." + +"That's just what I was thinking to myself, Huck." + +"If anybody tells, let Muff Potter do it, if he's fool enough. He's +generally drunk enough." + +Tom said nothing--went on thinking. Presently he whispered: + +"Huck, Muff Potter don't know it. How can he tell?" + +"What's the reason he don't know it?" + +"Because he'd just got that whack when Injun Joe done it. D'you reckon +he could see anything? D'you reckon he knowed anything?" + +"By hokey, that's so, Tom!" + +"And besides, look-a-here--maybe that whack done for HIM!" + +"No, 'taint likely, Tom. He had liquor in him; I could see that; and +besides, he always has. Well, when pap's full, you might take and belt +him over the head with a church and you couldn't phase him. He says so, +his own self. So it's the same with Muff Potter, of course. But if a +man was dead sober, I reckon maybe that whack might fetch him; I dono." + +After another reflective silence, Tom said: + +"Hucky, you sure you can keep mum?" + +"Tom, we GOT to keep mum. You know that. That Injun devil wouldn't +make any more of drownding us than a couple of cats, if we was to +squeak 'bout this and they didn't hang him. Now, look-a-here, Tom, less +take and swear to one another--that's what we got to do--swear to keep +mum." + +"I'm agreed. It's the best thing. Would you just hold hands and swear +that we--" + +"Oh no, that wouldn't do for this. That's good enough for little +rubbishy common things--specially with gals, cuz THEY go back on you +anyway, and blab if they get in a huff--but there orter be writing +'bout a big thing like this. And blood." + +Tom's whole being applauded this idea. It was deep, and dark, and +awful; the hour, the circumstances, the surroundings, were in keeping +with it. He picked up a clean pine shingle that lay in the moonlight, +took a little fragment of "red keel" out of his pocket, got the moon on +his work, and painfully scrawled these lines, emphasizing each slow +down-stroke by clamping his tongue between his teeth, and letting up +the pressure on the up-strokes. [See next page.] + + "Huck Finn and + Tom Sawyer swears + they will keep mum + about This and They + wish They may Drop + down dead in Their + Tracks if They ever + Tell and Rot." + +Huckleberry was filled with admiration of Tom's facility in writing, +and the sublimity of his language. He at once took a pin from his lapel +and was going to prick his flesh, but Tom said: + +"Hold on! Don't do that. A pin's brass. It might have verdigrease on +it." + +"What's verdigrease?" + +"It's p'ison. That's what it is. You just swaller some of it once +--you'll see." + +So Tom unwound the thread from one of his needles, and each boy +pricked the ball of his thumb and squeezed out a drop of blood. In +time, after many squeezes, Tom managed to sign his initials, using the +ball of his little finger for a pen. Then he showed Huckleberry how to +make an H and an F, and the oath was complete. They buried the shingle +close to the wall, with some dismal ceremonies and incantations, and +the fetters that bound their tongues were considered to be locked and +the key thrown away. + +A figure crept stealthily through a break in the other end of the +ruined building, now, but they did not notice it. + +"Tom," whispered Huckleberry, "does this keep us from EVER telling +--ALWAYS?" + +"Of course it does. It don't make any difference WHAT happens, we got +to keep mum. We'd drop down dead--don't YOU know that?" + +"Yes, I reckon that's so." + +They continued to whisper for some little time. Presently a dog set up +a long, lugubrious howl just outside--within ten feet of them. The boys +clasped each other suddenly, in an agony of fright. + +"Which of us does he mean?" gasped Huckleberry. + +"I dono--peep through the crack. Quick!" + +"No, YOU, Tom!" + +"I can't--I can't DO it, Huck!" + +"Please, Tom. There 'tis again!" + +"Oh, lordy, I'm thankful!" whispered Tom. "I know his voice. It's Bull +Harbison." * + +[* If Mr. Harbison owned a slave named Bull, Tom would have spoken of +him as "Harbison's Bull," but a son or a dog of that name was "Bull +Harbison."] + +"Oh, that's good--I tell you, Tom, I was most scared to death; I'd a +bet anything it was a STRAY dog." + +The dog howled again. The boys' hearts sank once more. + +"Oh, my! that ain't no Bull Harbison!" whispered Huckleberry. "DO, Tom!" + +Tom, quaking with fear, yielded, and put his eye to the crack. His +whisper was hardly audible when he said: + +"Oh, Huck, IT S A STRAY DOG!" + +"Quick, Tom, quick! Who does he mean?" + +"Huck, he must mean us both--we're right together." + +"Oh, Tom, I reckon we're goners. I reckon there ain't no mistake 'bout +where I'LL go to. I been so wicked." + +"Dad fetch it! This comes of playing hookey and doing everything a +feller's told NOT to do. I might a been good, like Sid, if I'd a tried +--but no, I wouldn't, of course. But if ever I get off this time, I lay +I'll just WALLER in Sunday-schools!" And Tom began to snuffle a little. + +"YOU bad!" and Huckleberry began to snuffle too. "Consound it, Tom +Sawyer, you're just old pie, 'longside o' what I am. Oh, LORDY, lordy, +lordy, I wisht I only had half your chance." + +Tom choked off and whispered: + +"Look, Hucky, look! He's got his BACK to us!" + +Hucky looked, with joy in his heart. + +"Well, he has, by jingoes! Did he before?" + +"Yes, he did. But I, like a fool, never thought. Oh, this is bully, +you know. NOW who can he mean?" + +The howling stopped. Tom pricked up his ears. + +"Sh! What's that?" he whispered. + +"Sounds like--like hogs grunting. No--it's somebody snoring, Tom." + +"That IS it! Where 'bouts is it, Huck?" + +"I bleeve it's down at 'tother end. Sounds so, anyway. Pap used to +sleep there, sometimes, 'long with the hogs, but laws bless you, he +just lifts things when HE snores. Besides, I reckon he ain't ever +coming back to this town any more." + +The spirit of adventure rose in the boys' souls once more. + +"Hucky, do you das't to go if I lead?" + +"I don't like to, much. Tom, s'pose it's Injun Joe!" + +Tom quailed. But presently the temptation rose up strong again and the +boys agreed to try, with the understanding that they would take to +their heels if the snoring stopped. So they went tiptoeing stealthily +down, the one behind the other. When they had got to within five steps +of the snorer, Tom stepped on a stick, and it broke with a sharp snap. +The man moaned, writhed a little, and his face came into the moonlight. +It was Muff Potter. The boys' hearts had stood still, and their hopes +too, when the man moved, but their fears passed away now. They tiptoed +out, through the broken weather-boarding, and stopped at a little +distance to exchange a parting word. That long, lugubrious howl rose on +the night air again! They turned and saw the strange dog standing +within a few feet of where Potter was lying, and FACING Potter, with +his nose pointing heavenward. + +"Oh, geeminy, it's HIM!" exclaimed both boys, in a breath. + +"Say, Tom--they say a stray dog come howling around Johnny Miller's +house, 'bout midnight, as much as two weeks ago; and a whippoorwill +come in and lit on the banisters and sung, the very same evening; and +there ain't anybody dead there yet." + +"Well, I know that. And suppose there ain't. Didn't Gracie Miller fall +in the kitchen fire and burn herself terrible the very next Saturday?" + +"Yes, but she ain't DEAD. And what's more, she's getting better, too." + +"All right, you wait and see. She's a goner, just as dead sure as Muff +Potter's a goner. That's what the niggers say, and they know all about +these kind of things, Huck." + +Then they separated, cogitating. When Tom crept in at his bedroom +window the night was almost spent. He undressed with excessive caution, +and fell asleep congratulating himself that nobody knew of his +escapade. He was not aware that the gently-snoring Sid was awake, and +had been so for an hour. + +When Tom awoke, Sid was dressed and gone. There was a late look in the +light, a late sense in the atmosphere. He was startled. Why had he not +been called--persecuted till he was up, as usual? The thought filled +him with bodings. Within five minutes he was dressed and down-stairs, +feeling sore and drowsy. The family were still at table, but they had +finished breakfast. There was no voice of rebuke; but there were +averted eyes; there was a silence and an air of solemnity that struck a +chill to the culprit's heart. He sat down and tried to seem gay, but it +was up-hill work; it roused no smile, no response, and he lapsed into +silence and let his heart sink down to the depths. + +After breakfast his aunt took him aside, and Tom almost brightened in +the hope that he was going to be flogged; but it was not so. His aunt +wept over him and asked him how he could go and break her old heart so; +and finally told him to go on, and ruin himself and bring her gray +hairs with sorrow to the grave, for it was no use for her to try any +more. This was worse than a thousand whippings, and Tom's heart was +sorer now than his body. He cried, he pleaded for forgiveness, promised +to reform over and over again, and then received his dismissal, feeling +that he had won but an imperfect forgiveness and established but a +feeble confidence. + +He left the presence too miserable to even feel revengeful toward Sid; +and so the latter's prompt retreat through the back gate was +unnecessary. He moped to school gloomy and sad, and took his flogging, +along with Joe Harper, for playing hookey the day before, with the air +of one whose heart was busy with heavier woes and wholly dead to +trifles. Then he betook himself to his seat, rested his elbows on his +desk and his jaws in his hands, and stared at the wall with the stony +stare of suffering that has reached the limit and can no further go. +His elbow was pressing against some hard substance. After a long time +he slowly and sadly changed his position, and took up this object with +a sigh. It was in a paper. He unrolled it. A long, lingering, colossal +sigh followed, and his heart broke. It was his brass andiron knob! + +This final feather broke the camel's back. + + + +CHAPTER XI + +CLOSE upon the hour of noon the whole village was suddenly electrified +with the ghastly news. No need of the as yet undreamed-of telegraph; +the tale flew from man to man, from group to group, from house to +house, with little less than telegraphic speed. Of course the +schoolmaster gave holiday for that afternoon; the town would have +thought strangely of him if he had not. + +A gory knife had been found close to the murdered man, and it had been +recognized by somebody as belonging to Muff Potter--so the story ran. +And it was said that a belated citizen had come upon Potter washing +himself in the "branch" about one or two o'clock in the morning, and +that Potter had at once sneaked off--suspicious circumstances, +especially the washing which was not a habit with Potter. It was also +said that the town had been ransacked for this "murderer" (the public +are not slow in the matter of sifting evidence and arriving at a +verdict), but that he could not be found. Horsemen had departed down +all the roads in every direction, and the Sheriff "was confident" that +he would be captured before night. + +All the town was drifting toward the graveyard. Tom's heartbreak +vanished and he joined the procession, not because he would not a +thousand times rather go anywhere else, but because an awful, +unaccountable fascination drew him on. Arrived at the dreadful place, +he wormed his small body through the crowd and saw the dismal +spectacle. It seemed to him an age since he was there before. Somebody +pinched his arm. He turned, and his eyes met Huckleberry's. Then both +looked elsewhere at once, and wondered if anybody had noticed anything +in their mutual glance. But everybody was talking, and intent upon the +grisly spectacle before them. + +"Poor fellow!" "Poor young fellow!" "This ought to be a lesson to +grave robbers!" "Muff Potter'll hang for this if they catch him!" This +was the drift of remark; and the minister said, "It was a judgment; His +hand is here." + +Now Tom shivered from head to heel; for his eye fell upon the stolid +face of Injun Joe. At this moment the crowd began to sway and struggle, +and voices shouted, "It's him! it's him! he's coming himself!" + +"Who? Who?" from twenty voices. + +"Muff Potter!" + +"Hallo, he's stopped!--Look out, he's turning! Don't let him get away!" + +People in the branches of the trees over Tom's head said he wasn't +trying to get away--he only looked doubtful and perplexed. + +"Infernal impudence!" said a bystander; "wanted to come and take a +quiet look at his work, I reckon--didn't expect any company." + +The crowd fell apart, now, and the Sheriff came through, +ostentatiously leading Potter by the arm. The poor fellow's face was +haggard, and his eyes showed the fear that was upon him. When he stood +before the murdered man, he shook as with a palsy, and he put his face +in his hands and burst into tears. + +"I didn't do it, friends," he sobbed; "'pon my word and honor I never +done it." + +"Who's accused you?" shouted a voice. + +This shot seemed to carry home. Potter lifted his face and looked +around him with a pathetic hopelessness in his eyes. He saw Injun Joe, +and exclaimed: + +"Oh, Injun Joe, you promised me you'd never--" + +"Is that your knife?" and it was thrust before him by the Sheriff. + +Potter would have fallen if they had not caught him and eased him to +the ground. Then he said: + +"Something told me 't if I didn't come back and get--" He shuddered; +then waved his nerveless hand with a vanquished gesture and said, "Tell +'em, Joe, tell 'em--it ain't any use any more." + +Then Huckleberry and Tom stood dumb and staring, and heard the +stony-hearted liar reel off his serene statement, they expecting every +moment that the clear sky would deliver God's lightnings upon his head, +and wondering to see how long the stroke was delayed. And when he had +finished and still stood alive and whole, their wavering impulse to +break their oath and save the poor betrayed prisoner's life faded and +vanished away, for plainly this miscreant had sold himself to Satan and +it would be fatal to meddle with the property of such a power as that. + +"Why didn't you leave? What did you want to come here for?" somebody +said. + +"I couldn't help it--I couldn't help it," Potter moaned. "I wanted to +run away, but I couldn't seem to come anywhere but here." And he fell +to sobbing again. + +Injun Joe repeated his statement, just as calmly, a few minutes +afterward on the inquest, under oath; and the boys, seeing that the +lightnings were still withheld, were confirmed in their belief that Joe +had sold himself to the devil. He was now become, to them, the most +balefully interesting object they had ever looked upon, and they could +not take their fascinated eyes from his face. + +They inwardly resolved to watch him nights, when opportunity should +offer, in the hope of getting a glimpse of his dread master. + +Injun Joe helped to raise the body of the murdered man and put it in a +wagon for removal; and it was whispered through the shuddering crowd +that the wound bled a little! The boys thought that this happy +circumstance would turn suspicion in the right direction; but they were +disappointed, for more than one villager remarked: + +"It was within three feet of Muff Potter when it done it." + +Tom's fearful secret and gnawing conscience disturbed his sleep for as +much as a week after this; and at breakfast one morning Sid said: + +"Tom, you pitch around and talk in your sleep so much that you keep me +awake half the time." + +Tom blanched and dropped his eyes. + +"It's a bad sign," said Aunt Polly, gravely. "What you got on your +mind, Tom?" + +"Nothing. Nothing 't I know of." But the boy's hand shook so that he +spilled his coffee. + +"And you do talk such stuff," Sid said. "Last night you said, 'It's +blood, it's blood, that's what it is!' You said that over and over. And +you said, 'Don't torment me so--I'll tell!' Tell WHAT? What is it +you'll tell?" + +Everything was swimming before Tom. There is no telling what might +have happened, now, but luckily the concern passed out of Aunt Polly's +face and she came to Tom's relief without knowing it. She said: + +"Sho! It's that dreadful murder. I dream about it most every night +myself. Sometimes I dream it's me that done it." + +Mary said she had been affected much the same way. Sid seemed +satisfied. Tom got out of the presence as quick as he plausibly could, +and after that he complained of toothache for a week, and tied up his +jaws every night. He never knew that Sid lay nightly watching, and +frequently slipped the bandage free and then leaned on his elbow +listening a good while at a time, and afterward slipped the bandage +back to its place again. Tom's distress of mind wore off gradually and +the toothache grew irksome and was discarded. If Sid really managed to +make anything out of Tom's disjointed mutterings, he kept it to himself. + +It seemed to Tom that his schoolmates never would get done holding +inquests on dead cats, and thus keeping his trouble present to his +mind. Sid noticed that Tom never was coroner at one of these inquiries, +though it had been his habit to take the lead in all new enterprises; +he noticed, too, that Tom never acted as a witness--and that was +strange; and Sid did not overlook the fact that Tom even showed a +marked aversion to these inquests, and always avoided them when he +could. Sid marvelled, but said nothing. However, even inquests went out +of vogue at last, and ceased to torture Tom's conscience. + +Every day or two, during this time of sorrow, Tom watched his +opportunity and went to the little grated jail-window and smuggled such +small comforts through to the "murderer" as he could get hold of. The +jail was a trifling little brick den that stood in a marsh at the edge +of the village, and no guards were afforded for it; indeed, it was +seldom occupied. These offerings greatly helped to ease Tom's +conscience. + +The villagers had a strong desire to tar-and-feather Injun Joe and +ride him on a rail, for body-snatching, but so formidable was his +character that nobody could be found who was willing to take the lead +in the matter, so it was dropped. He had been careful to begin both of +his inquest-statements with the fight, without confessing the +grave-robbery that preceded it; therefore it was deemed wisest not +to try the case in the courts at present. + + + +CHAPTER XII + +ONE of the reasons why Tom's mind had drifted away from its secret +troubles was, that it had found a new and weighty matter to interest +itself about. Becky Thatcher had stopped coming to school. Tom had +struggled with his pride a few days, and tried to "whistle her down the +wind," but failed. He began to find himself hanging around her father's +house, nights, and feeling very miserable. She was ill. What if she +should die! There was distraction in the thought. He no longer took an +interest in war, nor even in piracy. The charm of life was gone; there +was nothing but dreariness left. He put his hoop away, and his bat; +there was no joy in them any more. His aunt was concerned. She began to +try all manner of remedies on him. She was one of those people who are +infatuated with patent medicines and all new-fangled methods of +producing health or mending it. She was an inveterate experimenter in +these things. When something fresh in this line came out she was in a +fever, right away, to try it; not on herself, for she was never ailing, +but on anybody else that came handy. She was a subscriber for all the +"Health" periodicals and phrenological frauds; and the solemn ignorance +they were inflated with was breath to her nostrils. All the "rot" they +contained about ventilation, and how to go to bed, and how to get up, +and what to eat, and what to drink, and how much exercise to take, and +what frame of mind to keep one's self in, and what sort of clothing to +wear, was all gospel to her, and she never observed that her +health-journals of the current month customarily upset everything they +had recommended the month before. She was as simple-hearted and honest +as the day was long, and so she was an easy victim. She gathered +together her quack periodicals and her quack medicines, and thus armed +with death, went about on her pale horse, metaphorically speaking, with +"hell following after." But she never suspected that she was not an +angel of healing and the balm of Gilead in disguise, to the suffering +neighbors. + +The water treatment was new, now, and Tom's low condition was a +windfall to her. She had him out at daylight every morning, stood him +up in the woodshed and drowned him with a deluge of cold water; then +she scrubbed him down with a towel like a file, and so brought him to; +then she rolled him up in a wet sheet and put him away under blankets +till she sweated his soul clean and "the yellow stains of it came +through his pores"--as Tom said. + +Yet notwithstanding all this, the boy grew more and more melancholy +and pale and dejected. She added hot baths, sitz baths, shower baths, +and plunges. The boy remained as dismal as a hearse. She began to +assist the water with a slim oatmeal diet and blister-plasters. She +calculated his capacity as she would a jug's, and filled him up every +day with quack cure-alls. + +Tom had become indifferent to persecution by this time. This phase +filled the old lady's heart with consternation. This indifference must +be broken up at any cost. Now she heard of Pain-killer for the first +time. She ordered a lot at once. She tasted it and was filled with +gratitude. It was simply fire in a liquid form. She dropped the water +treatment and everything else, and pinned her faith to Pain-killer. She +gave Tom a teaspoonful and watched with the deepest anxiety for the +result. Her troubles were instantly at rest, her soul at peace again; +for the "indifference" was broken up. The boy could not have shown a +wilder, heartier interest, if she had built a fire under him. + +Tom felt that it was time to wake up; this sort of life might be +romantic enough, in his blighted condition, but it was getting to have +too little sentiment and too much distracting variety about it. So he +thought over various plans for relief, and finally hit pon that of +professing to be fond of Pain-killer. He asked for it so often that he +became a nuisance, and his aunt ended by telling him to help himself +and quit bothering her. If it had been Sid, she would have had no +misgivings to alloy her delight; but since it was Tom, she watched the +bottle clandestinely. She found that the medicine did really diminish, +but it did not occur to her that the boy was mending the health of a +crack in the sitting-room floor with it. + +One day Tom was in the act of dosing the crack when his aunt's yellow +cat came along, purring, eying the teaspoon avariciously, and begging +for a taste. Tom said: + +"Don't ask for it unless you want it, Peter." + +But Peter signified that he did want it. + +"You better make sure." + +Peter was sure. + +"Now you've asked for it, and I'll give it to you, because there ain't +anything mean about me; but if you find you don't like it, you mustn't +blame anybody but your own self." + +Peter was agreeable. So Tom pried his mouth open and poured down the +Pain-killer. Peter sprang a couple of yards in the air, and then +delivered a war-whoop and set off round and round the room, banging +against furniture, upsetting flower-pots, and making general havoc. +Next he rose on his hind feet and pranced around, in a frenzy of +enjoyment, with his head over his shoulder and his voice proclaiming +his unappeasable happiness. Then he went tearing around the house again +spreading chaos and destruction in his path. Aunt Polly entered in time +to see him throw a few double summersets, deliver a final mighty +hurrah, and sail through the open window, carrying the rest of the +flower-pots with him. The old lady stood petrified with astonishment, +peering over her glasses; Tom lay on the floor expiring with laughter. + +"Tom, what on earth ails that cat?" + +"I don't know, aunt," gasped the boy. + +"Why, I never see anything like it. What did make him act so?" + +"Deed I don't know, Aunt Polly; cats always act so when they're having +a good time." + +"They do, do they?" There was something in the tone that made Tom +apprehensive. + +"Yes'm. That is, I believe they do." + +"You DO?" + +"Yes'm." + +The old lady was bending down, Tom watching, with interest emphasized +by anxiety. Too late he divined her "drift." The handle of the telltale +teaspoon was visible under the bed-valance. Aunt Polly took it, held it +up. Tom winced, and dropped his eyes. Aunt Polly raised him by the +usual handle--his ear--and cracked his head soundly with her thimble. + +"Now, sir, what did you want to treat that poor dumb beast so, for?" + +"I done it out of pity for him--because he hadn't any aunt." + +"Hadn't any aunt!--you numskull. What has that got to do with it?" + +"Heaps. Because if he'd had one she'd a burnt him out herself! She'd a +roasted his bowels out of him 'thout any more feeling than if he was a +human!" + +Aunt Polly felt a sudden pang of remorse. This was putting the thing +in a new light; what was cruelty to a cat MIGHT be cruelty to a boy, +too. She began to soften; she felt sorry. Her eyes watered a little, +and she put her hand on Tom's head and said gently: + +"I was meaning for the best, Tom. And, Tom, it DID do you good." + +Tom looked up in her face with just a perceptible twinkle peeping +through his gravity. + +"I know you was meaning for the best, aunty, and so was I with Peter. +It done HIM good, too. I never see him get around so since--" + +"Oh, go 'long with you, Tom, before you aggravate me again. And you +try and see if you can't be a good boy, for once, and you needn't take +any more medicine." + +Tom reached school ahead of time. It was noticed that this strange +thing had been occurring every day latterly. And now, as usual of late, +he hung about the gate of the schoolyard instead of playing with his +comrades. He was sick, he said, and he looked it. He tried to seem to +be looking everywhere but whither he really was looking--down the road. +Presently Jeff Thatcher hove in sight, and Tom's face lighted; he gazed +a moment, and then turned sorrowfully away. When Jeff arrived, Tom +accosted him; and "led up" warily to opportunities for remark about +Becky, but the giddy lad never could see the bait. Tom watched and +watched, hoping whenever a frisking frock came in sight, and hating the +owner of it as soon as he saw she was not the right one. At last frocks +ceased to appear, and he dropped hopelessly into the dumps; he entered +the empty schoolhouse and sat down to suffer. Then one more frock +passed in at the gate, and Tom's heart gave a great bound. The next +instant he was out, and "going on" like an Indian; yelling, laughing, +chasing boys, jumping over the fence at risk of life and limb, throwing +handsprings, standing on his head--doing all the heroic things he could +conceive of, and keeping a furtive eye out, all the while, to see if +Becky Thatcher was noticing. But she seemed to be unconscious of it +all; she never looked. Could it be possible that she was not aware that +he was there? He carried his exploits to her immediate vicinity; came +war-whooping around, snatched a boy's cap, hurled it to the roof of the +schoolhouse, broke through a group of boys, tumbling them in every +direction, and fell sprawling, himself, under Becky's nose, almost +upsetting her--and she turned, with her nose in the air, and he heard +her say: "Mf! some people think they're mighty smart--always showing +off!" + +Tom's cheeks burned. He gathered himself up and sneaked off, crushed +and crestfallen. + + + +CHAPTER XIII + +TOM'S mind was made up now. He was gloomy and desperate. He was a +forsaken, friendless boy, he said; nobody loved him; when they found +out what they had driven him to, perhaps they would be sorry; he had +tried to do right and get along, but they would not let him; since +nothing would do them but to be rid of him, let it be so; and let them +blame HIM for the consequences--why shouldn't they? What right had the +friendless to complain? Yes, they had forced him to it at last: he +would lead a life of crime. There was no choice. + +By this time he was far down Meadow Lane, and the bell for school to +"take up" tinkled faintly upon his ear. He sobbed, now, to think he +should never, never hear that old familiar sound any more--it was very +hard, but it was forced on him; since he was driven out into the cold +world, he must submit--but he forgave them. Then the sobs came thick +and fast. + +Just at this point he met his soul's sworn comrade, Joe Harper +--hard-eyed, and with evidently a great and dismal purpose in his heart. +Plainly here were "two souls with but a single thought." Tom, wiping +his eyes with his sleeve, began to blubber out something about a +resolution to escape from hard usage and lack of sympathy at home by +roaming abroad into the great world never to return; and ended by +hoping that Joe would not forget him. + +But it transpired that this was a request which Joe had just been +going to make of Tom, and had come to hunt him up for that purpose. His +mother had whipped him for drinking some cream which he had never +tasted and knew nothing about; it was plain that she was tired of him +and wished him to go; if she felt that way, there was nothing for him +to do but succumb; he hoped she would be happy, and never regret having +driven her poor boy out into the unfeeling world to suffer and die. + +As the two boys walked sorrowing along, they made a new compact to +stand by each other and be brothers and never separate till death +relieved them of their troubles. Then they began to lay their plans. +Joe was for being a hermit, and living on crusts in a remote cave, and +dying, some time, of cold and want and grief; but after listening to +Tom, he conceded that there were some conspicuous advantages about a +life of crime, and so he consented to be a pirate. + +Three miles below St. Petersburg, at a point where the Mississippi +River was a trifle over a mile wide, there was a long, narrow, wooded +island, with a shallow bar at the head of it, and this offered well as +a rendezvous. It was not inhabited; it lay far over toward the further +shore, abreast a dense and almost wholly unpeopled forest. So Jackson's +Island was chosen. Who were to be the subjects of their piracies was a +matter that did not occur to them. Then they hunted up Huckleberry +Finn, and he joined them promptly, for all careers were one to him; he +was indifferent. They presently separated to meet at a lonely spot on +the river-bank two miles above the village at the favorite hour--which +was midnight. There was a small log raft there which they meant to +capture. Each would bring hooks and lines, and such provision as he +could steal in the most dark and mysterious way--as became outlaws. And +before the afternoon was done, they had all managed to enjoy the sweet +glory of spreading the fact that pretty soon the town would "hear +something." All who got this vague hint were cautioned to "be mum and +wait." + +About midnight Tom arrived with a boiled ham and a few trifles, +and stopped in a dense undergrowth on a small bluff overlooking the +meeting-place. It was starlight, and very still. The mighty river lay +like an ocean at rest. Tom listened a moment, but no sound disturbed the +quiet. Then he gave a low, distinct whistle. It was answered from under +the bluff. Tom whistled twice more; these signals were answered in the +same way. Then a guarded voice said: + +"Who goes there?" + +"Tom Sawyer, the Black Avenger of the Spanish Main. Name your names." + +"Huck Finn the Red-Handed, and Joe Harper the Terror of the Seas." Tom +had furnished these titles, from his favorite literature. + +"'Tis well. Give the countersign." + +Two hoarse whispers delivered the same awful word simultaneously to +the brooding night: + +"BLOOD!" + +Then Tom tumbled his ham over the bluff and let himself down after it, +tearing both skin and clothes to some extent in the effort. There was +an easy, comfortable path along the shore under the bluff, but it +lacked the advantages of difficulty and danger so valued by a pirate. + +The Terror of the Seas had brought a side of bacon, and had about worn +himself out with getting it there. Finn the Red-Handed had stolen a +skillet and a quantity of half-cured leaf tobacco, and had also brought +a few corn-cobs to make pipes with. But none of the pirates smoked or +"chewed" but himself. The Black Avenger of the Spanish Main said it +would never do to start without some fire. That was a wise thought; +matches were hardly known there in that day. They saw a fire +smouldering upon a great raft a hundred yards above, and they went +stealthily thither and helped themselves to a chunk. They made an +imposing adventure of it, saying, "Hist!" every now and then, and +suddenly halting with finger on lip; moving with hands on imaginary +dagger-hilts; and giving orders in dismal whispers that if "the foe" +stirred, to "let him have it to the hilt," because "dead men tell no +tales." They knew well enough that the raftsmen were all down at the +village laying in stores or having a spree, but still that was no +excuse for their conducting this thing in an unpiratical way. + +They shoved off, presently, Tom in command, Huck at the after oar and +Joe at the forward. Tom stood amidships, gloomy-browed, and with folded +arms, and gave his orders in a low, stern whisper: + +"Luff, and bring her to the wind!" + +"Aye-aye, sir!" + +"Steady, steady-y-y-y!" + +"Steady it is, sir!" + +"Let her go off a point!" + +"Point it is, sir!" + +As the boys steadily and monotonously drove the raft toward mid-stream +it was no doubt understood that these orders were given only for +"style," and were not intended to mean anything in particular. + +"What sail's she carrying?" + +"Courses, tops'ls, and flying-jib, sir." + +"Send the r'yals up! Lay out aloft, there, half a dozen of ye +--foretopmaststuns'l! Lively, now!" + +"Aye-aye, sir!" + +"Shake out that maintogalans'l! Sheets and braces! NOW my hearties!" + +"Aye-aye, sir!" + +"Hellum-a-lee--hard a port! Stand by to meet her when she comes! Port, +port! NOW, men! With a will! Stead-y-y-y!" + +"Steady it is, sir!" + +The raft drew beyond the middle of the river; the boys pointed her +head right, and then lay on their oars. The river was not high, so +there was not more than a two or three mile current. Hardly a word was +said during the next three-quarters of an hour. Now the raft was +passing before the distant town. Two or three glimmering lights showed +where it lay, peacefully sleeping, beyond the vague vast sweep of +star-gemmed water, unconscious of the tremendous event that was happening. +The Black Avenger stood still with folded arms, "looking his last" upon +the scene of his former joys and his later sufferings, and wishing +"she" could see him now, abroad on the wild sea, facing peril and death +with dauntless heart, going to his doom with a grim smile on his lips. +It was but a small strain on his imagination to remove Jackson's Island +beyond eyeshot of the village, and so he "looked his last" with a +broken and satisfied heart. The other pirates were looking their last, +too; and they all looked so long that they came near letting the +current drift them out of the range of the island. But they discovered +the danger in time, and made shift to avert it. About two o'clock in +the morning the raft grounded on the bar two hundred yards above the +head of the island, and they waded back and forth until they had landed +their freight. Part of the little raft's belongings consisted of an old +sail, and this they spread over a nook in the bushes for a tent to +shelter their provisions; but they themselves would sleep in the open +air in good weather, as became outlaws. + +They built a fire against the side of a great log twenty or thirty +steps within the sombre depths of the forest, and then cooked some +bacon in the frying-pan for supper, and used up half of the corn "pone" +stock they had brought. It seemed glorious sport to be feasting in that +wild, free way in the virgin forest of an unexplored and uninhabited +island, far from the haunts of men, and they said they never would +return to civilization. The climbing fire lit up their faces and threw +its ruddy glare upon the pillared tree-trunks of their forest temple, +and upon the varnished foliage and festooning vines. + +When the last crisp slice of bacon was gone, and the last allowance of +corn pone devoured, the boys stretched themselves out on the grass, +filled with contentment. They could have found a cooler place, but they +would not deny themselves such a romantic feature as the roasting +camp-fire. + +"AIN'T it gay?" said Joe. + +"It's NUTS!" said Tom. "What would the boys say if they could see us?" + +"Say? Well, they'd just die to be here--hey, Hucky!" + +"I reckon so," said Huckleberry; "anyways, I'm suited. I don't want +nothing better'n this. I don't ever get enough to eat, gen'ally--and +here they can't come and pick at a feller and bullyrag him so." + +"It's just the life for me," said Tom. "You don't have to get up, +mornings, and you don't have to go to school, and wash, and all that +blame foolishness. You see a pirate don't have to do ANYTHING, Joe, +when he's ashore, but a hermit HE has to be praying considerable, and +then he don't have any fun, anyway, all by himself that way." + +"Oh yes, that's so," said Joe, "but I hadn't thought much about it, +you know. I'd a good deal rather be a pirate, now that I've tried it." + +"You see," said Tom, "people don't go much on hermits, nowadays, like +they used to in old times, but a pirate's always respected. And a +hermit's got to sleep on the hardest place he can find, and put +sackcloth and ashes on his head, and stand out in the rain, and--" + +"What does he put sackcloth and ashes on his head for?" inquired Huck. + +"I dono. But they've GOT to do it. Hermits always do. You'd have to do +that if you was a hermit." + +"Dern'd if I would," said Huck. + +"Well, what would you do?" + +"I dono. But I wouldn't do that." + +"Why, Huck, you'd HAVE to. How'd you get around it?" + +"Why, I just wouldn't stand it. I'd run away." + +"Run away! Well, you WOULD be a nice old slouch of a hermit. You'd be +a disgrace." + +The Red-Handed made no response, being better employed. He had +finished gouging out a cob, and now he fitted a weed stem to it, loaded +it with tobacco, and was pressing a coal to the charge and blowing a +cloud of fragrant smoke--he was in the full bloom of luxurious +contentment. The other pirates envied him this majestic vice, and +secretly resolved to acquire it shortly. Presently Huck said: + +"What does pirates have to do?" + +Tom said: + +"Oh, they have just a bully time--take ships and burn them, and get +the money and bury it in awful places in their island where there's +ghosts and things to watch it, and kill everybody in the ships--make +'em walk a plank." + +"And they carry the women to the island," said Joe; "they don't kill +the women." + +"No," assented Tom, "they don't kill the women--they're too noble. And +the women's always beautiful, too. + +"And don't they wear the bulliest clothes! Oh no! All gold and silver +and di'monds," said Joe, with enthusiasm. + +"Who?" said Huck. + +"Why, the pirates." + +Huck scanned his own clothing forlornly. + +"I reckon I ain't dressed fitten for a pirate," said he, with a +regretful pathos in his voice; "but I ain't got none but these." + +But the other boys told him the fine clothes would come fast enough, +after they should have begun their adventures. They made him understand +that his poor rags would do to begin with, though it was customary for +wealthy pirates to start with a proper wardrobe. + +Gradually their talk died out and drowsiness began to steal upon the +eyelids of the little waifs. The pipe dropped from the fingers of the +Red-Handed, and he slept the sleep of the conscience-free and the +weary. The Terror of the Seas and the Black Avenger of the Spanish Main +had more difficulty in getting to sleep. They said their prayers +inwardly, and lying down, since there was nobody there with authority +to make them kneel and recite aloud; in truth, they had a mind not to +say them at all, but they were afraid to proceed to such lengths as +that, lest they might call down a sudden and special thunderbolt from +heaven. Then at once they reached and hovered upon the imminent verge +of sleep--but an intruder came, now, that would not "down." It was +conscience. They began to feel a vague fear that they had been doing +wrong to run away; and next they thought of the stolen meat, and then +the real torture came. They tried to argue it away by reminding +conscience that they had purloined sweetmeats and apples scores of +times; but conscience was not to be appeased by such thin +plausibilities; it seemed to them, in the end, that there was no +getting around the stubborn fact that taking sweetmeats was only +"hooking," while taking bacon and hams and such valuables was plain +simple stealing--and there was a command against that in the Bible. So +they inwardly resolved that so long as they remained in the business, +their piracies should not again be sullied with the crime of stealing. +Then conscience granted a truce, and these curiously inconsistent +pirates fell peacefully to sleep. + + + +CHAPTER XIV + +WHEN Tom awoke in the morning, he wondered where he was. He sat up and +rubbed his eyes and looked around. Then he comprehended. It was the +cool gray dawn, and there was a delicious sense of repose and peace in +the deep pervading calm and silence of the woods. Not a leaf stirred; +not a sound obtruded upon great Nature's meditation. Beaded dewdrops +stood upon the leaves and grasses. A white layer of ashes covered the +fire, and a thin blue breath of smoke rose straight into the air. Joe +and Huck still slept. + +Now, far away in the woods a bird called; another answered; presently +the hammering of a woodpecker was heard. Gradually the cool dim gray of +the morning whitened, and as gradually sounds multiplied and life +manifested itself. The marvel of Nature shaking off sleep and going to +work unfolded itself to the musing boy. A little green worm came +crawling over a dewy leaf, lifting two-thirds of his body into the air +from time to time and "sniffing around," then proceeding again--for he +was measuring, Tom said; and when the worm approached him, of its own +accord, he sat as still as a stone, with his hopes rising and falling, +by turns, as the creature still came toward him or seemed inclined to +go elsewhere; and when at last it considered a painful moment with its +curved body in the air and then came decisively down upon Tom's leg and +began a journey over him, his whole heart was glad--for that meant that +he was going to have a new suit of clothes--without the shadow of a +doubt a gaudy piratical uniform. Now a procession of ants appeared, +from nowhere in particular, and went about their labors; one struggled +manfully by with a dead spider five times as big as itself in its arms, +and lugged it straight up a tree-trunk. A brown spotted lady-bug +climbed the dizzy height of a grass blade, and Tom bent down close to +it and said, "Lady-bug, lady-bug, fly away home, your house is on fire, +your children's alone," and she took wing and went off to see about it +--which did not surprise the boy, for he knew of old that this insect was +credulous about conflagrations, and he had practised upon its +simplicity more than once. A tumblebug came next, heaving sturdily at +its ball, and Tom touched the creature, to see it shut its legs against +its body and pretend to be dead. The birds were fairly rioting by this +time. A catbird, the Northern mocker, lit in a tree over Tom's head, +and trilled out her imitations of her neighbors in a rapture of +enjoyment; then a shrill jay swept down, a flash of blue flame, and +stopped on a twig almost within the boy's reach, cocked his head to one +side and eyed the strangers with a consuming curiosity; a gray squirrel +and a big fellow of the "fox" kind came skurrying along, sitting up at +intervals to inspect and chatter at the boys, for the wild things had +probably never seen a human being before and scarcely knew whether to +be afraid or not. All Nature was wide awake and stirring, now; long +lances of sunlight pierced down through the dense foliage far and near, +and a few butterflies came fluttering upon the scene. + +Tom stirred up the other pirates and they all clattered away with a +shout, and in a minute or two were stripped and chasing after and +tumbling over each other in the shallow limpid water of the white +sandbar. They felt no longing for the little village sleeping in the +distance beyond the majestic waste of water. A vagrant current or a +slight rise in the river had carried off their raft, but this only +gratified them, since its going was something like burning the bridge +between them and civilization. + +They came back to camp wonderfully refreshed, glad-hearted, and +ravenous; and they soon had the camp-fire blazing up again. Huck found +a spring of clear cold water close by, and the boys made cups of broad +oak or hickory leaves, and felt that water, sweetened with such a +wildwood charm as that, would be a good enough substitute for coffee. +While Joe was slicing bacon for breakfast, Tom and Huck asked him to +hold on a minute; they stepped to a promising nook in the river-bank +and threw in their lines; almost immediately they had reward. Joe had +not had time to get impatient before they were back again with some +handsome bass, a couple of sun-perch and a small catfish--provisions +enough for quite a family. They fried the fish with the bacon, and were +astonished; for no fish had ever seemed so delicious before. They did +not know that the quicker a fresh-water fish is on the fire after he is +caught the better he is; and they reflected little upon what a sauce +open-air sleeping, open-air exercise, bathing, and a large ingredient +of hunger make, too. + +They lay around in the shade, after breakfast, while Huck had a smoke, +and then went off through the woods on an exploring expedition. They +tramped gayly along, over decaying logs, through tangled underbrush, +among solemn monarchs of the forest, hung from their crowns to the +ground with a drooping regalia of grape-vines. Now and then they came +upon snug nooks carpeted with grass and jeweled with flowers. + +They found plenty of things to be delighted with, but nothing to be +astonished at. They discovered that the island was about three miles +long and a quarter of a mile wide, and that the shore it lay closest to +was only separated from it by a narrow channel hardly two hundred yards +wide. They took a swim about every hour, so it was close upon the +middle of the afternoon when they got back to camp. They were too +hungry to stop to fish, but they fared sumptuously upon cold ham, and +then threw themselves down in the shade to talk. But the talk soon +began to drag, and then died. The stillness, the solemnity that brooded +in the woods, and the sense of loneliness, began to tell upon the +spirits of the boys. They fell to thinking. A sort of undefined longing +crept upon them. This took dim shape, presently--it was budding +homesickness. Even Finn the Red-Handed was dreaming of his doorsteps +and empty hogsheads. But they were all ashamed of their weakness, and +none was brave enough to speak his thought. + +For some time, now, the boys had been dully conscious of a peculiar +sound in the distance, just as one sometimes is of the ticking of a +clock which he takes no distinct note of. But now this mysterious sound +became more pronounced, and forced a recognition. The boys started, +glanced at each other, and then each assumed a listening attitude. +There was a long silence, profound and unbroken; then a deep, sullen +boom came floating down out of the distance. + +"What is it!" exclaimed Joe, under his breath. + +"I wonder," said Tom in a whisper. + +"'Tain't thunder," said Huckleberry, in an awed tone, "becuz thunder--" + +"Hark!" said Tom. "Listen--don't talk." + +They waited a time that seemed an age, and then the same muffled boom +troubled the solemn hush. + +"Let's go and see." + +They sprang to their feet and hurried to the shore toward the town. +They parted the bushes on the bank and peered out over the water. The +little steam ferryboat was about a mile below the village, drifting +with the current. Her broad deck seemed crowded with people. There were +a great many skiffs rowing about or floating with the stream in the +neighborhood of the ferryboat, but the boys could not determine what +the men in them were doing. Presently a great jet of white smoke burst +from the ferryboat's side, and as it expanded and rose in a lazy cloud, +that same dull throb of sound was borne to the listeners again. + +"I know now!" exclaimed Tom; "somebody's drownded!" + +"That's it!" said Huck; "they done that last summer, when Bill Turner +got drownded; they shoot a cannon over the water, and that makes him +come up to the top. Yes, and they take loaves of bread and put +quicksilver in 'em and set 'em afloat, and wherever there's anybody +that's drownded, they'll float right there and stop." + +"Yes, I've heard about that," said Joe. "I wonder what makes the bread +do that." + +"Oh, it ain't the bread, so much," said Tom; "I reckon it's mostly +what they SAY over it before they start it out." + +"But they don't say anything over it," said Huck. "I've seen 'em and +they don't." + +"Well, that's funny," said Tom. "But maybe they say it to themselves. +Of COURSE they do. Anybody might know that." + +The other boys agreed that there was reason in what Tom said, because +an ignorant lump of bread, uninstructed by an incantation, could not be +expected to act very intelligently when set upon an errand of such +gravity. + +"By jings, I wish I was over there, now," said Joe. + +"I do too" said Huck "I'd give heaps to know who it is." + +The boys still listened and watched. Presently a revealing thought +flashed through Tom's mind, and he exclaimed: + +"Boys, I know who's drownded--it's us!" + +They felt like heroes in an instant. Here was a gorgeous triumph; they +were missed; they were mourned; hearts were breaking on their account; +tears were being shed; accusing memories of unkindness to these poor +lost lads were rising up, and unavailing regrets and remorse were being +indulged; and best of all, the departed were the talk of the whole +town, and the envy of all the boys, as far as this dazzling notoriety +was concerned. This was fine. It was worth while to be a pirate, after +all. + +As twilight drew on, the ferryboat went back to her accustomed +business and the skiffs disappeared. The pirates returned to camp. They +were jubilant with vanity over their new grandeur and the illustrious +trouble they were making. They caught fish, cooked supper and ate it, +and then fell to guessing at what the village was thinking and saying +about them; and the pictures they drew of the public distress on their +account were gratifying to look upon--from their point of view. But +when the shadows of night closed them in, they gradually ceased to +talk, and sat gazing into the fire, with their minds evidently +wandering elsewhere. The excitement was gone, now, and Tom and Joe +could not keep back thoughts of certain persons at home who were not +enjoying this fine frolic as much as they were. Misgivings came; they +grew troubled and unhappy; a sigh or two escaped, unawares. By and by +Joe timidly ventured upon a roundabout "feeler" as to how the others +might look upon a return to civilization--not right now, but-- + +Tom withered him with derision! Huck, being uncommitted as yet, joined +in with Tom, and the waverer quickly "explained," and was glad to get +out of the scrape with as little taint of chicken-hearted homesickness +clinging to his garments as he could. Mutiny was effectually laid to +rest for the moment. + +As the night deepened, Huck began to nod, and presently to snore. Joe +followed next. Tom lay upon his elbow motionless, for some time, +watching the two intently. At last he got up cautiously, on his knees, +and went searching among the grass and the flickering reflections flung +by the camp-fire. He picked up and inspected several large +semi-cylinders of the thin white bark of a sycamore, and finally chose +two which seemed to suit him. Then he knelt by the fire and painfully +wrote something upon each of these with his "red keel"; one he rolled up +and put in his jacket pocket, and the other he put in Joe's hat and +removed it to a little distance from the owner. And he also put into the +hat certain schoolboy treasures of almost inestimable value--among them +a lump of chalk, an India-rubber ball, three fishhooks, and one of that +kind of marbles known as a "sure 'nough crystal." Then he tiptoed his +way cautiously among the trees till he felt that he was out of hearing, +and straightway broke into a keen run in the direction of the sandbar. + + + +CHAPTER XV + +A FEW minutes later Tom was in the shoal water of the bar, wading +toward the Illinois shore. Before the depth reached his middle he was +half-way over; the current would permit no more wading, now, so he +struck out confidently to swim the remaining hundred yards. He swam +quartering upstream, but still was swept downward rather faster than he +had expected. However, he reached the shore finally, and drifted along +till he found a low place and drew himself out. He put his hand on his +jacket pocket, found his piece of bark safe, and then struck through +the woods, following the shore, with streaming garments. Shortly before +ten o'clock he came out into an open place opposite the village, and +saw the ferryboat lying in the shadow of the trees and the high bank. +Everything was quiet under the blinking stars. He crept down the bank, +watching with all his eyes, slipped into the water, swam three or four +strokes and climbed into the skiff that did "yawl" duty at the boat's +stern. He laid himself down under the thwarts and waited, panting. + +Presently the cracked bell tapped and a voice gave the order to "cast +off." A minute or two later the skiff's head was standing high up, +against the boat's swell, and the voyage was begun. Tom felt happy in +his success, for he knew it was the boat's last trip for the night. At +the end of a long twelve or fifteen minutes the wheels stopped, and Tom +slipped overboard and swam ashore in the dusk, landing fifty yards +downstream, out of danger of possible stragglers. + +He flew along unfrequented alleys, and shortly found himself at his +aunt's back fence. He climbed over, approached the "ell," and looked in +at the sitting-room window, for a light was burning there. There sat +Aunt Polly, Sid, Mary, and Joe Harper's mother, grouped together, +talking. They were by the bed, and the bed was between them and the +door. Tom went to the door and began to softly lift the latch; then he +pressed gently and the door yielded a crack; he continued pushing +cautiously, and quaking every time it creaked, till he judged he might +squeeze through on his knees; so he put his head through and began, +warily. + +"What makes the candle blow so?" said Aunt Polly. Tom hurried up. +"Why, that door's open, I believe. Why, of course it is. No end of +strange things now. Go 'long and shut it, Sid." + +Tom disappeared under the bed just in time. He lay and "breathed" +himself for a time, and then crept to where he could almost touch his +aunt's foot. + +"But as I was saying," said Aunt Polly, "he warn't BAD, so to say +--only mischEEvous. Only just giddy, and harum-scarum, you know. He +warn't any more responsible than a colt. HE never meant any harm, and +he was the best-hearted boy that ever was"--and she began to cry. + +"It was just so with my Joe--always full of his devilment, and up to +every kind of mischief, but he was just as unselfish and kind as he +could be--and laws bless me, to think I went and whipped him for taking +that cream, never once recollecting that I throwed it out myself +because it was sour, and I never to see him again in this world, never, +never, never, poor abused boy!" And Mrs. Harper sobbed as if her heart +would break. + +"I hope Tom's better off where he is," said Sid, "but if he'd been +better in some ways--" + +"SID!" Tom felt the glare of the old lady's eye, though he could not +see it. "Not a word against my Tom, now that he's gone! God'll take +care of HIM--never you trouble YOURself, sir! Oh, Mrs. Harper, I don't +know how to give him up! I don't know how to give him up! He was such a +comfort to me, although he tormented my old heart out of me, 'most." + +"The Lord giveth and the Lord hath taken away--Blessed be the name of +the Lord! But it's so hard--Oh, it's so hard! Only last Saturday my +Joe busted a firecracker right under my nose and I knocked him +sprawling. Little did I know then, how soon--Oh, if it was to do over +again I'd hug him and bless him for it." + +"Yes, yes, yes, I know just how you feel, Mrs. Harper, I know just +exactly how you feel. No longer ago than yesterday noon, my Tom took +and filled the cat full of Pain-killer, and I did think the cretur +would tear the house down. And God forgive me, I cracked Tom's head +with my thimble, poor boy, poor dead boy. But he's out of all his +troubles now. And the last words I ever heard him say was to reproach--" + +But this memory was too much for the old lady, and she broke entirely +down. Tom was snuffling, now, himself--and more in pity of himself than +anybody else. He could hear Mary crying, and putting in a kindly word +for him from time to time. He began to have a nobler opinion of himself +than ever before. Still, he was sufficiently touched by his aunt's +grief to long to rush out from under the bed and overwhelm her with +joy--and the theatrical gorgeousness of the thing appealed strongly to +his nature, too, but he resisted and lay still. + +He went on listening, and gathered by odds and ends that it was +conjectured at first that the boys had got drowned while taking a swim; +then the small raft had been missed; next, certain boys said the +missing lads had promised that the village should "hear something" +soon; the wise-heads had "put this and that together" and decided that +the lads had gone off on that raft and would turn up at the next town +below, presently; but toward noon the raft had been found, lodged +against the Missouri shore some five or six miles below the village +--and then hope perished; they must be drowned, else hunger would have +driven them home by nightfall if not sooner. It was believed that the +search for the bodies had been a fruitless effort merely because the +drowning must have occurred in mid-channel, since the boys, being good +swimmers, would otherwise have escaped to shore. This was Wednesday +night. If the bodies continued missing until Sunday, all hope would be +given over, and the funerals would be preached on that morning. Tom +shuddered. + +Mrs. Harper gave a sobbing good-night and turned to go. Then with a +mutual impulse the two bereaved women flung themselves into each +other's arms and had a good, consoling cry, and then parted. Aunt Polly +was tender far beyond her wont, in her good-night to Sid and Mary. Sid +snuffled a bit and Mary went off crying with all her heart. + +Aunt Polly knelt down and prayed for Tom so touchingly, so +appealingly, and with such measureless love in her words and her old +trembling voice, that he was weltering in tears again, long before she +was through. + +He had to keep still long after she went to bed, for she kept making +broken-hearted ejaculations from time to time, tossing unrestfully, and +turning over. But at last she was still, only moaning a little in her +sleep. Now the boy stole out, rose gradually by the bedside, shaded the +candle-light with his hand, and stood regarding her. His heart was full +of pity for her. He took out his sycamore scroll and placed it by the +candle. But something occurred to him, and he lingered considering. His +face lighted with a happy solution of his thought; he put the bark +hastily in his pocket. Then he bent over and kissed the faded lips, and +straightway made his stealthy exit, latching the door behind him. + +He threaded his way back to the ferry landing, found nobody at large +there, and walked boldly on board the boat, for he knew she was +tenantless except that there was a watchman, who always turned in and +slept like a graven image. He untied the skiff at the stern, slipped +into it, and was soon rowing cautiously upstream. When he had pulled a +mile above the village, he started quartering across and bent himself +stoutly to his work. He hit the landing on the other side neatly, for +this was a familiar bit of work to him. He was moved to capture the +skiff, arguing that it might be considered a ship and therefore +legitimate prey for a pirate, but he knew a thorough search would be +made for it and that might end in revelations. So he stepped ashore and +entered the woods. + +He sat down and took a long rest, torturing himself meanwhile to keep +awake, and then started warily down the home-stretch. The night was far +spent. It was broad daylight before he found himself fairly abreast the +island bar. He rested again until the sun was well up and gilding the +great river with its splendor, and then he plunged into the stream. A +little later he paused, dripping, upon the threshold of the camp, and +heard Joe say: + +"No, Tom's true-blue, Huck, and he'll come back. He won't desert. He +knows that would be a disgrace to a pirate, and Tom's too proud for +that sort of thing. He's up to something or other. Now I wonder what?" + +"Well, the things is ours, anyway, ain't they?" + +"Pretty near, but not yet, Huck. The writing says they are if he ain't +back here to breakfast." + +"Which he is!" exclaimed Tom, with fine dramatic effect, stepping +grandly into camp. + +A sumptuous breakfast of bacon and fish was shortly provided, and as +the boys set to work upon it, Tom recounted (and adorned) his +adventures. They were a vain and boastful company of heroes when the +tale was done. Then Tom hid himself away in a shady nook to sleep till +noon, and the other pirates got ready to fish and explore. + + + +CHAPTER XVI + +AFTER dinner all the gang turned out to hunt for turtle eggs on the +bar. They went about poking sticks into the sand, and when they found a +soft place they went down on their knees and dug with their hands. +Sometimes they would take fifty or sixty eggs out of one hole. They +were perfectly round white things a trifle smaller than an English +walnut. They had a famous fried-egg feast that night, and another on +Friday morning. + +After breakfast they went whooping and prancing out on the bar, and +chased each other round and round, shedding clothes as they went, until +they were naked, and then continued the frolic far away up the shoal +water of the bar, against the stiff current, which latter tripped their +legs from under them from time to time and greatly increased the fun. +And now and then they stooped in a group and splashed water in each +other's faces with their palms, gradually approaching each other, with +averted faces to avoid the strangling sprays, and finally gripping and +struggling till the best man ducked his neighbor, and then they all +went under in a tangle of white legs and arms and came up blowing, +sputtering, laughing, and gasping for breath at one and the same time. + +When they were well exhausted, they would run out and sprawl on the +dry, hot sand, and lie there and cover themselves up with it, and by +and by break for the water again and go through the original +performance once more. Finally it occurred to them that their naked +skin represented flesh-colored "tights" very fairly; so they drew a +ring in the sand and had a circus--with three clowns in it, for none +would yield this proudest post to his neighbor. + +Next they got their marbles and played "knucks" and "ring-taw" and +"keeps" till that amusement grew stale. Then Joe and Huck had another +swim, but Tom would not venture, because he found that in kicking off +his trousers he had kicked his string of rattlesnake rattles off his +ankle, and he wondered how he had escaped cramp so long without the +protection of this mysterious charm. He did not venture again until he +had found it, and by that time the other boys were tired and ready to +rest. They gradually wandered apart, dropped into the "dumps," and fell +to gazing longingly across the wide river to where the village lay +drowsing in the sun. Tom found himself writing "BECKY" in the sand with +his big toe; he scratched it out, and was angry with himself for his +weakness. But he wrote it again, nevertheless; he could not help it. He +erased it once more and then took himself out of temptation by driving +the other boys together and joining them. + +But Joe's spirits had gone down almost beyond resurrection. He was so +homesick that he could hardly endure the misery of it. The tears lay +very near the surface. Huck was melancholy, too. Tom was downhearted, +but tried hard not to show it. He had a secret which he was not ready +to tell, yet, but if this mutinous depression was not broken up soon, +he would have to bring it out. He said, with a great show of +cheerfulness: + +"I bet there's been pirates on this island before, boys. We'll explore +it again. They've hid treasures here somewhere. How'd you feel to light +on a rotten chest full of gold and silver--hey?" + +But it roused only faint enthusiasm, which faded out, with no reply. +Tom tried one or two other seductions; but they failed, too. It was +discouraging work. Joe sat poking up the sand with a stick and looking +very gloomy. Finally he said: + +"Oh, boys, let's give it up. I want to go home. It's so lonesome." + +"Oh no, Joe, you'll feel better by and by," said Tom. "Just think of +the fishing that's here." + +"I don't care for fishing. I want to go home." + +"But, Joe, there ain't such another swimming-place anywhere." + +"Swimming's no good. I don't seem to care for it, somehow, when there +ain't anybody to say I sha'n't go in. I mean to go home." + +"Oh, shucks! Baby! You want to see your mother, I reckon." + +"Yes, I DO want to see my mother--and you would, too, if you had one. +I ain't any more baby than you are." And Joe snuffled a little. + +"Well, we'll let the cry-baby go home to his mother, won't we, Huck? +Poor thing--does it want to see its mother? And so it shall. You like +it here, don't you, Huck? We'll stay, won't we?" + +Huck said, "Y-e-s"--without any heart in it. + +"I'll never speak to you again as long as I live," said Joe, rising. +"There now!" And he moved moodily away and began to dress himself. + +"Who cares!" said Tom. "Nobody wants you to. Go 'long home and get +laughed at. Oh, you're a nice pirate. Huck and me ain't cry-babies. +We'll stay, won't we, Huck? Let him go if he wants to. I reckon we can +get along without him, per'aps." + +But Tom was uneasy, nevertheless, and was alarmed to see Joe go +sullenly on with his dressing. And then it was discomforting to see +Huck eying Joe's preparations so wistfully, and keeping up such an +ominous silence. Presently, without a parting word, Joe began to wade +off toward the Illinois shore. Tom's heart began to sink. He glanced at +Huck. Huck could not bear the look, and dropped his eyes. Then he said: + +"I want to go, too, Tom. It was getting so lonesome anyway, and now +it'll be worse. Let's us go, too, Tom." + +"I won't! You can all go, if you want to. I mean to stay." + +"Tom, I better go." + +"Well, go 'long--who's hendering you." + +Huck began to pick up his scattered clothes. He said: + +"Tom, I wisht you'd come, too. Now you think it over. We'll wait for +you when we get to shore." + +"Well, you'll wait a blame long time, that's all." + +Huck started sorrowfully away, and Tom stood looking after him, with a +strong desire tugging at his heart to yield his pride and go along too. +He hoped the boys would stop, but they still waded slowly on. It +suddenly dawned on Tom that it was become very lonely and still. He +made one final struggle with his pride, and then darted after his +comrades, yelling: + +"Wait! Wait! I want to tell you something!" + +They presently stopped and turned around. When he got to where they +were, he began unfolding his secret, and they listened moodily till at +last they saw the "point" he was driving at, and then they set up a +war-whoop of applause and said it was "splendid!" and said if he had +told them at first, they wouldn't have started away. He made a plausible +excuse; but his real reason had been the fear that not even the secret +would keep them with him any very great length of time, and so he had +meant to hold it in reserve as a last seduction. + +The lads came gayly back and went at their sports again with a will, +chattering all the time about Tom's stupendous plan and admiring the +genius of it. After a dainty egg and fish dinner, Tom said he wanted to +learn to smoke, now. Joe caught at the idea and said he would like to +try, too. So Huck made pipes and filled them. These novices had never +smoked anything before but cigars made of grape-vine, and they "bit" +the tongue, and were not considered manly anyway. + +Now they stretched themselves out on their elbows and began to puff, +charily, and with slender confidence. The smoke had an unpleasant +taste, and they gagged a little, but Tom said: + +"Why, it's just as easy! If I'd a knowed this was all, I'd a learnt +long ago." + +"So would I," said Joe. "It's just nothing." + +"Why, many a time I've looked at people smoking, and thought well I +wish I could do that; but I never thought I could," said Tom. + +"That's just the way with me, hain't it, Huck? You've heard me talk +just that way--haven't you, Huck? I'll leave it to Huck if I haven't." + +"Yes--heaps of times," said Huck. + +"Well, I have too," said Tom; "oh, hundreds of times. Once down by the +slaughter-house. Don't you remember, Huck? Bob Tanner was there, and +Johnny Miller, and Jeff Thatcher, when I said it. Don't you remember, +Huck, 'bout me saying that?" + +"Yes, that's so," said Huck. "That was the day after I lost a white +alley. No, 'twas the day before." + +"There--I told you so," said Tom. "Huck recollects it." + +"I bleeve I could smoke this pipe all day," said Joe. "I don't feel +sick." + +"Neither do I," said Tom. "I could smoke it all day. But I bet you +Jeff Thatcher couldn't." + +"Jeff Thatcher! Why, he'd keel over just with two draws. Just let him +try it once. HE'D see!" + +"I bet he would. And Johnny Miller--I wish could see Johnny Miller +tackle it once." + +"Oh, don't I!" said Joe. "Why, I bet you Johnny Miller couldn't any +more do this than nothing. Just one little snifter would fetch HIM." + +"'Deed it would, Joe. Say--I wish the boys could see us now." + +"So do I." + +"Say--boys, don't say anything about it, and some time when they're +around, I'll come up to you and say, 'Joe, got a pipe? I want a smoke.' +And you'll say, kind of careless like, as if it warn't anything, you'll +say, 'Yes, I got my OLD pipe, and another one, but my tobacker ain't +very good.' And I'll say, 'Oh, that's all right, if it's STRONG +enough.' And then you'll out with the pipes, and we'll light up just as +ca'm, and then just see 'em look!" + +"By jings, that'll be gay, Tom! I wish it was NOW!" + +"So do I! And when we tell 'em we learned when we was off pirating, +won't they wish they'd been along?" + +"Oh, I reckon not! I'll just BET they will!" + +So the talk ran on. But presently it began to flag a trifle, and grow +disjointed. The silences widened; the expectoration marvellously +increased. Every pore inside the boys' cheeks became a spouting +fountain; they could scarcely bail out the cellars under their tongues +fast enough to prevent an inundation; little overflowings down their +throats occurred in spite of all they could do, and sudden retchings +followed every time. Both boys were looking very pale and miserable, +now. Joe's pipe dropped from his nerveless fingers. Tom's followed. +Both fountains were going furiously and both pumps bailing with might +and main. Joe said feebly: + +"I've lost my knife. I reckon I better go and find it." + +Tom said, with quivering lips and halting utterance: + +"I'll help you. You go over that way and I'll hunt around by the +spring. No, you needn't come, Huck--we can find it." + +So Huck sat down again, and waited an hour. Then he found it lonesome, +and went to find his comrades. They were wide apart in the woods, both +very pale, both fast asleep. But something informed him that if they +had had any trouble they had got rid of it. + +They were not talkative at supper that night. They had a humble look, +and when Huck prepared his pipe after the meal and was going to prepare +theirs, they said no, they were not feeling very well--something they +ate at dinner had disagreed with them. + +About midnight Joe awoke, and called the boys. There was a brooding +oppressiveness in the air that seemed to bode something. The boys +huddled themselves together and sought the friendly companionship of +the fire, though the dull dead heat of the breathless atmosphere was +stifling. They sat still, intent and waiting. The solemn hush +continued. Beyond the light of the fire everything was swallowed up in +the blackness of darkness. Presently there came a quivering glow that +vaguely revealed the foliage for a moment and then vanished. By and by +another came, a little stronger. Then another. Then a faint moan came +sighing through the branches of the forest and the boys felt a fleeting +breath upon their cheeks, and shuddered with the fancy that the Spirit +of the Night had gone by. There was a pause. Now a weird flash turned +night into day and showed every little grass-blade, separate and +distinct, that grew about their feet. And it showed three white, +startled faces, too. A deep peal of thunder went rolling and tumbling +down the heavens and lost itself in sullen rumblings in the distance. A +sweep of chilly air passed by, rustling all the leaves and snowing the +flaky ashes broadcast about the fire. Another fierce glare lit up the +forest and an instant crash followed that seemed to rend the tree-tops +right over the boys' heads. They clung together in terror, in the thick +gloom that followed. A few big rain-drops fell pattering upon the +leaves. + +"Quick! boys, go for the tent!" exclaimed Tom. + +They sprang away, stumbling over roots and among vines in the dark, no +two plunging in the same direction. A furious blast roared through the +trees, making everything sing as it went. One blinding flash after +another came, and peal on peal of deafening thunder. And now a +drenching rain poured down and the rising hurricane drove it in sheets +along the ground. The boys cried out to each other, but the roaring +wind and the booming thunder-blasts drowned their voices utterly. +However, one by one they straggled in at last and took shelter under +the tent, cold, scared, and streaming with water; but to have company +in misery seemed something to be grateful for. They could not talk, the +old sail flapped so furiously, even if the other noises would have +allowed them. The tempest rose higher and higher, and presently the +sail tore loose from its fastenings and went winging away on the blast. +The boys seized each others' hands and fled, with many tumblings and +bruises, to the shelter of a great oak that stood upon the river-bank. +Now the battle was at its highest. Under the ceaseless conflagration of +lightning that flamed in the skies, everything below stood out in +clean-cut and shadowless distinctness: the bending trees, the billowy +river, white with foam, the driving spray of spume-flakes, the dim +outlines of the high bluffs on the other side, glimpsed through the +drifting cloud-rack and the slanting veil of rain. Every little while +some giant tree yielded the fight and fell crashing through the younger +growth; and the unflagging thunder-peals came now in ear-splitting +explosive bursts, keen and sharp, and unspeakably appalling. The storm +culminated in one matchless effort that seemed likely to tear the island +to pieces, burn it up, drown it to the tree-tops, blow it away, and +deafen every creature in it, all at one and the same moment. It was a +wild night for homeless young heads to be out in. + +But at last the battle was done, and the forces retired with weaker +and weaker threatenings and grumblings, and peace resumed her sway. The +boys went back to camp, a good deal awed; but they found there was +still something to be thankful for, because the great sycamore, the +shelter of their beds, was a ruin, now, blasted by the lightnings, and +they were not under it when the catastrophe happened. + +Everything in camp was drenched, the camp-fire as well; for they were +but heedless lads, like their generation, and had made no provision +against rain. Here was matter for dismay, for they were soaked through +and chilled. They were eloquent in their distress; but they presently +discovered that the fire had eaten so far up under the great log it had +been built against (where it curved upward and separated itself from +the ground), that a handbreadth or so of it had escaped wetting; so +they patiently wrought until, with shreds and bark gathered from the +under sides of sheltered logs, they coaxed the fire to burn again. Then +they piled on great dead boughs till they had a roaring furnace, and +were glad-hearted once more. They dried their boiled ham and had a +feast, and after that they sat by the fire and expanded and glorified +their midnight adventure until morning, for there was not a dry spot to +sleep on, anywhere around. + +As the sun began to steal in upon the boys, drowsiness came over them, +and they went out on the sandbar and lay down to sleep. They got +scorched out by and by, and drearily set about getting breakfast. After +the meal they felt rusty, and stiff-jointed, and a little homesick once +more. Tom saw the signs, and fell to cheering up the pirates as well as +he could. But they cared nothing for marbles, or circus, or swimming, +or anything. He reminded them of the imposing secret, and raised a ray +of cheer. While it lasted, he got them interested in a new device. This +was to knock off being pirates, for a while, and be Indians for a +change. They were attracted by this idea; so it was not long before +they were stripped, and striped from head to heel with black mud, like +so many zebras--all of them chiefs, of course--and then they went +tearing through the woods to attack an English settlement. + +By and by they separated into three hostile tribes, and darted upon +each other from ambush with dreadful war-whoops, and killed and scalped +each other by thousands. It was a gory day. Consequently it was an +extremely satisfactory one. + +They assembled in camp toward supper-time, hungry and happy; but now a +difficulty arose--hostile Indians could not break the bread of +hospitality together without first making peace, and this was a simple +impossibility without smoking a pipe of peace. There was no other +process that ever they had heard of. Two of the savages almost wished +they had remained pirates. However, there was no other way; so with +such show of cheerfulness as they could muster they called for the pipe +and took their whiff as it passed, in due form. + +And behold, they were glad they had gone into savagery, for they had +gained something; they found that they could now smoke a little without +having to go and hunt for a lost knife; they did not get sick enough to +be seriously uncomfortable. They were not likely to fool away this high +promise for lack of effort. No, they practised cautiously, after +supper, with right fair success, and so they spent a jubilant evening. +They were prouder and happier in their new acquirement than they would +have been in the scalping and skinning of the Six Nations. We will +leave them to smoke and chatter and brag, since we have no further use +for them at present. + + + +CHAPTER XVII + +BUT there was no hilarity in the little town that same tranquil +Saturday afternoon. The Harpers, and Aunt Polly's family, were being +put into mourning, with great grief and many tears. An unusual quiet +possessed the village, although it was ordinarily quiet enough, in all +conscience. The villagers conducted their concerns with an absent air, +and talked little; but they sighed often. The Saturday holiday seemed a +burden to the children. They had no heart in their sports, and +gradually gave them up. + +In the afternoon Becky Thatcher found herself moping about the +deserted schoolhouse yard, and feeling very melancholy. But she found +nothing there to comfort her. She soliloquized: + +"Oh, if I only had a brass andiron-knob again! But I haven't got +anything now to remember him by." And she choked back a little sob. + +Presently she stopped, and said to herself: + +"It was right here. Oh, if it was to do over again, I wouldn't say +that--I wouldn't say it for the whole world. But he's gone now; I'll +never, never, never see him any more." + +This thought broke her down, and she wandered away, with tears rolling +down her cheeks. Then quite a group of boys and girls--playmates of +Tom's and Joe's--came by, and stood looking over the paling fence and +talking in reverent tones of how Tom did so-and-so the last time they +saw him, and how Joe said this and that small trifle (pregnant with +awful prophecy, as they could easily see now!)--and each speaker +pointed out the exact spot where the lost lads stood at the time, and +then added something like "and I was a-standing just so--just as I am +now, and as if you was him--I was as close as that--and he smiled, just +this way--and then something seemed to go all over me, like--awful, you +know--and I never thought what it meant, of course, but I can see now!" + +Then there was a dispute about who saw the dead boys last in life, and +many claimed that dismal distinction, and offered evidences, more or +less tampered with by the witness; and when it was ultimately decided +who DID see the departed last, and exchanged the last words with them, +the lucky parties took upon themselves a sort of sacred importance, and +were gaped at and envied by all the rest. One poor chap, who had no +other grandeur to offer, said with tolerably manifest pride in the +remembrance: + +"Well, Tom Sawyer he licked me once." + +But that bid for glory was a failure. Most of the boys could say that, +and so that cheapened the distinction too much. The group loitered +away, still recalling memories of the lost heroes, in awed voices. + +When the Sunday-school hour was finished, the next morning, the bell +began to toll, instead of ringing in the usual way. It was a very still +Sabbath, and the mournful sound seemed in keeping with the musing hush +that lay upon nature. The villagers began to gather, loitering a moment +in the vestibule to converse in whispers about the sad event. But there +was no whispering in the house; only the funereal rustling of dresses +as the women gathered to their seats disturbed the silence there. None +could remember when the little church had been so full before. There +was finally a waiting pause, an expectant dumbness, and then Aunt Polly +entered, followed by Sid and Mary, and they by the Harper family, all +in deep black, and the whole congregation, the old minister as well, +rose reverently and stood until the mourners were seated in the front +pew. There was another communing silence, broken at intervals by +muffled sobs, and then the minister spread his hands abroad and prayed. +A moving hymn was sung, and the text followed: "I am the Resurrection +and the Life." + +As the service proceeded, the clergyman drew such pictures of the +graces, the winning ways, and the rare promise of the lost lads that +every soul there, thinking he recognized these pictures, felt a pang in +remembering that he had persistently blinded himself to them always +before, and had as persistently seen only faults and flaws in the poor +boys. The minister related many a touching incident in the lives of the +departed, too, which illustrated their sweet, generous natures, and the +people could easily see, now, how noble and beautiful those episodes +were, and remembered with grief that at the time they occurred they had +seemed rank rascalities, well deserving of the cowhide. The +congregation became more and more moved, as the pathetic tale went on, +till at last the whole company broke down and joined the weeping +mourners in a chorus of anguished sobs, the preacher himself giving way +to his feelings, and crying in the pulpit. + +There was a rustle in the gallery, which nobody noticed; a moment +later the church door creaked; the minister raised his streaming eyes +above his handkerchief, and stood transfixed! First one and then +another pair of eyes followed the minister's, and then almost with one +impulse the congregation rose and stared while the three dead boys came +marching up the aisle, Tom in the lead, Joe next, and Huck, a ruin of +drooping rags, sneaking sheepishly in the rear! They had been hid in +the unused gallery listening to their own funeral sermon! + +Aunt Polly, Mary, and the Harpers threw themselves upon their restored +ones, smothered them with kisses and poured out thanksgivings, while +poor Huck stood abashed and uncomfortable, not knowing exactly what to +do or where to hide from so many unwelcoming eyes. He wavered, and +started to slink away, but Tom seized him and said: + +"Aunt Polly, it ain't fair. Somebody's got to be glad to see Huck." + +"And so they shall. I'm glad to see him, poor motherless thing!" And +the loving attentions Aunt Polly lavished upon him were the one thing +capable of making him more uncomfortable than he was before. + +Suddenly the minister shouted at the top of his voice: "Praise God +from whom all blessings flow--SING!--and put your hearts in it!" + +And they did. Old Hundred swelled up with a triumphant burst, and +while it shook the rafters Tom Sawyer the Pirate looked around upon the +envying juveniles about him and confessed in his heart that this was +the proudest moment of his life. + +As the "sold" congregation trooped out they said they would almost be +willing to be made ridiculous again to hear Old Hundred sung like that +once more. + +Tom got more cuffs and kisses that day--according to Aunt Polly's +varying moods--than he had earned before in a year; and he hardly knew +which expressed the most gratefulness to God and affection for himself. + + + +CHAPTER XVIII + +THAT was Tom's great secret--the scheme to return home with his +brother pirates and attend their own funerals. They had paddled over to +the Missouri shore on a log, at dusk on Saturday, landing five or six +miles below the village; they had slept in the woods at the edge of the +town till nearly daylight, and had then crept through back lanes and +alleys and finished their sleep in the gallery of the church among a +chaos of invalided benches. + +At breakfast, Monday morning, Aunt Polly and Mary were very loving to +Tom, and very attentive to his wants. There was an unusual amount of +talk. In the course of it Aunt Polly said: + +"Well, I don't say it wasn't a fine joke, Tom, to keep everybody +suffering 'most a week so you boys had a good time, but it is a pity +you could be so hard-hearted as to let me suffer so. If you could come +over on a log to go to your funeral, you could have come over and give +me a hint some way that you warn't dead, but only run off." + +"Yes, you could have done that, Tom," said Mary; "and I believe you +would if you had thought of it." + +"Would you, Tom?" said Aunt Polly, her face lighting wistfully. "Say, +now, would you, if you'd thought of it?" + +"I--well, I don't know. 'Twould 'a' spoiled everything." + +"Tom, I hoped you loved me that much," said Aunt Polly, with a grieved +tone that discomforted the boy. "It would have been something if you'd +cared enough to THINK of it, even if you didn't DO it." + +"Now, auntie, that ain't any harm," pleaded Mary; "it's only Tom's +giddy way--he is always in such a rush that he never thinks of +anything." + +"More's the pity. Sid would have thought. And Sid would have come and +DONE it, too. Tom, you'll look back, some day, when it's too late, and +wish you'd cared a little more for me when it would have cost you so +little." + +"Now, auntie, you know I do care for you," said Tom. + +"I'd know it better if you acted more like it." + +"I wish now I'd thought," said Tom, with a repentant tone; "but I +dreamt about you, anyway. That's something, ain't it?" + +"It ain't much--a cat does that much--but it's better than nothing. +What did you dream?" + +"Why, Wednesday night I dreamt that you was sitting over there by the +bed, and Sid was sitting by the woodbox, and Mary next to him." + +"Well, so we did. So we always do. I'm glad your dreams could take +even that much trouble about us." + +"And I dreamt that Joe Harper's mother was here." + +"Why, she was here! Did you dream any more?" + +"Oh, lots. But it's so dim, now." + +"Well, try to recollect--can't you?" + +"Somehow it seems to me that the wind--the wind blowed the--the--" + +"Try harder, Tom! The wind did blow something. Come!" + +Tom pressed his fingers on his forehead an anxious minute, and then +said: + +"I've got it now! I've got it now! It blowed the candle!" + +"Mercy on us! Go on, Tom--go on!" + +"And it seems to me that you said, 'Why, I believe that that door--'" + +"Go ON, Tom!" + +"Just let me study a moment--just a moment. Oh, yes--you said you +believed the door was open." + +"As I'm sitting here, I did! Didn't I, Mary! Go on!" + +"And then--and then--well I won't be certain, but it seems like as if +you made Sid go and--and--" + +"Well? Well? What did I make him do, Tom? What did I make him do?" + +"You made him--you--Oh, you made him shut it." + +"Well, for the land's sake! I never heard the beat of that in all my +days! Don't tell ME there ain't anything in dreams, any more. Sereny +Harper shall know of this before I'm an hour older. I'd like to see her +get around THIS with her rubbage 'bout superstition. Go on, Tom!" + +"Oh, it's all getting just as bright as day, now. Next you said I +warn't BAD, only mischeevous and harum-scarum, and not any more +responsible than--than--I think it was a colt, or something." + +"And so it was! Well, goodness gracious! Go on, Tom!" + +"And then you began to cry." + +"So I did. So I did. Not the first time, neither. And then--" + +"Then Mrs. Harper she began to cry, and said Joe was just the same, +and she wished she hadn't whipped him for taking cream when she'd +throwed it out her own self--" + +"Tom! The sperrit was upon you! You was a prophesying--that's what you +was doing! Land alive, go on, Tom!" + +"Then Sid he said--he said--" + +"I don't think I said anything," said Sid. + +"Yes you did, Sid," said Mary. + +"Shut your heads and let Tom go on! What did he say, Tom?" + +"He said--I THINK he said he hoped I was better off where I was gone +to, but if I'd been better sometimes--" + +"THERE, d'you hear that! It was his very words!" + +"And you shut him up sharp." + +"I lay I did! There must 'a' been an angel there. There WAS an angel +there, somewheres!" + +"And Mrs. Harper told about Joe scaring her with a firecracker, and +you told about Peter and the Painkiller--" + +"Just as true as I live!" + +"And then there was a whole lot of talk 'bout dragging the river for +us, and 'bout having the funeral Sunday, and then you and old Miss +Harper hugged and cried, and she went." + +"It happened just so! It happened just so, as sure as I'm a-sitting in +these very tracks. Tom, you couldn't told it more like if you'd 'a' +seen it! And then what? Go on, Tom!" + +"Then I thought you prayed for me--and I could see you and hear every +word you said. And you went to bed, and I was so sorry that I took and +wrote on a piece of sycamore bark, 'We ain't dead--we are only off +being pirates,' and put it on the table by the candle; and then you +looked so good, laying there asleep, that I thought I went and leaned +over and kissed you on the lips." + +"Did you, Tom, DID you! I just forgive you everything for that!" And +she seized the boy in a crushing embrace that made him feel like the +guiltiest of villains. + +"It was very kind, even though it was only a--dream," Sid soliloquized +just audibly. + +"Shut up, Sid! A body does just the same in a dream as he'd do if he +was awake. Here's a big Milum apple I've been saving for you, Tom, if +you was ever found again--now go 'long to school. I'm thankful to the +good God and Father of us all I've got you back, that's long-suffering +and merciful to them that believe on Him and keep His word, though +goodness knows I'm unworthy of it, but if only the worthy ones got His +blessings and had His hand to help them over the rough places, there's +few enough would smile here or ever enter into His rest when the long +night comes. Go 'long Sid, Mary, Tom--take yourselves off--you've +hendered me long enough." + +The children left for school, and the old lady to call on Mrs. Harper +and vanquish her realism with Tom's marvellous dream. Sid had better +judgment than to utter the thought that was in his mind as he left the +house. It was this: "Pretty thin--as long a dream as that, without any +mistakes in it!" + +What a hero Tom was become, now! He did not go skipping and prancing, +but moved with a dignified swagger as became a pirate who felt that the +public eye was on him. And indeed it was; he tried not to seem to see +the looks or hear the remarks as he passed along, but they were food +and drink to him. Smaller boys than himself flocked at his heels, as +proud to be seen with him, and tolerated by him, as if he had been the +drummer at the head of a procession or the elephant leading a menagerie +into town. Boys of his own size pretended not to know he had been away +at all; but they were consuming with envy, nevertheless. They would +have given anything to have that swarthy suntanned skin of his, and his +glittering notoriety; and Tom would not have parted with either for a +circus. + +At school the children made so much of him and of Joe, and delivered +such eloquent admiration from their eyes, that the two heroes were not +long in becoming insufferably "stuck-up." They began to tell their +adventures to hungry listeners--but they only began; it was not a thing +likely to have an end, with imaginations like theirs to furnish +material. And finally, when they got out their pipes and went serenely +puffing around, the very summit of glory was reached. + +Tom decided that he could be independent of Becky Thatcher now. Glory +was sufficient. He would live for glory. Now that he was distinguished, +maybe she would be wanting to "make up." Well, let her--she should see +that he could be as indifferent as some other people. Presently she +arrived. Tom pretended not to see her. He moved away and joined a group +of boys and girls and began to talk. Soon he observed that she was +tripping gayly back and forth with flushed face and dancing eyes, +pretending to be busy chasing schoolmates, and screaming with laughter +when she made a capture; but he noticed that she always made her +captures in his vicinity, and that she seemed to cast a conscious eye +in his direction at such times, too. It gratified all the vicious +vanity that was in him; and so, instead of winning him, it only "set +him up" the more and made him the more diligent to avoid betraying that +he knew she was about. Presently she gave over skylarking, and moved +irresolutely about, sighing once or twice and glancing furtively and +wistfully toward Tom. Then she observed that now Tom was talking more +particularly to Amy Lawrence than to any one else. She felt a sharp +pang and grew disturbed and uneasy at once. She tried to go away, but +her feet were treacherous, and carried her to the group instead. She +said to a girl almost at Tom's elbow--with sham vivacity: + +"Why, Mary Austin! you bad girl, why didn't you come to Sunday-school?" + +"I did come--didn't you see me?" + +"Why, no! Did you? Where did you sit?" + +"I was in Miss Peters' class, where I always go. I saw YOU." + +"Did you? Why, it's funny I didn't see you. I wanted to tell you about +the picnic." + +"Oh, that's jolly. Who's going to give it?" + +"My ma's going to let me have one." + +"Oh, goody; I hope she'll let ME come." + +"Well, she will. The picnic's for me. She'll let anybody come that I +want, and I want you." + +"That's ever so nice. When is it going to be?" + +"By and by. Maybe about vacation." + +"Oh, won't it be fun! You going to have all the girls and boys?" + +"Yes, every one that's friends to me--or wants to be"; and she glanced +ever so furtively at Tom, but he talked right along to Amy Lawrence +about the terrible storm on the island, and how the lightning tore the +great sycamore tree "all to flinders" while he was "standing within +three feet of it." + +"Oh, may I come?" said Grace Miller. + +"Yes." + +"And me?" said Sally Rogers. + +"Yes." + +"And me, too?" said Susy Harper. "And Joe?" + +"Yes." + +And so on, with clapping of joyful hands till all the group had begged +for invitations but Tom and Amy. Then Tom turned coolly away, still +talking, and took Amy with him. Becky's lips trembled and the tears +came to her eyes; she hid these signs with a forced gayety and went on +chattering, but the life had gone out of the picnic, now, and out of +everything else; she got away as soon as she could and hid herself and +had what her sex call "a good cry." Then she sat moody, with wounded +pride, till the bell rang. She roused up, now, with a vindictive cast +in her eye, and gave her plaited tails a shake and said she knew what +SHE'D do. + +At recess Tom continued his flirtation with Amy with jubilant +self-satisfaction. And he kept drifting about to find Becky and lacerate +her with the performance. At last he spied her, but there was a sudden +falling of his mercury. She was sitting cosily on a little bench behind +the schoolhouse looking at a picture-book with Alfred Temple--and so +absorbed were they, and their heads so close together over the book, +that they did not seem to be conscious of anything in the world besides. +Jealousy ran red-hot through Tom's veins. He began to hate himself for +throwing away the chance Becky had offered for a reconciliation. He +called himself a fool, and all the hard names he could think of. He +wanted to cry with vexation. Amy chatted happily along, as they walked, +for her heart was singing, but Tom's tongue had lost its function. He +did not hear what Amy was saying, and whenever she paused expectantly he +could only stammer an awkward assent, which was as often misplaced as +otherwise. He kept drifting to the rear of the schoolhouse, again and +again, to sear his eyeballs with the hateful spectacle there. He could +not help it. And it maddened him to see, as he thought he saw, that +Becky Thatcher never once suspected that he was even in the land of the +living. But she did see, nevertheless; and she knew she was winning her +fight, too, and was glad to see him suffer as she had suffered. + +Amy's happy prattle became intolerable. Tom hinted at things he had to +attend to; things that must be done; and time was fleeting. But in +vain--the girl chirped on. Tom thought, "Oh, hang her, ain't I ever +going to get rid of her?" At last he must be attending to those +things--and she said artlessly that she would be "around" when school +let out. And he hastened away, hating her for it. + +"Any other boy!" Tom thought, grating his teeth. "Any boy in the whole +town but that Saint Louis smarty that thinks he dresses so fine and is +aristocracy! Oh, all right, I licked you the first day you ever saw +this town, mister, and I'll lick you again! You just wait till I catch +you out! I'll just take and--" + +And he went through the motions of thrashing an imaginary boy +--pummelling the air, and kicking and gouging. "Oh, you do, do you? You +holler 'nough, do you? Now, then, let that learn you!" And so the +imaginary flogging was finished to his satisfaction. + +Tom fled home at noon. His conscience could not endure any more of +Amy's grateful happiness, and his jealousy could bear no more of the +other distress. Becky resumed her picture inspections with Alfred, but +as the minutes dragged along and no Tom came to suffer, her triumph +began to cloud and she lost interest; gravity and absent-mindedness +followed, and then melancholy; two or three times she pricked up her +ear at a footstep, but it was a false hope; no Tom came. At last she +grew entirely miserable and wished she hadn't carried it so far. When +poor Alfred, seeing that he was losing her, he did not know how, kept +exclaiming: "Oh, here's a jolly one! look at this!" she lost patience +at last, and said, "Oh, don't bother me! I don't care for them!" and +burst into tears, and got up and walked away. + +Alfred dropped alongside and was going to try to comfort her, but she +said: + +"Go away and leave me alone, can't you! I hate you!" + +So the boy halted, wondering what he could have done--for she had said +she would look at pictures all through the nooning--and she walked on, +crying. Then Alfred went musing into the deserted schoolhouse. He was +humiliated and angry. He easily guessed his way to the truth--the girl +had simply made a convenience of him to vent her spite upon Tom Sawyer. +He was far from hating Tom the less when this thought occurred to him. +He wished there was some way to get that boy into trouble without much +risk to himself. Tom's spelling-book fell under his eye. Here was his +opportunity. He gratefully opened to the lesson for the afternoon and +poured ink upon the page. + +Becky, glancing in at a window behind him at the moment, saw the act, +and moved on, without discovering herself. She started homeward, now, +intending to find Tom and tell him; Tom would be thankful and their +troubles would be healed. Before she was half way home, however, she +had changed her mind. The thought of Tom's treatment of her when she +was talking about her picnic came scorching back and filled her with +shame. She resolved to let him get whipped on the damaged +spelling-book's account, and to hate him forever, into the bargain. + + + +CHAPTER XIX + +TOM arrived at home in a dreary mood, and the first thing his aunt +said to him showed him that he had brought his sorrows to an +unpromising market: + +"Tom, I've a notion to skin you alive!" + +"Auntie, what have I done?" + +"Well, you've done enough. Here I go over to Sereny Harper, like an +old softy, expecting I'm going to make her believe all that rubbage +about that dream, when lo and behold you she'd found out from Joe that +you was over here and heard all the talk we had that night. Tom, I +don't know what is to become of a boy that will act like that. It makes +me feel so bad to think you could let me go to Sereny Harper and make +such a fool of myself and never say a word." + +This was a new aspect of the thing. His smartness of the morning had +seemed to Tom a good joke before, and very ingenious. It merely looked +mean and shabby now. He hung his head and could not think of anything +to say for a moment. Then he said: + +"Auntie, I wish I hadn't done it--but I didn't think." + +"Oh, child, you never think. You never think of anything but your own +selfishness. You could think to come all the way over here from +Jackson's Island in the night to laugh at our troubles, and you could +think to fool me with a lie about a dream; but you couldn't ever think +to pity us and save us from sorrow." + +"Auntie, I know now it was mean, but I didn't mean to be mean. I +didn't, honest. And besides, I didn't come over here to laugh at you +that night." + +"What did you come for, then?" + +"It was to tell you not to be uneasy about us, because we hadn't got +drownded." + +"Tom, Tom, I would be the thankfullest soul in this world if I could +believe you ever had as good a thought as that, but you know you never +did--and I know it, Tom." + +"Indeed and 'deed I did, auntie--I wish I may never stir if I didn't." + +"Oh, Tom, don't lie--don't do it. It only makes things a hundred times +worse." + +"It ain't a lie, auntie; it's the truth. I wanted to keep you from +grieving--that was all that made me come." + +"I'd give the whole world to believe that--it would cover up a power +of sins, Tom. I'd 'most be glad you'd run off and acted so bad. But it +ain't reasonable; because, why didn't you tell me, child?" + +"Why, you see, when you got to talking about the funeral, I just got +all full of the idea of our coming and hiding in the church, and I +couldn't somehow bear to spoil it. So I just put the bark back in my +pocket and kept mum." + +"What bark?" + +"The bark I had wrote on to tell you we'd gone pirating. I wish, now, +you'd waked up when I kissed you--I do, honest." + +The hard lines in his aunt's face relaxed and a sudden tenderness +dawned in her eyes. + +"DID you kiss me, Tom?" + +"Why, yes, I did." + +"Are you sure you did, Tom?" + +"Why, yes, I did, auntie--certain sure." + +"What did you kiss me for, Tom?" + +"Because I loved you so, and you laid there moaning and I was so sorry." + +The words sounded like truth. The old lady could not hide a tremor in +her voice when she said: + +"Kiss me again, Tom!--and be off with you to school, now, and don't +bother me any more." + +The moment he was gone, she ran to a closet and got out the ruin of a +jacket which Tom had gone pirating in. Then she stopped, with it in her +hand, and said to herself: + +"No, I don't dare. Poor boy, I reckon he's lied about it--but it's a +blessed, blessed lie, there's such a comfort come from it. I hope the +Lord--I KNOW the Lord will forgive him, because it was such +goodheartedness in him to tell it. But I don't want to find out it's a +lie. I won't look." + +She put the jacket away, and stood by musing a minute. Twice she put +out her hand to take the garment again, and twice she refrained. Once +more she ventured, and this time she fortified herself with the +thought: "It's a good lie--it's a good lie--I won't let it grieve me." +So she sought the jacket pocket. A moment later she was reading Tom's +piece of bark through flowing tears and saying: "I could forgive the +boy, now, if he'd committed a million sins!" + + + +CHAPTER XX + +THERE was something about Aunt Polly's manner, when she kissed Tom, +that swept away his low spirits and made him lighthearted and happy +again. He started to school and had the luck of coming upon Becky +Thatcher at the head of Meadow Lane. His mood always determined his +manner. Without a moment's hesitation he ran to her and said: + +"I acted mighty mean to-day, Becky, and I'm so sorry. I won't ever, +ever do that way again, as long as ever I live--please make up, won't +you?" + +The girl stopped and looked him scornfully in the face: + +"I'll thank you to keep yourself TO yourself, Mr. Thomas Sawyer. I'll +never speak to you again." + +She tossed her head and passed on. Tom was so stunned that he had not +even presence of mind enough to say "Who cares, Miss Smarty?" until the +right time to say it had gone by. So he said nothing. But he was in a +fine rage, nevertheless. He moped into the schoolyard wishing she were +a boy, and imagining how he would trounce her if she were. He presently +encountered her and delivered a stinging remark as he passed. She +hurled one in return, and the angry breach was complete. It seemed to +Becky, in her hot resentment, that she could hardly wait for school to +"take in," she was so impatient to see Tom flogged for the injured +spelling-book. If she had had any lingering notion of exposing Alfred +Temple, Tom's offensive fling had driven it entirely away. + +Poor girl, she did not know how fast she was nearing trouble herself. +The master, Mr. Dobbins, had reached middle age with an unsatisfied +ambition. The darling of his desires was, to be a doctor, but poverty +had decreed that he should be nothing higher than a village +schoolmaster. Every day he took a mysterious book out of his desk and +absorbed himself in it at times when no classes were reciting. He kept +that book under lock and key. There was not an urchin in school but was +perishing to have a glimpse of it, but the chance never came. Every boy +and girl had a theory about the nature of that book; but no two +theories were alike, and there was no way of getting at the facts in +the case. Now, as Becky was passing by the desk, which stood near the +door, she noticed that the key was in the lock! It was a precious +moment. She glanced around; found herself alone, and the next instant +she had the book in her hands. The title-page--Professor Somebody's +ANATOMY--carried no information to her mind; so she began to turn the +leaves. She came at once upon a handsomely engraved and colored +frontispiece--a human figure, stark naked. At that moment a shadow fell +on the page and Tom Sawyer stepped in at the door and caught a glimpse +of the picture. Becky snatched at the book to close it, and had the +hard luck to tear the pictured page half down the middle. She thrust +the volume into the desk, turned the key, and burst out crying with +shame and vexation. + +"Tom Sawyer, you are just as mean as you can be, to sneak up on a +person and look at what they're looking at." + +"How could I know you was looking at anything?" + +"You ought to be ashamed of yourself, Tom Sawyer; you know you're +going to tell on me, and oh, what shall I do, what shall I do! I'll be +whipped, and I never was whipped in school." + +Then she stamped her little foot and said: + +"BE so mean if you want to! I know something that's going to happen. +You just wait and you'll see! Hateful, hateful, hateful!"--and she +flung out of the house with a new explosion of crying. + +Tom stood still, rather flustered by this onslaught. Presently he said +to himself: + +"What a curious kind of a fool a girl is! Never been licked in school! +Shucks! What's a licking! That's just like a girl--they're so +thin-skinned and chicken-hearted. Well, of course I ain't going to tell +old Dobbins on this little fool, because there's other ways of getting +even on her, that ain't so mean; but what of it? Old Dobbins will ask +who it was tore his book. Nobody'll answer. Then he'll do just the way +he always does--ask first one and then t'other, and when he comes to the +right girl he'll know it, without any telling. Girls' faces always tell +on them. They ain't got any backbone. She'll get licked. Well, it's a +kind of a tight place for Becky Thatcher, because there ain't any way +out of it." Tom conned the thing a moment longer, and then added: "All +right, though; she'd like to see me in just such a fix--let her sweat it +out!" + +Tom joined the mob of skylarking scholars outside. In a few moments +the master arrived and school "took in." Tom did not feel a strong +interest in his studies. Every time he stole a glance at the girls' +side of the room Becky's face troubled him. Considering all things, he +did not want to pity her, and yet it was all he could do to help it. He +could get up no exultation that was really worthy the name. Presently +the spelling-book discovery was made, and Tom's mind was entirely full +of his own matters for a while after that. Becky roused up from her +lethargy of distress and showed good interest in the proceedings. She +did not expect that Tom could get out of his trouble by denying that he +spilt the ink on the book himself; and she was right. The denial only +seemed to make the thing worse for Tom. Becky supposed she would be +glad of that, and she tried to believe she was glad of it, but she +found she was not certain. When the worst came to the worst, she had an +impulse to get up and tell on Alfred Temple, but she made an effort and +forced herself to keep still--because, said she to herself, "he'll tell +about me tearing the picture sure. I wouldn't say a word, not to save +his life!" + +Tom took his whipping and went back to his seat not at all +broken-hearted, for he thought it was possible that he had unknowingly +upset the ink on the spelling-book himself, in some skylarking bout--he +had denied it for form's sake and because it was custom, and had stuck +to the denial from principle. + +A whole hour drifted by, the master sat nodding in his throne, the air +was drowsy with the hum of study. By and by, Mr. Dobbins straightened +himself up, yawned, then unlocked his desk, and reached for his book, +but seemed undecided whether to take it out or leave it. Most of the +pupils glanced up languidly, but there were two among them that watched +his movements with intent eyes. Mr. Dobbins fingered his book absently +for a while, then took it out and settled himself in his chair to read! +Tom shot a glance at Becky. He had seen a hunted and helpless rabbit +look as she did, with a gun levelled at its head. Instantly he forgot +his quarrel with her. Quick--something must be done! done in a flash, +too! But the very imminence of the emergency paralyzed his invention. +Good!--he had an inspiration! He would run and snatch the book, spring +through the door and fly. But his resolution shook for one little +instant, and the chance was lost--the master opened the volume. If Tom +only had the wasted opportunity back again! Too late. There was no help +for Becky now, he said. The next moment the master faced the school. +Every eye sank under his gaze. There was that in it which smote even +the innocent with fear. There was silence while one might count ten +--the master was gathering his wrath. Then he spoke: "Who tore this book?" + +There was not a sound. One could have heard a pin drop. The stillness +continued; the master searched face after face for signs of guilt. + +"Benjamin Rogers, did you tear this book?" + +A denial. Another pause. + +"Joseph Harper, did you?" + +Another denial. Tom's uneasiness grew more and more intense under the +slow torture of these proceedings. The master scanned the ranks of +boys--considered a while, then turned to the girls: + +"Amy Lawrence?" + +A shake of the head. + +"Gracie Miller?" + +The same sign. + +"Susan Harper, did you do this?" + +Another negative. The next girl was Becky Thatcher. Tom was trembling +from head to foot with excitement and a sense of the hopelessness of +the situation. + +"Rebecca Thatcher" [Tom glanced at her face--it was white with terror] +--"did you tear--no, look me in the face" [her hands rose in appeal] +--"did you tear this book?" + +A thought shot like lightning through Tom's brain. He sprang to his +feet and shouted--"I done it!" + +The school stared in perplexity at this incredible folly. Tom stood a +moment, to gather his dismembered faculties; and when he stepped +forward to go to his punishment the surprise, the gratitude, the +adoration that shone upon him out of poor Becky's eyes seemed pay +enough for a hundred floggings. Inspired by the splendor of his own +act, he took without an outcry the most merciless flaying that even Mr. +Dobbins had ever administered; and also received with indifference the +added cruelty of a command to remain two hours after school should be +dismissed--for he knew who would wait for him outside till his +captivity was done, and not count the tedious time as loss, either. + +Tom went to bed that night planning vengeance against Alfred Temple; +for with shame and repentance Becky had told him all, not forgetting +her own treachery; but even the longing for vengeance had to give way, +soon, to pleasanter musings, and he fell asleep at last with Becky's +latest words lingering dreamily in his ear-- + +"Tom, how COULD you be so noble!" + + + +CHAPTER XXI + +VACATION was approaching. The schoolmaster, always severe, grew +severer and more exacting than ever, for he wanted the school to make a +good showing on "Examination" day. His rod and his ferule were seldom +idle now--at least among the smaller pupils. Only the biggest boys, and +young ladies of eighteen and twenty, escaped lashing. Mr. Dobbins' +lashings were very vigorous ones, too; for although he carried, under +his wig, a perfectly bald and shiny head, he had only reached middle +age, and there was no sign of feebleness in his muscle. As the great +day approached, all the tyranny that was in him came to the surface; he +seemed to take a vindictive pleasure in punishing the least +shortcomings. The consequence was, that the smaller boys spent their +days in terror and suffering and their nights in plotting revenge. They +threw away no opportunity to do the master a mischief. But he kept +ahead all the time. The retribution that followed every vengeful +success was so sweeping and majestic that the boys always retired from +the field badly worsted. At last they conspired together and hit upon a +plan that promised a dazzling victory. They swore in the sign-painter's +boy, told him the scheme, and asked his help. He had his own reasons +for being delighted, for the master boarded in his father's family and +had given the boy ample cause to hate him. The master's wife would go +on a visit to the country in a few days, and there would be nothing to +interfere with the plan; the master always prepared himself for great +occasions by getting pretty well fuddled, and the sign-painter's boy +said that when the dominie had reached the proper condition on +Examination Evening he would "manage the thing" while he napped in his +chair; then he would have him awakened at the right time and hurried +away to school. + +In the fulness of time the interesting occasion arrived. At eight in +the evening the schoolhouse was brilliantly lighted, and adorned with +wreaths and festoons of foliage and flowers. The master sat throned in +his great chair upon a raised platform, with his blackboard behind him. +He was looking tolerably mellow. Three rows of benches on each side and +six rows in front of him were occupied by the dignitaries of the town +and by the parents of the pupils. To his left, back of the rows of +citizens, was a spacious temporary platform upon which were seated the +scholars who were to take part in the exercises of the evening; rows of +small boys, washed and dressed to an intolerable state of discomfort; +rows of gawky big boys; snowbanks of girls and young ladies clad in +lawn and muslin and conspicuously conscious of their bare arms, their +grandmothers' ancient trinkets, their bits of pink and blue ribbon and +the flowers in their hair. All the rest of the house was filled with +non-participating scholars. + +The exercises began. A very little boy stood up and sheepishly +recited, "You'd scarce expect one of my age to speak in public on the +stage," etc.--accompanying himself with the painfully exact and +spasmodic gestures which a machine might have used--supposing the +machine to be a trifle out of order. But he got through safely, though +cruelly scared, and got a fine round of applause when he made his +manufactured bow and retired. + +A little shamefaced girl lisped, "Mary had a little lamb," etc., +performed a compassion-inspiring curtsy, got her meed of applause, and +sat down flushed and happy. + +Tom Sawyer stepped forward with conceited confidence and soared into +the unquenchable and indestructible "Give me liberty or give me death" +speech, with fine fury and frantic gesticulation, and broke down in the +middle of it. A ghastly stage-fright seized him, his legs quaked under +him and he was like to choke. True, he had the manifest sympathy of the +house but he had the house's silence, too, which was even worse than +its sympathy. The master frowned, and this completed the disaster. Tom +struggled awhile and then retired, utterly defeated. There was a weak +attempt at applause, but it died early. + +"The Boy Stood on the Burning Deck" followed; also "The Assyrian Came +Down," and other declamatory gems. Then there were reading exercises, +and a spelling fight. The meagre Latin class recited with honor. The +prime feature of the evening was in order, now--original "compositions" +by the young ladies. Each in her turn stepped forward to the edge of +the platform, cleared her throat, held up her manuscript (tied with +dainty ribbon), and proceeded to read, with labored attention to +"expression" and punctuation. The themes were the same that had been +illuminated upon similar occasions by their mothers before them, their +grandmothers, and doubtless all their ancestors in the female line +clear back to the Crusades. "Friendship" was one; "Memories of Other +Days"; "Religion in History"; "Dream Land"; "The Advantages of +Culture"; "Forms of Political Government Compared and Contrasted"; +"Melancholy"; "Filial Love"; "Heart Longings," etc., etc. + +A prevalent feature in these compositions was a nursed and petted +melancholy; another was a wasteful and opulent gush of "fine language"; +another was a tendency to lug in by the ears particularly prized words +and phrases until they were worn entirely out; and a peculiarity that +conspicuously marked and marred them was the inveterate and intolerable +sermon that wagged its crippled tail at the end of each and every one +of them. No matter what the subject might be, a brain-racking effort +was made to squirm it into some aspect or other that the moral and +religious mind could contemplate with edification. The glaring +insincerity of these sermons was not sufficient to compass the +banishment of the fashion from the schools, and it is not sufficient +to-day; it never will be sufficient while the world stands, perhaps. +There is no school in all our land where the young ladies do not feel +obliged to close their compositions with a sermon; and you will find +that the sermon of the most frivolous and the least religious girl in +the school is always the longest and the most relentlessly pious. But +enough of this. Homely truth is unpalatable. + +Let us return to the "Examination." The first composition that was +read was one entitled "Is this, then, Life?" Perhaps the reader can +endure an extract from it: + + "In the common walks of life, with what delightful + emotions does the youthful mind look forward to some + anticipated scene of festivity! Imagination is busy + sketching rose-tinted pictures of joy. In fancy, the + voluptuous votary of fashion sees herself amid the + festive throng, 'the observed of all observers.' Her + graceful form, arrayed in snowy robes, is whirling + through the mazes of the joyous dance; her eye is + brightest, her step is lightest in the gay assembly. + + "In such delicious fancies time quickly glides by, + and the welcome hour arrives for her entrance into + the Elysian world, of which she has had such bright + dreams. How fairy-like does everything appear to + her enchanted vision! Each new scene is more charming + than the last. But after a while she finds that + beneath this goodly exterior, all is vanity, the + flattery which once charmed her soul, now grates + harshly upon her ear; the ball-room has lost its + charms; and with wasted health and imbittered heart, + she turns away with the conviction that earthly + pleasures cannot satisfy the longings of the soul!" + +And so forth and so on. There was a buzz of gratification from time to +time during the reading, accompanied by whispered ejaculations of "How +sweet!" "How eloquent!" "So true!" etc., and after the thing had closed +with a peculiarly afflicting sermon the applause was enthusiastic. + +Then arose a slim, melancholy girl, whose face had the "interesting" +paleness that comes of pills and indigestion, and read a "poem." Two +stanzas of it will do: + + "A MISSOURI MAIDEN'S FAREWELL TO ALABAMA + + "Alabama, good-bye! I love thee well! + But yet for a while do I leave thee now! + Sad, yes, sad thoughts of thee my heart doth swell, + And burning recollections throng my brow! + For I have wandered through thy flowery woods; + Have roamed and read near Tallapoosa's stream; + Have listened to Tallassee's warring floods, + And wooed on Coosa's side Aurora's beam. + + "Yet shame I not to bear an o'er-full heart, + Nor blush to turn behind my tearful eyes; + 'Tis from no stranger land I now must part, + 'Tis to no strangers left I yield these sighs. + Welcome and home were mine within this State, + Whose vales I leave--whose spires fade fast from me + And cold must be mine eyes, and heart, and tete, + When, dear Alabama! they turn cold on thee!" + +There were very few there who knew what "tete" meant, but the poem was +very satisfactory, nevertheless. + +Next appeared a dark-complexioned, black-eyed, black-haired young +lady, who paused an impressive moment, assumed a tragic expression, and +began to read in a measured, solemn tone: + + "A VISION + + "Dark and tempestuous was night. Around the + throne on high not a single star quivered; but + the deep intonations of the heavy thunder + constantly vibrated upon the ear; whilst the + terrific lightning revelled in angry mood + through the cloudy chambers of heaven, seeming + to scorn the power exerted over its terror by + the illustrious Franklin! Even the boisterous + winds unanimously came forth from their mystic + homes, and blustered about as if to enhance by + their aid the wildness of the scene. + + "At such a time, so dark, so dreary, for human + sympathy my very spirit sighed; but instead thereof, + + "'My dearest friend, my counsellor, my comforter + and guide--My joy in grief, my second bliss + in joy,' came to my side. She moved like one of + those bright beings pictured in the sunny walks + of fancy's Eden by the romantic and young, a + queen of beauty unadorned save by her own + transcendent loveliness. So soft was her step, it + failed to make even a sound, and but for the + magical thrill imparted by her genial touch, as + other unobtrusive beauties, she would have glided + away un-perceived--unsought. A strange sadness + rested upon her features, like icy tears upon + the robe of December, as she pointed to the + contending elements without, and bade me contemplate + the two beings presented." + +This nightmare occupied some ten pages of manuscript and wound up with +a sermon so destructive of all hope to non-Presbyterians that it took +the first prize. This composition was considered to be the very finest +effort of the evening. The mayor of the village, in delivering the +prize to the author of it, made a warm speech in which he said that it +was by far the most "eloquent" thing he had ever listened to, and that +Daniel Webster himself might well be proud of it. + +It may be remarked, in passing, that the number of compositions in +which the word "beauteous" was over-fondled, and human experience +referred to as "life's page," was up to the usual average. + +Now the master, mellow almost to the verge of geniality, put his chair +aside, turned his back to the audience, and began to draw a map of +America on the blackboard, to exercise the geography class upon. But he +made a sad business of it with his unsteady hand, and a smothered +titter rippled over the house. He knew what the matter was, and set +himself to right it. He sponged out lines and remade them; but he only +distorted them more than ever, and the tittering was more pronounced. +He threw his entire attention upon his work, now, as if determined not +to be put down by the mirth. He felt that all eyes were fastened upon +him; he imagined he was succeeding, and yet the tittering continued; it +even manifestly increased. And well it might. There was a garret above, +pierced with a scuttle over his head; and down through this scuttle +came a cat, suspended around the haunches by a string; she had a rag +tied about her head and jaws to keep her from mewing; as she slowly +descended she curved upward and clawed at the string, she swung +downward and clawed at the intangible air. The tittering rose higher +and higher--the cat was within six inches of the absorbed teacher's +head--down, down, a little lower, and she grabbed his wig with her +desperate claws, clung to it, and was snatched up into the garret in an +instant with her trophy still in her possession! And how the light did +blaze abroad from the master's bald pate--for the sign-painter's boy +had GILDED it! + +That broke up the meeting. The boys were avenged. Vacation had come. + + NOTE:--The pretended "compositions" quoted in + this chapter are taken without alteration from a + volume entitled "Prose and Poetry, by a Western + Lady"--but they are exactly and precisely after + the schoolgirl pattern, and hence are much + happier than any mere imitations could be. + + + +CHAPTER XXII + +TOM joined the new order of Cadets of Temperance, being attracted by +the showy character of their "regalia." He promised to abstain from +smoking, chewing, and profanity as long as he remained a member. Now he +found out a new thing--namely, that to promise not to do a thing is the +surest way in the world to make a body want to go and do that very +thing. Tom soon found himself tormented with a desire to drink and +swear; the desire grew to be so intense that nothing but the hope of a +chance to display himself in his red sash kept him from withdrawing +from the order. Fourth of July was coming; but he soon gave that up +--gave it up before he had worn his shackles over forty-eight hours--and +fixed his hopes upon old Judge Frazer, justice of the peace, who was +apparently on his deathbed and would have a big public funeral, since +he was so high an official. During three days Tom was deeply concerned +about the Judge's condition and hungry for news of it. Sometimes his +hopes ran high--so high that he would venture to get out his regalia +and practise before the looking-glass. But the Judge had a most +discouraging way of fluctuating. At last he was pronounced upon the +mend--and then convalescent. Tom was disgusted; and felt a sense of +injury, too. He handed in his resignation at once--and that night the +Judge suffered a relapse and died. Tom resolved that he would never +trust a man like that again. + +The funeral was a fine thing. The Cadets paraded in a style calculated +to kill the late member with envy. Tom was a free boy again, however +--there was something in that. He could drink and swear, now--but found +to his surprise that he did not want to. The simple fact that he could, +took the desire away, and the charm of it. + +Tom presently wondered to find that his coveted vacation was beginning +to hang a little heavily on his hands. + +He attempted a diary--but nothing happened during three days, and so +he abandoned it. + +The first of all the negro minstrel shows came to town, and made a +sensation. Tom and Joe Harper got up a band of performers and were +happy for two days. + +Even the Glorious Fourth was in some sense a failure, for it rained +hard, there was no procession in consequence, and the greatest man in +the world (as Tom supposed), Mr. Benton, an actual United States +Senator, proved an overwhelming disappointment--for he was not +twenty-five feet high, nor even anywhere in the neighborhood of it. + +A circus came. The boys played circus for three days afterward in +tents made of rag carpeting--admission, three pins for boys, two for +girls--and then circusing was abandoned. + +A phrenologist and a mesmerizer came--and went again and left the +village duller and drearier than ever. + +There were some boys-and-girls' parties, but they were so few and so +delightful that they only made the aching voids between ache the harder. + +Becky Thatcher was gone to her Constantinople home to stay with her +parents during vacation--so there was no bright side to life anywhere. + +The dreadful secret of the murder was a chronic misery. It was a very +cancer for permanency and pain. + +Then came the measles. + +During two long weeks Tom lay a prisoner, dead to the world and its +happenings. He was very ill, he was interested in nothing. When he got +upon his feet at last and moved feebly down-town, a melancholy change +had come over everything and every creature. There had been a +"revival," and everybody had "got religion," not only the adults, but +even the boys and girls. Tom went about, hoping against hope for the +sight of one blessed sinful face, but disappointment crossed him +everywhere. He found Joe Harper studying a Testament, and turned sadly +away from the depressing spectacle. He sought Ben Rogers, and found him +visiting the poor with a basket of tracts. He hunted up Jim Hollis, who +called his attention to the precious blessing of his late measles as a +warning. Every boy he encountered added another ton to his depression; +and when, in desperation, he flew for refuge at last to the bosom of +Huckleberry Finn and was received with a Scriptural quotation, his +heart broke and he crept home and to bed realizing that he alone of all +the town was lost, forever and forever. + +And that night there came on a terrific storm, with driving rain, +awful claps of thunder and blinding sheets of lightning. He covered his +head with the bedclothes and waited in a horror of suspense for his +doom; for he had not the shadow of a doubt that all this hubbub was +about him. He believed he had taxed the forbearance of the powers above +to the extremity of endurance and that this was the result. It might +have seemed to him a waste of pomp and ammunition to kill a bug with a +battery of artillery, but there seemed nothing incongruous about the +getting up such an expensive thunderstorm as this to knock the turf +from under an insect like himself. + +By and by the tempest spent itself and died without accomplishing its +object. The boy's first impulse was to be grateful, and reform. His +second was to wait--for there might not be any more storms. + +The next day the doctors were back; Tom had relapsed. The three weeks +he spent on his back this time seemed an entire age. When he got abroad +at last he was hardly grateful that he had been spared, remembering how +lonely was his estate, how companionless and forlorn he was. He drifted +listlessly down the street and found Jim Hollis acting as judge in a +juvenile court that was trying a cat for murder, in the presence of her +victim, a bird. He found Joe Harper and Huck Finn up an alley eating a +stolen melon. Poor lads! they--like Tom--had suffered a relapse. + + + +CHAPTER XXIII + +AT last the sleepy atmosphere was stirred--and vigorously: the murder +trial came on in the court. It became the absorbing topic of village +talk immediately. Tom could not get away from it. Every reference to +the murder sent a shudder to his heart, for his troubled conscience and +fears almost persuaded him that these remarks were put forth in his +hearing as "feelers"; he did not see how he could be suspected of +knowing anything about the murder, but still he could not be +comfortable in the midst of this gossip. It kept him in a cold shiver +all the time. He took Huck to a lonely place to have a talk with him. +It would be some relief to unseal his tongue for a little while; to +divide his burden of distress with another sufferer. Moreover, he +wanted to assure himself that Huck had remained discreet. + +"Huck, have you ever told anybody about--that?" + +"'Bout what?" + +"You know what." + +"Oh--'course I haven't." + +"Never a word?" + +"Never a solitary word, so help me. What makes you ask?" + +"Well, I was afeard." + +"Why, Tom Sawyer, we wouldn't be alive two days if that got found out. +YOU know that." + +Tom felt more comfortable. After a pause: + +"Huck, they couldn't anybody get you to tell, could they?" + +"Get me to tell? Why, if I wanted that half-breed devil to drownd me +they could get me to tell. They ain't no different way." + +"Well, that's all right, then. I reckon we're safe as long as we keep +mum. But let's swear again, anyway. It's more surer." + +"I'm agreed." + +So they swore again with dread solemnities. + +"What is the talk around, Huck? I've heard a power of it." + +"Talk? Well, it's just Muff Potter, Muff Potter, Muff Potter all the +time. It keeps me in a sweat, constant, so's I want to hide som'ers." + +"That's just the same way they go on round me. I reckon he's a goner. +Don't you feel sorry for him, sometimes?" + +"Most always--most always. He ain't no account; but then he hain't +ever done anything to hurt anybody. Just fishes a little, to get money +to get drunk on--and loafs around considerable; but lord, we all do +that--leastways most of us--preachers and such like. But he's kind of +good--he give me half a fish, once, when there warn't enough for two; +and lots of times he's kind of stood by me when I was out of luck." + +"Well, he's mended kites for me, Huck, and knitted hooks on to my +line. I wish we could get him out of there." + +"My! we couldn't get him out, Tom. And besides, 'twouldn't do any +good; they'd ketch him again." + +"Yes--so they would. But I hate to hear 'em abuse him so like the +dickens when he never done--that." + +"I do too, Tom. Lord, I hear 'em say he's the bloodiest looking +villain in this country, and they wonder he wasn't ever hung before." + +"Yes, they talk like that, all the time. I've heard 'em say that if he +was to get free they'd lynch him." + +"And they'd do it, too." + +The boys had a long talk, but it brought them little comfort. As the +twilight drew on, they found themselves hanging about the neighborhood +of the little isolated jail, perhaps with an undefined hope that +something would happen that might clear away their difficulties. But +nothing happened; there seemed to be no angels or fairies interested in +this luckless captive. + +The boys did as they had often done before--went to the cell grating +and gave Potter some tobacco and matches. He was on the ground floor +and there were no guards. + +His gratitude for their gifts had always smote their consciences +before--it cut deeper than ever, this time. They felt cowardly and +treacherous to the last degree when Potter said: + +"You've been mighty good to me, boys--better'n anybody else in this +town. And I don't forget it, I don't. Often I says to myself, says I, +'I used to mend all the boys' kites and things, and show 'em where the +good fishin' places was, and befriend 'em what I could, and now they've +all forgot old Muff when he's in trouble; but Tom don't, and Huck +don't--THEY don't forget him, says I, 'and I don't forget them.' Well, +boys, I done an awful thing--drunk and crazy at the time--that's the +only way I account for it--and now I got to swing for it, and it's +right. Right, and BEST, too, I reckon--hope so, anyway. Well, we won't +talk about that. I don't want to make YOU feel bad; you've befriended +me. But what I want to say, is, don't YOU ever get drunk--then you won't +ever get here. Stand a litter furder west--so--that's it; it's a prime +comfort to see faces that's friendly when a body's in such a muck of +trouble, and there don't none come here but yourn. Good friendly +faces--good friendly faces. Git up on one another's backs and let me +touch 'em. That's it. Shake hands--yourn'll come through the bars, but +mine's too big. Little hands, and weak--but they've helped Muff Potter +a power, and they'd help him more if they could." + +Tom went home miserable, and his dreams that night were full of +horrors. The next day and the day after, he hung about the court-room, +drawn by an almost irresistible impulse to go in, but forcing himself +to stay out. Huck was having the same experience. They studiously +avoided each other. Each wandered away, from time to time, but the same +dismal fascination always brought them back presently. Tom kept his +ears open when idlers sauntered out of the court-room, but invariably +heard distressing news--the toils were closing more and more +relentlessly around poor Potter. At the end of the second day the +village talk was to the effect that Injun Joe's evidence stood firm and +unshaken, and that there was not the slightest question as to what the +jury's verdict would be. + +Tom was out late, that night, and came to bed through the window. He +was in a tremendous state of excitement. It was hours before he got to +sleep. All the village flocked to the court-house the next morning, for +this was to be the great day. Both sexes were about equally represented +in the packed audience. After a long wait the jury filed in and took +their places; shortly afterward, Potter, pale and haggard, timid and +hopeless, was brought in, with chains upon him, and seated where all +the curious eyes could stare at him; no less conspicuous was Injun Joe, +stolid as ever. There was another pause, and then the judge arrived and +the sheriff proclaimed the opening of the court. The usual whisperings +among the lawyers and gathering together of papers followed. These +details and accompanying delays worked up an atmosphere of preparation +that was as impressive as it was fascinating. + +Now a witness was called who testified that he found Muff Potter +washing in the brook, at an early hour of the morning that the murder +was discovered, and that he immediately sneaked away. After some +further questioning, counsel for the prosecution said: + +"Take the witness." + +The prisoner raised his eyes for a moment, but dropped them again when +his own counsel said: + +"I have no questions to ask him." + +The next witness proved the finding of the knife near the corpse. +Counsel for the prosecution said: + +"Take the witness." + +"I have no questions to ask him," Potter's lawyer replied. + +A third witness swore he had often seen the knife in Potter's +possession. + +"Take the witness." + +Counsel for Potter declined to question him. The faces of the audience +began to betray annoyance. Did this attorney mean to throw away his +client's life without an effort? + +Several witnesses deposed concerning Potter's guilty behavior when +brought to the scene of the murder. They were allowed to leave the +stand without being cross-questioned. + +Every detail of the damaging circumstances that occurred in the +graveyard upon that morning which all present remembered so well was +brought out by credible witnesses, but none of them were cross-examined +by Potter's lawyer. The perplexity and dissatisfaction of the house +expressed itself in murmurs and provoked a reproof from the bench. +Counsel for the prosecution now said: + +"By the oaths of citizens whose simple word is above suspicion, we +have fastened this awful crime, beyond all possibility of question, +upon the unhappy prisoner at the bar. We rest our case here." + +A groan escaped from poor Potter, and he put his face in his hands and +rocked his body softly to and fro, while a painful silence reigned in +the court-room. Many men were moved, and many women's compassion +testified itself in tears. Counsel for the defence rose and said: + +"Your honor, in our remarks at the opening of this trial, we +foreshadowed our purpose to prove that our client did this fearful deed +while under the influence of a blind and irresponsible delirium +produced by drink. We have changed our mind. We shall not offer that +plea." [Then to the clerk:] "Call Thomas Sawyer!" + +A puzzled amazement awoke in every face in the house, not even +excepting Potter's. Every eye fastened itself with wondering interest +upon Tom as he rose and took his place upon the stand. The boy looked +wild enough, for he was badly scared. The oath was administered. + +"Thomas Sawyer, where were you on the seventeenth of June, about the +hour of midnight?" + +Tom glanced at Injun Joe's iron face and his tongue failed him. The +audience listened breathless, but the words refused to come. After a +few moments, however, the boy got a little of his strength back, and +managed to put enough of it into his voice to make part of the house +hear: + +"In the graveyard!" + +"A little bit louder, please. Don't be afraid. You were--" + +"In the graveyard." + +A contemptuous smile flitted across Injun Joe's face. + +"Were you anywhere near Horse Williams' grave?" + +"Yes, sir." + +"Speak up--just a trifle louder. How near were you?" + +"Near as I am to you." + +"Were you hidden, or not?" + +"I was hid." + +"Where?" + +"Behind the elms that's on the edge of the grave." + +Injun Joe gave a barely perceptible start. + +"Any one with you?" + +"Yes, sir. I went there with--" + +"Wait--wait a moment. Never mind mentioning your companion's name. We +will produce him at the proper time. Did you carry anything there with +you." + +Tom hesitated and looked confused. + +"Speak out, my boy--don't be diffident. The truth is always +respectable. What did you take there?" + +"Only a--a--dead cat." + +There was a ripple of mirth, which the court checked. + +"We will produce the skeleton of that cat. Now, my boy, tell us +everything that occurred--tell it in your own way--don't skip anything, +and don't be afraid." + +Tom began--hesitatingly at first, but as he warmed to his subject his +words flowed more and more easily; in a little while every sound ceased +but his own voice; every eye fixed itself upon him; with parted lips +and bated breath the audience hung upon his words, taking no note of +time, rapt in the ghastly fascinations of the tale. The strain upon +pent emotion reached its climax when the boy said: + +"--and as the doctor fetched the board around and Muff Potter fell, +Injun Joe jumped with the knife and--" + +Crash! Quick as lightning the half-breed sprang for a window, tore his +way through all opposers, and was gone! + + + +CHAPTER XXIV + +TOM was a glittering hero once more--the pet of the old, the envy of +the young. His name even went into immortal print, for the village +paper magnified him. There were some that believed he would be +President, yet, if he escaped hanging. + +As usual, the fickle, unreasoning world took Muff Potter to its bosom +and fondled him as lavishly as it had abused him before. But that sort +of conduct is to the world's credit; therefore it is not well to find +fault with it. + +Tom's days were days of splendor and exultation to him, but his nights +were seasons of horror. Injun Joe infested all his dreams, and always +with doom in his eye. Hardly any temptation could persuade the boy to +stir abroad after nightfall. Poor Huck was in the same state of +wretchedness and terror, for Tom had told the whole story to the lawyer +the night before the great day of the trial, and Huck was sore afraid +that his share in the business might leak out, yet, notwithstanding +Injun Joe's flight had saved him the suffering of testifying in court. +The poor fellow had got the attorney to promise secrecy, but what of +that? Since Tom's harassed conscience had managed to drive him to the +lawyer's house by night and wring a dread tale from lips that had been +sealed with the dismalest and most formidable of oaths, Huck's +confidence in the human race was well-nigh obliterated. + +Daily Muff Potter's gratitude made Tom glad he had spoken; but nightly +he wished he had sealed up his tongue. + +Half the time Tom was afraid Injun Joe would never be captured; the +other half he was afraid he would be. He felt sure he never could draw +a safe breath again until that man was dead and he had seen the corpse. + +Rewards had been offered, the country had been scoured, but no Injun +Joe was found. One of those omniscient and awe-inspiring marvels, a +detective, came up from St. Louis, moused around, shook his head, +looked wise, and made that sort of astounding success which members of +that craft usually achieve. That is to say, he "found a clew." But you +can't hang a "clew" for murder, and so after that detective had got +through and gone home, Tom felt just as insecure as he was before. + +The slow days drifted on, and each left behind it a slightly lightened +weight of apprehension. + + + +CHAPTER XXV + +THERE comes a time in every rightly-constructed boy's life when he has +a raging desire to go somewhere and dig for hidden treasure. This +desire suddenly came upon Tom one day. He sallied out to find Joe +Harper, but failed of success. Next he sought Ben Rogers; he had gone +fishing. Presently he stumbled upon Huck Finn the Red-Handed. Huck +would answer. Tom took him to a private place and opened the matter to +him confidentially. Huck was willing. Huck was always willing to take a +hand in any enterprise that offered entertainment and required no +capital, for he had a troublesome superabundance of that sort of time +which is not money. "Where'll we dig?" said Huck. + +"Oh, most anywhere." + +"Why, is it hid all around?" + +"No, indeed it ain't. It's hid in mighty particular places, Huck +--sometimes on islands, sometimes in rotten chests under the end of a +limb of an old dead tree, just where the shadow falls at midnight; but +mostly under the floor in ha'nted houses." + +"Who hides it?" + +"Why, robbers, of course--who'd you reckon? Sunday-school +sup'rintendents?" + +"I don't know. If 'twas mine I wouldn't hide it; I'd spend it and have +a good time." + +"So would I. But robbers don't do that way. They always hide it and +leave it there." + +"Don't they come after it any more?" + +"No, they think they will, but they generally forget the marks, or +else they die. Anyway, it lays there a long time and gets rusty; and by +and by somebody finds an old yellow paper that tells how to find the +marks--a paper that's got to be ciphered over about a week because it's +mostly signs and hy'roglyphics." + +"Hyro--which?" + +"Hy'roglyphics--pictures and things, you know, that don't seem to mean +anything." + +"Have you got one of them papers, Tom?" + +"No." + +"Well then, how you going to find the marks?" + +"I don't want any marks. They always bury it under a ha'nted house or +on an island, or under a dead tree that's got one limb sticking out. +Well, we've tried Jackson's Island a little, and we can try it again +some time; and there's the old ha'nted house up the Still-House branch, +and there's lots of dead-limb trees--dead loads of 'em." + +"Is it under all of them?" + +"How you talk! No!" + +"Then how you going to know which one to go for?" + +"Go for all of 'em!" + +"Why, Tom, it'll take all summer." + +"Well, what of that? Suppose you find a brass pot with a hundred +dollars in it, all rusty and gray, or rotten chest full of di'monds. +How's that?" + +Huck's eyes glowed. + +"That's bully. Plenty bully enough for me. Just you gimme the hundred +dollars and I don't want no di'monds." + +"All right. But I bet you I ain't going to throw off on di'monds. Some +of 'em's worth twenty dollars apiece--there ain't any, hardly, but's +worth six bits or a dollar." + +"No! Is that so?" + +"Cert'nly--anybody'll tell you so. Hain't you ever seen one, Huck?" + +"Not as I remember." + +"Oh, kings have slathers of them." + +"Well, I don' know no kings, Tom." + +"I reckon you don't. But if you was to go to Europe you'd see a raft +of 'em hopping around." + +"Do they hop?" + +"Hop?--your granny! No!" + +"Well, what did you say they did, for?" + +"Shucks, I only meant you'd SEE 'em--not hopping, of course--what do +they want to hop for?--but I mean you'd just see 'em--scattered around, +you know, in a kind of a general way. Like that old humpbacked Richard." + +"Richard? What's his other name?" + +"He didn't have any other name. Kings don't have any but a given name." + +"No?" + +"But they don't." + +"Well, if they like it, Tom, all right; but I don't want to be a king +and have only just a given name, like a nigger. But say--where you +going to dig first?" + +"Well, I don't know. S'pose we tackle that old dead-limb tree on the +hill t'other side of Still-House branch?" + +"I'm agreed." + +So they got a crippled pick and a shovel, and set out on their +three-mile tramp. They arrived hot and panting, and threw themselves +down in the shade of a neighboring elm to rest and have a smoke. + +"I like this," said Tom. + +"So do I." + +"Say, Huck, if we find a treasure here, what you going to do with your +share?" + +"Well, I'll have pie and a glass of soda every day, and I'll go to +every circus that comes along. I bet I'll have a gay time." + +"Well, ain't you going to save any of it?" + +"Save it? What for?" + +"Why, so as to have something to live on, by and by." + +"Oh, that ain't any use. Pap would come back to thish-yer town some +day and get his claws on it if I didn't hurry up, and I tell you he'd +clean it out pretty quick. What you going to do with yourn, Tom?" + +"I'm going to buy a new drum, and a sure-'nough sword, and a red +necktie and a bull pup, and get married." + +"Married!" + +"That's it." + +"Tom, you--why, you ain't in your right mind." + +"Wait--you'll see." + +"Well, that's the foolishest thing you could do. Look at pap and my +mother. Fight! Why, they used to fight all the time. I remember, mighty +well." + +"That ain't anything. The girl I'm going to marry won't fight." + +"Tom, I reckon they're all alike. They'll all comb a body. Now you +better think 'bout this awhile. I tell you you better. What's the name +of the gal?" + +"It ain't a gal at all--it's a girl." + +"It's all the same, I reckon; some says gal, some says girl--both's +right, like enough. Anyway, what's her name, Tom?" + +"I'll tell you some time--not now." + +"All right--that'll do. Only if you get married I'll be more lonesomer +than ever." + +"No you won't. You'll come and live with me. Now stir out of this and +we'll go to digging." + +They worked and sweated for half an hour. No result. They toiled +another half-hour. Still no result. Huck said: + +"Do they always bury it as deep as this?" + +"Sometimes--not always. Not generally. I reckon we haven't got the +right place." + +So they chose a new spot and began again. The labor dragged a little, +but still they made progress. They pegged away in silence for some +time. Finally Huck leaned on his shovel, swabbed the beaded drops from +his brow with his sleeve, and said: + +"Where you going to dig next, after we get this one?" + +"I reckon maybe we'll tackle the old tree that's over yonder on +Cardiff Hill back of the widow's." + +"I reckon that'll be a good one. But won't the widow take it away from +us, Tom? It's on her land." + +"SHE take it away! Maybe she'd like to try it once. Whoever finds one +of these hid treasures, it belongs to him. It don't make any difference +whose land it's on." + +That was satisfactory. The work went on. By and by Huck said: + +"Blame it, we must be in the wrong place again. What do you think?" + +"It is mighty curious, Huck. I don't understand it. Sometimes witches +interfere. I reckon maybe that's what's the trouble now." + +"Shucks! Witches ain't got no power in the daytime." + +"Well, that's so. I didn't think of that. Oh, I know what the matter +is! What a blamed lot of fools we are! You got to find out where the +shadow of the limb falls at midnight, and that's where you dig!" + +"Then consound it, we've fooled away all this work for nothing. Now +hang it all, we got to come back in the night. It's an awful long way. +Can you get out?" + +"I bet I will. We've got to do it to-night, too, because if somebody +sees these holes they'll know in a minute what's here and they'll go +for it." + +"Well, I'll come around and maow to-night." + +"All right. Let's hide the tools in the bushes." + +The boys were there that night, about the appointed time. They sat in +the shadow waiting. It was a lonely place, and an hour made solemn by +old traditions. Spirits whispered in the rustling leaves, ghosts lurked +in the murky nooks, the deep baying of a hound floated up out of the +distance, an owl answered with his sepulchral note. The boys were +subdued by these solemnities, and talked little. By and by they judged +that twelve had come; they marked where the shadow fell, and began to +dig. Their hopes commenced to rise. Their interest grew stronger, and +their industry kept pace with it. The hole deepened and still deepened, +but every time their hearts jumped to hear the pick strike upon +something, they only suffered a new disappointment. It was only a stone +or a chunk. At last Tom said: + +"It ain't any use, Huck, we're wrong again." + +"Well, but we CAN'T be wrong. We spotted the shadder to a dot." + +"I know it, but then there's another thing." + +"What's that?". + +"Why, we only guessed at the time. Like enough it was too late or too +early." + +Huck dropped his shovel. + +"That's it," said he. "That's the very trouble. We got to give this +one up. We can't ever tell the right time, and besides this kind of +thing's too awful, here this time of night with witches and ghosts +a-fluttering around so. I feel as if something's behind me all the time; +and I'm afeard to turn around, becuz maybe there's others in front +a-waiting for a chance. I been creeping all over, ever since I got here." + +"Well, I've been pretty much so, too, Huck. They most always put in a +dead man when they bury a treasure under a tree, to look out for it." + +"Lordy!" + +"Yes, they do. I've always heard that." + +"Tom, I don't like to fool around much where there's dead people. A +body's bound to get into trouble with 'em, sure." + +"I don't like to stir 'em up, either. S'pose this one here was to +stick his skull out and say something!" + +"Don't Tom! It's awful." + +"Well, it just is. Huck, I don't feel comfortable a bit." + +"Say, Tom, let's give this place up, and try somewheres else." + +"All right, I reckon we better." + +"What'll it be?" + +Tom considered awhile; and then said: + +"The ha'nted house. That's it!" + +"Blame it, I don't like ha'nted houses, Tom. Why, they're a dern sight +worse'n dead people. Dead people might talk, maybe, but they don't come +sliding around in a shroud, when you ain't noticing, and peep over your +shoulder all of a sudden and grit their teeth, the way a ghost does. I +couldn't stand such a thing as that, Tom--nobody could." + +"Yes, but, Huck, ghosts don't travel around only at night. They won't +hender us from digging there in the daytime." + +"Well, that's so. But you know mighty well people don't go about that +ha'nted house in the day nor the night." + +"Well, that's mostly because they don't like to go where a man's been +murdered, anyway--but nothing's ever been seen around that house except +in the night--just some blue lights slipping by the windows--no regular +ghosts." + +"Well, where you see one of them blue lights flickering around, Tom, +you can bet there's a ghost mighty close behind it. It stands to +reason. Becuz you know that they don't anybody but ghosts use 'em." + +"Yes, that's so. But anyway they don't come around in the daytime, so +what's the use of our being afeard?" + +"Well, all right. We'll tackle the ha'nted house if you say so--but I +reckon it's taking chances." + +They had started down the hill by this time. There in the middle of +the moonlit valley below them stood the "ha'nted" house, utterly +isolated, its fences gone long ago, rank weeds smothering the very +doorsteps, the chimney crumbled to ruin, the window-sashes vacant, a +corner of the roof caved in. The boys gazed awhile, half expecting to +see a blue light flit past a window; then talking in a low tone, as +befitted the time and the circumstances, they struck far off to the +right, to give the haunted house a wide berth, and took their way +homeward through the woods that adorned the rearward side of Cardiff +Hill. + + + +CHAPTER XXVI + +ABOUT noon the next day the boys arrived at the dead tree; they had +come for their tools. Tom was impatient to go to the haunted house; +Huck was measurably so, also--but suddenly said: + +"Lookyhere, Tom, do you know what day it is?" + +Tom mentally ran over the days of the week, and then quickly lifted +his eyes with a startled look in them-- + +"My! I never once thought of it, Huck!" + +"Well, I didn't neither, but all at once it popped onto me that it was +Friday." + +"Blame it, a body can't be too careful, Huck. We might 'a' got into an +awful scrape, tackling such a thing on a Friday." + +"MIGHT! Better say we WOULD! There's some lucky days, maybe, but +Friday ain't." + +"Any fool knows that. I don't reckon YOU was the first that found it +out, Huck." + +"Well, I never said I was, did I? And Friday ain't all, neither. I had +a rotten bad dream last night--dreampt about rats." + +"No! Sure sign of trouble. Did they fight?" + +"No." + +"Well, that's good, Huck. When they don't fight it's only a sign that +there's trouble around, you know. All we got to do is to look mighty +sharp and keep out of it. We'll drop this thing for to-day, and play. +Do you know Robin Hood, Huck?" + +"No. Who's Robin Hood?" + +"Why, he was one of the greatest men that was ever in England--and the +best. He was a robber." + +"Cracky, I wisht I was. Who did he rob?" + +"Only sheriffs and bishops and rich people and kings, and such like. +But he never bothered the poor. He loved 'em. He always divided up with +'em perfectly square." + +"Well, he must 'a' been a brick." + +"I bet you he was, Huck. Oh, he was the noblest man that ever was. +They ain't any such men now, I can tell you. He could lick any man in +England, with one hand tied behind him; and he could take his yew bow +and plug a ten-cent piece every time, a mile and a half." + +"What's a YEW bow?" + +"I don't know. It's some kind of a bow, of course. And if he hit that +dime only on the edge he would set down and cry--and curse. But we'll +play Robin Hood--it's nobby fun. I'll learn you." + +"I'm agreed." + +So they played Robin Hood all the afternoon, now and then casting a +yearning eye down upon the haunted house and passing a remark about the +morrow's prospects and possibilities there. As the sun began to sink +into the west they took their way homeward athwart the long shadows of +the trees and soon were buried from sight in the forests of Cardiff +Hill. + +On Saturday, shortly after noon, the boys were at the dead tree again. +They had a smoke and a chat in the shade, and then dug a little in +their last hole, not with great hope, but merely because Tom said there +were so many cases where people had given up a treasure after getting +down within six inches of it, and then somebody else had come along and +turned it up with a single thrust of a shovel. The thing failed this +time, however, so the boys shouldered their tools and went away feeling +that they had not trifled with fortune, but had fulfilled all the +requirements that belong to the business of treasure-hunting. + +When they reached the haunted house there was something so weird and +grisly about the dead silence that reigned there under the baking sun, +and something so depressing about the loneliness and desolation of the +place, that they were afraid, for a moment, to venture in. Then they +crept to the door and took a trembling peep. They saw a weed-grown, +floorless room, unplastered, an ancient fireplace, vacant windows, a +ruinous staircase; and here, there, and everywhere hung ragged and +abandoned cobwebs. They presently entered, softly, with quickened +pulses, talking in whispers, ears alert to catch the slightest sound, +and muscles tense and ready for instant retreat. + +In a little while familiarity modified their fears and they gave the +place a critical and interested examination, rather admiring their own +boldness, and wondering at it, too. Next they wanted to look up-stairs. +This was something like cutting off retreat, but they got to daring +each other, and of course there could be but one result--they threw +their tools into a corner and made the ascent. Up there were the same +signs of decay. In one corner they found a closet that promised +mystery, but the promise was a fraud--there was nothing in it. Their +courage was up now and well in hand. They were about to go down and +begin work when-- + +"Sh!" said Tom. + +"What is it?" whispered Huck, blanching with fright. + +"Sh!... There!... Hear it?" + +"Yes!... Oh, my! Let's run!" + +"Keep still! Don't you budge! They're coming right toward the door." + +The boys stretched themselves upon the floor with their eyes to +knot-holes in the planking, and lay waiting, in a misery of fear. + +"They've stopped.... No--coming.... Here they are. Don't whisper +another word, Huck. My goodness, I wish I was out of this!" + +Two men entered. Each boy said to himself: "There's the old deaf and +dumb Spaniard that's been about town once or twice lately--never saw +t'other man before." + +"T'other" was a ragged, unkempt creature, with nothing very pleasant +in his face. The Spaniard was wrapped in a serape; he had bushy white +whiskers; long white hair flowed from under his sombrero, and he wore +green goggles. When they came in, "t'other" was talking in a low voice; +they sat down on the ground, facing the door, with their backs to the +wall, and the speaker continued his remarks. His manner became less +guarded and his words more distinct as he proceeded: + +"No," said he, "I've thought it all over, and I don't like it. It's +dangerous." + +"Dangerous!" grunted the "deaf and dumb" Spaniard--to the vast +surprise of the boys. "Milksop!" + +This voice made the boys gasp and quake. It was Injun Joe's! There was +silence for some time. Then Joe said: + +"What's any more dangerous than that job up yonder--but nothing's come +of it." + +"That's different. Away up the river so, and not another house about. +'Twon't ever be known that we tried, anyway, long as we didn't succeed." + +"Well, what's more dangerous than coming here in the daytime!--anybody +would suspicion us that saw us." + +"I know that. But there warn't any other place as handy after that +fool of a job. I want to quit this shanty. I wanted to yesterday, only +it warn't any use trying to stir out of here, with those infernal boys +playing over there on the hill right in full view." + +"Those infernal boys" quaked again under the inspiration of this +remark, and thought how lucky it was that they had remembered it was +Friday and concluded to wait a day. They wished in their hearts they +had waited a year. + +The two men got out some food and made a luncheon. After a long and +thoughtful silence, Injun Joe said: + +"Look here, lad--you go back up the river where you belong. Wait there +till you hear from me. I'll take the chances on dropping into this town +just once more, for a look. We'll do that 'dangerous' job after I've +spied around a little and think things look well for it. Then for +Texas! We'll leg it together!" + +This was satisfactory. Both men presently fell to yawning, and Injun +Joe said: + +"I'm dead for sleep! It's your turn to watch." + +He curled down in the weeds and soon began to snore. His comrade +stirred him once or twice and he became quiet. Presently the watcher +began to nod; his head drooped lower and lower, both men began to snore +now. + +The boys drew a long, grateful breath. Tom whispered: + +"Now's our chance--come!" + +Huck said: + +"I can't--I'd die if they was to wake." + +Tom urged--Huck held back. At last Tom rose slowly and softly, and +started alone. But the first step he made wrung such a hideous creak +from the crazy floor that he sank down almost dead with fright. He +never made a second attempt. The boys lay there counting the dragging +moments till it seemed to them that time must be done and eternity +growing gray; and then they were grateful to note that at last the sun +was setting. + +Now one snore ceased. Injun Joe sat up, stared around--smiled grimly +upon his comrade, whose head was drooping upon his knees--stirred him +up with his foot and said: + +"Here! YOU'RE a watchman, ain't you! All right, though--nothing's +happened." + +"My! have I been asleep?" + +"Oh, partly, partly. Nearly time for us to be moving, pard. What'll we +do with what little swag we've got left?" + +"I don't know--leave it here as we've always done, I reckon. No use to +take it away till we start south. Six hundred and fifty in silver's +something to carry." + +"Well--all right--it won't matter to come here once more." + +"No--but I'd say come in the night as we used to do--it's better." + +"Yes: but look here; it may be a good while before I get the right +chance at that job; accidents might happen; 'tain't in such a very good +place; we'll just regularly bury it--and bury it deep." + +"Good idea," said the comrade, who walked across the room, knelt down, +raised one of the rearward hearth-stones and took out a bag that +jingled pleasantly. He subtracted from it twenty or thirty dollars for +himself and as much for Injun Joe, and passed the bag to the latter, +who was on his knees in the corner, now, digging with his bowie-knife. + +The boys forgot all their fears, all their miseries in an instant. +With gloating eyes they watched every movement. Luck!--the splendor of +it was beyond all imagination! Six hundred dollars was money enough to +make half a dozen boys rich! Here was treasure-hunting under the +happiest auspices--there would not be any bothersome uncertainty as to +where to dig. They nudged each other every moment--eloquent nudges and +easily understood, for they simply meant--"Oh, but ain't you glad NOW +we're here!" + +Joe's knife struck upon something. + +"Hello!" said he. + +"What is it?" said his comrade. + +"Half-rotten plank--no, it's a box, I believe. Here--bear a hand and +we'll see what it's here for. Never mind, I've broke a hole." + +He reached his hand in and drew it out-- + +"Man, it's money!" + +The two men examined the handful of coins. They were gold. The boys +above were as excited as themselves, and as delighted. + +Joe's comrade said: + +"We'll make quick work of this. There's an old rusty pick over amongst +the weeds in the corner the other side of the fireplace--I saw it a +minute ago." + +He ran and brought the boys' pick and shovel. Injun Joe took the pick, +looked it over critically, shook his head, muttered something to +himself, and then began to use it. The box was soon unearthed. It was +not very large; it was iron bound and had been very strong before the +slow years had injured it. The men contemplated the treasure awhile in +blissful silence. + +"Pard, there's thousands of dollars here," said Injun Joe. + +"'Twas always said that Murrel's gang used to be around here one +summer," the stranger observed. + +"I know it," said Injun Joe; "and this looks like it, I should say." + +"Now you won't need to do that job." + +The half-breed frowned. Said he: + +"You don't know me. Least you don't know all about that thing. 'Tain't +robbery altogether--it's REVENGE!" and a wicked light flamed in his +eyes. "I'll need your help in it. When it's finished--then Texas. Go +home to your Nance and your kids, and stand by till you hear from me." + +"Well--if you say so; what'll we do with this--bury it again?" + +"Yes. [Ravishing delight overhead.] NO! by the great Sachem, no! +[Profound distress overhead.] I'd nearly forgot. That pick had fresh +earth on it! [The boys were sick with terror in a moment.] What +business has a pick and a shovel here? What business with fresh earth +on them? Who brought them here--and where are they gone? Have you heard +anybody?--seen anybody? What! bury it again and leave them to come and +see the ground disturbed? Not exactly--not exactly. We'll take it to my +den." + +"Why, of course! Might have thought of that before. You mean Number +One?" + +"No--Number Two--under the cross. The other place is bad--too common." + +"All right. It's nearly dark enough to start." + +Injun Joe got up and went about from window to window cautiously +peeping out. Presently he said: + +"Who could have brought those tools here? Do you reckon they can be +up-stairs?" + +The boys' breath forsook them. Injun Joe put his hand on his knife, +halted a moment, undecided, and then turned toward the stairway. The +boys thought of the closet, but their strength was gone. The steps came +creaking up the stairs--the intolerable distress of the situation woke +the stricken resolution of the lads--they were about to spring for the +closet, when there was a crash of rotten timbers and Injun Joe landed +on the ground amid the debris of the ruined stairway. He gathered +himself up cursing, and his comrade said: + +"Now what's the use of all that? If it's anybody, and they're up +there, let them STAY there--who cares? If they want to jump down, now, +and get into trouble, who objects? It will be dark in fifteen minutes +--and then let them follow us if they want to. I'm willing. In my +opinion, whoever hove those things in here caught a sight of us and +took us for ghosts or devils or something. I'll bet they're running +yet." + +Joe grumbled awhile; then he agreed with his friend that what daylight +was left ought to be economized in getting things ready for leaving. +Shortly afterward they slipped out of the house in the deepening +twilight, and moved toward the river with their precious box. + +Tom and Huck rose up, weak but vastly relieved, and stared after them +through the chinks between the logs of the house. Follow? Not they. +They were content to reach ground again without broken necks, and take +the townward track over the hill. They did not talk much. They were too +much absorbed in hating themselves--hating the ill luck that made them +take the spade and the pick there. But for that, Injun Joe never would +have suspected. He would have hidden the silver with the gold to wait +there till his "revenge" was satisfied, and then he would have had the +misfortune to find that money turn up missing. Bitter, bitter luck that +the tools were ever brought there! + +They resolved to keep a lookout for that Spaniard when he should come +to town spying out for chances to do his revengeful job, and follow him +to "Number Two," wherever that might be. Then a ghastly thought +occurred to Tom. + +"Revenge? What if he means US, Huck!" + +"Oh, don't!" said Huck, nearly fainting. + +They talked it all over, and as they entered town they agreed to +believe that he might possibly mean somebody else--at least that he +might at least mean nobody but Tom, since only Tom had testified. + +Very, very small comfort it was to Tom to be alone in danger! Company +would be a palpable improvement, he thought. + + + +CHAPTER XXVII + +THE adventure of the day mightily tormented Tom's dreams that night. +Four times he had his hands on that rich treasure and four times it +wasted to nothingness in his fingers as sleep forsook him and +wakefulness brought back the hard reality of his misfortune. As he lay +in the early morning recalling the incidents of his great adventure, he +noticed that they seemed curiously subdued and far away--somewhat as if +they had happened in another world, or in a time long gone by. Then it +occurred to him that the great adventure itself must be a dream! There +was one very strong argument in favor of this idea--namely, that the +quantity of coin he had seen was too vast to be real. He had never seen +as much as fifty dollars in one mass before, and he was like all boys +of his age and station in life, in that he imagined that all references +to "hundreds" and "thousands" were mere fanciful forms of speech, and +that no such sums really existed in the world. He never had supposed +for a moment that so large a sum as a hundred dollars was to be found +in actual money in any one's possession. If his notions of hidden +treasure had been analyzed, they would have been found to consist of a +handful of real dimes and a bushel of vague, splendid, ungraspable +dollars. + +But the incidents of his adventure grew sensibly sharper and clearer +under the attrition of thinking them over, and so he presently found +himself leaning to the impression that the thing might not have been a +dream, after all. This uncertainty must be swept away. He would snatch +a hurried breakfast and go and find Huck. Huck was sitting on the +gunwale of a flatboat, listlessly dangling his feet in the water and +looking very melancholy. Tom concluded to let Huck lead up to the +subject. If he did not do it, then the adventure would be proved to +have been only a dream. + +"Hello, Huck!" + +"Hello, yourself." + +Silence, for a minute. + +"Tom, if we'd 'a' left the blame tools at the dead tree, we'd 'a' got +the money. Oh, ain't it awful!" + +"'Tain't a dream, then, 'tain't a dream! Somehow I most wish it was. +Dog'd if I don't, Huck." + +"What ain't a dream?" + +"Oh, that thing yesterday. I been half thinking it was." + +"Dream! If them stairs hadn't broke down you'd 'a' seen how much dream +it was! I've had dreams enough all night--with that patch-eyed Spanish +devil going for me all through 'em--rot him!" + +"No, not rot him. FIND him! Track the money!" + +"Tom, we'll never find him. A feller don't have only one chance for +such a pile--and that one's lost. I'd feel mighty shaky if I was to see +him, anyway." + +"Well, so'd I; but I'd like to see him, anyway--and track him out--to +his Number Two." + +"Number Two--yes, that's it. I been thinking 'bout that. But I can't +make nothing out of it. What do you reckon it is?" + +"I dono. It's too deep. Say, Huck--maybe it's the number of a house!" + +"Goody!... No, Tom, that ain't it. If it is, it ain't in this +one-horse town. They ain't no numbers here." + +"Well, that's so. Lemme think a minute. Here--it's the number of a +room--in a tavern, you know!" + +"Oh, that's the trick! They ain't only two taverns. We can find out +quick." + +"You stay here, Huck, till I come." + +Tom was off at once. He did not care to have Huck's company in public +places. He was gone half an hour. He found that in the best tavern, No. +2 had long been occupied by a young lawyer, and was still so occupied. +In the less ostentatious house, No. 2 was a mystery. The +tavern-keeper's young son said it was kept locked all the time, and he +never saw anybody go into it or come out of it except at night; he did +not know any particular reason for this state of things; had had some +little curiosity, but it was rather feeble; had made the most of the +mystery by entertaining himself with the idea that that room was +"ha'nted"; had noticed that there was a light in there the night before. + +"That's what I've found out, Huck. I reckon that's the very No. 2 +we're after." + +"I reckon it is, Tom. Now what you going to do?" + +"Lemme think." + +Tom thought a long time. Then he said: + +"I'll tell you. The back door of that No. 2 is the door that comes out +into that little close alley between the tavern and the old rattle trap +of a brick store. Now you get hold of all the door-keys you can find, +and I'll nip all of auntie's, and the first dark night we'll go there +and try 'em. And mind you, keep a lookout for Injun Joe, because he +said he was going to drop into town and spy around once more for a +chance to get his revenge. If you see him, you just follow him; and if +he don't go to that No. 2, that ain't the place." + +"Lordy, I don't want to foller him by myself!" + +"Why, it'll be night, sure. He mightn't ever see you--and if he did, +maybe he'd never think anything." + +"Well, if it's pretty dark I reckon I'll track him. I dono--I dono. +I'll try." + +"You bet I'll follow him, if it's dark, Huck. Why, he might 'a' found +out he couldn't get his revenge, and be going right after that money." + +"It's so, Tom, it's so. I'll foller him; I will, by jingoes!" + +"Now you're TALKING! Don't you ever weaken, Huck, and I won't." + + + +CHAPTER XXVIII + +THAT night Tom and Huck were ready for their adventure. They hung +about the neighborhood of the tavern until after nine, one watching the +alley at a distance and the other the tavern door. Nobody entered the +alley or left it; nobody resembling the Spaniard entered or left the +tavern door. The night promised to be a fair one; so Tom went home with +the understanding that if a considerable degree of darkness came on, +Huck was to come and "maow," whereupon he would slip out and try the +keys. But the night remained clear, and Huck closed his watch and +retired to bed in an empty sugar hogshead about twelve. + +Tuesday the boys had the same ill luck. Also Wednesday. But Thursday +night promised better. Tom slipped out in good season with his aunt's +old tin lantern, and a large towel to blindfold it with. He hid the +lantern in Huck's sugar hogshead and the watch began. An hour before +midnight the tavern closed up and its lights (the only ones +thereabouts) were put out. No Spaniard had been seen. Nobody had +entered or left the alley. Everything was auspicious. The blackness of +darkness reigned, the perfect stillness was interrupted only by +occasional mutterings of distant thunder. + +Tom got his lantern, lit it in the hogshead, wrapped it closely in the +towel, and the two adventurers crept in the gloom toward the tavern. +Huck stood sentry and Tom felt his way into the alley. Then there was a +season of waiting anxiety that weighed upon Huck's spirits like a +mountain. He began to wish he could see a flash from the lantern--it +would frighten him, but it would at least tell him that Tom was alive +yet. It seemed hours since Tom had disappeared. Surely he must have +fainted; maybe he was dead; maybe his heart had burst under terror and +excitement. In his uneasiness Huck found himself drawing closer and +closer to the alley; fearing all sorts of dreadful things, and +momentarily expecting some catastrophe to happen that would take away +his breath. There was not much to take away, for he seemed only able to +inhale it by thimblefuls, and his heart would soon wear itself out, the +way it was beating. Suddenly there was a flash of light and Tom came +tearing by him: "Run!" said he; "run, for your life!" + +He needn't have repeated it; once was enough; Huck was making thirty +or forty miles an hour before the repetition was uttered. The boys +never stopped till they reached the shed of a deserted slaughter-house +at the lower end of the village. Just as they got within its shelter +the storm burst and the rain poured down. As soon as Tom got his breath +he said: + +"Huck, it was awful! I tried two of the keys, just as soft as I could; +but they seemed to make such a power of racket that I couldn't hardly +get my breath I was so scared. They wouldn't turn in the lock, either. +Well, without noticing what I was doing, I took hold of the knob, and +open comes the door! It warn't locked! I hopped in, and shook off the +towel, and, GREAT CAESAR'S GHOST!" + +"What!--what'd you see, Tom?" + +"Huck, I most stepped onto Injun Joe's hand!" + +"No!" + +"Yes! He was lying there, sound asleep on the floor, with his old +patch on his eye and his arms spread out." + +"Lordy, what did you do? Did he wake up?" + +"No, never budged. Drunk, I reckon. I just grabbed that towel and +started!" + +"I'd never 'a' thought of the towel, I bet!" + +"Well, I would. My aunt would make me mighty sick if I lost it." + +"Say, Tom, did you see that box?" + +"Huck, I didn't wait to look around. I didn't see the box, I didn't +see the cross. I didn't see anything but a bottle and a tin cup on the +floor by Injun Joe; yes, I saw two barrels and lots more bottles in the +room. Don't you see, now, what's the matter with that ha'nted room?" + +"How?" + +"Why, it's ha'nted with whiskey! Maybe ALL the Temperance Taverns have +got a ha'nted room, hey, Huck?" + +"Well, I reckon maybe that's so. Who'd 'a' thought such a thing? But +say, Tom, now's a mighty good time to get that box, if Injun Joe's +drunk." + +"It is, that! You try it!" + +Huck shuddered. + +"Well, no--I reckon not." + +"And I reckon not, Huck. Only one bottle alongside of Injun Joe ain't +enough. If there'd been three, he'd be drunk enough and I'd do it." + +There was a long pause for reflection, and then Tom said: + +"Lookyhere, Huck, less not try that thing any more till we know Injun +Joe's not in there. It's too scary. Now, if we watch every night, we'll +be dead sure to see him go out, some time or other, and then we'll +snatch that box quicker'n lightning." + +"Well, I'm agreed. I'll watch the whole night long, and I'll do it +every night, too, if you'll do the other part of the job." + +"All right, I will. All you got to do is to trot up Hooper Street a +block and maow--and if I'm asleep, you throw some gravel at the window +and that'll fetch me." + +"Agreed, and good as wheat!" + +"Now, Huck, the storm's over, and I'll go home. It'll begin to be +daylight in a couple of hours. You go back and watch that long, will +you?" + +"I said I would, Tom, and I will. I'll ha'nt that tavern every night +for a year! I'll sleep all day and I'll stand watch all night." + +"That's all right. Now, where you going to sleep?" + +"In Ben Rogers' hayloft. He lets me, and so does his pap's nigger man, +Uncle Jake. I tote water for Uncle Jake whenever he wants me to, and +any time I ask him he gives me a little something to eat if he can +spare it. That's a mighty good nigger, Tom. He likes me, becuz I don't +ever act as if I was above him. Sometime I've set right down and eat +WITH him. But you needn't tell that. A body's got to do things when +he's awful hungry he wouldn't want to do as a steady thing." + +"Well, if I don't want you in the daytime, I'll let you sleep. I won't +come bothering around. Any time you see something's up, in the night, +just skip right around and maow." + + + +CHAPTER XXIX + +THE first thing Tom heard on Friday morning was a glad piece of news +--Judge Thatcher's family had come back to town the night before. Both +Injun Joe and the treasure sunk into secondary importance for a moment, +and Becky took the chief place in the boy's interest. He saw her and +they had an exhausting good time playing "hi-spy" and "gully-keeper" +with a crowd of their school-mates. The day was completed and crowned +in a peculiarly satisfactory way: Becky teased her mother to appoint +the next day for the long-promised and long-delayed picnic, and she +consented. The child's delight was boundless; and Tom's not more +moderate. The invitations were sent out before sunset, and straightway +the young folks of the village were thrown into a fever of preparation +and pleasurable anticipation. Tom's excitement enabled him to keep +awake until a pretty late hour, and he had good hopes of hearing Huck's +"maow," and of having his treasure to astonish Becky and the picnickers +with, next day; but he was disappointed. No signal came that night. + +Morning came, eventually, and by ten or eleven o'clock a giddy and +rollicking company were gathered at Judge Thatcher's, and everything +was ready for a start. It was not the custom for elderly people to mar +the picnics with their presence. The children were considered safe +enough under the wings of a few young ladies of eighteen and a few +young gentlemen of twenty-three or thereabouts. The old steam ferryboat +was chartered for the occasion; presently the gay throng filed up the +main street laden with provision-baskets. Sid was sick and had to miss +the fun; Mary remained at home to entertain him. The last thing Mrs. +Thatcher said to Becky, was: + +"You'll not get back till late. Perhaps you'd better stay all night +with some of the girls that live near the ferry-landing, child." + +"Then I'll stay with Susy Harper, mamma." + +"Very well. And mind and behave yourself and don't be any trouble." + +Presently, as they tripped along, Tom said to Becky: + +"Say--I'll tell you what we'll do. 'Stead of going to Joe Harper's +we'll climb right up the hill and stop at the Widow Douglas'. She'll +have ice-cream! She has it most every day--dead loads of it. And she'll +be awful glad to have us." + +"Oh, that will be fun!" + +Then Becky reflected a moment and said: + +"But what will mamma say?" + +"How'll she ever know?" + +The girl turned the idea over in her mind, and said reluctantly: + +"I reckon it's wrong--but--" + +"But shucks! Your mother won't know, and so what's the harm? All she +wants is that you'll be safe; and I bet you she'd 'a' said go there if +she'd 'a' thought of it. I know she would!" + +The Widow Douglas' splendid hospitality was a tempting bait. It and +Tom's persuasions presently carried the day. So it was decided to say +nothing anybody about the night's programme. Presently it occurred to +Tom that maybe Huck might come this very night and give the signal. The +thought took a deal of the spirit out of his anticipations. Still he +could not bear to give up the fun at Widow Douglas'. And why should he +give it up, he reasoned--the signal did not come the night before, so +why should it be any more likely to come to-night? The sure fun of the +evening outweighed the uncertain treasure; and, boy-like, he determined +to yield to the stronger inclination and not allow himself to think of +the box of money another time that day. + +Three miles below town the ferryboat stopped at the mouth of a woody +hollow and tied up. The crowd swarmed ashore and soon the forest +distances and craggy heights echoed far and near with shoutings and +laughter. All the different ways of getting hot and tired were gone +through with, and by-and-by the rovers straggled back to camp fortified +with responsible appetites, and then the destruction of the good things +began. After the feast there was a refreshing season of rest and chat +in the shade of spreading oaks. By-and-by somebody shouted: + +"Who's ready for the cave?" + +Everybody was. Bundles of candles were procured, and straightway there +was a general scamper up the hill. The mouth of the cave was up the +hillside--an opening shaped like a letter A. Its massive oaken door +stood unbarred. Within was a small chamber, chilly as an ice-house, and +walled by Nature with solid limestone that was dewy with a cold sweat. +It was romantic and mysterious to stand here in the deep gloom and look +out upon the green valley shining in the sun. But the impressiveness of +the situation quickly wore off, and the romping began again. The moment +a candle was lighted there was a general rush upon the owner of it; a +struggle and a gallant defence followed, but the candle was soon +knocked down or blown out, and then there was a glad clamor of laughter +and a new chase. But all things have an end. By-and-by the procession +went filing down the steep descent of the main avenue, the flickering +rank of lights dimly revealing the lofty walls of rock almost to their +point of junction sixty feet overhead. This main avenue was not more +than eight or ten feet wide. Every few steps other lofty and still +narrower crevices branched from it on either hand--for McDougal's cave +was but a vast labyrinth of crooked aisles that ran into each other and +out again and led nowhere. It was said that one might wander days and +nights together through its intricate tangle of rifts and chasms, and +never find the end of the cave; and that he might go down, and down, +and still down, into the earth, and it was just the same--labyrinth +under labyrinth, and no end to any of them. No man "knew" the cave. +That was an impossible thing. Most of the young men knew a portion of +it, and it was not customary to venture much beyond this known portion. +Tom Sawyer knew as much of the cave as any one. + +The procession moved along the main avenue some three-quarters of a +mile, and then groups and couples began to slip aside into branch +avenues, fly along the dismal corridors, and take each other by +surprise at points where the corridors joined again. Parties were able +to elude each other for the space of half an hour without going beyond +the "known" ground. + +By-and-by, one group after another came straggling back to the mouth +of the cave, panting, hilarious, smeared from head to foot with tallow +drippings, daubed with clay, and entirely delighted with the success of +the day. Then they were astonished to find that they had been taking no +note of time and that night was about at hand. The clanging bell had +been calling for half an hour. However, this sort of close to the day's +adventures was romantic and therefore satisfactory. When the ferryboat +with her wild freight pushed into the stream, nobody cared sixpence for +the wasted time but the captain of the craft. + +Huck was already upon his watch when the ferryboat's lights went +glinting past the wharf. He heard no noise on board, for the young +people were as subdued and still as people usually are who are nearly +tired to death. He wondered what boat it was, and why she did not stop +at the wharf--and then he dropped her out of his mind and put his +attention upon his business. The night was growing cloudy and dark. Ten +o'clock came, and the noise of vehicles ceased, scattered lights began +to wink out, all straggling foot-passengers disappeared, the village +betook itself to its slumbers and left the small watcher alone with the +silence and the ghosts. Eleven o'clock came, and the tavern lights were +put out; darkness everywhere, now. Huck waited what seemed a weary long +time, but nothing happened. His faith was weakening. Was there any use? +Was there really any use? Why not give it up and turn in? + +A noise fell upon his ear. He was all attention in an instant. The +alley door closed softly. He sprang to the corner of the brick store. +The next moment two men brushed by him, and one seemed to have +something under his arm. It must be that box! So they were going to +remove the treasure. Why call Tom now? It would be absurd--the men +would get away with the box and never be found again. No, he would +stick to their wake and follow them; he would trust to the darkness for +security from discovery. So communing with himself, Huck stepped out +and glided along behind the men, cat-like, with bare feet, allowing +them to keep just far enough ahead not to be invisible. + +They moved up the river street three blocks, then turned to the left +up a cross-street. They went straight ahead, then, until they came to +the path that led up Cardiff Hill; this they took. They passed by the +old Welshman's house, half-way up the hill, without hesitating, and +still climbed upward. Good, thought Huck, they will bury it in the old +quarry. But they never stopped at the quarry. They passed on, up the +summit. They plunged into the narrow path between the tall sumach +bushes, and were at once hidden in the gloom. Huck closed up and +shortened his distance, now, for they would never be able to see him. +He trotted along awhile; then slackened his pace, fearing he was +gaining too fast; moved on a piece, then stopped altogether; listened; +no sound; none, save that he seemed to hear the beating of his own +heart. The hooting of an owl came over the hill--ominous sound! But no +footsteps. Heavens, was everything lost! He was about to spring with +winged feet, when a man cleared his throat not four feet from him! +Huck's heart shot into his throat, but he swallowed it again; and then +he stood there shaking as if a dozen agues had taken charge of him at +once, and so weak that he thought he must surely fall to the ground. He +knew where he was. He knew he was within five steps of the stile +leading into Widow Douglas' grounds. Very well, he thought, let them +bury it there; it won't be hard to find. + +Now there was a voice--a very low voice--Injun Joe's: + +"Damn her, maybe she's got company--there's lights, late as it is." + +"I can't see any." + +This was that stranger's voice--the stranger of the haunted house. A +deadly chill went to Huck's heart--this, then, was the "revenge" job! +His thought was, to fly. Then he remembered that the Widow Douglas had +been kind to him more than once, and maybe these men were going to +murder her. He wished he dared venture to warn her; but he knew he +didn't dare--they might come and catch him. He thought all this and +more in the moment that elapsed between the stranger's remark and Injun +Joe's next--which was-- + +"Because the bush is in your way. Now--this way--now you see, don't +you?" + +"Yes. Well, there IS company there, I reckon. Better give it up." + +"Give it up, and I just leaving this country forever! Give it up and +maybe never have another chance. I tell you again, as I've told you +before, I don't care for her swag--you may have it. But her husband was +rough on me--many times he was rough on me--and mainly he was the +justice of the peace that jugged me for a vagrant. And that ain't all. +It ain't a millionth part of it! He had me HORSEWHIPPED!--horsewhipped +in front of the jail, like a nigger!--with all the town looking on! +HORSEWHIPPED!--do you understand? He took advantage of me and died. But +I'll take it out of HER." + +"Oh, don't kill her! Don't do that!" + +"Kill? Who said anything about killing? I would kill HIM if he was +here; but not her. When you want to get revenge on a woman you don't +kill her--bosh! you go for her looks. You slit her nostrils--you notch +her ears like a sow!" + +"By God, that's--" + +"Keep your opinion to yourself! It will be safest for you. I'll tie +her to the bed. If she bleeds to death, is that my fault? I'll not cry, +if she does. My friend, you'll help me in this thing--for MY sake +--that's why you're here--I mightn't be able alone. If you flinch, I'll +kill you. Do you understand that? And if I have to kill you, I'll kill +her--and then I reckon nobody'll ever know much about who done this +business." + +"Well, if it's got to be done, let's get at it. The quicker the +better--I'm all in a shiver." + +"Do it NOW? And company there? Look here--I'll get suspicious of you, +first thing you know. No--we'll wait till the lights are out--there's +no hurry." + +Huck felt that a silence was going to ensue--a thing still more awful +than any amount of murderous talk; so he held his breath and stepped +gingerly back; planted his foot carefully and firmly, after balancing, +one-legged, in a precarious way and almost toppling over, first on one +side and then on the other. He took another step back, with the same +elaboration and the same risks; then another and another, and--a twig +snapped under his foot! His breath stopped and he listened. There was +no sound--the stillness was perfect. His gratitude was measureless. Now +he turned in his tracks, between the walls of sumach bushes--turned +himself as carefully as if he were a ship--and then stepped quickly but +cautiously along. When he emerged at the quarry he felt secure, and so +he picked up his nimble heels and flew. Down, down he sped, till he +reached the Welshman's. He banged at the door, and presently the heads +of the old man and his two stalwart sons were thrust from windows. + +"What's the row there? Who's banging? What do you want?" + +"Let me in--quick! I'll tell everything." + +"Why, who are you?" + +"Huckleberry Finn--quick, let me in!" + +"Huckleberry Finn, indeed! It ain't a name to open many doors, I +judge! But let him in, lads, and let's see what's the trouble." + +"Please don't ever tell I told you," were Huck's first words when he +got in. "Please don't--I'd be killed, sure--but the widow's been good +friends to me sometimes, and I want to tell--I WILL tell if you'll +promise you won't ever say it was me." + +"By George, he HAS got something to tell, or he wouldn't act so!" +exclaimed the old man; "out with it and nobody here'll ever tell, lad." + +Three minutes later the old man and his sons, well armed, were up the +hill, and just entering the sumach path on tiptoe, their weapons in +their hands. Huck accompanied them no further. He hid behind a great +bowlder and fell to listening. There was a lagging, anxious silence, +and then all of a sudden there was an explosion of firearms and a cry. + +Huck waited for no particulars. He sprang away and sped down the hill +as fast as his legs could carry him. + + + +CHAPTER XXX + +AS the earliest suspicion of dawn appeared on Sunday morning, Huck +came groping up the hill and rapped gently at the old Welshman's door. +The inmates were asleep, but it was a sleep that was set on a +hair-trigger, on account of the exciting episode of the night. A call +came from a window: + +"Who's there!" + +Huck's scared voice answered in a low tone: + +"Please let me in! It's only Huck Finn!" + +"It's a name that can open this door night or day, lad!--and welcome!" + +These were strange words to the vagabond boy's ears, and the +pleasantest he had ever heard. He could not recollect that the closing +word had ever been applied in his case before. The door was quickly +unlocked, and he entered. Huck was given a seat and the old man and his +brace of tall sons speedily dressed themselves. + +"Now, my boy, I hope you're good and hungry, because breakfast will be +ready as soon as the sun's up, and we'll have a piping hot one, too +--make yourself easy about that! I and the boys hoped you'd turn up and +stop here last night." + +"I was awful scared," said Huck, "and I run. I took out when the +pistols went off, and I didn't stop for three mile. I've come now becuz +I wanted to know about it, you know; and I come before daylight becuz I +didn't want to run across them devils, even if they was dead." + +"Well, poor chap, you do look as if you'd had a hard night of it--but +there's a bed here for you when you've had your breakfast. No, they +ain't dead, lad--we are sorry enough for that. You see we knew right +where to put our hands on them, by your description; so we crept along +on tiptoe till we got within fifteen feet of them--dark as a cellar +that sumach path was--and just then I found I was going to sneeze. It +was the meanest kind of luck! I tried to keep it back, but no use +--'twas bound to come, and it did come! I was in the lead with my pistol +raised, and when the sneeze started those scoundrels a-rustling to get +out of the path, I sung out, 'Fire boys!' and blazed away at the place +where the rustling was. So did the boys. But they were off in a jiffy, +those villains, and we after them, down through the woods. I judge we +never touched them. They fired a shot apiece as they started, but their +bullets whizzed by and didn't do us any harm. As soon as we lost the +sound of their feet we quit chasing, and went down and stirred up the +constables. They got a posse together, and went off to guard the river +bank, and as soon as it is light the sheriff and a gang are going to +beat up the woods. My boys will be with them presently. I wish we had +some sort of description of those rascals--'twould help a good deal. +But you couldn't see what they were like, in the dark, lad, I suppose?" + +"Oh yes; I saw them down-town and follered them." + +"Splendid! Describe them--describe them, my boy!" + +"One's the old deaf and dumb Spaniard that's ben around here once or +twice, and t'other's a mean-looking, ragged--" + +"That's enough, lad, we know the men! Happened on them in the woods +back of the widow's one day, and they slunk away. Off with you, boys, +and tell the sheriff--get your breakfast to-morrow morning!" + +The Welshman's sons departed at once. As they were leaving the room +Huck sprang up and exclaimed: + +"Oh, please don't tell ANYbody it was me that blowed on them! Oh, +please!" + +"All right if you say it, Huck, but you ought to have the credit of +what you did." + +"Oh no, no! Please don't tell!" + +When the young men were gone, the old Welshman said: + +"They won't tell--and I won't. But why don't you want it known?" + +Huck would not explain, further than to say that he already knew too +much about one of those men and would not have the man know that he +knew anything against him for the whole world--he would be killed for +knowing it, sure. + +The old man promised secrecy once more, and said: + +"How did you come to follow these fellows, lad? Were they looking +suspicious?" + +Huck was silent while he framed a duly cautious reply. Then he said: + +"Well, you see, I'm a kind of a hard lot,--least everybody says so, +and I don't see nothing agin it--and sometimes I can't sleep much, on +account of thinking about it and sort of trying to strike out a new way +of doing. That was the way of it last night. I couldn't sleep, and so I +come along up-street 'bout midnight, a-turning it all over, and when I +got to that old shackly brick store by the Temperance Tavern, I backed +up agin the wall to have another think. Well, just then along comes +these two chaps slipping along close by me, with something under their +arm, and I reckoned they'd stole it. One was a-smoking, and t'other one +wanted a light; so they stopped right before me and the cigars lit up +their faces and I see that the big one was the deaf and dumb Spaniard, +by his white whiskers and the patch on his eye, and t'other one was a +rusty, ragged-looking devil." + +"Could you see the rags by the light of the cigars?" + +This staggered Huck for a moment. Then he said: + +"Well, I don't know--but somehow it seems as if I did." + +"Then they went on, and you--" + +"Follered 'em--yes. That was it. I wanted to see what was up--they +sneaked along so. I dogged 'em to the widder's stile, and stood in the +dark and heard the ragged one beg for the widder, and the Spaniard +swear he'd spile her looks just as I told you and your two--" + +"What! The DEAF AND DUMB man said all that!" + +Huck had made another terrible mistake! He was trying his best to keep +the old man from getting the faintest hint of who the Spaniard might +be, and yet his tongue seemed determined to get him into trouble in +spite of all he could do. He made several efforts to creep out of his +scrape, but the old man's eye was upon him and he made blunder after +blunder. Presently the Welshman said: + +"My boy, don't be afraid of me. I wouldn't hurt a hair of your head +for all the world. No--I'd protect you--I'd protect you. This Spaniard +is not deaf and dumb; you've let that slip without intending it; you +can't cover that up now. You know something about that Spaniard that +you want to keep dark. Now trust me--tell me what it is, and trust me +--I won't betray you." + +Huck looked into the old man's honest eyes a moment, then bent over +and whispered in his ear: + +"'Tain't a Spaniard--it's Injun Joe!" + +The Welshman almost jumped out of his chair. In a moment he said: + +"It's all plain enough, now. When you talked about notching ears and +slitting noses I judged that that was your own embellishment, because +white men don't take that sort of revenge. But an Injun! That's a +different matter altogether." + +During breakfast the talk went on, and in the course of it the old man +said that the last thing which he and his sons had done, before going +to bed, was to get a lantern and examine the stile and its vicinity for +marks of blood. They found none, but captured a bulky bundle of-- + +"Of WHAT?" + +If the words had been lightning they could not have leaped with a more +stunning suddenness from Huck's blanched lips. His eyes were staring +wide, now, and his breath suspended--waiting for the answer. The +Welshman started--stared in return--three seconds--five seconds--ten +--then replied: + +"Of burglar's tools. Why, what's the MATTER with you?" + +Huck sank back, panting gently, but deeply, unutterably grateful. The +Welshman eyed him gravely, curiously--and presently said: + +"Yes, burglar's tools. That appears to relieve you a good deal. But +what did give you that turn? What were YOU expecting we'd found?" + +Huck was in a close place--the inquiring eye was upon him--he would +have given anything for material for a plausible answer--nothing +suggested itself--the inquiring eye was boring deeper and deeper--a +senseless reply offered--there was no time to weigh it, so at a venture +he uttered it--feebly: + +"Sunday-school books, maybe." + +Poor Huck was too distressed to smile, but the old man laughed loud +and joyously, shook up the details of his anatomy from head to foot, +and ended by saying that such a laugh was money in a-man's pocket, +because it cut down the doctor's bill like everything. Then he added: + +"Poor old chap, you're white and jaded--you ain't well a bit--no +wonder you're a little flighty and off your balance. But you'll come +out of it. Rest and sleep will fetch you out all right, I hope." + +Huck was irritated to think he had been such a goose and betrayed such +a suspicious excitement, for he had dropped the idea that the parcel +brought from the tavern was the treasure, as soon as he had heard the +talk at the widow's stile. He had only thought it was not the treasure, +however--he had not known that it wasn't--and so the suggestion of a +captured bundle was too much for his self-possession. But on the whole +he felt glad the little episode had happened, for now he knew beyond +all question that that bundle was not THE bundle, and so his mind was +at rest and exceedingly comfortable. In fact, everything seemed to be +drifting just in the right direction, now; the treasure must be still +in No. 2, the men would be captured and jailed that day, and he and Tom +could seize the gold that night without any trouble or any fear of +interruption. + +Just as breakfast was completed there was a knock at the door. Huck +jumped for a hiding-place, for he had no mind to be connected even +remotely with the late event. The Welshman admitted several ladies and +gentlemen, among them the Widow Douglas, and noticed that groups of +citizens were climbing up the hill--to stare at the stile. So the news +had spread. The Welshman had to tell the story of the night to the +visitors. The widow's gratitude for her preservation was outspoken. + +"Don't say a word about it, madam. There's another that you're more +beholden to than you are to me and my boys, maybe, but he don't allow +me to tell his name. We wouldn't have been there but for him." + +Of course this excited a curiosity so vast that it almost belittled +the main matter--but the Welshman allowed it to eat into the vitals of +his visitors, and through them be transmitted to the whole town, for he +refused to part with his secret. When all else had been learned, the +widow said: + +"I went to sleep reading in bed and slept straight through all that +noise. Why didn't you come and wake me?" + +"We judged it warn't worth while. Those fellows warn't likely to come +again--they hadn't any tools left to work with, and what was the use of +waking you up and scaring you to death? My three negro men stood guard +at your house all the rest of the night. They've just come back." + +More visitors came, and the story had to be told and retold for a +couple of hours more. + +There was no Sabbath-school during day-school vacation, but everybody +was early at church. The stirring event was well canvassed. News came +that not a sign of the two villains had been yet discovered. When the +sermon was finished, Judge Thatcher's wife dropped alongside of Mrs. +Harper as she moved down the aisle with the crowd and said: + +"Is my Becky going to sleep all day? I just expected she would be +tired to death." + +"Your Becky?" + +"Yes," with a startled look--"didn't she stay with you last night?" + +"Why, no." + +Mrs. Thatcher turned pale, and sank into a pew, just as Aunt Polly, +talking briskly with a friend, passed by. Aunt Polly said: + +"Good-morning, Mrs. Thatcher. Good-morning, Mrs. Harper. I've got a +boy that's turned up missing. I reckon my Tom stayed at your house last +night--one of you. And now he's afraid to come to church. I've got to +settle with him." + +Mrs. Thatcher shook her head feebly and turned paler than ever. + +"He didn't stay with us," said Mrs. Harper, beginning to look uneasy. +A marked anxiety came into Aunt Polly's face. + +"Joe Harper, have you seen my Tom this morning?" + +"No'm." + +"When did you see him last?" + +Joe tried to remember, but was not sure he could say. The people had +stopped moving out of church. Whispers passed along, and a boding +uneasiness took possession of every countenance. Children were +anxiously questioned, and young teachers. They all said they had not +noticed whether Tom and Becky were on board the ferryboat on the +homeward trip; it was dark; no one thought of inquiring if any one was +missing. One young man finally blurted out his fear that they were +still in the cave! Mrs. Thatcher swooned away. Aunt Polly fell to +crying and wringing her hands. + +The alarm swept from lip to lip, from group to group, from street to +street, and within five minutes the bells were wildly clanging and the +whole town was up! The Cardiff Hill episode sank into instant +insignificance, the burglars were forgotten, horses were saddled, +skiffs were manned, the ferryboat ordered out, and before the horror +was half an hour old, two hundred men were pouring down highroad and +river toward the cave. + +All the long afternoon the village seemed empty and dead. Many women +visited Aunt Polly and Mrs. Thatcher and tried to comfort them. They +cried with them, too, and that was still better than words. All the +tedious night the town waited for news; but when the morning dawned at +last, all the word that came was, "Send more candles--and send food." +Mrs. Thatcher was almost crazed; and Aunt Polly, also. Judge Thatcher +sent messages of hope and encouragement from the cave, but they +conveyed no real cheer. + +The old Welshman came home toward daylight, spattered with +candle-grease, smeared with clay, and almost worn out. He found Huck +still in the bed that had been provided for him, and delirious with +fever. The physicians were all at the cave, so the Widow Douglas came +and took charge of the patient. She said she would do her best by him, +because, whether he was good, bad, or indifferent, he was the Lord's, +and nothing that was the Lord's was a thing to be neglected. The +Welshman said Huck had good spots in him, and the widow said: + +"You can depend on it. That's the Lord's mark. He don't leave it off. +He never does. Puts it somewhere on every creature that comes from his +hands." + +Early in the forenoon parties of jaded men began to straggle into the +village, but the strongest of the citizens continued searching. All the +news that could be gained was that remotenesses of the cavern were +being ransacked that had never been visited before; that every corner +and crevice was going to be thoroughly searched; that wherever one +wandered through the maze of passages, lights were to be seen flitting +hither and thither in the distance, and shoutings and pistol-shots sent +their hollow reverberations to the ear down the sombre aisles. In one +place, far from the section usually traversed by tourists, the names +"BECKY & TOM" had been found traced upon the rocky wall with +candle-smoke, and near at hand a grease-soiled bit of ribbon. Mrs. +Thatcher recognized the ribbon and cried over it. She said it was the +last relic she should ever have of her child; and that no other memorial +of her could ever be so precious, because this one parted latest from +the living body before the awful death came. Some said that now and +then, in the cave, a far-away speck of light would glimmer, and then a +glorious shout would burst forth and a score of men go trooping down the +echoing aisle--and then a sickening disappointment always followed; the +children were not there; it was only a searcher's light. + +Three dreadful days and nights dragged their tedious hours along, and +the village sank into a hopeless stupor. No one had heart for anything. +The accidental discovery, just made, that the proprietor of the +Temperance Tavern kept liquor on his premises, scarcely fluttered the +public pulse, tremendous as the fact was. In a lucid interval, Huck +feebly led up to the subject of taverns, and finally asked--dimly +dreading the worst--if anything had been discovered at the Temperance +Tavern since he had been ill. + +"Yes," said the widow. + +Huck started up in bed, wild-eyed: + +"What? What was it?" + +"Liquor!--and the place has been shut up. Lie down, child--what a turn +you did give me!" + +"Only tell me just one thing--only just one--please! Was it Tom Sawyer +that found it?" + +The widow burst into tears. "Hush, hush, child, hush! I've told you +before, you must NOT talk. You are very, very sick!" + +Then nothing but liquor had been found; there would have been a great +powwow if it had been the gold. So the treasure was gone forever--gone +forever! But what could she be crying about? Curious that she should +cry. + +These thoughts worked their dim way through Huck's mind, and under the +weariness they gave him he fell asleep. The widow said to herself: + +"There--he's asleep, poor wreck. Tom Sawyer find it! Pity but somebody +could find Tom Sawyer! Ah, there ain't many left, now, that's got hope +enough, or strength enough, either, to go on searching." + + + +CHAPTER XXXI + +NOW to return to Tom and Becky's share in the picnic. They tripped +along the murky aisles with the rest of the company, visiting the +familiar wonders of the cave--wonders dubbed with rather +over-descriptive names, such as "The Drawing-Room," "The Cathedral," +"Aladdin's Palace," and so on. Presently the hide-and-seek frolicking +began, and Tom and Becky engaged in it with zeal until the exertion +began to grow a trifle wearisome; then they wandered down a sinuous +avenue holding their candles aloft and reading the tangled web-work of +names, dates, post-office addresses, and mottoes with which the rocky +walls had been frescoed (in candle-smoke). Still drifting along and +talking, they scarcely noticed that they were now in a part of the cave +whose walls were not frescoed. They smoked their own names under an +overhanging shelf and moved on. Presently they came to a place where a +little stream of water, trickling over a ledge and carrying a limestone +sediment with it, had, in the slow-dragging ages, formed a laced and +ruffled Niagara in gleaming and imperishable stone. Tom squeezed his +small body behind it in order to illuminate it for Becky's +gratification. He found that it curtained a sort of steep natural +stairway which was enclosed between narrow walls, and at once the +ambition to be a discoverer seized him. Becky responded to his call, +and they made a smoke-mark for future guidance, and started upon their +quest. They wound this way and that, far down into the secret depths of +the cave, made another mark, and branched off in search of novelties to +tell the upper world about. In one place they found a spacious cavern, +from whose ceiling depended a multitude of shining stalactites of the +length and circumference of a man's leg; they walked all about it, +wondering and admiring, and presently left it by one of the numerous +passages that opened into it. This shortly brought them to a bewitching +spring, whose basin was incrusted with a frostwork of glittering +crystals; it was in the midst of a cavern whose walls were supported by +many fantastic pillars which had been formed by the joining of great +stalactites and stalagmites together, the result of the ceaseless +water-drip of centuries. Under the roof vast knots of bats had packed +themselves together, thousands in a bunch; the lights disturbed the +creatures and they came flocking down by hundreds, squeaking and +darting furiously at the candles. Tom knew their ways and the danger of +this sort of conduct. He seized Becky's hand and hurried her into the +first corridor that offered; and none too soon, for a bat struck +Becky's light out with its wing while she was passing out of the +cavern. The bats chased the children a good distance; but the fugitives +plunged into every new passage that offered, and at last got rid of the +perilous things. Tom found a subterranean lake, shortly, which +stretched its dim length away until its shape was lost in the shadows. +He wanted to explore its borders, but concluded that it would be best +to sit down and rest awhile, first. Now, for the first time, the deep +stillness of the place laid a clammy hand upon the spirits of the +children. Becky said: + +"Why, I didn't notice, but it seems ever so long since I heard any of +the others." + +"Come to think, Becky, we are away down below them--and I don't know +how far away north, or south, or east, or whichever it is. We couldn't +hear them here." + +Becky grew apprehensive. + +"I wonder how long we've been down here, Tom? We better start back." + +"Yes, I reckon we better. P'raps we better." + +"Can you find the way, Tom? It's all a mixed-up crookedness to me." + +"I reckon I could find it--but then the bats. If they put our candles +out it will be an awful fix. Let's try some other way, so as not to go +through there." + +"Well. But I hope we won't get lost. It would be so awful!" and the +girl shuddered at the thought of the dreadful possibilities. + +They started through a corridor, and traversed it in silence a long +way, glancing at each new opening, to see if there was anything +familiar about the look of it; but they were all strange. Every time +Tom made an examination, Becky would watch his face for an encouraging +sign, and he would say cheerily: + +"Oh, it's all right. This ain't the one, but we'll come to it right +away!" + +But he felt less and less hopeful with each failure, and presently +began to turn off into diverging avenues at sheer random, in desperate +hope of finding the one that was wanted. He still said it was "all +right," but there was such a leaden dread at his heart that the words +had lost their ring and sounded just as if he had said, "All is lost!" +Becky clung to his side in an anguish of fear, and tried hard to keep +back the tears, but they would come. At last she said: + +"Oh, Tom, never mind the bats, let's go back that way! We seem to get +worse and worse off all the time." + +"Listen!" said he. + +Profound silence; silence so deep that even their breathings were +conspicuous in the hush. Tom shouted. The call went echoing down the +empty aisles and died out in the distance in a faint sound that +resembled a ripple of mocking laughter. + +"Oh, don't do it again, Tom, it is too horrid," said Becky. + +"It is horrid, but I better, Becky; they might hear us, you know," and +he shouted again. + +The "might" was even a chillier horror than the ghostly laughter, it +so confessed a perishing hope. The children stood still and listened; +but there was no result. Tom turned upon the back track at once, and +hurried his steps. It was but a little while before a certain +indecision in his manner revealed another fearful fact to Becky--he +could not find his way back! + +"Oh, Tom, you didn't make any marks!" + +"Becky, I was such a fool! Such a fool! I never thought we might want +to come back! No--I can't find the way. It's all mixed up." + +"Tom, Tom, we're lost! we're lost! We never can get out of this awful +place! Oh, why DID we ever leave the others!" + +She sank to the ground and burst into such a frenzy of crying that Tom +was appalled with the idea that she might die, or lose her reason. He +sat down by her and put his arms around her; she buried her face in his +bosom, she clung to him, she poured out her terrors, her unavailing +regrets, and the far echoes turned them all to jeering laughter. Tom +begged her to pluck up hope again, and she said she could not. He fell +to blaming and abusing himself for getting her into this miserable +situation; this had a better effect. She said she would try to hope +again, she would get up and follow wherever he might lead if only he +would not talk like that any more. For he was no more to blame than +she, she said. + +So they moved on again--aimlessly--simply at random--all they could do +was to move, keep moving. For a little while, hope made a show of +reviving--not with any reason to back it, but only because it is its +nature to revive when the spring has not been taken out of it by age +and familiarity with failure. + +By-and-by Tom took Becky's candle and blew it out. This economy meant +so much! Words were not needed. Becky understood, and her hope died +again. She knew that Tom had a whole candle and three or four pieces in +his pockets--yet he must economize. + +By-and-by, fatigue began to assert its claims; the children tried to +pay attention, for it was dreadful to think of sitting down when time +was grown to be so precious, moving, in some direction, in any +direction, was at least progress and might bear fruit; but to sit down +was to invite death and shorten its pursuit. + +At last Becky's frail limbs refused to carry her farther. She sat +down. Tom rested with her, and they talked of home, and the friends +there, and the comfortable beds and, above all, the light! Becky cried, +and Tom tried to think of some way of comforting her, but all his +encouragements were grown threadbare with use, and sounded like +sarcasms. Fatigue bore so heavily upon Becky that she drowsed off to +sleep. Tom was grateful. He sat looking into her drawn face and saw it +grow smooth and natural under the influence of pleasant dreams; and +by-and-by a smile dawned and rested there. The peaceful face reflected +somewhat of peace and healing into his own spirit, and his thoughts +wandered away to bygone times and dreamy memories. While he was deep in +his musings, Becky woke up with a breezy little laugh--but it was +stricken dead upon her lips, and a groan followed it. + +"Oh, how COULD I sleep! I wish I never, never had waked! No! No, I +don't, Tom! Don't look so! I won't say it again." + +"I'm glad you've slept, Becky; you'll feel rested, now, and we'll find +the way out." + +"We can try, Tom; but I've seen such a beautiful country in my dream. +I reckon we are going there." + +"Maybe not, maybe not. Cheer up, Becky, and let's go on trying." + +They rose up and wandered along, hand in hand and hopeless. They tried +to estimate how long they had been in the cave, but all they knew was +that it seemed days and weeks, and yet it was plain that this could not +be, for their candles were not gone yet. A long time after this--they +could not tell how long--Tom said they must go softly and listen for +dripping water--they must find a spring. They found one presently, and +Tom said it was time to rest again. Both were cruelly tired, yet Becky +said she thought she could go a little farther. She was surprised to +hear Tom dissent. She could not understand it. They sat down, and Tom +fastened his candle to the wall in front of them with some clay. +Thought was soon busy; nothing was said for some time. Then Becky broke +the silence: + +"Tom, I am so hungry!" + +Tom took something out of his pocket. + +"Do you remember this?" said he. + +Becky almost smiled. + +"It's our wedding-cake, Tom." + +"Yes--I wish it was as big as a barrel, for it's all we've got." + +"I saved it from the picnic for us to dream on, Tom, the way grown-up +people do with wedding-cake--but it'll be our--" + +She dropped the sentence where it was. Tom divided the cake and Becky +ate with good appetite, while Tom nibbled at his moiety. There was +abundance of cold water to finish the feast with. By-and-by Becky +suggested that they move on again. Tom was silent a moment. Then he +said: + +"Becky, can you bear it if I tell you something?" + +Becky's face paled, but she thought she could. + +"Well, then, Becky, we must stay here, where there's water to drink. +That little piece is our last candle!" + +Becky gave loose to tears and wailings. Tom did what he could to +comfort her, but with little effect. At length Becky said: + +"Tom!" + +"Well, Becky?" + +"They'll miss us and hunt for us!" + +"Yes, they will! Certainly they will!" + +"Maybe they're hunting for us now, Tom." + +"Why, I reckon maybe they are. I hope they are." + +"When would they miss us, Tom?" + +"When they get back to the boat, I reckon." + +"Tom, it might be dark then--would they notice we hadn't come?" + +"I don't know. But anyway, your mother would miss you as soon as they +got home." + +A frightened look in Becky's face brought Tom to his senses and he saw +that he had made a blunder. Becky was not to have gone home that night! +The children became silent and thoughtful. In a moment a new burst of +grief from Becky showed Tom that the thing in his mind had struck hers +also--that the Sabbath morning might be half spent before Mrs. Thatcher +discovered that Becky was not at Mrs. Harper's. + +The children fastened their eyes upon their bit of candle and watched +it melt slowly and pitilessly away; saw the half inch of wick stand +alone at last; saw the feeble flame rise and fall, climb the thin +column of smoke, linger at its top a moment, and then--the horror of +utter darkness reigned! + +How long afterward it was that Becky came to a slow consciousness that +she was crying in Tom's arms, neither could tell. All that they knew +was, that after what seemed a mighty stretch of time, both awoke out of +a dead stupor of sleep and resumed their miseries once more. Tom said +it might be Sunday, now--maybe Monday. He tried to get Becky to talk, +but her sorrows were too oppressive, all her hopes were gone. Tom said +that they must have been missed long ago, and no doubt the search was +going on. He would shout and maybe some one would come. He tried it; +but in the darkness the distant echoes sounded so hideously that he +tried it no more. + +The hours wasted away, and hunger came to torment the captives again. +A portion of Tom's half of the cake was left; they divided and ate it. +But they seemed hungrier than before. The poor morsel of food only +whetted desire. + +By-and-by Tom said: + +"SH! Did you hear that?" + +Both held their breath and listened. There was a sound like the +faintest, far-off shout. Instantly Tom answered it, and leading Becky +by the hand, started groping down the corridor in its direction. +Presently he listened again; again the sound was heard, and apparently +a little nearer. + +"It's them!" said Tom; "they're coming! Come along, Becky--we're all +right now!" + +The joy of the prisoners was almost overwhelming. Their speed was +slow, however, because pitfalls were somewhat common, and had to be +guarded against. They shortly came to one and had to stop. It might be +three feet deep, it might be a hundred--there was no passing it at any +rate. Tom got down on his breast and reached as far down as he could. +No bottom. They must stay there and wait until the searchers came. They +listened; evidently the distant shoutings were growing more distant! a +moment or two more and they had gone altogether. The heart-sinking +misery of it! Tom whooped until he was hoarse, but it was of no use. He +talked hopefully to Becky; but an age of anxious waiting passed and no +sounds came again. + +The children groped their way back to the spring. The weary time +dragged on; they slept again, and awoke famished and woe-stricken. Tom +believed it must be Tuesday by this time. + +Now an idea struck him. There were some side passages near at hand. It +would be better to explore some of these than bear the weight of the +heavy time in idleness. He took a kite-line from his pocket, tied it to +a projection, and he and Becky started, Tom in the lead, unwinding the +line as he groped along. At the end of twenty steps the corridor ended +in a "jumping-off place." Tom got down on his knees and felt below, and +then as far around the corner as he could reach with his hands +conveniently; he made an effort to stretch yet a little farther to the +right, and at that moment, not twenty yards away, a human hand, holding +a candle, appeared from behind a rock! Tom lifted up a glorious shout, +and instantly that hand was followed by the body it belonged to--Injun +Joe's! Tom was paralyzed; he could not move. He was vastly gratified +the next moment, to see the "Spaniard" take to his heels and get +himself out of sight. Tom wondered that Joe had not recognized his +voice and come over and killed him for testifying in court. But the +echoes must have disguised the voice. Without doubt, that was it, he +reasoned. Tom's fright weakened every muscle in his body. He said to +himself that if he had strength enough to get back to the spring he +would stay there, and nothing should tempt him to run the risk of +meeting Injun Joe again. He was careful to keep from Becky what it was +he had seen. He told her he had only shouted "for luck." + +But hunger and wretchedness rise superior to fears in the long run. +Another tedious wait at the spring and another long sleep brought +changes. The children awoke tortured with a raging hunger. Tom believed +that it must be Wednesday or Thursday or even Friday or Saturday, now, +and that the search had been given over. He proposed to explore another +passage. He felt willing to risk Injun Joe and all other terrors. But +Becky was very weak. She had sunk into a dreary apathy and would not be +roused. She said she would wait, now, where she was, and die--it would +not be long. She told Tom to go with the kite-line and explore if he +chose; but she implored him to come back every little while and speak +to her; and she made him promise that when the awful time came, he +would stay by her and hold her hand until all was over. + +Tom kissed her, with a choking sensation in his throat, and made a +show of being confident of finding the searchers or an escape from the +cave; then he took the kite-line in his hand and went groping down one +of the passages on his hands and knees, distressed with hunger and sick +with bodings of coming doom. + + + +CHAPTER XXXII + +TUESDAY afternoon came, and waned to the twilight. The village of St. +Petersburg still mourned. The lost children had not been found. Public +prayers had been offered up for them, and many and many a private +prayer that had the petitioner's whole heart in it; but still no good +news came from the cave. The majority of the searchers had given up the +quest and gone back to their daily avocations, saying that it was plain +the children could never be found. Mrs. Thatcher was very ill, and a +great part of the time delirious. People said it was heartbreaking to +hear her call her child, and raise her head and listen a whole minute +at a time, then lay it wearily down again with a moan. Aunt Polly had +drooped into a settled melancholy, and her gray hair had grown almost +white. The village went to its rest on Tuesday night, sad and forlorn. + +Away in the middle of the night a wild peal burst from the village +bells, and in a moment the streets were swarming with frantic half-clad +people, who shouted, "Turn out! turn out! they're found! they're +found!" Tin pans and horns were added to the din, the population massed +itself and moved toward the river, met the children coming in an open +carriage drawn by shouting citizens, thronged around it, joined its +homeward march, and swept magnificently up the main street roaring +huzzah after huzzah! + +The village was illuminated; nobody went to bed again; it was the +greatest night the little town had ever seen. During the first half-hour +a procession of villagers filed through Judge Thatcher's house, seized +the saved ones and kissed them, squeezed Mrs. Thatcher's hand, tried to +speak but couldn't--and drifted out raining tears all over the place. + +Aunt Polly's happiness was complete, and Mrs. Thatcher's nearly so. It +would be complete, however, as soon as the messenger dispatched with +the great news to the cave should get the word to her husband. Tom lay +upon a sofa with an eager auditory about him and told the history of +the wonderful adventure, putting in many striking additions to adorn it +withal; and closed with a description of how he left Becky and went on +an exploring expedition; how he followed two avenues as far as his +kite-line would reach; how he followed a third to the fullest stretch of +the kite-line, and was about to turn back when he glimpsed a far-off +speck that looked like daylight; dropped the line and groped toward it, +pushed his head and shoulders through a small hole, and saw the broad +Mississippi rolling by! And if it had only happened to be night he would +not have seen that speck of daylight and would not have explored that +passage any more! He told how he went back for Becky and broke the good +news and she told him not to fret her with such stuff, for she was +tired, and knew she was going to die, and wanted to. He described how he +labored with her and convinced her; and how she almost died for joy when +she had groped to where she actually saw the blue speck of daylight; how +he pushed his way out at the hole and then helped her out; how they sat +there and cried for gladness; how some men came along in a skiff and Tom +hailed them and told them their situation and their famished condition; +how the men didn't believe the wild tale at first, "because," said they, +"you are five miles down the river below the valley the cave is in" +--then took them aboard, rowed to a house, gave them supper, made them +rest till two or three hours after dark and then brought them home. + +Before day-dawn, Judge Thatcher and the handful of searchers with him +were tracked out, in the cave, by the twine clews they had strung +behind them, and informed of the great news. + +Three days and nights of toil and hunger in the cave were not to be +shaken off at once, as Tom and Becky soon discovered. They were +bedridden all of Wednesday and Thursday, and seemed to grow more and +more tired and worn, all the time. Tom got about, a little, on +Thursday, was down-town Friday, and nearly as whole as ever Saturday; +but Becky did not leave her room until Sunday, and then she looked as +if she had passed through a wasting illness. + +Tom learned of Huck's sickness and went to see him on Friday, but +could not be admitted to the bedroom; neither could he on Saturday or +Sunday. He was admitted daily after that, but was warned to keep still +about his adventure and introduce no exciting topic. The Widow Douglas +stayed by to see that he obeyed. At home Tom learned of the Cardiff +Hill event; also that the "ragged man's" body had eventually been found +in the river near the ferry-landing; he had been drowned while trying +to escape, perhaps. + +About a fortnight after Tom's rescue from the cave, he started off to +visit Huck, who had grown plenty strong enough, now, to hear exciting +talk, and Tom had some that would interest him, he thought. Judge +Thatcher's house was on Tom's way, and he stopped to see Becky. The +Judge and some friends set Tom to talking, and some one asked him +ironically if he wouldn't like to go to the cave again. Tom said he +thought he wouldn't mind it. The Judge said: + +"Well, there are others just like you, Tom, I've not the least doubt. +But we have taken care of that. Nobody will get lost in that cave any +more." + +"Why?" + +"Because I had its big door sheathed with boiler iron two weeks ago, +and triple-locked--and I've got the keys." + +Tom turned as white as a sheet. + +"What's the matter, boy! Here, run, somebody! Fetch a glass of water!" + +The water was brought and thrown into Tom's face. + +"Ah, now you're all right. What was the matter with you, Tom?" + +"Oh, Judge, Injun Joe's in the cave!" + + + +CHAPTER XXXIII + +WITHIN a few minutes the news had spread, and a dozen skiff-loads of +men were on their way to McDougal's cave, and the ferryboat, well +filled with passengers, soon followed. Tom Sawyer was in the skiff that +bore Judge Thatcher. + +When the cave door was unlocked, a sorrowful sight presented itself in +the dim twilight of the place. Injun Joe lay stretched upon the ground, +dead, with his face close to the crack of the door, as if his longing +eyes had been fixed, to the latest moment, upon the light and the cheer +of the free world outside. Tom was touched, for he knew by his own +experience how this wretch had suffered. His pity was moved, but +nevertheless he felt an abounding sense of relief and security, now, +which revealed to him in a degree which he had not fully appreciated +before how vast a weight of dread had been lying upon him since the day +he lifted his voice against this bloody-minded outcast. + +Injun Joe's bowie-knife lay close by, its blade broken in two. The +great foundation-beam of the door had been chipped and hacked through, +with tedious labor; useless labor, too, it was, for the native rock +formed a sill outside it, and upon that stubborn material the knife had +wrought no effect; the only damage done was to the knife itself. But if +there had been no stony obstruction there the labor would have been +useless still, for if the beam had been wholly cut away Injun Joe could +not have squeezed his body under the door, and he knew it. So he had +only hacked that place in order to be doing something--in order to pass +the weary time--in order to employ his tortured faculties. Ordinarily +one could find half a dozen bits of candle stuck around in the crevices +of this vestibule, left there by tourists; but there were none now. The +prisoner had searched them out and eaten them. He had also contrived to +catch a few bats, and these, also, he had eaten, leaving only their +claws. The poor unfortunate had starved to death. In one place, near at +hand, a stalagmite had been slowly growing up from the ground for ages, +builded by the water-drip from a stalactite overhead. The captive had +broken off the stalagmite, and upon the stump had placed a stone, +wherein he had scooped a shallow hollow to catch the precious drop +that fell once in every three minutes with the dreary regularity of a +clock-tick--a dessertspoonful once in four and twenty hours. That drop +was falling when the Pyramids were new; when Troy fell; when the +foundations of Rome were laid; when Christ was crucified; when the +Conqueror created the British empire; when Columbus sailed; when the +massacre at Lexington was "news." It is falling now; it will still be +falling when all these things shall have sunk down the afternoon of +history, and the twilight of tradition, and been swallowed up in the +thick night of oblivion. Has everything a purpose and a mission? Did +this drop fall patiently during five thousand years to be ready for +this flitting human insect's need? and has it another important object +to accomplish ten thousand years to come? No matter. It is many and +many a year since the hapless half-breed scooped out the stone to catch +the priceless drops, but to this day the tourist stares longest at that +pathetic stone and that slow-dropping water when he comes to see the +wonders of McDougal's cave. Injun Joe's cup stands first in the list of +the cavern's marvels; even "Aladdin's Palace" cannot rival it. + +Injun Joe was buried near the mouth of the cave; and people flocked +there in boats and wagons from the towns and from all the farms and +hamlets for seven miles around; they brought their children, and all +sorts of provisions, and confessed that they had had almost as +satisfactory a time at the funeral as they could have had at the +hanging. + +This funeral stopped the further growth of one thing--the petition to +the governor for Injun Joe's pardon. The petition had been largely +signed; many tearful and eloquent meetings had been held, and a +committee of sappy women been appointed to go in deep mourning and wail +around the governor, and implore him to be a merciful ass and trample +his duty under foot. Injun Joe was believed to have killed five +citizens of the village, but what of that? If he had been Satan himself +there would have been plenty of weaklings ready to scribble their names +to a pardon-petition, and drip a tear on it from their permanently +impaired and leaky water-works. + +The morning after the funeral Tom took Huck to a private place to have +an important talk. Huck had learned all about Tom's adventure from the +Welshman and the Widow Douglas, by this time, but Tom said he reckoned +there was one thing they had not told him; that thing was what he +wanted to talk about now. Huck's face saddened. He said: + +"I know what it is. You got into No. 2 and never found anything but +whiskey. Nobody told me it was you; but I just knowed it must 'a' ben +you, soon as I heard 'bout that whiskey business; and I knowed you +hadn't got the money becuz you'd 'a' got at me some way or other and +told me even if you was mum to everybody else. Tom, something's always +told me we'd never get holt of that swag." + +"Why, Huck, I never told on that tavern-keeper. YOU know his tavern +was all right the Saturday I went to the picnic. Don't you remember you +was to watch there that night?" + +"Oh yes! Why, it seems 'bout a year ago. It was that very night that I +follered Injun Joe to the widder's." + +"YOU followed him?" + +"Yes--but you keep mum. I reckon Injun Joe's left friends behind him, +and I don't want 'em souring on me and doing me mean tricks. If it +hadn't ben for me he'd be down in Texas now, all right." + +Then Huck told his entire adventure in confidence to Tom, who had only +heard of the Welshman's part of it before. + +"Well," said Huck, presently, coming back to the main question, +"whoever nipped the whiskey in No. 2, nipped the money, too, I reckon +--anyways it's a goner for us, Tom." + +"Huck, that money wasn't ever in No. 2!" + +"What!" Huck searched his comrade's face keenly. "Tom, have you got on +the track of that money again?" + +"Huck, it's in the cave!" + +Huck's eyes blazed. + +"Say it again, Tom." + +"The money's in the cave!" + +"Tom--honest injun, now--is it fun, or earnest?" + +"Earnest, Huck--just as earnest as ever I was in my life. Will you go +in there with me and help get it out?" + +"I bet I will! I will if it's where we can blaze our way to it and not +get lost." + +"Huck, we can do that without the least little bit of trouble in the +world." + +"Good as wheat! What makes you think the money's--" + +"Huck, you just wait till we get in there. If we don't find it I'll +agree to give you my drum and every thing I've got in the world. I +will, by jings." + +"All right--it's a whiz. When do you say?" + +"Right now, if you say it. Are you strong enough?" + +"Is it far in the cave? I ben on my pins a little, three or four days, +now, but I can't walk more'n a mile, Tom--least I don't think I could." + +"It's about five mile into there the way anybody but me would go, +Huck, but there's a mighty short cut that they don't anybody but me +know about. Huck, I'll take you right to it in a skiff. I'll float the +skiff down there, and I'll pull it back again all by myself. You +needn't ever turn your hand over." + +"Less start right off, Tom." + +"All right. We want some bread and meat, and our pipes, and a little +bag or two, and two or three kite-strings, and some of these +new-fangled things they call lucifer matches. I tell you, many's +the time I wished I had some when I was in there before." + +A trifle after noon the boys borrowed a small skiff from a citizen who +was absent, and got under way at once. When they were several miles +below "Cave Hollow," Tom said: + +"Now you see this bluff here looks all alike all the way down from the +cave hollow--no houses, no wood-yards, bushes all alike. But do you see +that white place up yonder where there's been a landslide? Well, that's +one of my marks. We'll get ashore, now." + +They landed. + +"Now, Huck, where we're a-standing you could touch that hole I got out +of with a fishing-pole. See if you can find it." + +Huck searched all the place about, and found nothing. Tom proudly +marched into a thick clump of sumach bushes and said: + +"Here you are! Look at it, Huck; it's the snuggest hole in this +country. You just keep mum about it. All along I've been wanting to be +a robber, but I knew I'd got to have a thing like this, and where to +run across it was the bother. We've got it now, and we'll keep it +quiet, only we'll let Joe Harper and Ben Rogers in--because of course +there's got to be a Gang, or else there wouldn't be any style about it. +Tom Sawyer's Gang--it sounds splendid, don't it, Huck?" + +"Well, it just does, Tom. And who'll we rob?" + +"Oh, most anybody. Waylay people--that's mostly the way." + +"And kill them?" + +"No, not always. Hive them in the cave till they raise a ransom." + +"What's a ransom?" + +"Money. You make them raise all they can, off'n their friends; and +after you've kept them a year, if it ain't raised then you kill them. +That's the general way. Only you don't kill the women. You shut up the +women, but you don't kill them. They're always beautiful and rich, and +awfully scared. You take their watches and things, but you always take +your hat off and talk polite. They ain't anybody as polite as robbers +--you'll see that in any book. Well, the women get to loving you, and +after they've been in the cave a week or two weeks they stop crying and +after that you couldn't get them to leave. If you drove them out they'd +turn right around and come back. It's so in all the books." + +"Why, it's real bully, Tom. I believe it's better'n to be a pirate." + +"Yes, it's better in some ways, because it's close to home and +circuses and all that." + +By this time everything was ready and the boys entered the hole, Tom +in the lead. They toiled their way to the farther end of the tunnel, +then made their spliced kite-strings fast and moved on. A few steps +brought them to the spring, and Tom felt a shudder quiver all through +him. He showed Huck the fragment of candle-wick perched on a lump of +clay against the wall, and described how he and Becky had watched the +flame struggle and expire. + +The boys began to quiet down to whispers, now, for the stillness and +gloom of the place oppressed their spirits. They went on, and presently +entered and followed Tom's other corridor until they reached the +"jumping-off place." The candles revealed the fact that it was not +really a precipice, but only a steep clay hill twenty or thirty feet +high. Tom whispered: + +"Now I'll show you something, Huck." + +He held his candle aloft and said: + +"Look as far around the corner as you can. Do you see that? There--on +the big rock over yonder--done with candle-smoke." + +"Tom, it's a CROSS!" + +"NOW where's your Number Two? 'UNDER THE CROSS,' hey? Right yonder's +where I saw Injun Joe poke up his candle, Huck!" + +Huck stared at the mystic sign awhile, and then said with a shaky voice: + +"Tom, less git out of here!" + +"What! and leave the treasure?" + +"Yes--leave it. Injun Joe's ghost is round about there, certain." + +"No it ain't, Huck, no it ain't. It would ha'nt the place where he +died--away out at the mouth of the cave--five mile from here." + +"No, Tom, it wouldn't. It would hang round the money. I know the ways +of ghosts, and so do you." + +Tom began to fear that Huck was right. Misgivings gathered in his +mind. But presently an idea occurred to him-- + +"Lookyhere, Huck, what fools we're making of ourselves! Injun Joe's +ghost ain't a going to come around where there's a cross!" + +The point was well taken. It had its effect. + +"Tom, I didn't think of that. But that's so. It's luck for us, that +cross is. I reckon we'll climb down there and have a hunt for that box." + +Tom went first, cutting rude steps in the clay hill as he descended. +Huck followed. Four avenues opened out of the small cavern which the +great rock stood in. The boys examined three of them with no result. +They found a small recess in the one nearest the base of the rock, with +a pallet of blankets spread down in it; also an old suspender, some +bacon rind, and the well-gnawed bones of two or three fowls. But there +was no money-box. The lads searched and researched this place, but in +vain. Tom said: + +"He said UNDER the cross. Well, this comes nearest to being under the +cross. It can't be under the rock itself, because that sets solid on +the ground." + +They searched everywhere once more, and then sat down discouraged. +Huck could suggest nothing. By-and-by Tom said: + +"Lookyhere, Huck, there's footprints and some candle-grease on the +clay about one side of this rock, but not on the other sides. Now, +what's that for? I bet you the money IS under the rock. I'm going to +dig in the clay." + +"That ain't no bad notion, Tom!" said Huck with animation. + +Tom's "real Barlow" was out at once, and he had not dug four inches +before he struck wood. + +"Hey, Huck!--you hear that?" + +Huck began to dig and scratch now. Some boards were soon uncovered and +removed. They had concealed a natural chasm which led under the rock. +Tom got into this and held his candle as far under the rock as he +could, but said he could not see to the end of the rift. He proposed to +explore. He stooped and passed under; the narrow way descended +gradually. He followed its winding course, first to the right, then to +the left, Huck at his heels. Tom turned a short curve, by-and-by, and +exclaimed: + +"My goodness, Huck, lookyhere!" + +It was the treasure-box, sure enough, occupying a snug little cavern, +along with an empty powder-keg, a couple of guns in leather cases, two +or three pairs of old moccasins, a leather belt, and some other rubbish +well soaked with the water-drip. + +"Got it at last!" said Huck, ploughing among the tarnished coins with +his hand. "My, but we're rich, Tom!" + +"Huck, I always reckoned we'd get it. It's just too good to believe, +but we HAVE got it, sure! Say--let's not fool around here. Let's snake +it out. Lemme see if I can lift the box." + +It weighed about fifty pounds. Tom could lift it, after an awkward +fashion, but could not carry it conveniently. + +"I thought so," he said; "THEY carried it like it was heavy, that day +at the ha'nted house. I noticed that. I reckon I was right to think of +fetching the little bags along." + +The money was soon in the bags and the boys took it up to the cross +rock. + +"Now less fetch the guns and things," said Huck. + +"No, Huck--leave them there. They're just the tricks to have when we +go to robbing. We'll keep them there all the time, and we'll hold our +orgies there, too. It's an awful snug place for orgies." + +"What orgies?" + +"I dono. But robbers always have orgies, and of course we've got to +have them, too. Come along, Huck, we've been in here a long time. It's +getting late, I reckon. I'm hungry, too. We'll eat and smoke when we +get to the skiff." + +They presently emerged into the clump of sumach bushes, looked warily +out, found the coast clear, and were soon lunching and smoking in the +skiff. As the sun dipped toward the horizon they pushed out and got +under way. Tom skimmed up the shore through the long twilight, chatting +cheerily with Huck, and landed shortly after dark. + +"Now, Huck," said Tom, "we'll hide the money in the loft of the +widow's woodshed, and I'll come up in the morning and we'll count it +and divide, and then we'll hunt up a place out in the woods for it +where it will be safe. Just you lay quiet here and watch the stuff till +I run and hook Benny Taylor's little wagon; I won't be gone a minute." + +He disappeared, and presently returned with the wagon, put the two +small sacks into it, threw some old rags on top of them, and started +off, dragging his cargo behind him. When the boys reached the +Welshman's house, they stopped to rest. Just as they were about to move +on, the Welshman stepped out and said: + +"Hallo, who's that?" + +"Huck and Tom Sawyer." + +"Good! Come along with me, boys, you are keeping everybody waiting. +Here--hurry up, trot ahead--I'll haul the wagon for you. Why, it's not +as light as it might be. Got bricks in it?--or old metal?" + +"Old metal," said Tom. + +"I judged so; the boys in this town will take more trouble and fool +away more time hunting up six bits' worth of old iron to sell to the +foundry than they would to make twice the money at regular work. But +that's human nature--hurry along, hurry along!" + +The boys wanted to know what the hurry was about. + +"Never mind; you'll see, when we get to the Widow Douglas'." + +Huck said with some apprehension--for he was long used to being +falsely accused: + +"Mr. Jones, we haven't been doing nothing." + +The Welshman laughed. + +"Well, I don't know, Huck, my boy. I don't know about that. Ain't you +and the widow good friends?" + +"Yes. Well, she's ben good friends to me, anyway." + +"All right, then. What do you want to be afraid for?" + +This question was not entirely answered in Huck's slow mind before he +found himself pushed, along with Tom, into Mrs. Douglas' drawing-room. +Mr. Jones left the wagon near the door and followed. + +The place was grandly lighted, and everybody that was of any +consequence in the village was there. The Thatchers were there, the +Harpers, the Rogerses, Aunt Polly, Sid, Mary, the minister, the editor, +and a great many more, and all dressed in their best. The widow +received the boys as heartily as any one could well receive two such +looking beings. They were covered with clay and candle-grease. Aunt +Polly blushed crimson with humiliation, and frowned and shook her head +at Tom. Nobody suffered half as much as the two boys did, however. Mr. +Jones said: + +"Tom wasn't at home, yet, so I gave him up; but I stumbled on him and +Huck right at my door, and so I just brought them along in a hurry." + +"And you did just right," said the widow. "Come with me, boys." + +She took them to a bedchamber and said: + +"Now wash and dress yourselves. Here are two new suits of clothes +--shirts, socks, everything complete. They're Huck's--no, no thanks, +Huck--Mr. Jones bought one and I the other. But they'll fit both of you. +Get into them. We'll wait--come down when you are slicked up enough." + +Then she left. + + + +CHAPTER XXXIV + +HUCK said: "Tom, we can slope, if we can find a rope. The window ain't +high from the ground." + +"Shucks! what do you want to slope for?" + +"Well, I ain't used to that kind of a crowd. I can't stand it. I ain't +going down there, Tom." + +"Oh, bother! It ain't anything. I don't mind it a bit. I'll take care +of you." + +Sid appeared. + +"Tom," said he, "auntie has been waiting for you all the afternoon. +Mary got your Sunday clothes ready, and everybody's been fretting about +you. Say--ain't this grease and clay, on your clothes?" + +"Now, Mr. Siddy, you jist 'tend to your own business. What's all this +blow-out about, anyway?" + +"It's one of the widow's parties that she's always having. This time +it's for the Welshman and his sons, on account of that scrape they +helped her out of the other night. And say--I can tell you something, +if you want to know." + +"Well, what?" + +"Why, old Mr. Jones is going to try to spring something on the people +here to-night, but I overheard him tell auntie to-day about it, as a +secret, but I reckon it's not much of a secret now. Everybody knows +--the widow, too, for all she tries to let on she don't. Mr. Jones was +bound Huck should be here--couldn't get along with his grand secret +without Huck, you know!" + +"Secret about what, Sid?" + +"About Huck tracking the robbers to the widow's. I reckon Mr. Jones +was going to make a grand time over his surprise, but I bet you it will +drop pretty flat." + +Sid chuckled in a very contented and satisfied way. + +"Sid, was it you that told?" + +"Oh, never mind who it was. SOMEBODY told--that's enough." + +"Sid, there's only one person in this town mean enough to do that, and +that's you. If you had been in Huck's place you'd 'a' sneaked down the +hill and never told anybody on the robbers. You can't do any but mean +things, and you can't bear to see anybody praised for doing good ones. +There--no thanks, as the widow says"--and Tom cuffed Sid's ears and +helped him to the door with several kicks. "Now go and tell auntie if +you dare--and to-morrow you'll catch it!" + +Some minutes later the widow's guests were at the supper-table, and a +dozen children were propped up at little side-tables in the same room, +after the fashion of that country and that day. At the proper time Mr. +Jones made his little speech, in which he thanked the widow for the +honor she was doing himself and his sons, but said that there was +another person whose modesty-- + +And so forth and so on. He sprung his secret about Huck's share in the +adventure in the finest dramatic manner he was master of, but the +surprise it occasioned was largely counterfeit and not as clamorous and +effusive as it might have been under happier circumstances. However, +the widow made a pretty fair show of astonishment, and heaped so many +compliments and so much gratitude upon Huck that he almost forgot the +nearly intolerable discomfort of his new clothes in the entirely +intolerable discomfort of being set up as a target for everybody's gaze +and everybody's laudations. + +The widow said she meant to give Huck a home under her roof and have +him educated; and that when she could spare the money she would start +him in business in a modest way. Tom's chance was come. He said: + +"Huck don't need it. Huck's rich." + +Nothing but a heavy strain upon the good manners of the company kept +back the due and proper complimentary laugh at this pleasant joke. But +the silence was a little awkward. Tom broke it: + +"Huck's got money. Maybe you don't believe it, but he's got lots of +it. Oh, you needn't smile--I reckon I can show you. You just wait a +minute." + +Tom ran out of doors. The company looked at each other with a +perplexed interest--and inquiringly at Huck, who was tongue-tied. + +"Sid, what ails Tom?" said Aunt Polly. "He--well, there ain't ever any +making of that boy out. I never--" + +Tom entered, struggling with the weight of his sacks, and Aunt Polly +did not finish her sentence. Tom poured the mass of yellow coin upon +the table and said: + +"There--what did I tell you? Half of it's Huck's and half of it's mine!" + +The spectacle took the general breath away. All gazed, nobody spoke +for a moment. Then there was a unanimous call for an explanation. Tom +said he could furnish it, and he did. The tale was long, but brimful of +interest. There was scarcely an interruption from any one to break the +charm of its flow. When he had finished, Mr. Jones said: + +"I thought I had fixed up a little surprise for this occasion, but it +don't amount to anything now. This one makes it sing mighty small, I'm +willing to allow." + +The money was counted. The sum amounted to a little over twelve +thousand dollars. It was more than any one present had ever seen at one +time before, though several persons were there who were worth +considerably more than that in property. + + + +CHAPTER XXXV + +THE reader may rest satisfied that Tom's and Huck's windfall made a +mighty stir in the poor little village of St. Petersburg. So vast a +sum, all in actual cash, seemed next to incredible. It was talked +about, gloated over, glorified, until the reason of many of the +citizens tottered under the strain of the unhealthy excitement. Every +"haunted" house in St. Petersburg and the neighboring villages was +dissected, plank by plank, and its foundations dug up and ransacked for +hidden treasure--and not by boys, but men--pretty grave, unromantic +men, too, some of them. Wherever Tom and Huck appeared they were +courted, admired, stared at. The boys were not able to remember that +their remarks had possessed weight before; but now their sayings were +treasured and repeated; everything they did seemed somehow to be +regarded as remarkable; they had evidently lost the power of doing and +saying commonplace things; moreover, their past history was raked up +and discovered to bear marks of conspicuous originality. The village +paper published biographical sketches of the boys. + +The Widow Douglas put Huck's money out at six per cent., and Judge +Thatcher did the same with Tom's at Aunt Polly's request. Each lad had +an income, now, that was simply prodigious--a dollar for every week-day +in the year and half of the Sundays. It was just what the minister got +--no, it was what he was promised--he generally couldn't collect it. A +dollar and a quarter a week would board, lodge, and school a boy in +those old simple days--and clothe him and wash him, too, for that +matter. + +Judge Thatcher had conceived a great opinion of Tom. He said that no +commonplace boy would ever have got his daughter out of the cave. When +Becky told her father, in strict confidence, how Tom had taken her +whipping at school, the Judge was visibly moved; and when she pleaded +grace for the mighty lie which Tom had told in order to shift that +whipping from her shoulders to his own, the Judge said with a fine +outburst that it was a noble, a generous, a magnanimous lie--a lie that +was worthy to hold up its head and march down through history breast to +breast with George Washington's lauded Truth about the hatchet! Becky +thought her father had never looked so tall and so superb as when he +walked the floor and stamped his foot and said that. She went straight +off and told Tom about it. + +Judge Thatcher hoped to see Tom a great lawyer or a great soldier some +day. He said he meant to look to it that Tom should be admitted to the +National Military Academy and afterward trained in the best law school +in the country, in order that he might be ready for either career or +both. + +Huck Finn's wealth and the fact that he was now under the Widow +Douglas' protection introduced him into society--no, dragged him into +it, hurled him into it--and his sufferings were almost more than he +could bear. The widow's servants kept him clean and neat, combed and +brushed, and they bedded him nightly in unsympathetic sheets that had +not one little spot or stain which he could press to his heart and know +for a friend. He had to eat with a knife and fork; he had to use +napkin, cup, and plate; he had to learn his book, he had to go to +church; he had to talk so properly that speech was become insipid in +his mouth; whithersoever he turned, the bars and shackles of +civilization shut him in and bound him hand and foot. + +He bravely bore his miseries three weeks, and then one day turned up +missing. For forty-eight hours the widow hunted for him everywhere in +great distress. The public were profoundly concerned; they searched +high and low, they dragged the river for his body. Early the third +morning Tom Sawyer wisely went poking among some old empty hogsheads +down behind the abandoned slaughter-house, and in one of them he found +the refugee. Huck had slept there; he had just breakfasted upon some +stolen odds and ends of food, and was lying off, now, in comfort, with +his pipe. He was unkempt, uncombed, and clad in the same old ruin of +rags that had made him picturesque in the days when he was free and +happy. Tom routed him out, told him the trouble he had been causing, +and urged him to go home. Huck's face lost its tranquil content, and +took a melancholy cast. He said: + +"Don't talk about it, Tom. I've tried it, and it don't work; it don't +work, Tom. It ain't for me; I ain't used to it. The widder's good to +me, and friendly; but I can't stand them ways. She makes me get up just +at the same time every morning; she makes me wash, they comb me all to +thunder; she won't let me sleep in the woodshed; I got to wear them +blamed clothes that just smothers me, Tom; they don't seem to any air +git through 'em, somehow; and they're so rotten nice that I can't set +down, nor lay down, nor roll around anywher's; I hain't slid on a +cellar-door for--well, it 'pears to be years; I got to go to church and +sweat and sweat--I hate them ornery sermons! I can't ketch a fly in +there, I can't chaw. I got to wear shoes all Sunday. The widder eats by +a bell; she goes to bed by a bell; she gits up by a bell--everything's +so awful reg'lar a body can't stand it." + +"Well, everybody does that way, Huck." + +"Tom, it don't make no difference. I ain't everybody, and I can't +STAND it. It's awful to be tied up so. And grub comes too easy--I don't +take no interest in vittles, that way. I got to ask to go a-fishing; I +got to ask to go in a-swimming--dern'd if I hain't got to ask to do +everything. Well, I'd got to talk so nice it wasn't no comfort--I'd got +to go up in the attic and rip out awhile, every day, to git a taste in +my mouth, or I'd a died, Tom. The widder wouldn't let me smoke; she +wouldn't let me yell, she wouldn't let me gape, nor stretch, nor +scratch, before folks--" [Then with a spasm of special irritation and +injury]--"And dad fetch it, she prayed all the time! I never see such a +woman! I HAD to shove, Tom--I just had to. And besides, that school's +going to open, and I'd a had to go to it--well, I wouldn't stand THAT, +Tom. Looky here, Tom, being rich ain't what it's cracked up to be. It's +just worry and worry, and sweat and sweat, and a-wishing you was dead +all the time. Now these clothes suits me, and this bar'l suits me, and +I ain't ever going to shake 'em any more. Tom, I wouldn't ever got into +all this trouble if it hadn't 'a' ben for that money; now you just take +my sheer of it along with your'n, and gimme a ten-center sometimes--not +many times, becuz I don't give a dern for a thing 'thout it's tollable +hard to git--and you go and beg off for me with the widder." + +"Oh, Huck, you know I can't do that. 'Tain't fair; and besides if +you'll try this thing just a while longer you'll come to like it." + +"Like it! Yes--the way I'd like a hot stove if I was to set on it long +enough. No, Tom, I won't be rich, and I won't live in them cussed +smothery houses. I like the woods, and the river, and hogsheads, and +I'll stick to 'em, too. Blame it all! just as we'd got guns, and a +cave, and all just fixed to rob, here this dern foolishness has got to +come up and spile it all!" + +Tom saw his opportunity-- + +"Lookyhere, Huck, being rich ain't going to keep me back from turning +robber." + +"No! Oh, good-licks; are you in real dead-wood earnest, Tom?" + +"Just as dead earnest as I'm sitting here. But Huck, we can't let you +into the gang if you ain't respectable, you know." + +Huck's joy was quenched. + +"Can't let me in, Tom? Didn't you let me go for a pirate?" + +"Yes, but that's different. A robber is more high-toned than what a +pirate is--as a general thing. In most countries they're awful high up +in the nobility--dukes and such." + +"Now, Tom, hain't you always ben friendly to me? You wouldn't shet me +out, would you, Tom? You wouldn't do that, now, WOULD you, Tom?" + +"Huck, I wouldn't want to, and I DON'T want to--but what would people +say? Why, they'd say, 'Mph! Tom Sawyer's Gang! pretty low characters in +it!' They'd mean you, Huck. You wouldn't like that, and I wouldn't." + +Huck was silent for some time, engaged in a mental struggle. Finally +he said: + +"Well, I'll go back to the widder for a month and tackle it and see if +I can come to stand it, if you'll let me b'long to the gang, Tom." + +"All right, Huck, it's a whiz! Come along, old chap, and I'll ask the +widow to let up on you a little, Huck." + +"Will you, Tom--now will you? That's good. If she'll let up on some of +the roughest things, I'll smoke private and cuss private, and crowd +through or bust. When you going to start the gang and turn robbers?" + +"Oh, right off. We'll get the boys together and have the initiation +to-night, maybe." + +"Have the which?" + +"Have the initiation." + +"What's that?" + +"It's to swear to stand by one another, and never tell the gang's +secrets, even if you're chopped all to flinders, and kill anybody and +all his family that hurts one of the gang." + +"That's gay--that's mighty gay, Tom, I tell you." + +"Well, I bet it is. And all that swearing's got to be done at +midnight, in the lonesomest, awfulest place you can find--a ha'nted +house is the best, but they're all ripped up now." + +"Well, midnight's good, anyway, Tom." + +"Yes, so it is. And you've got to swear on a coffin, and sign it with +blood." + +"Now, that's something LIKE! Why, it's a million times bullier than +pirating. I'll stick to the widder till I rot, Tom; and if I git to be +a reg'lar ripper of a robber, and everybody talking 'bout it, I reckon +she'll be proud she snaked me in out of the wet." + + + +CONCLUSION + +SO endeth this chronicle. It being strictly a history of a BOY, it +must stop here; the story could not go much further without becoming +the history of a MAN. When one writes a novel about grown people, he +knows exactly where to stop--that is, with a marriage; but when he +writes of juveniles, he must stop where he best can. + +Most of the characters that perform in this book still live, and are +prosperous and happy. Some day it may seem worth while to take up the +story of the younger ones again and see what sort of men and women they +turned out to be; therefore it will be wisest not to reveal any of that +part of their lives at present. + + + + + +End of the Project Gutenberg EBook of The Adventures of Tom Sawyer, Complete +by Mark Twain (Samuel Clemens) diff --git a/vendor/github.com/klauspost/compress/testdata/e.txt b/vendor/github.com/klauspost/compress/testdata/e.txt new file mode 100644 index 0000000..5ca186f --- /dev/null +++ b/vendor/github.com/klauspost/compress/testdata/e.txt @@ -0,0 +1 @@ +2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274274663919320030599218174135966290435729003342952605956307381323286279434907632338298807531952510190115738341879307021540891499348841675092447614606680822648001684774118537423454424371075390777449920695517027618386062613313845830007520449338265602976067371132007093287091274437470472306969772093101416928368190255151086574637721112523897844250569536967707854499699679468644549059879316368892300987931277361782154249992295763514822082698951936680331825288693984964651058209392398294887933203625094431173012381970684161403970198376793206832823764648042953118023287825098194558153017567173613320698112509961818815930416903515988885193458072738667385894228792284998920868058257492796104841984443634632449684875602336248270419786232090021609902353043699418491463140934317381436405462531520961836908887070167683964243781405927145635490613031072085103837505101157477041718986106873969655212671546889570350354021234078498193343210681701210056278802351930332247450158539047304199577770935036604169973297250886876966403555707162268447162560798826517871341951246652010305921236677194325278675398558944896970964097545918569563802363701621120477427228364896134225164450781824423529486363721417402388934412479635743702637552944483379980161254922785092577825620926226483262779333865664816277251640191059004916449982893150566047258027786318641551956532442586982946959308019152987211725563475463964479101459040905862984967912874068705048958586717479854667757573205681288459205413340539220001137863009455606881667400169842055804033637953764520304024322566135278369511778838638744396625322498506549958862342818997077332761717839280349465014345588970719425863987727547109629537415211151368350627526023264847287039207643100595841166120545297030236472549296669381151373227536450988890313602057248176585118063036442812314965507047510254465011727211555194866850800368532281831521960037356252794495158284188294787610852639813955990067376482922443752871846245780361929819713991475644882626039033814418232625150974827987779964373089970388867782271383605772978824125611907176639465070633045279546618550966661856647097113444740160704626215680717481877844371436988218559670959102596862002353718588748569652200050311734392073211390803293634479727355955277349071783793421637012050054513263835440001863239914907054797780566978533580489669062951194324730995876552368128590413832411607226029983305353708761389396391779574540161372236187893652605381558415871869255386061647798340254351284396129460352913325942794904337299085731580290958631382683291477116396337092400316894586360606458459251269946557248391865642097526850823075442545993769170419777800853627309417101634349076964237222943523661255725088147792231519747780605696725380171807763603462459278778465850656050780844211529697521890874019660906651803516501792504619501366585436632712549639908549144200014574760819302212066024330096412704894390397177195180699086998606636583232278709376502260149291011517177635944602023249300280401867723910288097866605651183260043688508817157238669842242201024950551881694803221002515426494639812873677658927688163598312477886520141174110913601164995076629077943646005851941998560162647907615321038727557126992518275687989302761761146162549356495903798045838182323368612016243736569846703785853305275833337939907521660692380533698879565137285593883499894707416181550125397064648171946708348197214488898790676503795903669672494992545279033729636162658976039498576741397359441023744329709355477982629614591442936451428617158587339746791897571211956187385783644758448423555581050025611492391518893099463428413936080383091662818811503715284967059741625628236092168075150177725387402564253470879089137291722828611515915683725241630772254406337875931059826760944203261924285317018781772960235413060672136046000389661093647095141417185777014180606443636815464440053316087783143174440811949422975599314011888683314832802706553833004693290115744147563139997221703804617092894579096271662260740718749975359212756084414737823303270330168237193648002173285734935947564334129943024850235732214597843282641421684878721673367010615094243456984401873312810107945127223737886126058165668053714396127888732527373890392890506865324138062796025930387727697783792868409325365880733988457218746021005311483351323850047827169376218004904795597959290591655470505777514308175112698985188408718564026035305583737832422924185625644255022672155980274012617971928047139600689163828665277009752767069777036439260224372841840883251848770472638440379530166905465937461619323840363893131364327137688841026811219891275223056256756254701725086349765367288605966752740868627407912856576996313789753034660616669804218267724560530660773899624218340859882071864682623215080288286359746839654358856685503773131296587975810501214916207656769950659715344763470320853215603674828608378656803073062657633469774295634643716709397193060876963495328846833613038829431040800296873869117066666146800015121143442256023874474325250769387077775193299942137277211258843608715834835626961661980572526612206797540621062080649882918454395301529982092503005498257043390553570168653120526495614857249257386206917403695213533732531666345466588597286659451136441370331393672118569553952108458407244323835586063106806964924851232632699514603596037297253198368423363904632136710116192821711150282801604488058802382031981493096369596735832742024988245684941273860566491352526706046234450549227581151709314921879592718001940968866986837037302200475314338181092708030017205935530520700706072233999463990571311587099635777359027196285061146514837526209565346713290025994397663114545902685898979115837093419370441155121920117164880566945938131183843765620627846310490346293950029458341164824114969758326011800731699437393506966295712410273239138741754923071862454543222039552735295240245903805744502892246886285336542213815722131163288112052146489805180092024719391710555390113943316681515828843687606961102505171007392762385553386272553538830960671644662370922646809671254061869502143176211668140097595281493907222601112681153108387317617323235263605838173151034595736538223534992935822836851007810884634349983518404451704270189381994243410090575376257767571118090088164183319201962623416288166521374717325477727783488774366518828752156685719506371936565390389449366421764003121527870222366463635755503565576948886549500270853923617105502131147413744106134445544192101336172996285694899193369184729478580729156088510396781959429833186480756083679551496636448965592948187851784038773326247051945050419847742014183947731202815886845707290544057510601285258056594703046836344592652552137008068752009593453607316226118728173928074623094685367823106097921599360019946237993434210687813497346959246469752506246958616909178573976595199392993995567542714654910456860702099012606818704984178079173924071945996323060254707901774527513186809982284730860766536866855516467702911336827563107223346726113705490795365834538637196235856312618387156774118738527722922594743373785695538456246801013905727871016512966636764451872465653730402443684140814488732957847348490003019477888020460324660842875351848364959195082888323206522128104190448047247949291342284951970022601310430062410717971502793433263407995960531446053230488528972917659876016667811937932372453857209607582277178483361613582612896226118129455927462767137794487586753657544861407611931125958512655759734573015333642630767985443385761715333462325270572005303988289499034259566232975782488735029259166825894456894655992658454762694528780516501720674785417887982276806536650641910973434528878338621726156269582654478205672987756426325321594294418039943217000090542650763095588465895171709147607437136893319469090981904501290307099566226620303182649365733698419555776963787624918852865686607600566025605445711337286840205574416030837052312242587223438854123179481388550075689381124935386318635287083799845692619981794523364087429591180747453419551420351726184200845509170845682368200897739455842679214273477560879644279202708312150156406341341617166448069815483764491573900121217041547872591998943825364950514771379399147205219529079396137621107238494290616357604596231253506068537651423115349665683715116604220796394466621163255157729070978473156278277598788136491951257483328793771571459091064841642678309949723674420175862269402159407924480541255360431317992696739157542419296607312393763542139230617876753958711436104089409966089471418340698362993675362621545247298464213752891079884381306095552622720837518629837066787224430195793793786072107254277289071732854874374355781966511716618330881129120245204048682200072344035025448202834254187884653602591506445271657700044521097735585897622655484941621714989532383421600114062950718490427789258552743035221396835679018076406042138307308774460170842688272261177180842664333651780002171903449234264266292261456004337383868335555343453004264818473989215627086095650629340405264943244261445665921291225648893569655009154306426134252668472594914314239398845432486327461842846655985332312210466259890141712103446084271616619001257195870793217569698544013397622096749454185407118446433946990162698351607848924514058940946395267807354579700307051163682519487701189764002827648414160587206184185297189154019688253289309149665345753571427318482016384644832499037886069008072709327673127581966563941148961716832980455139729506687604740915420428429993541025829113502241690769431668574242522509026939034814856451303069925199590436384028429267412573422447765584177886171737265462085498294498946787350929581652632072258992368768457017823038096567883112289305809140572610865884845873101658151167533327674887014829167419701512559782572707406431808601428149024146780472327597684269633935773542930186739439716388611764209004068663398856841681003872389214483176070116684503887212364367043314091155733280182977988736590916659612402021778558854876176161989370794380056663364884365089144805571039765214696027662583599051987042300179465536788567430285974600143785483237068701190078499404930918919181649327259774030074879681484882342932023012128032327460392219687528340516906974194257614673978110715464186273369091584973185011183960482533518748438923177292613543024932562896371361977285456622924461644497284597867711574125670307871885109336344480149675240618536569532074170533486782754827815415561966911055101472799040386897220465550833170782394808785990501947563108984124144672821865459971596639015641941751820935932616316888380132758752601460507676098392625726411120135288591317848299475682472564885533357279772205543568126302535748216585414000805314820697137262149755576051890481622376790414926742600071045922695314835188137463887104273544767623577933993970632396604969145303273887874557905934937772320142954803345000695256980935282887783710670585567749481373858630385762823040694005665340584887527005308832459182183494318049834199639981458773435863115940570443683515285383609442955964360676090221741896883548131643997437764158365242234642619597390455450680695232850751868719449064767791886720306418630751053512149851051207313846648717547518382979990189317751550639981016466414592102406838294603208535554058147159273220677567669213664081505900806952540610628536408293276621931939933861623836069111767785448236129326858199965239275488427435414402884536455595124735546139403154952097397051896240157976832639450633230452192645049651735466775699295718989690470902730288544945416699791992948038254980285946029052763145580316514066229171223429375806143993484914362107993576737317948964252488813720435579287511385856973381976083524423240466778020948399639946684833774706725483618848273000648319163826022110555221246733323184463005504481849916996622087746140216157021029603318588727333298779352570182393861244026868339555870607758169954398469568540671174444932479519572159419645863736126915526457574786985964242176592896862383506370433939811671397544736228625506803682664135541448048997721373174119199970017293907303350869020922519124447393278376156321810842898207706974138707053266117683698647741787180202729412982310888796831880854367327806879771659111654224453806625861711729498038248879986504061563975629936962809358189761491017145343556659542757064194408833816841111166200759787244137082333917886114708228657531078536674695018462140736493917366254937783014074302668422150335117736471853872324040421037907750266020114814935482228916663640782450166815341213505278578539332606110249802273093636740213515386431693015267460536064351732154701091440650878823636764236831187390937464232609021646365627553976834019482932795750624399645272578624400375983422050808935129023122475970644105678361870877172333555465482598906861201410107222465904008553798235253885171623518256518482203125214950700378300411216212126052726059944320443056274522916128891766814160639131235975350390320077529587392412476451850809163911459296071156344204347133544720981178461451077872399140606290228276664309264900592249810291068759434533858330391178747575977065953570979640012224092199031158229259667913153991561438070129260780197022589662923368154312499412259460023399472228171056603931877226800493833148980338548909468685130789292064242819174795866199944411196208730498064385006852620258432842085582338566936649849720817046135376163584015342840674118587581546514598270228676671855309311923340191286170613364873183197560812569460089402953094429119590295968563923037689976327462283900735457144596414108229285922239332836210192822937243590283003884445701383771632056518351970100115722010956997890484964453434612129224964732356126321951155701565824427661599326463155806672053127596948538057364208384918887095176052287817339462747644656858900936266123311152910816041524100214195937349786431661556732702792109593543055579732660554677963552005378304619540636971842916168582734122217145885870814274090248185446421774876925093328785670674677381226752831653559245204578070541352576903253522738963847495646255940378924925007624386893776475310102323746733771474581625530698032499033676455430305274561512961214585944432150749051491453950981001388737926379964873728396416897555132275962011838248650746985492038097691932606437608743209385602815642849756549307909733854185583515789409814007691892389063090542534883896831762904120212949167195811935791203162514344096503132835216728021372415947344095498316138322505486708172221475138425166790445416617303200820330902895488808516797258495813407132180533988828139346049850532340472595097214331492586604248511405819579711564191458842833000525684776874305916390494306871343118796189637475503362820939949343690321031976898112055595369465424704173323895394046035325396758354395350516720261647961347790912327995264929045151148307923369382166010702872651938143844844532639517394110131152502750465749343063766541866128915264446926222884366299462732467958736383501937142786471398054038215513463223702071533134887083174146591492406359493020921122052610312390682941345696785958518393491382340884274312419099152870804332809132993078936867127413922890033069995875921815297612482409116951587789964090352577345938248232053055567238095022266790439614231852991989181065554412477204508510210071522352342792531266930108270633942321762570076323139159349709946933241013908779161651226804414809765618979735043151396066913258379033748620836695475083280318786707751177525663963479259219733577949555498655214193398170268639987388347010255262052312317215254062571636771270010760912281528326508984359568975961038372157726831170734552250194121701541318793651818502020877326906133592182000762327269503283827391243828198170871168108951187896746707073377869592565542713340052326706040004348843432902760360498027862160749469654989210474443927871934536701798673920803845633723311983855862638008516345597194441994344624761123844617615736242015935078520825600604101556889899501732554337298073561699861101908472096600708320280569917042590103876928658336557728758684250492690370934262028022399861803400211320742198642917383679176232826444645756330336556777374808644109969141827774253417010988435853189339175934511574023847292909015468559163792696196841000676598399744972047287881831200233383298030567865480871476464512824264478216644266616732096012564794514827125671326697067367144617795643752391742928503987022583734069852309190464967260243411270345611114149835783901793499713790913696706497637127248466613279908254305449295528594932793818341607827091326680865655921102733746700132583428715240835661522165574998431236278287106649401564670141943713823863454729606978693335973109537126499416282656463708490580151538205338326511289504938566468752921135932220265681856418260827538790002407915892646028490894922299966167437731347776134150965262448332709343898412056926145108857812249139616912534202918139898683901335795857624435194008943955180554746554000051766240202825944828833811886381749594284892013520090951007864941868256009273977667585642598378587497776669563350170748579027248701370264203283965756348010818356182372177082236423186591595883669487322411726504487268392328453010991677518376831599821263237123854357312681202445175401852132663740538802901249728180895021553100673598184430429105288459323064725590442355960551978839325930339572934663055160430923785677229293537208416693134575284011873746854691620648991164726909428982971065606801805807843600461866223562874591385185904416250663222249561448724413813849763797102676020845531824111963927941069619465426480006761727618115630063644321116224837379105623611358836334550102286170517890440570419577859833348463317921904494652923021469259756566389965893747728751393377105569802455757436190501772466214587592374418657530064998056688376964229825501195065837843125232135309371235243969149662310110328243570065781487677299160941153954063362752423712935549926713485031578238899567545287915578420483105749330060197958207739558522807307048950936235550769837881926357141779338750216344391014187576711938914416277109602859415809719913429313295145924373636456473035037374538503489286113141638094752301745088784885645741275003353303416138096560043105860548355773946625033230034341587814634602169235079216111013148948281895391028916816328709309713184139815427678818067628650978085718262117003140003377301581536334149093237034703637513354537634521050370995452942055232078817449370937677056009306353645510913481627378204985657055608784211964039972344556458607689515569686899384896439195225232309703301037277227710870564912966121061494072782442033414057441446459968236966118878411656290355117839944070961772567164919790168195234523807446299877664824873753313018142763910519234685081979001796519907050490865237442841652776611425351538665162781316090964802801234493372427866930894827913465443931965254154829494577875758599482099181824522449312077768250830768282335001597040419199560509705364696473142448453825888112602753909548852639708652339052941829691802357120545328231809270356491743371932080628731303589640570873779967845174740515317401384878082881006046388936711640477755985481263907504747295012609419990373721246201677030517790352952793168766305099837441859803498821239340919805055103821539827677291373138006715339240126954586376422065097810852907639079727841301764553247527073788764069366420012194745702358295481365781809867944020220280822637957006755393575808086318932075864444206644691649334467698180811716568665213389686173592450920801465312529777966137198695916451869432324246404401672381978020728394418264502183131483366019384891972317817154372192103946638473715630226701801343515930442853848941825678870721238520597263859224934763623122188113706307506918260109689069251417142514218153491532129077723748506635489170892850760234351768218355008829647410655814882049239533702270536705630750317499788187009989251020178015601042277836283644323729779929935160925884515772055232896978333126427671291093993103773425910592303277652667641874842441076564447767097790392324958416348527735171981064673837142742974468992320406932506062834468937543016787815320616009057693404906146176607094380110915443261929000745209895959201159412324102274845482605404361871836330268992858623582145643879695210235266673372434423091577183277565800211928270391042391966426911155333594569685782817020325495552528875464466074620294766116004435551604735044292127916358748473501590215522120388281168021413865865168464569964810015633741255098479730138656275460161279246359783661480163871602794405482710196290774543628092612567507181773641749763254436773503632580004042919906963117397787875081560227368824967077635559869284901628768699628053790181848148810833946900016380791075960745504688912686792812391148880036720729730801354431325347713094186717178607522981373539126772812593958220524289991371690685650421575056729991274177149279608831502358697816190894908487717722503860872618384947939757440664912760518878124233683125467278331513186758915668300679210215947336858591201395360301678110413444411030903388761520488296909104689167671555373346622545575975202624771242796225983278405833585897671474205724047439720232895903726148688388003174146490203843590358527993123871042845981608996101945691646983837718267264685264869172948414153004604004299585035164101899027529366867431834955447458124140190754681607770977920579383895378192128847409929537040546962226547278807248685508046571043123854873351653070570784584243335550958221912862797205455466267099131902370311779690892786623112661337671178512943059323281605826535623848164192144732543731002062738466812351691016359252588256806438946389880872735284406462208149513862275239938938734905082625472417781702582044129853760499827899020083498387362992498125742354568439023012261733665820546785671147973065077035475620567428300187473019197310881157516777005071432012726354601912460800451608108641835539669946936947322271670748972850464195392966434725254724357659192969949061670189061433616907056148280980363243454128229968275980226694045642181328624517549652147221620839824594576613342710564957193564431561774500828376935700995419541839029151033187933907614207467028867968594985439789457300768939890070073924697461812855764662265412913204052279071212820653775058280040897163467163709024906774736309136904002615646432159560910851092445162454420141442641660181385990017417408244245378610158433361777292580611159192008414091888191208858207627011483671760749046980914443057262211104583300789331698191603917150622792986282709446275915009683226345073725451366858172483498470080840163868209726371345205439802277866337293290829914010645589761697455978409211409167684020269370229231743334499986901841510888993165125090001163719114994852024821586396216294981753094623047604832399379391002142532996476235163569009445086058091202459904612118623318278614464727795523218635916551883057930657703331498510068357135624341881884405780028844018129031378653794869614630467726914552953690154167025838032477842272417994513653582260971652588356712133519546838335349801503269359798167463231847628306340588324731228951257944267639877946713121042763380872695738609314631539148548792514028885025189788076023838995615684850391995855029256054176767663145354058496296796781349420116003325874431438746248313850214980401681940795687219268462617287403480967931949965604299190281810597603263251746405016454606266765529010639868703668263299050577706266397868453584384057673298268163448646707439990917504018892319267557518354054956017732907127219134577524905771512773358423314008356080926962298894163047287780054743798498545562870729968407382937218623831766524716090967192007237658894226186550487552614557855898773008703234726418384831040394818743616224455286163287628541175946460497027724490799275146445792982549802258601001772437840167723166802004162547244179415547810554178036773553354467030326469619447560812831933095679685582771932031205941616693902049665352189672822671972640029493307384717544753761937017882976382487233361813499414541694736549254840633793674361541081593464960431603544354737728802361047743115330785159902977771499610274627769759612488879448609863349422852847651310277926279743981957617505591300993377368240510902583759345170015340522266144077237050890044496613295859536020556034009492820943862994618834790932894161098856594954213114335608810239423706087108026465913203560121875933791639666437282836752328391688865373751335794859860107569374889645657187292540448508624449947816273842517229343960137212406286783636675845331904743954740664015260871940915743955282773904303868772728262065663129387459875317749973799293043294371763801856280061141619563942414312254397099163565102848315765427037906837175764870230052388197498746636856292655058222887713221781440489538099681072143012394693530931524054081215705402274414521876541901428386744260011889041724570537470755550581632831687247110220353727166112304857340460879272501694701067831178927095527253222125224361673343366384756590949728221809418684074238351567868893421148203905824224324264643630201441787982022116248471657468291146315407563770222740135841109076078464780070182766336227978104546331131294044833570134869585165267459515187680033395522410548181767867772152798270250117195816577603549732923724732067853690257536233971216884390878879262188202305529937132397194333083536231248870386416194361506529551267334207198502259771408638122015980894363561808597010080081622557455039101321981979045520049618583777721048046635533806616517023595097133203631578945644487800945620369784973459902004606886572701865867757842758530645706617127194967371083950603267501532435909029491516973738110897934782297684100117657987098185725131372267749706609250481876835516003714638685918913011736805218743265426063700710595364425062760458252336880552521181566417553430681181548267844169315284408461087588214317641649835663127518728182948655658524206852221830755306118393326934164459415342651778653397980580828158806300749952897558204686612590853678738603318442905510689778698417735603118111677563872589911516803236547002987989628986181014596471307916144369564690909518788574398821730583884980809523077569358851616027719521488998358632323127308909861560777386006984035267826785387215920936255817889813416247486456433211043194821421299793188104636399541496539441501383868748384870224681829391860319598667962363489309283087840712400431022706137591368056518861313458307990705003607588327248867879324093380071864152853317943535073401891193638546730000660453783784472469288830546979000131248952100446949032058838294923613919284305249167833012980192255157050378521810552961623637523647962685751660066539364142273063001648652613891842243501797455993616794063303522111829071597538821839777552812981538570168702202620274678647916644030729018445497956399844836807851997088201407769199261674991148329821854382718946282165387064858588646221611410343570342878862979083418871606214430014533275029715104673156021000043869510583773779766003460887624861640938645252177935289947578496255243925598620521409052346250847830487046492688313289470553891357290706967599556298586669559721686506052072801342104355762779184021797626656484580261591407173477009039475168017709900129391137881248534255949312866653465033728846390649968460644741907524313323903404908195233044389559060547854954620263256676813262435925020249516275607080900436460421497025691488555265022810327762115842282433269528629137662675481993546118143913367579700141255870143319434764035725376914388899683088262844616425575034001428982557620386364384137906519612917777354183694676232982904981261717676191554292570438432239918482261744350470199171258214687683172646078959690569981353264435973965173473319484798758064137926885413552523275720457329477215706850016950046959758389373527538622664943456437071610511521617176237598050900553232154896062817794302268640579555845730600598376482703339859420098582351400179507104569019191359062304102336798080907240196312675268916362136351032648077232914950859151265812143823371072949148088472355286394195993455684156344577951727033374238129903260198160571971183950662758220321837136059718025940870615534713104482272716848395524105913605919812444978458110854511231668173534838253724825347636777581712867205865148285317273569069839935110763432091319780314031658897379628301178409806410175016511072932907832177487566289310650383806093372841399226733384778203302020700517188941706465146238366720632742644336612174011766914919235570905644803016342294301837655263108450172510307540942604409687066288066265900569082451407632599158164499361455172452057020443093722305550217222299706209749268609762787409626448772056043078634808885709143464793241536214303199965695610753570417207285334250171325558818113295504095217830139465216436594262960768570585698507157151317262928960072587601564840556088613165411835958628710665496282599535127193244635791046554389165150954187306071015034430609582302257455974944275067630926322529966338219395202927917973247094559691016402983683080426309910481567503623509654924302589575273521412445149542462972258510120707802110188106722347972579330653187713438466713807546383471635428854957610942841898601794658721444495198801550804042506452191484989920400007310672369944655246020908767882300064337725657385010969899058191290957079866699453765080407917852438222041070599278889267745752084287526377986730360561230710723922581504781379172731261234878334034473833573601973235946604273704635201327182592410906040097638585857716958419563109577748529579836844756803121874818202833941887076311731615289811756429711334181497218078040465077657204457082859417475114926179367379999220181789399433337731146911970737861041963986422166045588965683206701337505745038872111332436739840284188639147633491695114032583475841514170325690161784931455706904169858050217798497637014758914810543205854914100662201721719726878930012101267481270235940855162601689425111458499658315589660460091525797881670384625905383256920520425791378948827579603278877535466861441826827797651258953563761485994485049706638406266121957141911063246061774180577212381659872472432252969098533628440799030007594546281549235506086481557928961969617060715201589825299772803520002610888814176506636216905928021516429198484077446143617891415191517976537848282687018750030264867608433204658525470555882410254654806040437372771834769014720664234434374255514129178503032471263418076525187802925534774001104853996960549926508093910691337614841834884596365621526610332239417467064368340504749943339802285610313083038484571294767389856293937641914407036507544622061186499127249643799875806537850203753189972618014404667793050140301580709266213229273649718653952866567538572115133606114457222800851183757899219543063413692302293139751143702404830227357629039911794499248480915071002444078482866598579406525539141041497342780203520135419925977628178182825372022920108186449448349255421793982723279357095828748597126780783134286180750497175747373730296280477376908932558914598141724852658299510882230055223242218586191394795184220131553319634363922684259164168669438122537135960710031743651959027712571604588486044820674410935215327906816032054215967959066411120187618531256710150212239401285668608469435937408158536481912528004920724042172170913983123118054043277015835629513656274610248827706488865037765175678806872498861657094846665770674577000207144332525555736557083150320019082992096545498737419756608619533492312940263904930982014700371161829485939931199955070455381196711289367735249958182011774799788636393286405807810818657337668157893827656450642917396685579555053188715314552353070355994740186225988149854660737787698781542360397080977412361518245964026869979609564523828584235953564615185448165799966460648261396618720304839119560250381111550938420209894591555760083897989949964566262540514195610780090298667014635238532066032574466820259430618801773091109212741138269148784355679352572808875543164693077235363768226036080174040660997151176880434927489197133087822951123746632635635328517394189466510943745768270782209928468034684157443127739811044186762032954475468077511126663685479944460934809992951875666499902261686019672053749149951226823637895865245462813439289338365156536992413109638102559114643923805213907862893561660998836479175633176725856523591069520326895990054884753424160586689820067483163174286329119633399132709086065074595260357157323069712106423424081597068328707624437165532750228797802598690981111226558888151520837482450034463046505984569690276166958278982913613535306291331427881888249342136442417833519319786543940201465328083410341785272489879050919932369270996567133507711905899945951923990615156165480300145359212550696405345263823452155999210578191371030188979206408883974767667144727314254467923500524618849237455307575734902707342496298879996942094595961008702501329453325358045689285707241207965919809225550560061971283541270202072583994171175520920820151096509526685113897577150810849443508285458749912943857563115668324566827992991861539009255871716840495663991959154034218364537212023678608655364745175654879318925644085274489190918193411667583563439758886046349413111875241038425467937999203546910411935443113219136068129657568583611774564654674861061988591414805799318725367531243470335482637527081353105570818049642498584646147973467599315946514787025065271083508782350656532331797738656666181652390017664988485456054961300215776115255813396184027067814900350252876823607822107397102339146870159735868589015297010347780503292154014359595298683404657471756232196640515401477953167461726208727304820634652469109953327375561090578378455945469160223687689641425960164689647106348074109928546482353083540132332924864037318003195202317476206537726163717445360549726690601711176761047774971666890152163838974311714180622222345718567941507299526201086205084783127474791909996889937275229053674785020500038630036526218800670926674104806027341997756660029427941090400064654281074454007616429525362460261476180471744322889953285828397762184600967669267581270302806519535452053173536808954589902180783145775891280203970053633193821100095443241244197949192916205234421346395653840781209416214835001155883618421164283992454027590719621537570187067083731012246141362048926555668109467076386536083015847614512581588569610030337081197058344452874666198891534664244887911940711423940115986970795745946337170243268484864632018986352827092313047089215684758207753034387689978702323438584381125011714013265769320554911860153519551654627941175593967947958810333935413289702528893533748106257875620364294270257512121137330213811951395756419122685155962476203282038726342066227347868223036522019655729325905068134849292299647248229359787842720945578267329975853818536442370617353517653060396801087899490506654491544577952166038552398013798104340564182403396162494910454712104839439200945914647542424785991096900046541371091630096785951563947332190934511838669964622788855817353221326876634958059123761251203010983867841195725887799206041260049865895027247133146763722204388398558347770112599424691208308595666787531942465131444389971195968105937957532155524204659410081418351120174196853432672343271868099625045432475688702055341969199545300952644398446384346598830418262932239295612610045884644244285011551557765935780379565026806130721758672048541797157896401554276881090475899564605488362989140226580026134158039480357971019004151547655018391755772677897148793477372747525743898158705040701968215101218826088040084551332795162841280679678965570163917067779841529149397403158167896865448841319046368332179115059107813898261026271979696826411179918656038993895418928488851750122504754778999508544083983800725431468842988412616042682248823097788556495765424017114510393927980290997604904428832198976751320535115230545666467143795931915272680278210241540629795828828466355623580986725638200565215519951793551069127710538552661926903526081367717666435071213453983711357500975854405939558661737828297120544693182260401670308530911657973113259516101749193468250063285777004686987177255226525708428745733039859744230639751837209975339055095883623642814493247460522424051972825153787541962759327436278819283740253185668545040893929401040561666867664402868211607294830305236465560955351079987185041352121321534713770667681396211443891632403235741573773787908838267618458756361026435182951815392455211729022985278518025598478407179607904114472041476091765804302984501746867981277584971731733287305281134969591668387877072315968334322509070204019030503595891994666652037530271923764252552910347950343816357721698115464329245608951158732012675424975710520894362639501382962152214033621065422821876739580121286442788547491928976959315766891987305176388698461503354594898541849550251690616888419122873385522699976822609645007504500096116866129171093180282355042553653997166054753907348915189650027442328981181709248273610863801576007240601649547082331349361582435128299050405405333992577071321011503713898695076713447940748097845416328110406350804863393555238405735580863718763530261867971725608155328716436111474875107033512913923595452951407437943144900950809932872153235195999616750297532475931909938012968640379783553559071355708369947311923538531051736669154087312467233440702525006918026747725078958903448856673081487299464807786497709361969389290891718228134002845552513917355978456150353144603409441211512001738697261466786933733154341007587514908295822756919350542184106448264951943804240543255345965248373785310657979037977505031436474651422484768831323479762673689855474944277949916560108528257618964374464656819789319422077536824661110427671936481836360534108748971066866318805026555929568123959680449295166615409802610781691689418764353363449482900125929366840591370059526914934421861891742142561071896846626335874414976973921566392767687720145153302241853125308442727245771161505550519076276250016522166274796257424425420546785767478190959486500575711016264847833741198041625940813327229905891486422127968042984725356237202887830051788539737909455265135144073130049869453403245984236934627060242579432563660640597549471239092372458126154582526667304702319359866523378856244229188278436440434628094888288712101968642736370461639297485616780079779959696843367730352483047478240669928277140069031660709951473154191919911453182543906294573298686613524886500574780251977607442660798300291573030523199052185718628543687577860915726925232573171665625274275808460620177046433101212443409281314659760221360416223031167750085960128475289259463348312408766740128170543067985261868949895004918275008304998926472034986965363326210919830621495095877228260815566702155693484634079776879525038204442326697479264829899016938511552124688935873289878336267819361764023681714606495185508780596635354698788205094762016350757090024201498400967867845405354130050482404996646978558002628931826518708714613909521454987992300431779500489569529280112698632533646737179519363094399609176354568799002814515169743717518330632232942199132137614506411391269837128970829395360832883050256072727563548374205497856659895469089938558918441085605111510354367477810778500572718180809661542709143010161515013086522842238721618109043183163796046431523184434669799904865336375319295967726080853457652274714047941973192220960296582500937408249714373040087376988068797038047223488825819819025644086847749767508999164153502160223967816357097637814023962825054332801828798160046910336602415904504637333597488119998663995617171089911809851197616486499233594328274275983382931099806461605360243604040848379619072542165869409486682092396143083817303621520642297839982533698027039931804024928814430649614747600087654305571672697259114631990688823893005380061568007730984416061355843701277573463708822073792921409548717956947854414951731561828176343929570234710460088230637509877521391223419548471196982303169544468045517922669260631327498272520906329003279972932906827204647650366969765227673645419031639887433042226322021325368176044169612053532174352764937901877252263626883107879345194133825996368795020985033021472307603375442346871647223795507794130304865403488955400210765171630884759704098331306109510294140865574071074640401937347718815339902047036749084359309086354777210564861918603858715882024476138160390378532660185842568914109194464566162667753712365992832481865739251429498555141512136758288423285957759412684479036912662015308418041737698963759002546999454131659341985624780714434977201991702665380714107259910648709897259362243300706760476097690456341576573395549588448948093604077155688747288451838106069038026528318275560395905381507241627615047252487759578650784894547389096573312763852962664517004459626327934637721151028545472312880039058405918498833810711366073657536918428084655898982349219315205257478363855266205400703561310260405145079325925798227406012199249391735122145336707913500607486561657301854049217477162051678486507913573336334257685988361252720250944019430674728667983441293018131344299088234006652915385763779110955708000600143579956351811596764725075668367726052352939773016348235753572874236648294604770429166438403558846422370760111774821079625901180265548868995181239470625954254584491340203400196442965370643088660925268811549596291166168612036195319253262662271108142149856132646467211954801142455133946382385908540917878668826947602781853283155445565265933912487885639504644196022475186011405239187543742526581685003052301877096152411653980646785444273124462179491306502631062903402737260479940181929954454297256377507172705659271779285537195547433852182309492703218343678206382655341157162788603990157495208065443409462446634653253581574814022471260618973060860559065082163068709634119751925774318683671722139063093061019303182326666420628155129647685313861018672921889347039342072245556791239578260248978371473556820782675452142687314252252601795889759116238720807580527221031327444754083319215135934526961397220564699247718289310588394769170851420631557192703636345039529604362885088555160008371973526383838996789184600327073682083234847108471706160879195227388252347506380811606090840124222431476103563328940609282430125462013806032608121942876847907192546246309055749298781661271916548229644317263587524548607563020667656942355342774617635549231817456159185668061686428714964129290560130053913469569829490891003991259088290348791943368696942620662946948514931472688923571615032405542263391673583102728579723061998175868700492227418629077079508809336215346303842967525604369606110193842723883107587771653594778681499030978765900869583480043137176832954871752604714113064847270887246697164585218774442100900090916189819413456305028950484575822161887397443918833085509908566008543102796375247476265353031558684515120283396640547496946343986288291957510384781539068343717740714095628337554413567955424664601335663617305811711646062717854078898495334329100315985673932305693426085376230981047171826940937686754301837015557540822371538037838383342702379535934403549452173960327095407712107332936507766465603712364707109272580867897181182493799540477008369348889220963814281561595610931815183701135104790176383595168144627670903450457460997444500166918675661035889313483800512736411157304599205955471122443903196476642761038164285918037488354360663299436899730090925177601162043761411616688128178292382311221745850238080733727204908880095181889576314103157447684338100457385008523652069340710078955916549813037292944462306371284357984809871964143085146878525033128989319500645722582281175483887671061073178169281242483613796475692482076321356427357261609825142445262515952514875273805633150964052552659776922077806644338105562443538136258941809788015677378951310313157361136026047890761945591820289365770116416881703644242694283057457471567494391573593353763114830246668754727566653059819746822346578699972291792416156043557665183382167059157867799311835820189855730344883681934418305987021880502259192818047775223884407167894780414701414651073580452021499197980812095692195622632313741870979731320870864552236740416185590793816745658234353037283309503729022429802768451559528656923189798000383061378732434546500582722712325031420712488100290697226311129067629080951145758060270806092801504406139446350643069742785469477459876821004441453438033759717384777232052065301037861326418823586036569054773343070911759152582503029410738914441818378779490613137536794654893375260322906277631983337976816641721083140551864133302224787118511817036598365960493964571491686005656771360533192423185262166760222073368844844409234470948568027905894191829969467724456269443308241243846160408284006424867072583661011433404214473683453638496544701067827313169538435919120440283949541956874453676459875488726170687163109591315801609722382049772577307454562979127906177531663252857205858766376754282917933549923678212008601904369428956102301731743150352204665675088491593025926618816581008701658499456495586855628208747248318351516339189292646558880593601275151838235485893426165223086697314511412035659916934103076974774451947043836739600076578628245472064617380804602903639144493859012422380173377038154675297645596518492676039300171943042511794045679862114630138402371099347243455794730048929825402680821621522346560274258486595687074510352794291633405915025075992398611224340312056999780516223878772230396359709132856830486160362127579561601328561866388146004722200580017580282279272167842720649966956840905752590774886105493806116954293569077377792821084159737469613143291808510446953973485067590503662391722108732333169909603363771705474725026941732982890400239372879549386540463828596742216318201530139629734398479588628632934746650690284066719018081265539973675916799759010867483920062877888531102781695087545740384607594616919584610655963327283485609570305572502494416337066573150237126843581984154103154401008430380631442183776750349813408169325201240813452285974626715177152223063741359255747513535160669108359443999692315898156732033027129284241219651936303734407981204656795322986357374589031654007016472204989445629050395873788912680565516464274460174738175296313458739390484560414203426465560422112239134631023161290836446988901247285192778589195228773637440432659264672239982186452797664826673070168802722052338600372842903155828454593854349099449420750911108532138744823216151007808922516285123275724355101999038195993350032641446053470357293073912578481757987468353429629749652545426864234949270336399427519354240001973125098882419600095766257217621860474573769577649582201796258392376391717855799468922496750179251915218219624653575570564228220399546682648329822996167217080156801080799777126517156274295763666959661983507435667132218383358509536665806605597148376773866922551603463644386269977295750658468929599809168949981898588529537874489519527097766262684177088590284321676352132630838812766335363319004134332844347630067982023716933653652880580156390360562722752187272454764258840995216482554453662083811789117725225682611478014242896970967121967502094421226279437073328703410646312100557376727450271638975234111426287828736758358819056742163061523416789476056879277154789714326222041069587947186435439940738639948986836168919377836648327137363654676901173760246643082285362494712605173293777247276797635865806019396287718060679122426813922872134061694882029506831654589707623668302556167559477498715183426989208952182644710514911419441192277010977616645850068963849426165593473112961064282379048216056210094265076173838082479030510998790719611852832556787472942907151041468948104916751035295897242381802288151276582257190705537652455285511598636421244284176256230139538669970308943645907600684938040875210854159851278070333207779865635907968462191534944587677170063778573171211036517486371634098385626541555573292664616402279791195975248525300376741774056125700303625811704838385391207273191845064713669122576415213769896260940351804147432053600369234179035440735703058314741623452840188940808983125191307741823338981880316339159565954543405777784331681162551898060409183018907512170192983622897099598983405484962284289398469847938668614293324543983592637036699355184231661615244505980576745765335552338715678211466689996845227042954589710922163652573965950289645637766038988037941517917867910675199009966139206238732318786758420544279396366759104126821843375015743069045967947046685602358283919759975285865384338189120042853787549302768972168199113340697282255535300044743958830079799736518459131437946494086272149669719100359399974735262764126125995350902609540048669398955899487421379590802893196914845826873123710180229775301190684280440780938156598081694611679374425663244656799606363751546304833112722231812338371779800439731087402647536582575657351059978314264831879619843765495877803685261751835391844920488198629786329743136948511780579298636452193232481339393090754566368038513630619718033957979522539508697432546502659123585049283028832934489284591373621624852528877442891851104093746333590660233239711922814450735588373324057814862662207486215513375036775585494138678352928273109003823116855374520901095101174796663003330352534143230024288248051396631446632656081582045216883922312025671065388459503224002320453633895521539919011035217362720909565500846486605368975498478995875596103167696587161281951919668893326641203784750417081752273735270989343717167642329956935697166213782736138899530515711822960896394055380431939398453970864418654291655853168697537052760701061488025700785387150835779480952313152747735711713643356413242974208137266896149109564214803567792270566625834289773407718710649866150447478726164249976671481383053947984958938064202886667951943482750168192023591633247099185942520392818083953020434979919361853380201407072481627304313418985942503858404365993281651941497377286729589582881907490040331593436076189609669494800067194371424058105327517721952474344983414191979918179909864631583246021516575531754156198940698289315745851842783390581029411600498699307751428513021286202539508732388779357409781288187000829944831476678183644656510024467827445695591845768068704978044824105799710771577579093525803824227377612436908709875189149049904225568041463131309240101049368241449253427992201346380538342369643767428862595140146178201810734100565466708236854312816339049676558789901487477972479202502227218169405159042170892104287552188658308608452708423928652597536146290037780167001654671681605343292907573031466562485809639550080023347676187068086526878722783177420214068980703410506200235273632267291964034093571225623659496432076928058165514428643204955256838543079254299909353199329432966018220787933122323225928276556048763399988478426451731890365879756498207607478270258861409976050788036706732268192473513646356758611212953074644777149423343867876705824452296605797007134458987594126654609414211447540007211790607458330686866231309155780005966522736183536340439991445294960728379007338249976020630448806064574892740547730693971337007962746135534442514745423654662752252624869916077111131569725392943756732215758704952417232428206555322808868670153681482911738542735797154157943689491063759749151524510096986573825654899585216747260540468342338610760823605782941948009334370046866568258579827323875158302566720152604684361412652956519894291184887986819088277339147282063794512260294515707367105637720023427811802621502691790400488001808901847311751199425460594416773315777951735444490965752131026306836047140331442314298077895617051256930051804287472368435536402764392777908638966566390166776625678575354239947427919442544664643315554138265543388487778859972063679660692327601733858843763144148113561693030468420017434061395220072403658812798249143261731617813894970955038369479594617979829257740992171922783223006387384996138434398468502234780438733784470928703890536420557474836284616809363650973790900204118525835525201575239280826462555785658190226958376345342663420946214426672453987171047721482128157607275305173330963455909323664528978019175132987747952929099598069790148515839540444283988381797511245355548426126784217797728268989735007954505834273726937288386902125284843370917479603207479554080911491866208687184899550445210616155437083299502854903659617362726552868081324793106686855857401668022408227992433394360936223390321499357262507480617409173636062365464458476384647869520547719533384203403990244761056010612777546471464177412625548519830144627405538601855708359981544891286863480720710061787059669365218674805943569985859699554089329219507269337550235821561424994538234781138316591662683103065194730233419384164076823699357668723462219641322516076261161976034708844046473083172682611277723613381938490606534404043904909864126903479263503943531836741051762565704797064478004684323069430241749029731181951132935746854550484711078742905499870600373983113761544808189067620753424526993443755719446665453524088287267537759197074526286322840219629557247932987132852479994638938924943286917770190128914220188747760484939855471168524810559991574441551507431214406120333762869533792439547155394213121021954430556748370425907553004950664994802614794524739012802842646689229455664958621308118913500279654910344806150170407268010067948926855360944990373928383520627992820181576427054962997401900837493444950600754365525758905546552402103412862124809003162941975876195941956592556732874237856112669741771367104424821916671499611728903944393665340294226514575682907490402153401026923964977275904729573320027982816062130523130658731513076913832317193626664465502290735017347656293033318520949298475227462534564256702254695786484819977513326393221579478212493307051107367474918016345667888810782101151826314878755138027101379868751299375133303843885631415175908928986956197561123025310875057188962535763225834275763348421016668109884514141469311719314272028007223449941999003964948245457520704922091620614222912795322688239046498239081592961111003756999529251250673688233852648213896986384052437049402152187547825163347082430303521036927849762517317825860862215614519165573478940019558704784741658847364803865995119651409542615026615147651220820245816010801218275982577477652393859159165067449846149161165153821266726927461290533753163055654440793427876550267301214578324885948736899073512166118397877342715872870912311383472485146035661382188014840560716074652441118841800734067898587159273982452147328317214621907330492060817440914125388918087968538960627860118193099489240811702350413554126823863744341209267781729790694714759018264824761112414556423937732224538665992861551475342773370683344173073150805440138894084087253197595538897613986400165639906934600670780501058567196636796167140097031535132386972899001749862948883362389858632127176571330142071330179992326381982094042993377790345261665892577931395405145369730429462079488033141099249907113241694504241391265397274078984953073730364134893688060340009640631540701820289244667315059736321311926231179142794944897281477264038321021720718017561601025111179022163703476297572233435788863537030535008357679180120653016668316780269873860755423748298548246360981608957670421903145684942967286646362305101773132268579232832164818921732941553151386988781837232271364011755881332524294135348699384658137175857614330952147617551708342432434174779579226338663454959438736807839569911987059388085500837507984051126658973018149321061950769007587519836861526164087252594820126991923916722273718430385263107266000047367872474915828601694439920041571102706081507270147619679971490141639274282889578424398001497985658130305740620028554097382687819891158955487586486645709231721825870342960508203415938806006561845735081804032347750084214100574577342802985404049555529215986404933246481040773076611691605586804857302606467764258503301836174306413323887707999698641372275526317649662882467901094531117120243890323410259937511584651917675138077575448307953064925086002835629697045016137935696266759775923436166369375035368699454550392874449940328328128905560530091416446608691247256021455381248285307613556149618444364923014290938289373215312818797541139219415606631622784836152140668972661027123715779503062132916001988806369127647416567067485490795342762338253943990022498972883660263920518704790601584084302914787302246651371144395418253441269003331181914268070735159284180415100555199146564934872796969351992963117195821262627236458009708099166752820365818699111948365866102758375863322993225541477479210421324166848264953111826527351008031659958888814809945737293785681411438021523876706455063233067233939551964260397443829874822322662036352861302543796600943104500158604854027036789711934695579989189112302233381602302236277726084846296189550730850698061500281436425336666311433321645213882557346329366870956708432252564333895997812402164189946978348320376011613913855499933990786652305860332060641949298931012423081105800169745975038516887112037747631577311831360002742502722451570906304496369230938382329175076469684003556425503797106891999812319602533733677437970687713814747552190142928586781724044248049323750330957002929126630316970587409214456472022710796484778657310660832173093768033821742156446602190335203981531618935787083561603302255162155107179460621892674335641960083663483835896703409115513087820138723494714321400450513941428998350576038799343355677628023346565854351219361896876831439866735726040869511136649881229957801618882834124004126142251475184552502502640896823664946401177803776799157180146386554733265278569418005501363433953502870836220605121839418516239153709790768084909674194289061134979961034672077354959593868862427986411437928435620575955500144308051267664432183688321434583708549082240014585748228606859593502657405750939203135881722442164955416889785558265198046245527898343289578416968890756237467281044803018524217706136533236073856228166664597654076844715963930782091017090763377917711485205493367936868430832404126789220929930411890501756484917499452393770674524578019171841679541825554377930299249277892416277257788147974770446005423669346157135208417428211847353652367573702352791459837645712257646122605628127852169580892808988394594406165340521932514843306105322700231133680378433377389724881307874325614952744243584753011150345103737688223837573804282007358586938044331529253129961025096113761670187568525921208929131354473196308440066835155160913925692912175784379179004808848023029304392630921342768601226558630456913133560978156776098711809238440656353136182676923761613389237802972720736243967239854144480757286813436768000573823963610796223140429490728058551444771338682314499547929338131259971996894072233847404542592316639781608209399269744676323921370773991899853301483814622364299493902073285072098040905300059160091641710175605409814301906444379905831277826625762288108104414704097708248077905168225857235732665234414956169007985520848841886027352780861218049418060017941147110410688703738674378147161236141950474056521041002268987858525470689031657094677131822113205505046579701869337769278257145248837213394613987859786320048011792814546859096532616616068403160077901584946840224344163938313618742275417712170336151163782359059685168880561304838542087505126933144171705880517278127917564053282929427357971823360842784676292324980318169828654166132873909074116734612367109059236155113860447246378721244612580406931724769152219217409096880209008801535633471775664392125733993165330324425899852598966724744126503608416484160724482125980550754851232313331300621490042708542735985913041306918279258584509440150719217604794274047740253314305451367710311947544521321732225875550489799267468541529538871443696399406391099267018219539890685186755868574434469213792094590683677929528246795437302263472495359466300235998990248299853826140395410812427393530207575128774273992824866921285637240069184859771126480352376025469714309316636539718514623865421671429236191647402172547787238964043145364190541101514371773797752463632741619269990461595895793940622986041489302535678633503526382069821487003578061101552210224486633247184367035502326672749787730470216165019711937442505629639916559369593557640005236360445141148916155147776301876302136068825296274460238077523189646894043033182148655637014692476427395401909403584437251915352134557610698046469739424511797999048754951422010043090235713636892619493763602673645872492900162675597083797995647487354531686531900176427222751039446099641439322672532108666047912598938351926694497553568096931962642014042788365702610390456105151611792018698900673027082384103280213487456720062839744828713298223957579105420819286308176631987048287388639069922461848323992902685392499812367091421613488781501234093387999776097433615750910992585468475923085725368613605356762146929424264323906626708602846163376051573599050869800314239735368928435294958099434465414316189806451480849292695749412903363373410480943579407321266012450796613789442208485840536446021616517885568969302685188950832476793300404851688934411125834396590422211152736276278672366665845757559585409486248261694480201791748223085835007862255216359325125768382924978090431102048708975715033330963651576804501966025215527080352103848176167004443740572131294252820989545456276344353575741673638980108310579931697917916718271145837435222026387771805250290791645414791173616253155840768495583288190293564201219633684854080865928095131505012602919562576032932512847250469881908146475324342363863860247943921015193235101390117789997483527186469346024554247028375300033725403910085997650987642832802908445662021678362267272292737780213652404028817217012490974899454430826861772239385250883760749742195942655217301733355851389407457348144161511380845358039740277795072051893487170722955427683655826706766313911972211811528466502223383490906676554168336907959409404576472940901354356409277969379842065738891481990225399022315913388145851487225126560927576795873759207013915029216513720851137197522734365458411622066281660256333632074449918511469174455062297146086578736313585389023662557285424516018080487167823688885575325066254262367702604215835160174851981885460860036597606743233346410471991027562358645341748631726556391320606407754779439671383653877377610828300019937359760370467245737880967939894493795829602910746901609451288456550071458091887879542641820145369659962842686882363495879277007025298960996798975941955735253914237782443302746708282008722602053415292735847582937522487377937899136764642153727843553986244015856488692101644781661602962113570056638347990334049623875941092886778920270077504951511405782565295015024484968204744379710872943108541684540513016310902267112951959140520827546866418137305837933236150599142045255880213558474751516267815309465541240524091663857551298894834797423322854504140527354235070335984964593699534959698554244978249586929179182415068053002553370412778703476446244329205906832901886692400222391918714603175399666877477960121790688623311002908668305431787009355066944389131913333586368037447530664502418437136030852288582121720231274167009740351431532131803978033680228154223490183737494117973254478594157962104378787072154814091725163615415163381388912588517924237727229603497305533840942889918919161186249580560073570527227874940321250645426206304469470804277945973817146810395192821550688079136701210109944220737024613687196031491162370967939354636396448139025711768057799751751298979667073292674886430097398814873780767363792886767781170520534367705731566895899181530825761606591843760505051704242093231358724816618683821026679970982966436224723644898648976857100173643547336955619347638598187756855912376232580849341570570863450733443976604780386678461711520325115528237161469200634713570383377229877321365028868868859434051205798386937002783312365427450532283462669786446920780944052138528653384627970748017872477988461146015077617116261800781557915472305214759943058006652042710117125674185860274188801377931279938153727692612114066810156521441903567333926116697140453812010040811760123270513163743154487571768761575554916236601762880220601068655524141619314312671535587154866747899398685510873576261006923021359580838145290642217792987748784161516349497309700794368305080955621264592795333690631936594413261117944256602433064619312002953123619348034504503004315096798588111896950537335671086336886944665564112662287921812114121425167348136472449021275252555647623248505638391391630760976364990288930588053406631352470996993362568102360392264043588787550723319888417590521211390376609272658409023873553418516426444865247805763826160023858280693148922231457758783791564902227590699346481624734399733206013058796068136378152964615963260698744961105368384203105364183675373594176373955988088591188920114871545460924735613515979992999722298041707112256996310945945097765566409972722824015293663094891067963296735505830412258608050740410916678539569261234499102819759563955711753011823480304181029089719655278245770283085321733741593938595853203645590564229716679900322284081259569032886928291260139267587858284765599075828016611120063145411315144108875767081854894287737618991537664505164279985451077400771946398046265077776614053524831090497899859510873112620613018757108643735744708366215377470972660188656210681516328000908086198554303597948479869789466434027029290899143432223920333487108261968698934611177160561910681226015874410833093070377506876977485840324132474643763087889666151972556180371472590029550718424245405129246729039791532535999005557334600111693557020225722442772950263840538309433999383388018839553821540371447394465152512354603526742382254148328248990134023054550811390236768038649723899924257800315803725555410178461863478690646045865826036072306952576113184134225274786464852363324759102670562466350802553058142201552282050989197818420425028259521880098846231828512448393059455162005455907776121981297954040150653985341579053629101777939776957892084510979265382905626736402636703151957650493344879513766262192237185642999150828898080904189181015450813145034385734032579549707819385285699926238835221520814478940626889936085239827537174490903769904145555260249190126341431327373827075950390882531223536876389814182564965563294518709637484074360669912550026080424160562533591856230955376566866124027875883101021495284600804805028045254063691285010599912421270508133194975917146762267305044225075915290251742774636494555052325186322411388406191257012917881384181566918237215400893603475101448554254698937834239606460813666829750019379115061709452680984785152862123171377897417492087541064556959508967969794980679770961683057941674310519254486327358885118436597143583348756027405400165571178309126113117314169066606067613797690123141099672013123730329707678988740099317309687380126740538923612230370779727025191340850390101739924877352408881040807749924412635346413181858792480760553268122881584307471326768283097203149049868884456187976015468233715478415429742230166504759393312132256510189175368566338139736836336126010908419590215582111816677413843969205870515074254852744810154541079359513596653630049188769523677579147319184225806802539818418929888943038224766186405856591859943091324575886587044653095332668532261321209825839180538360814144791320319699276037194760191286674308615217243049852806380129834255379486287824758850820609389214668693729881191560115633701248675404205911464930888219050248857645752083363921499441937170268576222251074166230901665867067714568862793343153513505688216165112807318529333124070912343832502302341169501745502360505475824093175657701604884577017762183184615567978427541088499501610912720817913532406784267161792013428902861583277304794830971705537485109380418091491750245433432217445924133037928381694330975012918544596923388733288616144238100112755828623259628572648121538348900698511503485369544461542161283241700533583180520082915722904696365553178152398468725451306350506984981006205514844020769539324155096762680887603572463913955278222246439122592651921288446961107463586148252820017348957533954255019475442643148903233373926763409115527189768429887783617346613535388507656327107814312435018965109238453660236940276060642119384227665755210663671879603217527184404651560427289869560206997012906367847161654793068868305846508082886614111979138822898112498261434559408961813509226857611474609406147937240008842153535862052780125014270055274468359151840373309373580494342483940467505708347927948338133276237937844629209323999417593374917899786484958148818865149169302451512835579818112344900827168644548306546633975256079615935830821400021951611342337058359111545217293721664061708131602078213341260356852013161345136871600980378712556766143923146458085652084039744217352744813741215277475202259244561520365608268890193913957991844109971588312780020898275935898106482117936157951837937026741451400902833064466209280549839169261068975151083963132117128513257434964510681479694782619701483204392206140109523453209269311762298139422044308117317394338867965739135764377642819353621467837436136161591167926578700137748127848510041447845416464568496606699139509524527949914769441031612575776863713634644477006787131066832417871556281779122339077841275184193161188155887229676749605752053192594847679397486414128879475647133049543555044790277128690095643357913405127375570391806822344718167939329121448449553897728696601037841520390662890781218240141299368590465146519209198605347788576842696538459445700169758422531241268031418456268722581132040056433413524302102739213788415250475704533878002467378571470021087314693254557923134757243640544448132093266582986850659125571745568328831440322798049274104403921761438405750750288608423536966715191668510428001748971774811216784160854454400190449242294333666338347684438072624307319019363571067447363413698467328522605570126450123348367412135721830146848071241856625742852208909104583727386227300781566668914250733456373259567253354316171586533339843321723688126003809020585719930855573100508771533737446465211874481748868710652311198691114058503492239156755462142467550498676710264926176510110766876596258810039163948397811986615585196216487695936398904500383258041054420595482859955239065758108017936807080830518996468540836412752905182813744878769639548306385089756146421874889271294890398025623046812175145502330254086076115859321603465240763923593699949180470780496764486889980902123735780457040380820770357387588525976042434608851075199334470112741787878845674656640471901619633546770714090590826954225196409446319547658653032104723804625249971910690110456227579220926904132753699634145768795242244563973018311291451151322757841320376225862458224784696669785947914981610522628786944136373683125108310682898766123782697506343047263278453719024447970975017396831214493357290791648779915089163278018852504558488782722376705263811803792477835540018117452957747339714012352011459901984753358434861297092928529424139865507522507808919352104173963493428604871342370429572757862549365917805401652536330410692033704691093097588782938291296447890613200063096560747882082122140978472301680600835812336957051454650181292694364578357815608503303392466039553797630836137289498678842851139853615593352782103740733076818433040893624460576706096188294529171362940967592507631348636606011346115980434147450705511490716640635688739020690279453438236930531133440901381392849163507484449076828386687476663619303412376248380175840467851210698290605196112357188811150723607303158506622574566366740720668999061320627793994112805759798332878792144188725498543014546662945079670707688135022230580562225942983096887732856788971494623888272184647618153045844390967248232348259587963698908456664795754200195991919240707615823002328977439748112690476546256873684352229063217889227643289360535947903046811114130586348244566489159211382258867880972564351646404364328416076247766114349880319792230537889671148058968061594279189647401954989466232962162567264739015818692956765601444248501821713300527995551312539849919933907083138030214072556753022600033565715934283182650908979350869698950542635843046765145668997627989606295925119763672907762567862769469947280606094290314917493590511523235698715397127866718077578671910380368991445381484562682604003456798248689847811138328054940490519768008320299631757043011485087384048591850157264392187414592464617404735275250506783992273121600117160338604710710015235631159734711153198198710616109850375758965576728904060387168114313084172893710817412764581206119054145955378853200366615264923610030157044627231777788649806700723598889528747481372190175074700005571108178930354895017924552067329003818814068686247959272205591627902292600592107710510448103392878991286820705448979977319695574374529708195463942431669050083984398993036790655541596099324867822475424361758944371791403787168166189093900243862038610001362193667280872414291108080291896093127526202667881902085595708111853836166128848729527875143202956393295910508349687029060692838441522579419764824996318479414814660898281725690484184326061946254276693688953540732363428302189694947766126078346328490315128061501009539164530614554234923393806214007779256337619373052025699319099789404390847443596972052065999017828537676265683558625452697455260991024576619614037537859594506363227095122489241931813728141668427013096050734578659047904243852086508154491350136491698639048125666610843702294730266721499164849610746803261583352580352858275799038584091667618877199539888680431991650866887781701439663176815592262016991396613153738021294160006906947533431677802632207226265881842757216055461439677336258462997385077307751473833315101468395296411397329672457933540390136107395245686243008096720460995545708974893048753897955544443791303790422346037768729236001386569593952300768091377768847789746299699489949016141866131552200856673695770822720338936659590666350594330040363762591189195691561626122704788696510356062748423100605472091437069471661080277379848576543481249822444235828329813543645124092220896643987201997945619030397327254617823136363375927622656301565813545578319730419339269008282952718252138855126583037630477490625995514925943105307478901043009876580816508144862607975129633326675259272351611791836777128931053144471668835182920514343609292493191180249366051791485330421043899773019267686085347768149502299280938065840007311767895491286098112311307002535600347898600653805084532572431553654422067661352337408211307834360326940015926958459588297845649462271300855594293344520727007718206398887404742186697709349647758173683580193168322111365547392288184271373843690526638607662451284299368435082612881367358536293873792369928837047900484722240370919885912556341130849457067599032002751632513926694249485692320904596897775676762684224768120033279577059394613185252356456291805905295974791266162882381429824622654141067246487216174351317397697122228010100668178786776119825961537643641828573481088089988571570279722274734750248439022607880448075724807701621064670166965100202654371260046641935546165838945950143502160890185703558173661823437491622669077311800121188299737319891006060966841193266075165452741829459541189277264192546108246351931647783837078295218389645376236304858042774417907169146356546201215125418664885396161542055152375000426794253417764590821513675258479774465114750438460596325820468809667795709044645884673847481638045635188183210386594798204376334738389017759714236223057776395541011294523488098341476645559342209402059733452337956309441446698222457026367119493286653989491344225517746402732596722993581333110831711807234044326813737231209669052411856734897392234152750707954137453460386506786693396236535556479102508529284294227710593056660625152290924148057080971159783458351173168204129645967070633303569271821496292272073250126955216172649821895790908865085382490848904421755530946832055636316431893917626269931034289485184392539670922412565933079102365485294162132200251193795272480340133135247014182195618419055761030190199521647459734401211601239235679307823190770288415814605647291481745105388060109787505925537152356112290181284710137917215124667428500061818271276125025241876177485994084521492727902567005925854431027704636911098800554312457229683836980470864041706010966962231877065395275783874454229129966623016408054769705821417128636329650130416501278156397799631957412627634011130135082721772287129164002237230234809031485343677016544959380750634285293053131127965945266651960426350406454862543383772209428482543536823186182982713182489884498260285705690699045790998144649193654563259496570044689011049923939218088155626191834404362264965506449848521612498442375928443642612004256628602157801140467879662339228190804577624109076487087406157070486658398144845855803277997327929143195789110373530019873110486895656281917362036703039179710646309906285483702836118486672219457621775034511770110458001291255925462680537427727378863726783016568351092332280649908459179620305691566806180826586923920561895421631986004793961133953226395999749526798801074576466538377400437463695133685671362553184054638475191646737948743270916620098057717103475575333102702706317395612448413745782734376330101853438497450236265733191742446567787499665000938706441886733491099877926005340862442833450486907338279348425305698737469497333364267191968992849534561045719338665222471536681145666596959735075972188416698767321649331898967182978657974612216573922404856900225324160367805329990925438960169901664189038843548375648056012628830409421321300206164540821986138099462721214327234457806819925823202851398237118926541234460723597174777907172041523181575194793527456442984630888846385381068621715274531612303165705848974316209831401326306699896632888532682145204083110738032052784669279984003137878996525635126885368435559620598057278951754498694219326972133205286374577983487319388899574634252048213337552584571056619586932031563299451502519194559691231437579991138301656117185508816658756751184338145761060365142858427872190232598107834593970738225147111878311540875777560020664124562293239116606733386480367086953749244898068000217666674827426925968686433731916548717750106343608307376281613984107392410037196754833838054369880310983922140260514297591221159148505938770679068701351029862207502287721123345624421024715163941251258954337788492834236361124473822814504596821452253550035968325337489186278678359443979041598043992124889848660795045011701169092519383155609441705397900600291315024253848282782826223304151370929502192196508374714697845805550615914539506437316401173317807741497557116733034632008408954066541694665746735785483133770133628948904397670025863002540635264006601631712883920305576358989492412827022489373848906764385339931878608019223108328847459816417701264089078551777830131616162049792779670521847212730327970738223860581986744668610994383049960437407323195784473254857416239738852016202384784256163512597161783106850156299135559874758848151014815490937380933394074455700842090155903853444962128368313687375166780513082594599771257467939781491953642874321122421579851584491669362551569370916855252644720786527971466476760328471332985501945689772758983450586004316822658631176606237201721007922216410188299330808409384014213759697185976897042759041500946595252763487628135867117352364964121058854934496645898651826545634382851159137631569519895230262881794959971545221250667461174394884433312659432286710965281109501693028351496524082850120190831078678067061851145740970787563117610746428835593915985421673115153096948758378955979586132649569817205284291038172721213138681565524428109871168862743968021885581515367531218374119972919471325465199144188500672036481975944167950887487934416759598361960010994838744709079104099785974656112459851972157558134628546189728615020774374529539536929655449012953097288963767713353842429715394179547179095580120134210175150931491664699052366350233024087218654727629639065723341455005903913890253699317155917179823065162679744711857951506573868504088229934804445549850597823297898617029498418376255258757455303112991914341109413088238114443068843062655305601658801408561023324210300218460588586954418502977463085858496130037238190325162225570729975710727306066072916922978033647048840958711228045188511908718588299514331534128549297173849768523136276076868494780364948299904475715771141080958058141208956059471668626290036145602625334863284986816039463372436667112964460292915746181117789169695839947080954788863503281129626899231110099889317815313946681882028368363373822281414974006917942192888817139116283910295684918233358930813360131488748366464224381776081007739183393749346933644748150564933649323157235306109385796839902153381449126925350768211098738352197507736653475499431740580563099143218212547336281359488317681489194306530426029773885492974570569448783077945878865062970895499843760181694031056909587141386804846359853684034105948341788438963179956468815791937174656705047441528027712541569401365862097760735632832966564135817028088013546326104892768731829917950379944446328158595181380144716817284996793061814177131912099236282922612543236071226270324572637946863533391758737446552006008819975294017572421299723542069630427857950608911113416534893431149175314953530067419744979017235181671568754163484949491289001739377451431928382431183263265079530371177806185851153508809998200482761808307209649636476943066172549186143700971387567940218696710148540307471561091358933165600167252126542502898612259306484105898847129649230941215144563947889999327145875969555737090855150648002321476443037232466147111552578583071024936898814562568786834745518893385181791667579054210421036349316257870476543126790661216644142285017446278477132740595579600648343288827864837043456066966456899746910373987712891593313271266247505582258634928427718355831641593667712218537642376222104779338956378722902509543014182257180331300148113377736941508488867501893156994849838936052666818012783912005801431596441910546663236810148207799356523056490420711364192200177189107935243234322761787712568251126481332974354926568682748715986654943041648468220593921673359485057849622807932422649812705271398407720995707236227009245067665680069149966555737866411877079767754867028786431817941521796178310655030287157272282250812017060713380339641841211253856248920130010782462165136989511064611133562443838185366273563783436921279354709230119655914915800561707258518503167289370411936374780625824298250726464801821523430268081486978164824349353456855843696378384153838051184406043696871666416514036129729992912630842812149152469877429332305214999981829046119471676727503742221367186614654042534463141660649871499001000660041544868437352208483059495953182872280520828676300361091734508632133033647289584176588755345227938480297724485711815574893561311524926772006362198369980664159549388683836411891430443767715498026544959061738265591178545999378510861446014967645550103653971251138583505085112442517772923814396233043724036032603181442991365750246012787514117944901305803452199992701148071712847770301254994886841867572975189214295652512486943983729047410363121899124217339550688778643130750024823361832738729697376598820053895902935486054979802320400472236873557411858132734337978931582039412878989728973298812553514507641535360519462112217000676321611195841029252568536561813138784086477147099724553013170761712163186600291464501378587854802096244703771373587720086738054108140042311418525803293267396324596914044834665722042880679280616029884043400536534009706581694636096660911110968789751801325224478246957913251892122653056085866541115373584912790254654369020869419871125588453729063224423222287139122012248769976837147645598526739225904997885514250047585260297929306159913444898341973583316070107516452301310796620382579278533125161760789984630103493496981494261055367836366022561213767081421091373531780682420175737470287189310207606953355721704357535177461573524838432101571399813798596607129664438314791296359275429627129436142685922138993054980645399144588692472767598544271527788443836760149912897358259961869729756588978741082189422337344547375227693199222635973520722998387368484349176841191020246627479579564349615012657433845758638834735832242535328142047826934473129971189346354502994681747128179298167439644524956655532311649920677163664580318205849626132234652606175413532444702007661807418914040158148560001030119994109595492321434406067634769713089513389171050503856336503545166431774489640061738861761193622676890576955693918707703942304940038440622614449572516631017080642923345170422426679607075404028551182398361531383751432493056398381877995594942545196756559181968690885283434886050828529642437578712929439366177362830136595872723080969468398938676366226456791132977469812675226595621009318322081754694778878755356188335083870248295346078597023609865656376722755704495258739871812593441903785275571333409842450127258596692434317689018966145404453679047136294238156127656824247864736176671770647002431119711090007474065945650315375044177982192306323700872039212085499569681061379189029961178936752146022386905665481382858280449537530160921422195940638787074787991194920898374091788534417523064715030278397979864517336625329511775105559014160459873338186887977858817291976604516353353556047648420520888811722831990044504284486852338334530105533929637308039738230604714104525470094899407601215247602819963846343554852932377161410869591950786873276075400085220065031871239272857835807010762542769655355964789450166013816295177908531139811092831583216931563867459747449584385282701658246192092219529134323496779345585613140207765996142546463288677356891785576835169608392864188830094883324700447958316931533832382377876344426323456301679513671047510469669001217777128065522453689371871451567394733440447280450959433090683667110655953338602938000999949010642769859623260401863733572846679531229683156358145420890540651226419162015504500430562136991850941034609601030543816694795964585804425194905110733387679946734471718615647723811737035654917628707589456035519195603962301157866323750234725054461073979402475184415558178087962822231972692984516683306919505079993357259165675557294585962182052650473353712351623662770479333289322136141858785972771685682725303734836891911847197133753088446777943274857148827821608844765700041403499921376794209627560883081509438030705666022764678117533361028187800710219794428777313146387857817205661409023041499923248268982477222109852189758140879763486146763606368674611966620347304608917277240045953051376938375381543486981101990651706961774052218247422657652138152740612699012706880875386408669901461740890540981877671880076124151967064152117653084325544261017536348281196837493395825742541244634247233586360777980960199745187758845459645895956779558869098404768259253477849930457883128541747079059795909431627722327844578918694214929451540174214623240300841907975296782445969183509474202123617940309048634960534054931299919496087957952586977170236680033862505764938088740994009589948109397983231108838769236490221499111120870639202892490698435333152727991330986335454324971441378059132240814960156485679843966464780280409057580889190254236606774500413415794312112501275232250148067232979652230488493751166084976116412777395311302041566848265531411348993243747890268935173904043294851610659785832253168204202834993641595980197343889883020994152152288611175126686173051956249367180053845637855129171848417841594797435580617856680758491080185805695567990185198397660693358224779136504562705766735170961550493338390452612404395517449136885115987454340932040102218982707539212403241042424451570052968378815749468441508011138612561164102477190903050040240662278945607061512108266146098662040425010583978098192019726759010749924884966139441184159734610382401178556739080566483321039073867083298691078093495828888707110651559651222542929154212923108071159723275797510859911398076844732639426419452063138217862260999160086752446265457028969067192282283045169111363652774517975842147102219099906257373383472726498678244401048998507631630668050267115944636293525120269424810854530602810627264236538250773340575475701704367039596467715959261029438313074897245505729085688496091346323165819468660587092144653716755655531962091865952628448253731353698162517351930115341581171353292035873164168839107994000677266031617527582917398395852606454113318985505747847121053505795649095931672167565624818782002769963734155880000867852567422461511406015760115910256449002264980039498403358091309140197877843650167960167465370287466062584346329708303725980494653589318912163976013193079476972058034710553111117215859219066231028099212084069283091906017370764654655683413207556315315006453462321007133584907633048328153458698497332599801187479664273140279381289961720524540674695271948079930396730194274036466594154400092799908634806622334906695224044652158992864203435098858422692019340575496840904812955522654754650713532842543496616084954788090727649930252702815067862810825243222979985391759845188868387004477101866772159439708514664612871148749531862180941719676843144666435175837688436786081446319641912566574047718699160915550910878919431253671945651261878486910876729910565595155159739659034383628124629118117760949411880105946336671039049777312004243578115790429823045072038322781246413671297959415082918378213212876890545963586369344879749784841123274921331663162812456388238288715648447883142417650147980187858215768793063001153788998014623690135803753306246148576074932567807682651045738059018831237617271889933790487113395588485234240255002352200613574914318259142479829367775490496399350755839668967578364316618369307625603528602940662803255416535431518013714821941772672244005268401996533334184004345525296592918502940131600651124395297874364222806977720437363717873457948420238745151249157913139411148608416429347958793681868609689684640858334131017858142710955416293375915178392341303110543328703526599993904966822112768158316511246866451167351378214345336650598328347443536290312393672084593164394941881138607974670134709640378534907149089842317891739783650654751982883367395714360000003439863363212091718954899055748693397700245632475954504411422582410783866837655467400137324322809113692670682805397549111166171102397437749479335174036135005397581475520834285772800986189401984375446435081498218360112577632447389452051636938585136484259964518361856989088721789764694721246807900330925083496645841656554261294195108847197209106605105540933731954888406444080280579549008076040034154662137669606444293774985897353625591959618552448187940317374508256072895120945456562159540405425814886929842786582357673195799285293120866275922366115137445767916063621675267440451221051052090834707443986137829082352772895849625656881972792768694795806100573787084121444815034797422312103295359297822377134077549545477791813823542607184617108389097825964406170543546968567030745411634244134486308676327949177682923093183221341455482591367202823284396549001805653203960795517074496039006696990334199278212696767771835209083959545341866777944872740383733381985235884202840150981579594685874537989503257362809837592216229258598599123843993575573285028613155970362934249814178056461615863415338635077223269996508860870999964899373049307170967888740149746147542880387421250689212155876692242387434701120990859082164073576380817386959755176083877600277517253037133445654852635661720197563001580049790223419586738061442401502436288957503206533690825756785507020555105572381878574650371086308158185862815883054564662297694803970618265491385181326737485227188267917919091354407852685476254126683398240534022469989966652573155637645862251862823092085424412805997628505488913098331761884983352975136073772030571342739638126588567405013841074788943393996603591853934198416322617654857376671943132840050626295140357877264680649549355746326408186979718630218760025813995719923601345374229758918285167511358171472625828596940798518571870075823122317068134867930884899275181661399609753105295773584618525865211893339375771859916335112163441037910451845019023066893064178977808158101360449495409665363660370075881004450265734935127707426742578608784898185628869980851665713320835842613381142623855420315774246613108873106318111989880289722849790551075148403702290580483052731884959994156606537314021296702220821915862905952604040620011815269664910068587592655660567562963361434230232810747488395040380984981860056164646099819257616235478710913832967563761506732550860683433720438748186791668975746563456020002562889601191100980453350423842063824039434163502977688802779835087481178298349417211674919425601608685332435385951152061809031241698182079314615062073826097180458265687043623935757495737332781578904386011378078508110273049446611821957450170106059384336519458628360682108585130499820420578458577175933849015564447305834515291412561679970569657426139901681932056241927977282026714297258700193234337873153939403115411184101414292741703537542003698760608765500109345299007034032401334806388514095769557147190364152027721127070187421548123931953220997506553022646844227700020589045922742423904937051507367764629844971682121994198274794049092601715727439368569721862936007387077810797440975556627807371228030350048829843919546433753355787895064018998685060281902452191177018634505171087023903398550540704454189088472042376499749035038518949505897971286631644699407490959473411581934618336692169573605081585080837952036335619947691937965065016808710250735070825260046821242820434367245824478859256555487861614478717581068572356895150707602217433511627331709472765932413249132702425519391509083601346239612335001086614623850633127072987745618984384288764099836164964775714638573247333226653894523588365972955159905187411779288608760239306160016168434070611663449248395156319152882728822831375458678269830696691220130954815935450754923554167766876455212545681242936427474153815692219503331560151614492247512488957534835926226263545406704767033866410025277276800886383266629488582740369655329362236090572479794734434077704284318507901973469071141230364111729224929307731939309795452877412451183953480382210373644697046967493042810911797232448615413264031578430955396671061468083815548947146733652483679138566431084747848676243012018489329109615281108087617422779131629345494425395422727309645057976122885347393189600810965202090151104579377602529543130188938184010247010134929317443562883578609861545691161669857388024973756940558138630581099823372565164920155443216861690537054630176154809626620800633059320775897175589925862195462096455464624399535391743228225433267174308492508396461328929584567927365409119947616225155964704061297047759818551878441419948614013153859322060745185909608884280218943358691959604936409651570327527570641500776261323783648149005245481413195989296398441371781402764122087644989688629798910870164270169014007825748311598976330612951195680427485317886333041169767175063822135213839779138443325644288490872919067009802496281560626258636942322658490628628035057282983101266919109637258378149363774960594515216932644945188292639525772348420077356021656909077097264985642831778694777804964343991762549216500608626285329471055602670413384500507827390640287529864161287496473708235188892189612641279553536442286955430551308700009878557534223100547153412810957024870812654319123261956462149376527526356402127388765103883255007364899937167183280028398832319373301564123277185395654932422977953016534830128490677845037490891749347389015649588574802194996722621185874361039774946338633057887487405540005440439344888192044102134790034598411927024921557026873700970995205391930979319495883265922171508324621942300185974396706491149559411733728199869021311629886680267446443489233020607003821262841723679627307191405008084085703978151998148822390059948911946474438682533745889962375133378280532928272016815977970066488394482446332210928320504045983008943565954267256879714918703447338237767914829203283196838105907715727191903042365315650957464549643425328069510396558733549803850995143463506175361480050195045201350200180281506933241918267855737764414097080945745624854867704904368368717590918057269794010465019484853146726642978667687697789291431128505043098192949736165944259471754765135205245072597538577958372797702972231435199958499522344049394502115428867244188717409524554771867484911475031801773304689909317974472957035192387686405544278134169807249382219749124257510162187439772902147704638010731470653154201300583810458905006764557332998149945854655105526374914354195867992595981412218735238407957416123372264063860431988936249867649693592569592128495906254446474331759999685163660305216426770428154681777589339252115538590526823311608302751194384823861552852465010329467297198112105314125898165100120742688143577590825227466863206188376830450921784582526239594189673003640808624233657620979111641766331328852352062487922978959456450333733139422384778582717195412347860434376165241568717943562570215636666680088531006728947033079540804583324192188488870712275670333173939262509073556164513677064199539111948881240659821685787131385056850623094155206877987539740658484250135205615103489821873770245063583314243624807432542464195984647411575625441010389671576677263196442524931941806472423789334668561083789808830313571333157729435664956078125304917594015895146954965223118559669048559467607968190167266634650186182955669893965019614544401768162810604465068448139561667220729261210164692339016793399632833013163850830967942792934551268435760356901970523138364640961311774904600772840862214747547653221505518116489887879087780918009050706040061220010051271575991225725282523378026809030528461581739558198122397010092017202251606352922464781615533532275453264543087093320924631855976580561717446840450048285353396546862678852330044967795580761661801833668792312510460809773895565488962815089519622093675058841609752282328250433712970186608193748968699961301486924694482420723632912367052542145464162968910442981633373266871675946715392611950649224725627254543274193495995569590243279097174392258098103601486364409101491734183079646345064833303404765711827040276868271418084574998493392039317445402616663674646668754385093967129918067471909885312710726724428584870694307099756567949198418996425748884764622030325637751112534060087936904565779272035205921345924272965206683338510673615276261016026647772485083344719891986802656197236420847504962661607797092906844757798251795569758235084371746103310387911789239441630112634077535773520558040066982523191225570519133631407211349723226549151062961739050617857127509403623146700931176133132018631158730886798239298009805089491510788371194099750375473674305745187265414016446924576792185753680363289139664155342066705623272936001177781498886100830877849571709880858667023104043242526785955562077310543072298032125941107957349146684680220501816192150766649106862033378713826058987655210423668198670177861672671972374156917880001690656659046965316154923604061891820982414006103779407166342002735828911994182647812782659666207030384795881442790246669264032799404016800137293477301530941805070587421153284642203006550763966756168318897005152026656649929417382840327305940740147117478464839241225676523593418554066440983706083636457657081801664285044258224551650808864421212113914352453935225522162483791737330329812349528984098613273709957407786789349311975204237925022851375880436791854547836416773151821457226504640800104202100410766027807729152555503218182387221708112766208665317651926458452495269685376314437998340336947124447247796973890514941120010934140073794061859447165516612674930799374705772930521750426383798367668159183589049652163726492960837147204067428996276720315410211504333742057182854090136325721437592054640471894328548696883599785122262130812989581571391597464534806099601555877223193450760315411663112963843719400333736013305526352571490454327925190794007111504785378036370897340146753465517470747096935814912797188187854376797751675927822300312945518595042883902735494672667647506072643698761394806879080593531793001711000214417701504495496412454361656210150919997862972495905809191825255486358703529320142005857057855419217730505342687533799076038746689684283402648733290888881745453047194740939258407362058242849349024756883352446212456101562729065130618520732925434179252299417447855189995098959999877410951464170076989305620163502192692653166599093238118295411937545448509428621839424186218067457128099385258842631930670182098008050900019819621758458932516877698594110522845465835679362969619219080897536813210484518784516230623911878024604050824909336069998094776253792973597037759066145994638578378211017122446355845171941670344732162722443265914858595797823752976323442911242311368603724514438765801271594060878788638511089680883165505046309006148832545452819908256238805872042843941834687865142541377686054291079721004271658 diff --git a/vendor/github.com/klauspost/compress/testdata/pi.txt b/vendor/github.com/klauspost/compress/testdata/pi.txt new file mode 100644 index 0000000..ca99bbc --- /dev/null +++ b/vendor/github.com/klauspost/compress/testdata/pi.txt @@ -0,0 +1 @@ +3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275900994657640789512694683983525957098258226205224894077267194782684826014769909026401363944374553050682034962524517493996514314298091906592509372216964615157098583874105978859597729754989301617539284681382686838689427741559918559252459539594310499725246808459872736446958486538367362226260991246080512438843904512441365497627807977156914359977001296160894416948685558484063534220722258284886481584560285060168427394522674676788952521385225499546667278239864565961163548862305774564980355936345681743241125150760694794510965960940252288797108931456691368672287489405601015033086179286809208747609178249385890097149096759852613655497818931297848216829989487226588048575640142704775551323796414515237462343645428584447952658678210511413547357395231134271661021359695362314429524849371871101457654035902799344037420073105785390621983874478084784896833214457138687519435064302184531910484810053706146806749192781911979399520614196634287544406437451237181921799983910159195618146751426912397489409071864942319615679452080951465502252316038819301420937621378559566389377870830390697920773467221825625996615014215030680384477345492026054146659252014974428507325186660021324340881907104863317346496514539057962685610055081066587969981635747363840525714591028970641401109712062804390397595156771577004203378699360072305587631763594218731251471205329281918261861258673215791984148488291644706095752706957220917567116722910981690915280173506712748583222871835209353965725121083579151369882091444210067510334671103141267111369908658516398315019701651511685171437657618351556508849099898599823873455283316355076479185358932261854896321329330898570642046752590709154814165498594616371802709819943099244889575712828905923233260972997120844335732654893823911932597463667305836041428138830320382490375898524374417029132765618093773444030707469211201913020330380197621101100449293215160842444859637669838952286847831235526582131449576857262433441893039686426243410773226978028073189154411010446823252716201052652272111660396665573092547110557853763466820653109896526918620564769312570586356620185581007293606598764861179104533488503461136576867532494416680396265797877185560845529654126654085306143444318586769751456614068007002378776591344017127494704205622305389945613140711270004078547332699390814546646458807972708266830634328587856983052358089330657574067954571637752542021149557615814002501262285941302164715509792592309907965473761255176567513575178296664547791745011299614890304639947132962107340437518957359614589019389713111790429782856475032031986915140287080859904801094121472213179476477726224142548545403321571853061422881375850430633217518297986622371721591607716692547487389866549494501146540628433663937900397692656721463853067360965712091807638327166416274888800786925602902284721040317211860820419000422966171196377921337575114959501566049631862947265473642523081770367515906735023507283540567040386743513622224771589150495309844489333096340878076932599397805419341447377441842631298608099888687413260472156951623965864573021631598193195167353812974167729478672422924654366800980676928238280689964004824354037014163149658979409243237896907069779422362508221688957383798623001593776471651228935786015881617557829735233446042815126272037343146531977774160319906655418763979293344195215413418994854447345673831624993419131814809277771038638773431772075456545322077709212019051660962804909263601975988281613323166636528619326686336062735676303544776280350450777235547105859548702790814356240145171806246436267945612753181340783303362542327839449753824372058353114771199260638133467768796959703098339130771098704085913374641442822772634659470474587847787201927715280731767907707157213444730605700733492436931138350493163128404251219256517980694113528013147013047816437885185290928545201165839341965621349143415956258658655705526904965209858033850722426482939728584783163057777560688876446248246857926039535277348030480290058760758251047470916439613626760449256274204208320856611906254543372131535958450687724602901618766795240616342522577195429162991930645537799140373404328752628889639958794757291746426357455254079091451357111369410911939325191076020825202618798531887705842972591677813149699009019211697173727847684726860849003377024242916513005005168323364350389517029893922334517220138128069650117844087451960121228599371623130171144484640903890644954440061986907548516026327505298349187407866808818338510228334508504860825039302133219715518430635455007668282949304137765527939751754613953984683393638304746119966538581538420568533862186725233402830871123282789212507712629463229563989898935821167456270102183564622013496715188190973038119800497340723961036854066431939509790190699639552453005450580685501956730229219139339185680344903982059551002263535361920419947455385938102343955449597783779023742161727111723643435439478221818528624085140066604433258885698670543154706965747458550332323342107301545940516553790686627333799585115625784322988273723198987571415957811196358330059408730681216028764962867446047746491599505497374256269010490377819868359381465741268049256487985561453723478673303904688383436346553794986419270563872931748723320837601123029911367938627089438799362016295154133714248928307220126901475466847653576164773794675200490757155527819653621323926406160136358155907422020203187277605277219005561484255518792530343513984425322341576233610642506390497500865627109535919465897514131034822769306247435363256916078154781811528436679570611086153315044521274739245449454236828860613408414863776700961207151249140430272538607648236341433462351897576645216413767969031495019108575984423919862916421939949072362346468441173940326591840443780513338945257423995082965912285085558215725031071257012668302402929525220118726767562204154205161841634847565169998116141010029960783869092916030288400269104140792886215078424516709087000699282120660418371806535567252532567532861291042487761825829765157959847035622262934860034158722980534989650226291748788202734209222245339856264766914905562842503912757710284027998066365825488926488025456610172967026640765590429099456815065265305371829412703369313785178609040708667114965583434347693385781711386455873678123014587687126603489139095620099393610310291616152881384379099042317473363948045759314931405297634757481193567091101377517210080315590248530906692037671922033229094334676851422144773793937517034436619910403375111735471918550464490263655128162288244625759163330391072253837421821408835086573917715096828874782656995995744906617583441375223970968340800535598491754173818839994469748676265516582765848358845314277568790029095170283529716344562129640435231176006651012412006597558512761785838292041974844236080071930457618932349229279650198751872127267507981255470958904556357921221033346697499235630254947802490114195212382815309114079073860251522742995818072471625916685451333123948049470791191532673430282441860414263639548000448002670496248201792896476697583183271314251702969234889627668440323260927524960357996469256504936818360900323809293459588970695365349406034021665443755890045632882250545255640564482465151875471196218443965825337543885690941130315095261793780029741207665147939425902989695946995565761218656196733786236256125216320862869222103274889218654364802296780705765615144632046927906821207388377814233562823608963208068222468012248261177185896381409183903673672220888321513755600372798394004152970028783076670944474560134556417254370906979396122571429894671543578468788614445812314593571984922528471605049221242470141214780573455105008019086996033027634787081081754501193071412233908663938339529425786905076431006383519834389341596131854347546495569781038293097164651438407007073604112373599843452251610507027056235266012764848308407611830130527932054274628654036036745328651057065874882256981579367897669742205750596834408697350201410206723585020072452256326513410559240190274216248439140359989535394590944070469120914093870012645600162374288021092764579310657922955249887275846101264836999892256959688159205600101655256375678566722796619885782794848855834397518744545512965634434803966420557982936804352202770984294232533022576341807039476994159791594530069752148293366555661567873640053666564165473217043903521329543529169414599041608753201868379370234888689479151071637852902345292440773659495630510074210871426134974595615138498713757047101787957310422969066670214498637464595280824369445789772330048764765241339075920434019634039114732023380715095222010682563427471646024335440051521266932493419673977041595683753555166730273900749729736354964533288869844061196496162773449518273695588220757355176651589855190986665393549481068873206859907540792342402300925900701731960362254756478940647548346647760411463233905651343306844953979070903023460461470961696886885014083470405460742958699138296682468185710318879065287036650832431974404771855678934823089431068287027228097362480939962706074726455399253994428081137369433887294063079261595995462624629707062594845569034711972996409089418059534393251236235508134949004364278527138315912568989295196427287573946914272534366941532361004537304881985517065941217352462589548730167600298865925786628561249665523533829428785425340483083307016537228563559152534784459818313411290019992059813522051173365856407826484942764411376393866924803118364453698589175442647399882284621844900877769776312795722672655562596282542765318300134070922334365779160128093179401718598599933849235495640057099558561134980252499066984233017350358044081168552653117099570899427328709258487894436460050410892266917835258707859512983441729535195378855345737426085902908176515578039059464087350612322611200937310804854852635722825768203416050484662775045003126200800799804925485346941469775164932709504934639382432227188515974054702148289711177792376122578873477188196825462981268685817050740272550263329044976277894423621674119186269439650671515779586756482399391760426017633870454990176143641204692182370764887834196896861181558158736062938603810171215855272668300823834046564758804051380801633638874216371406435495561868964112282140753302655100424104896783528588290243670904887118190909494533144218287661810310073547705498159680772009474696134360928614849417850171807793068108546900094458995279424398139213505586422196483491512639012803832001097738680662877923971801461343244572640097374257007359210031541508936793008169980536520276007277496745840028362405346037263416554259027601834840306811381855105979705664007509426087885735796037324514146786703688098806097164258497595138069309449401515422221943291302173912538355915031003330325111749156969174502714943315155885403922164097229101129035521815762823283182342548326111912800928252561902052630163911477247331485739107775874425387611746578671169414776421441111263583553871361011023267987756410246824032264834641766369806637857681349204530224081972785647198396308781543221166912246415911776732253264335686146186545222681268872684459684424161078540167681420808850280054143613146230821025941737562389942075713627516745731891894562835257044133543758575342698699472547031656613991999682628247270641336222178923903176085428943733935618891651250424404008952719837873864805847268954624388234375178852014395600571048119498842390606136957342315590796703461491434478863604103182350736502778590897578272731305048893989009923913503373250855982655867089242612429473670193907727130706869170926462548423240748550366080136046689511840093668609546325002145852930950000907151058236267293264537382104938724996699339424685516483261134146110680267446637334375340764294026682973865220935701626384648528514903629320199199688285171839536691345222444708045923966028171565515656661113598231122506289058549145097157553900243931535190902107119457300243880176615035270862602537881797519478061013715004489917210022201335013106016391541589578037117792775225978742891917915522417189585361680594741234193398420218745649256443462392531953135103311476394911995072858430658361935369329699289837914941939406085724863968836903265564364216644257607914710869984315733749648835292769328220762947282381537409961545598798259891093717126218283025848112389011968221429457667580718653806506487026133892822994972574530332838963818439447707794022843598834100358385423897354243956475556840952248445541392394100016207693636846776413017819659379971557468541946334893748439129742391433659360410035234377706588867781139498616478747140793263858738624732889645643598774667638479466504074111825658378878454858148962961273998413442726086061872455452360643153710112746809778704464094758280348769758948328241239292960582948619196670918958089833201210318430340128495116203534280144127617285830243559830032042024512072872535581195840149180969253395075778400067465526031446167050827682772223534191102634163157147406123850425845988419907611287258059113935689601431668283176323567325417073420817332230462987992804908514094790368878687894930546955703072619009502076433493359106024545086453628935456862958531315337183868265617862273637169757741830239860065914816164049449650117321313895747062088474802365371031150898427992754426853277974311395143574172219759799359685252285745263796289612691572357986620573408375766873884266405990993505000813375432454635967504844235284874701443545419576258473564216198134073468541117668831186544893776979566517279662326714810338643913751865946730024434500544995399742372328712494834706044063471606325830649829795510109541836235030309453097335834462839476304775645015008507578949548931393944899216125525597701436858943585877526379625597081677643800125436502371412783467926101995585224717220177723700417808419423948725406801556035998390548985723546745642390585850216719031395262944554391316631345308939062046784387785054239390524731362012947691874975191011472315289326772533918146607300089027768963114810902209724520759167297007850580717186381054967973100167870850694207092232908070383263453452038027860990556900134137182368370991949516489600755049341267876436746384902063964019766685592335654639138363185745698147196210841080961884605456039038455343729141446513474940784884423772175154334260306698831768331001133108690421939031080143784334151370924353013677631084913516156422698475074303297167469640666531527035325467112667522460551199581831963763707617991919203579582007595605302346267757943936307463056901080114942714100939136913810725813781357894005599500183542511841721360557275221035268037357265279224173736057511278872181908449006178013889710770822931002797665935838758909395688148560263224393726562472776037890814458837855019702843779362407825052704875816470324581290878395232453237896029841669225489649715606981192186584926770403956481278102179913217416305810554598801300484562997651121241536374515005635070127815926714241342103301566165356024733807843028655257222753049998837015348793008062601809623815161366903341111386538510919367393835229345888322550887064507539473952043968079067086806445096986548801682874343786126453815834280753061845485903798217994599681154419742536344399602902510015888272164745006820704193761584547123183460072629339550548239557137256840232268213012476794522644820910235647752723082081063518899152692889108455571126603965034397896278250016110153235160519655904211844949907789992007329476905868577878720982901352956613978884860509786085957017731298155314951681467176959760994210036183559138777817698458758104466283998806006162298486169353373865787735983361613384133853684211978938900185295691967804554482858483701170967212535338758621582310133103877668272115726949518179589754693992642197915523385766231676275475703546994148929041301863861194391962838870543677743224276809132365449485366768000001065262485473055861598999140170769838548318875014293890899506854530765116803337322265175662207526951791442252808165171667766727930354851542040238174608923283917032754257508676551178593950027933895920576682789677644531840404185540104351348389531201326378369283580827193783126549617459970567450718332065034556644034490453627560011250184335607361222765949278393706478426456763388188075656121689605041611390390639601620221536849410926053876887148379895599991120991646464411918568277004574243434021672276445589330127781586869525069499364610175685060167145354315814801054588605645501332037586454858403240298717093480910556211671546848477803944756979804263180991756422809873998766973237695737015808068229045992123661689025962730430679316531149401764737693873514093361833216142802149763399189835484875625298752423873077559555955465196394401821840998412489826236737714672260616336432964063357281070788758164043814850188411431885988276944901193212968271588841338694346828590066640806314077757725705630729400492940302420498416565479736705485580445865720227637840466823379852827105784319753541795011347273625774080213476826045022851579795797647467022840999561601569108903845824502679265942055503958792298185264800706837650418365620945554346135134152570065974881916341359556719649654032187271602648593049039787489589066127250794828276938953521753621850796297785146188432719223223810158744450528665238022532843891375273845892384422535472653098171578447834215822327020690287232330053862163479885094695472004795231120150432932266282727632177908840087861480221475376578105819702226309717495072127248479478169572961423658595782090830733233560348465318730293026659645013718375428897557971449924654038681799213893469244741985097334626793321072686870768062639919361965044099542167627840914669856925715074315740793805323925239477557441591845821562518192155233709607483329234921034514626437449805596103307994145347784574699992128599999399612281615219314888769388022281083001986016549416542616968586788372609587745676182507275992950893180521872924610867639958916145855058397274209809097817293239301067663868240401113040247007350857828724627134946368531815469690466968693925472519413992914652423857762550047485295476814795467007050347999588867695016124972282040303995463278830695976249361510102436555352230690612949388599015734661023712235478911292547696176005047974928060721268039226911027772261025441492215765045081206771735712027180242968106203776578837166909109418074487814049075517820385653909910477594141321543284406250301802757169650820964273484146957263978842560084531214065935809041271135920041975985136254796160632288736181367373244506079244117639975974619383584574915988097667447093006546342423460634237474666080431701260052055928493695941434081468529815053947178900451835755154125223590590687264878635752541911288877371766374860276606349603536794702692322971868327717393236192007774522126247518698334951510198642698878471719396649769070825217423365662725928440620430214113719922785269984698847702323823840055655517889087661360130477098438611687052310553149162517283732728676007248172987637569816335415074608838663640693470437206688651275688266149730788657015685016918647488541679154596507234287730699853713904300266530783987763850323818215535597323530686043010675760838908627049841888595138091030423595782495143988590113185835840667472370297149785084145853085781339156270760356390763947311455495832266945702494139831634332378975955680856836297253867913275055542524491943589128405045226953812179131914513500993846311774017971512283785460116035955402864405902496466930707769055481028850208085800878115773817191741776017330738554758006056014337743299012728677253043182519757916792969965041460706645712588834697979642931622965520168797300035646304579308840327480771811555330909887025505207680463034608658165394876951960044084820659673794731680864156456505300498816164905788311543454850526600698230931577765003780704661264706021457505793270962047825615247145918965223608396645624105195510522357239739512881816405978591427914816542632892004281609136937773722299983327082082969955737727375667615527113922588055201898876201141680054687365580633471603734291703907986396522961312801782679717289822936070288069087768660593252746378405397691848082041021944719713869256084162451123980620113184541244782050110798760717155683154078865439041210873032402010685341947230476666721749869868547076781205124736792479193150856444775379853799732234456122785843296846647513336573692387201464723679427870042503255589926884349592876124007558756946413705625140011797133166207153715436006876477318675587148783989081074295309410605969443158477539700943988394914432353668539209946879645066533985738887866147629443414010498889931600512076781035886116602029611936396821349607501116498327856353161451684576956871090029997698412632665023477167286573785790857466460772283415403114415294188047825438761770790430001566986776795760909966936075594965152736349811896413043311662774712338817406037317439705406703109676765748695358789670031925866259410510533584384656023391796749267844763708474978333655579007384191473198862713525954625181604342253729962863267496824058060296421146386436864224724887283434170441573482481833301640566959668866769563491416328426414974533349999480002669987588815935073578151958899005395120853510357261373640343675347141048360175464883004078464167452167371904831096767113443494819262681110739948250607394950735031690197318521195526356325843390998224986240670310768318446607291248747540316179699411397387765899868554170318847788675929026070043212666179192235209382278788809886335991160819235355570464634911320859189796132791319756490976000139962344455350143464268604644958624769094347048293294140411146540923988344435159133201077394411184074107684981066347241048239358274019449356651610884631256785297769734684303061462418035852933159734583038455410337010916767763742762102137013548544509263071901147318485749233181672072137279355679528443925481560913728128406333039373562420016045664557414588166052166608738748047243391212955877763906969037078828527753894052460758496231574369171131761347838827194168606625721036851321566478001476752310393578606896111259960281839309548709059073861351914591819510297327875571049729011487171897180046961697770017913919613791417162707018958469214343696762927459109940060084983568425201915593703701011049747339493877885989417433031785348707603221982970579751191440510994235883034546353492349826883624043327267415540301619505680654180939409982020609994140216890900708213307230896621197755306659188141191577836272927461561857103721724710095214236964830864102592887457999322374955191221951903424452307535133806856807354464995127203174487195403976107308060269906258076020292731455252078079914184290638844373499681458273372072663917670201183004648190002413083508846584152148991276106513741539435657211390328574918769094413702090517031487773461652879848235338297260136110984514841823808120540996125274580881099486972216128524897425555516076371675054896173016809613803811914361143992106380050832140987604599309324851025168294467260666138151745712559754953580239983146982203613380828499356705575524712902745397762140493182014658008021566536067765508783804304134310591804606800834591136640834887408005741272586704792258319127415739080914383138456424150940849133918096840251163991936853225557338966953749026620923261318855891580832455571948453875628786128859004106006073746501402627824027346962528217174941582331749239683530136178653673760642166778137739951006589528877427662636841830680190804609849809469763667335662282915132352788806157768278159588669180238940333076441912403412022316368577860357276941541778826435238131905028087018575047046312933353757285386605888904583111450773942935201994321971171642235005644042979892081594307167019857469273848653833436145794634175922573898588001698014757420542995801242958105456510831046297282937584161162532562516572498078492099897990620035936509934721582965174135798491047111660791587436986541222348341887722929446335178653856731962559852026072947674072616767145573649812105677716893484917660771705277187601199908144113058645577910525684304811440261938402322470939249802933550731845890355397133088446174107959162511714864874468611247605428673436709046678468670274091881014249711149657817724279347070216688295610877794405048437528443375108828264771978540006509704033021862556147332117771174413350281608840351781452541964320309576018694649088681545285621346988355444560249556668436602922195124830910605377201980218310103270417838665447181260397190688462370857518080035327047185659499476124248110999288679158969049563947624608424065930948621507690314987020673533848349550836366017848771060809804269247132410009464014373603265645184566792456669551001502298330798496079949882497061723674493612262229617908143114146609412341593593095854079139087208322733549572080757165171876599449856937956238755516175754380917805280294642004472153962807463602113294255916002570735628126387331060058910652457080244749375431841494014821199962764531068006631183823761639663180931444671298615527598201451410275600689297502463040173514891945763607893528555053173314164570504996443890936308438744847839616840518452732884032345202470568516465716477139323775517294795126132398229602394548579754586517458787713318138752959809412174227300352296508089177705068259248822322154938048371454781647213976820963320508305647920482085920475499857320388876391601995240918938945576768749730856955958010659526503036266159750662225084067428898265907510637563569968211510949669744580547288693631020367823250182323708459790111548472087618212477813266330412076216587312970811230758159821248639807212407868878114501655825136178903070860870198975889807456643955157415363193191981070575336633738038272152798849350397480015890519420879711308051233933221903466249917169150948541401871060354603794643379005890957721180804465743962806186717861017156740967662080295766577051291209907944304632892947306159510430902221439371849560634056189342513057268291465783293340524635028929175470872564842600349629611654138230077313327298305001602567240141851520418907011542885799208121984493156999059182011819733500126187728036812481995877070207532406361259313438595542547781961142935163561223496661522614735399674051584998603552953329245752388810136202347624669055816438967863097627365504724348643071218494373485300606387644566272186661701238127715621379746149861328744117714552444708997144522885662942440230184791205478498574521634696448973892062401943518310088283480249249085403077863875165911302873958787098100772718271874529013972836614842142871705531796543076504534324600536361472618180969976933486264077435199928686323835088756683595097265574815431940195576850437248001020413749831872259677387154958399718444907279141965845930083942637020875635398216962055324803212267498911402678528599673405242031091797899905718821949391320753431707980023736590985375520238911643467185582906853711897952626234492483392496342449714656846591248918556629589329909035239233333647435203707701010843880032907598342170185542283861617210417603011645918780539367447472059985023582891833692922337323999480437108419659473162654825748099482509991833006976569367159689364493348864744213500840700660883597235039532340179582557036016936990988671132109798897070517280755855191269930673099250704070245568507786790694766126298082251633136399521170984528092630375922426742575599892892783704744452189363203489415521044597261883800300677617931381399162058062701651024458869247649246891924612125310275731390840470007143561362316992371694848132554200914530410371354532966206392105479824392125172540132314902740585892063217589494345489068463993137570910346332714153162232805522972979538018801628590735729554162788676498274186164218789885741071649069191851162815285486794173638906653885764229158342500673612453849160674137340173572779956341043326883569507814931378007362354180070619180267328551191942676091221035987469241172837493126163395001239599240508454375698507957046222664619000103500490183034153545842833764378111988556318777792537201166718539541835984438305203762819440761594106820716970302285152250573126093046898423433152732131361216582808075212631547730604423774753505952287174402666389148817173086436111389069420279088143119448799417154042103412190847094080254023932942945493878640230512927119097513536000921971105412096683111516328705423028470073120658032626417116165957613272351566662536672718998534199895236884830999302757419916463841427077988708874229277053891227172486322028898425125287217826030500994510824783572905691988555467886079462805371227042466543192145281760741482403827835829719301017888345674167811398954750448339314689630763396657226727043393216745421824557062524797219978668542798977992339579057581890622525473582205236424850783407110144980478726691990186438822932305382318559732869780922253529591017341407334884761005564018242392192695062083183814546983923664613639891012102177095976704908305081854704194664371312299692358895384930136356576186106062228705599423371631021278457446463989738188566746260879482018647487672727222062676465338099801966883680994159075776852639865146253336312450536402610569605513183813174261184420189088853196356986962795036738424313011331753305329802016688817481342988681585577810343231753064784983210629718425184385534427620128234570716988530518326179641178579608888150329602290705614476220915094739035946646916235396809201394578175891088931992112260073928149169481615273842736264298098234063200244024495894456129167049508235812487391799648641133480324757775219708932772262349486015046652681439877051615317026696929704928316285504212898146706195331970269507214378230476875280287354126166391708245925170010714180854800636923259462019002278087409859771921805158532147392653251559035410209284665925299914353791825314545290598415817637058927906909896911164381187809435371521332261443625314490127454772695739393481546916311624928873574718824071503995009446731954316193855485207665738825139639163576723151005556037263394867208207808653734942440115799667507360711159351331959197120948964717553024531364770942094635696982226673775209945168450643623824211853534887989395673187806606107885440005508276570305587448541805778891719207881423351138662929667179643468760077047999537883387870348718021842437342112273940255717690819603092018240188427057046092622564178375265263358324240661253311529423457965569502506810018310900411245379015332966156970522379210325706937051090830789479999004999395322153622748476603613677697978567386584670936679588583788795625946464891376652199588286933801836011932368578558558195556042156250883650203322024513762158204618106705195330653060606501054887167245377942831338871631395596905832083416898476065607118347136218123246227258841990286142087284956879639325464285343075301105285713829643709990356948885285190402956047346131138263878897551788560424998748316382804046848618938189590542039889872650697620201995548412650005394428203930127481638158530396439925470201672759328574366661644110962566337305409219519675148328734808957477775278344221091073111351828046036347198185655572957144747682552857863349342858423118749440003229690697758315903858039353521358860079600342097547392296733310649395601812237812854584317605561733861126734780745850676063048229409653041118306671081893031108871728167519579675347188537229309616143204006381322465841111157758358581135018569047815368938137718472814751998350504781297718599084707621974605887423256995828892535041937958260616211842368768511418316068315867994601652057740529423053601780313357263267054790338401257305912339601880137825421927094767337191987287385248057421248921183470876629667207272325650565129333126059505777727542471241648312832982072361750574673870128209575544305968395555686861188397135522084452852640081252027665557677495969626612604565245684086139238265768583384698499778726706555191854468698469478495734622606294219624557085371272776523098955450193037732166649182578154677292005212667143463209637891852323215018976126034373684067194193037746880999296877582441047878123266253181845960453853543839114496775312864260925211537673258866722604042523491087026958099647595805794663973419064010036361904042033113579336542426303561457009011244800890020801478056603710154122328891465722393145076071670643556827437743965789067972687438473076346451677562103098604092717090951280863090297385044527182892749689212106670081648583395537735919136950153162018908887484210798706899114804669270650940762046502772528650728905328548561433160812693005693785417861096969202538865034577183176686885923681488475276498468821949739729707737187188400414323127636504814531122850990020742409255859252926103021067368154347015252348786351643976235860419194129697690405264832347009911154242601273438022089331096686367898694977994001260164227609260823493041180643829138347354679725399262338791582998486459271734059225620749105308531537182911681637219395188700957788181586850464507699343940987433514431626330317247747486897918209239480833143970840673084079589358108966564775859905563769525232653614424780230826811831037735887089240613031336477371011628214614661679404090518615260360092521947218890918107335871964142144478654899528582343947050079830388538860831035719306002771194558021911942899922722353458707566246926177663178855144350218287026685610665003531050216318206017609217984684936863161293727951873078972637353717150256378733579771808184878458866504335824377004147710414934927438457587107159731559439426412570270965125108115548247939403597681188117282472158250109496096625393395380922195591918188552678062149923172763163218339896938075616855911752998450132067129392404144593862398809381240452191484831646210147389182510109096773869066404158973610476436500068077105656718486281496371118832192445663945814491486165500495676982690308911185687986929470513524816091743243015383684707292898982846022237301452655679898627767968091469798378268764311598832109043715611299766521539635464420869197567370005738764978437686287681792497469438427465256316323005551304174227341646455127812784577772457520386543754282825671412885834544435132562054464241011037955464190581168623059644769587054072141985212106734332410756767575818456990693046047522770167005684543969234041711089888993416350585157887353430815520811772071880379104046983069578685473937656433631979786803671873079693924236321448450354776315670255390065423117920153464977929066241508328858395290542637687668968805033317227800185885069736232403894700471897619347344308437443759925034178807972235859134245813144049847701732361694719765715353197754997162785663119046912609182591249890367654176979903623755286526375733763526969344354400473067198868901968147428767790866979688522501636949856730217523132529265375896415171479559538784278499866456302878831962099830494519874396369070682762657485810439112232618794059941554063270131989895703761105323606298674803779153767511583043208498720920280929752649812569163425000522908872646925284666104665392171482080130502298052637836426959733707053922789153510568883938113249757071331029504430346715989448786847116438328050692507766274500122003526203709466023414648998390252588830148678162196775194583167718762757200505439794412459900771152051546199305098386982542846407255540927403132571632640792934183342147090412542533523248021932277075355546795871638358750181593387174236061551171013123525633485820365146141870049205704372018261733194715700867578539336078622739558185797587258744102542077105475361294047460100094095444959662881486915903899071865980563617137692227290764197755177720104276496949611056220592502420217704269622154958726453989227697660310524980855759471631075870133208861463266412591148633881220284440694169488261529577625325019870359870674380469821942056381255833436421949232275937221289056420943082352544084110864545369404969271494003319782861318186188811118408257865928757426384450059944229568586460481033015388911499486935436030221810943466764000022362550573631294626296096198760564259963946138692330837196265954739234624134597795748524647837980795693198650815977675350553918991151335252298736112779182748542008689539658359421963331502869561192012298889887006079992795411188269023078913107603617634779489432032102773359416908650071932804017163840644987871753756781185321328408216571107549528294974936214608215583205687232185574065161096274874375098092230211609982633033915469494644491004515280925089745074896760324090768983652940657920198315265410658136823791984090645712468948470209357761193139980246813405200394781949866202624008902150166163813538381515037735022966074627952910384068685569070157516624192987244482719429331004854824454580718897633003232525821581280327467962002814762431828622171054352898348208273451680186131719593324711074662228508710666117703465352839577625997744672185715816126411143271794347885990892808486694914139097716736900277758502686646540565950394867841110790116104008572744562938425494167594605487117235946429105850909950214958793112196135908315882620682332156153086833730838173279328196983875087083483880463884784418840031847126974543709373298362402875197920802321878744882872843727378017827008058782410749357514889978911739746129320351081432703251409030487462262942344327571260086642508333187688650756429271605525289544921537651751492196367181049435317858383453865255656640657251363575064353236508936790431702597878177190314867963840828810209461490079715137717099061954969640070867667102330048672631475510537231757114322317411411680622864206388906210192355223546711662137499693269321737043105987225039456574924616978260970253359475020913836673772894438696400028110344026084712899000746807764844088711341352503367877316797709372778682166117865344231732264637847697875144332095340001650692130546476890985050203015044880834261845208730530973189492916425322933612431514306578264070283898409841602950309241897120971601649265613413433422298827909921786042679812457285345801338260995877178113102167340256562744007296834066198480676615805021691833723680399027931606420436812079900316264449146190219458229690992122788553948783538305646864881655562294315673128274390826450611628942803501661336697824051770155219626522725455850738640585299830379180350432876703809252167907571204061237596327685674845079151147313440001832570344920909712435809447900462494313455028900680648704293534037436032625820535790118395649089354345101342969617545249573960621490288728932792520696535386396443225388327522499605986974759882329916263545973324445163755334377492928990581175786355555626937426910947117002165411718219750519831787137106051063795558588905568852887989084750915764639074693619881507814685262133252473837651192990156109189777922008705793396463827490680698769168197492365624226087154176100430608904377976678519661891404144925270480881971498801542057787006521594009289777601330756847966992955433656139847738060394368895887646054983871478968482805384701730871117761159663505039979343869339119789887109156541709133082607647406305711411098839388095481437828474528838368079418884342666222070438722887413947801017721392281911992365405516395893474263953824829609036900288359327745855060801317988407162446563997948275783650195514221551339281978226984278638391679715091262410548725700924070045488485692950448110738087996547481568913935380943474556972128919827177020766613602489581468119133614121258783895577357194986317210844398901423948496659251731388171602663261931065366535041473070804414939169363262373767777095850313255990095762731957308648042467701212327020533742667053142448208168130306397378736642483672539837487690980602182785786216512738563513290148903509883270617258932575363993979055729175160097615459044771692265806315111028038436017374742152476085152099016158582312571590733421736576267142390478279587281505095633092802668458937649649770232973641319060982740633531089792464242134583740901169391964250459128813403498810635400887596820054408364386516617880557608956896727531538081942077332597917278437625661184319891025007491829086475149794003160703845549465385946027452447466812314687943441610993338908992638411847425257044572517459325738989565185716575961481266020310797628254165590506042479114016957900338356574869252800743025623419498286467914476322774005529460903940177536335655471931000175430047504719144899841040015867946179241610016454716551337074073950260442769538553834397550548871099785205401175169747581344926079433689543783221172450687344231989878844128542064742809735625807066983106979935260693392135685881391214807354728463227784908087002467776303605551232386656295178853719673034634701222939581606792509153217489030840886516061119011498443412350124646928028805996134283511884715449771278473361766285062169778717743824362565711779450064477718370221999106695021656757644044997940765037999954845002710665987813603802314126836905783190460792765297277694043613023051787080546511542469395265127101052927070306673024447125973939950514628404767431363739978259184541176413327906460636584152927019030276017339474866960348694976541752429306040727005059039503148522921392575594845078867977925253931765156416197168443524369794447355964260633391055126826061595726217036698506473281266724521989060549880280782881429796336696744124805982192146339565745722102298677599746738126069367069134081559412016115960190237753525556300606247983261249881288192937343476862689219239777833910733106588256813777172328315329082525092733047850724977139448333892552081175608452966590553940965568541706001179857293813998258319293679100391844099286575605993598910002969864460974714718470101531283762631146774209145574041815908800064943237855839308530828305476076799524357391631221886057549673832243195650655460852881201902363644712703748634421727257879503428486312944916318475347531435041392096108796057730987201352484075057637199253650470908582513936863463863368042891767107602111159828875539940120076013947033661793715396306139863655492213741597905119083588290097656647300733879314678913181465109316761575821351424860442292445304113160652700974330088499034675405518640677342603583409608605533747362760935658853109760994238347382222087292464497684560579562516765574088410321731345627735856052358236389532038534024842273371639123973215995440828421666636023296545694703577184873442034227706653837387506169212768015766181095420097708363604361110592409117889540338021426523948929686439808926114635414571535194342850721353453018315875628275733898268898523557799295727645229391567477566676051087887648453493636068278050564622813598885879259940946446041705204470046315137975431737187756039815962647501410906658866162180038266989961965580587208639721176995219466789857011798332440601811575658074284182910615193917630059194314434605154047710570054339000182453117733718955857603607182860506356479979004139761808955363669603162193113250223851791672055180659263518036251214575926238369348222665895576994660491938112486609099798128571823494006615552196112207203092277646200999315244273589488710576623894693889446495093960330454340842102462401048723328750081749179875543879387381439894238011762700837196053094383940063756116458560943129517597713935396074322792489221267045808183313764165818269562105872892447740035947009268662659651422050630078592002488291860839743732353849083964326147000532423540647042089499210250404726781059083644007466380020870126664209457181702946752278540074508552377720890581683918446592829417018288233014971554235235911774818628592967605048203864343108779562892925405638946621948268711042828163893975711757786915430165058602965217459581988878680408110328432739867198621306205559855266036405046282152306154594474489908839081999738747452969810776201487134000122535522246695409315213115337915798026979555710508507473874750758068765376445782524432638046143042889235934852961058269382103498000405248407084403561167817170512813378805705643450616119330424440798260377951198548694559152051960093041271007277849301555038895360338261929343797081874320949914159593396368110627557295278004254863060054523839151068998913578820019411786535682149118528207852130125518518493711503422159542244511900207393539627400208110465530207932867254740543652717595893500716336076321614725815407642053020045340183572338292661915308354095120226329165054426123619197051613839357326693760156914429944943744856809775696303129588719161129294681884936338647392747601226964158848900965717086160598147204467428664208765334799858222090619802173211614230419477754990738738567941189824660913091691772274207233367635032678340586301930193242996397204445179288122854478211953530898910125342975524727635730226281382091807439748671453590778633530160821559911314144205091447293535022230817193663509346865858656314855575862447818620108711889760652969899269328178705576435143382060141077329261063431525337182243385263520217735440715281898137698755157574546939727150488469793619500477720970561793913828989845327426227288647108883270173723258818244658436249580592560338105215606206155713299156084892064340303395262263451454283678698288074251422567451806184149564686111635404971897682154227722479474033571527436819409892050113653400123846714296551867344153741615042563256713430247655125219218035780169240326699541746087592409207004669340396510178134857835694440760470232540755557764728450751826890418293966113310160131119077398632462778219023650660374041606724962490137433217246454097412995570529142438208076098364823465973886691349919784013108015581343979194852830436739012482082444814128095443773898320059864909159505322857914576884962578665885999179867520554558099004556461178755249370124553217170194282884617402736649978475508294228020232901221630102309772151569446427909802190826689868834263071609207914085197695235553488657743425277531197247430873043619511396119080030255878387644206085044730631299277888942729189727169890575925244679660189707482960949190648764693702750773866432391919042254290235318923377293166736086996228032557185308919284403805071030064776847863243191000223929785255372375566213644740096760539439838235764606992465260089090624105904215453927904411529580345334500256244101006359530039598864466169595626351878060688513723462707997327233134693971456285542615467650632465676620279245208581347717608521691340946520307673391841147504140168924121319826881568664561485380287539331160232292555618941042995335640095786495340935115266454024418775949316930560448686420862757201172319526405023099774567647838488973464317215980626787671838005247696884084989185086149003432403476742686245952395890358582135006450998178244636087317754378859677672919526111213859194725451400301180503437875277664402762618941017576872680428176623860680477885242887430259145247073950546525135339459598789619778911041890292943818567205070964606263541732944649576612651953495701860015412623962286413897796733329070567376962156498184506842263690367849555970026079867996261019039331263768556968767029295371162528005543100786408728939225714512481135778627664902425161990277471090335933309304948380597856628844787441469841499067123764789582263294904679812089984857163571087831191848630254501620929805829208334813638405421720056121989353669371336733392464416125223196943471206417375491216357008573694397305979709719726666642267431117762176403068681310351899112271339724036887000996862922546465006385288620393800504778276912835603372548255793912985251506829969107754257647488325341412132800626717094009098223529657957997803018282428490221470748111124018607613415150387569830918652780658896682362523937845272634530420418802508442363190383318384550522367992357752929106925043261446950109861088899914658551881873582528164302520939285258077969737620845637482114433988162710031703151334402309526351929588680690821355853680161000213740851154484912685841268695899174149133820578492800698255195740201818105641297250836070356851055331787840829000041552511865779453963317538532092149720526607831260281961164858098684587525129997404092797683176639914655386108937587952214971731728131517932904431121815871023518740757222100123768721944747209349312324107065080618562372526732540733324875754482967573450019321902199119960797989373383673242576103938985349278777473980508080015544764061053522202325409443567718794565430406735896491017610775948364540823486130254718476485189575836674399791508512858020607820554462991723202028222914886959399729974297471155371858924238493855858595407438104882624648788053304271463011941589896328792678327322456103852197011130466587100500083285177311776489735230926661234588873102883515626446023671996644554727608310118788389151149340939344750073025855814756190881398752357812331342279866503522725367171230756861045004548970360079569827626392344107146584895780241408158405229536937499710665594894459246286619963556350652623405339439142111271810691052290024657423604130093691889255865784668461215679554256605416005071276641766056874274200329577160643448606201239821698271723197826816628249938714995449137302051843669076723577400053932662622760323659751718925901801104290384274185507894887438832703063283279963007200698012244365116394086922220745320244624121155804354542064215121585056896157356414313068883443185280853975927734433655384188340303517822946253702015782157373265523185763554098954033236382319219892171177449469403678296185920803403867575834111518824177439145077366384071880489358256868542011645031357633355509440319236720348651010561049872726472131986543435450409131859513145181276437310438972507004981987052176272494065214619959232142314439776546708351714749367986186552791715824080651063799500184295938799158350171580759883784962257398512129810326379376218322456594236685376799113140108043139732335449090824910499143325843298821033984698141715756010829706583065211347076803680695322971990599904451209087275776225351040902392888779424630483280319132710495478599180196967835321464441189260631526618167443193550817081875477050802654025294109218264858213857526688155584113198560022135158887210365696087515063187533002942118682221893775546027227291290504292259787710667873840000616772154638441292371193521828499824350920891801685572798156421858191197490985730570332667646460728757430565372602768982373259745084479649545648030771598153955827779139373601717422996027353102768719449444917939785144631597314435351850491413941557329382048542123508173912549749819308714396615132942045919380106231421774199184060180347949887691051557905554806953878540066453375981862846419905220452803306263695626490910827627115903856995051246529996062855443838330327638599800792922846659503551211245284087516229060262011857775313747949362055496401073001348853150735487353905602908933526400713274732621960311773433943673385759124508149335736911664541281788171454023054750667136518258284898099512139193995633241336556777098003081910272040997148687418134667006094051021462690280449159646545330107754695413088714165312544813061192407821188690056027781824235022696189344352547633573536485619363254417756613981703930632872166905722259745209192917262199844409646158269456380239502837121686446561785235565164127712826918688615572716201474934052276946595712198314943381622114006936307430444173284786101777743837977037231795255434107223445512555589998646183876764903972461167959018100035098928641204195163551108763204267612979826529425882951141275841262732790798807559751851576841264742209479721843309352972665210015662514552994745127631550917636730259462132930190402837954246323258550301096706922720227074863419005438302650681214142135057154175057508639907673946335146209082888934938376439399256900604067311422093312195936202982972351163259386772241477911629572780752395056251581603133359382311500518626890530658368129988108663263271980611271548858798093487912913707498230575929091862939195014721197586067270092547718025750337730799397134539532646195269996596385654917590458333585799102012713204583903200853878881633637685182083727885131175227769609787962142372162545214591281831798216044111311671406914827170981015457781939202311563871950805024679725792497605772625913328559726371211201905720771409148645074094926718035815157571514050397610963846755569298970383547314100223802583468767350129775413279532060971154506484212185936490997917766874774481882870632315515865032898164228288232746866106592732197907162384642153489852476216789050260998045266483929542357287343977680495774091449538391575565485459058976495198513801007958010783759945775299196700547602252552034453988712538780171960718164078124847847257912407824544361682345239570689514272269750431873633263011103053423335821609333191218806608268341428910415173247216053355849993224548730778822905252324234861531520976938461042582849714963475341837562003014915703279685301868631572488401526639835689563634657435321783493199825542117308467745297085839507616458229630324424328237737450517028560698067889521768198156710781633405266759539424926280756968326107495323390536223090807081455919837355377748742029039018142937311529334644468151212945097596534306284215319445727118614900017650558177095302468875263250119705209476159416768727784472000192789137251841622857783792284439084301181121496366424659033634194540657183544771912446621259392656620306888520055599121235363718226922531781458792593750441448933981608657900876165024635197045828895481793756681046474614105142498870252139936870509372305447734112641354892806841059107716677821238332810262185587751312721179344448201440425745083063944738363793906283008973306241380614589414227694747931665717623182472168350678076487573420491557628217583972975134478990696589532548940335615613167403276472469212505759116251529654568544633498114317670257295661844775487469378464233737238981920662048511894378868224807279352022501796545343757274163910791972952950812942922205347717304184477915673991738418311710362524395716152714669005814700002633010452643547865903290733205468338872078735444762647925297690170912007874183736735087713376977683496344252419949951388315074877537433849458259765560996555954318040920178497184685497370696212088524377013853757681416632722412634423982152941645378000492507262765150789085071265997036708726692764308377229685985169122305037462744310852934305273078865283977335246017463527703205938179125396915621063637625882937571373840754406468964783100704580613446731271591194608435935825987782835266531151065041623295329047772174083559349723758552138048305090009646676088301540612824308740645594431853413755220166305812111033453120745086824339432159043594430312431227471385842030390106070940315235556172767994160020393975099897629335325855575624808996691829864222677502360193257974726742578211119734709402357457222271212526852384295874273501563660093188045493338989741571490544182559738080871565281430102670460284316819230392535297795765862414392701549740879273131051636119137577008929564823323648298263024607975875767745377160102490804624301856524161756655600160859121534556267602192689982855377872583145144082654583484409478463178777374794653580169960779405568701192328608041130904629350871827125934668712766694873899824598527786499569165464029458935064964335809824765965165142090986755203808309203230487342703468288751604071546653834619611223013759451579252696743642531927390036038608236450762698827497618723575476762889950752114804852527950845033958570838130476937881321123674281319487950228066320170022460331989671970649163741175854851878484012054844672588851401562725019821719066960812627785485964818369621410721714214986361918774754509650308957099470934337856981674465828267911940611956037845397855839240761276344105766751024307559814552786167815949657062559755074306521085301597908073343736079432866757890533483669555486803913433720156498834220893399971641479746938696905480089193067138057171505857307148815649920714086758259602876056459782423770242469805328056632787041926768467116266879463486950464507420219373945259262668613552940624781361206202636498199999498405143868285258956342264328707663299304891723400725471764188685351372332667877921738347541480022803392997357936152412755829569276837231234798989446274330454566790062032420516396282588443085438307201495672106460533238537203143242112607424485845094580494081820927639140008540422023556260218564348994145439950410980591817948882628052066441086319001688568155169229486203010738897181007709290590480749092427141018933542818429995988169660993836961644381528877214085268088757488293258735809905670755817017949161906114001908553744882726200936685604475596557476485674008177381703307380305476973609786543859382187220583902344443508867499866506040645874346005331827436296177862518081893144363251205107094690813586440519229512932450078833398788429339342435126343365204385812912834345297308652909783300671261798130316794385535726296998740359570458452230856390098913179475948752126397078375944861139451960286751210561638976008880092746115860800207803341591451797073036835196977766076373785333012024120112046988609209339085365773222392412449051532780950955866459477634482269986074813297302630975028812103517723124465095349653693090018637764094094349837313251321862080214809922685502948454661814715557444709669530177690434272031892770604717784527939160472281534379803539679861424370956683221491465438014593829277393396032754048009552231816667380357183932757077142046723838624617803976292377131209580789363841447929802588065522129262093623930637313496640186619510811583471173312025805866727639992763579078063818813069156366274125431259589936119647626101405563503399523140323113819656236327198961837254845333702062563464223952766943568376761368711962921818754576081617053031590728828700712313666308722754918661395773730546065997437810987649802414011242142773668082751390959313404155826266789510846776118665957660165998178089414985754976284387856100263796543178313634025135814161151902096499133548733131115022700681930135929595971640197196053625033558479980963488718039111612813595968565478868325856437896173159762002419621552896297904819822199462269487137462444729093456470028537694958859591606789282491054412515996300781368367490209374915732896270028656829344431342347351239298259166739503425995868970697267332582735903121288746660451461487850346142827765991608090398652575717263081833494441820193533385071292345774375579344062178711330063106003324053991693682603746176638565758877580201229366353270267100681261825172914608202541892885935244491070138206211553827793565296914576502048643282865557934707209634807372692141186895467322767751335690190153723669036865389161291688887876407525493494249733427181178892759931596719354758988097924525262363659036320070854440784544797348291802082044926670634420437555325050527522833778887040804033531923407685630109347772125639088640413101073817853338316038135280828119040832564401842053746792992622037698718018061122624490909242641985820861751177113789051609140381575003366424156095216328197122335023167422600567941281406217219641842705784328959802882335059828208196666249035857789940333152274817776952843681630088531769694783690580671064828083598046698841098135158654906933319522394363287923990534810987830274500172065433699066117784554364687723631844464768069142828004551074686645392805399409108754939166095731619715033166968309929466349142798780842257220697148875580637480308862995118473187124777291910070227588893486939456289515802965372150409603107761289831263589964893410247036036645058687287589051406841238124247386385427908282733827973326885504935874303160274749063129572349742611221517417153133618622410913869500688835898962349276317316478340077460886655598733382113829928776911495492184192087771606068472874673681886167507221017261103830671787856694812948785048943063086169948798703160515884108282351274153538513365895332948629494495061868514779105804696039069372662670386512905201137810858616188886947957607413585534585151768051973334433495230120395770739623771316030242887200537320998253008977618973129817881944671731160647231476248457551928732782825127182446807824215216469567819294098238926284943760248852279003620219386696482215628093605373178040863727268426696421929946819214908701707533361094791381804063287387593848269535583077395761447997270003472880182785281389503217986345216111066608839314053226944905455527867894417579202440021450780192099804461382547805858048442416404775031536054906591430078158372430123137511562284015838644270890718284816757527123846782459534334449622010096071051370608461801187543120725491334994247617115633321408934609156561550600317384218701570226103101916603887064661438897736318780940711527528174689576401581047016965247557740891644568677717158500583269943401677202156767724068128366565264122982439465133197359199709403275938502669557470231813203243716420586141033606524536939160050644953060161267822648942437397166717661231048975031885732165554988342121802846912529086101485527815277625623750456375769497734336846015607727035509629049392487088406281067943622418704747008368842671022558302403599841645951122485272633632645114017395248086194635840783753556885622317115520947223065437092606797351000565549381224575483728545711797393615756167641692895805257297522338558611388322171107362265816218842443178857488798109026653793426664216990914056536432249301334867988154886628665052346997235574738424830590423677143278792316422403877764330192600192284778313837632536121025336935812624086866699738275977365682227907215832478888642369346396164363308730139814211430306008730666164803678984091335926293402304324974926887831643602681011309570716141912830686577323532639653677390317661361315965553584999398600565155921936759977717933019744688148371103206503693192894521402650915465184309936553493337183425298433679915939417466223900389527673813330617747629574943868716978453767219493506590875711917720875477107189937960894774512654757501871194870738736785890200617373321075693302216320628432065671192096950585761173961632326217708945426214609858410237813215817727602222738133495410481003073275107799948991977963883530734443457532975914263768405442264784216063122769646967156473999043715903323906560726644116438605404838847161912109008701019130726071044114143241976796828547885524779476481802959736049439700479596040292746299203572099761950140348315380947714601056333446998820822120587281510729182971211917876424880354672316916541852256729234429187128163232596965413548589577133208339911288775917226115273379010341362085614577992398778325083550730199818459025958355989260553299673770491722454935329683300002230181517226575787524058832249085821280089747909326100762578770428656006996176212176845478996440705066241710213327486796237430229155358200780141165348065647488230615003392068983794766255036549822805329662862117930628430170492402301985719978948836897183043805182174419147660429752437251683435411217038631379411422095295885798060152938752753799030938871683572095760715221900279379292786303637268765822681241993384808166021603722154710143007377537792699069587121289288019052031601285861825494413353820784883465311632650407642428390870121015194231961652268422003711230464300673442064747718021353070124098860353399152667923871101706221865883573781210935179775604425634694999787251125440854522274810914874307259869602040275941178942581281882159952359658979181144077653354321757595255536158128001163846720319346507296807990793963714961774312119402021297573125165253768017359101557338153772001952444543620071848475663415407442328621060997613243487548847434539665981338717466093020535070271952983943271425371155766600025784423031073429551533945060486222764966687624079324353192992639253731076892135352572321080889819339168668278948281170472624501948409700975760920983724090074717973340788141825195842598096241747610138252643955135259311885045636264188300338539652435997416931322894719878308427600401368074703904097238473945834896186539790594118599310356168436869219485382055780395773881360679549900085123259442529724486666766834641402189915944565309423440650667851948417766779470472041958822043295380326310537494883122180391279678446100139726753892195119117836587662528083690053249004597410947068772912328214304635337283519953648274325833119144459017809607782883583730111857543659958982724531925310588115026307542571493943024453931870179923608166611305426253995833897942971602070338767815033010280120095997252222280801423571094760351925544434929986767817891045559063015953809761875920358937341978962358931125983902598310267193304189215109689156225069659119828323455503059081730735195503721665870288053992138576037035377105178021280129566841984140362872725623214428754302210909472721073474134975514190737043318276626177275996888826027225247133683353452816692779591328861381766349857728936900965749562287103024362590772412219094300871755692625758065709912016659622436080242870024547362036394841255954881727272473653467783647201918303998717627037515724649922289467932322693619177641614618795613956699567783068290316589699430767333508234990790624100202506134057344300695745474682175690441651540636584680463692621274211075399042188716127617787014258864825775223889184599523376292377915585744549477361295525952226578636462118377598473700347971408206994145580719080213590732269233100831759510659019121294795408603640757358750205890208704579670007055262505811420663907459215273309406823649441590891009220296680523325266198911311842016291631076894084723564366808182168657219688268358402785500782804043453710183651096951782335743030504852653738073531074185917705610397395062640355442275156101107261779370634723804990666922161971194259120445084641746383589938239946517395509000859479990136026674261494290066467115067175422177038774507673563742154782905911012619157555870238957001405117822646989944917908301795475876760168094100135837613578591356924455647764464178667115391951357696104864922490083446715486383054477914330097680486878348184672733758436892724310447406807685278625585165092088263813233623148733336714764520450876627614950389949504809560460989604329123358348859990294526400284994280878624039811814884767301216754161106629995553668193123287425702063738352020086863691311733469731741219153633246745325630871347302792174956227014687325867891734558379964351358800959350877556356248810493852999007675135513527792412429277488565888566513247302514710210575352516511814850902750476845518252096331899068527614435138213662152368890578786699432288816028377482035506016029894009119713850179871683633744139275973644017007014763706655703504338121113576415018451821413619823495159601064752712575935185304332875537783057509567425442684712219618709178560783936144511383335649103256405733898667178123972237519316430617013859539474367843392670986712452211189690840236327411496601243483098929941738030588417166613073040067588380432111555379440605497721705942821514886165672771240903387727745629097110134885184374118695655449745736845218066982911045058004299887953899027804383596282409421860556287788428802127553884803728640019441614257499904272009595204654170598104989967504511936471172772220436102614079750809686975176600237187748348016120310234680567112644766123747627852190241202569943534716226660893675219833111813511146503854895025120655772636145473604426859498074396932331297127377157347099713952291182653485155587137336629120242714302503763269501350911612952993785864681307226486008270881333538193703682598867893321238327053297625857382790097826460545598555131836688844628265133798491667839409761353766251798258249663458771950124384040359140849209733754642474488176184070023569580177410177696925077814893386672557898564589851056891960924398841569280696983352240225634570497312245269354193837004843183357196516626721575524193401933099018319309196582920969656247667683659647019595754739345514337413708761517323677204227385674279170698204549953095918872434939524094441678998846319845504852393662972079777452814399418256789457795712552426826089940863317371538896262889629402112108884427376568624527612130371017300785135715404533041507959447776143597437803742436646973247138410492124314138903579092416036406314038149831481905251720937103964026808994832572297954564042701757722904173234796073618787889913318305843069394825961318713816423467218730845133877219086975104942843769325024981656673816260615941768252509993741672883951744066932549653403101452225316189009235376486378482881344209870048096227171226407489571939002918573307460104360729190945767994614929290427981687729426487729952858434647775386906950148984133924540394144680263625402118614317031251117577642829914644533408920976961699098372652361768745605894704968170136974909523072082682887890730190018253425805343421705928713931737993142410852647390948284596418093614138475831136130576108462366837237695913492615824516221552134879244145041756848064120636520170386330129532777699023118648020067556905682295016354931992305914246396217025329747573114094220180199368035026495636955866425906762685687372110339156793839895765565193177883000241613539562437777840801748819373095020699900890899328088397430367736595524891300156633294077907139615464534088791510300651321934486673248275907946807879819425019582622320395131252014109960531260696555404248670549986786923021746989009547850725672978794769888831093487464426400718183160331655511534276155622405474473378049246214952133258527698847336269182649174338987824789278468918828054669982303689939783413747587025805716349413568433929396068192061773331791738208562436433635359863494496890781064019674074436583667071586924521182997893804077137501290858646578905771426833582768978554717687184427726120509266486102051535642840632368481807287940717127966820060727559555904040233178749447346454760628189541512139162918444297651066947969354016866010055196077687335396511614930937570968554559381513789569039251014953265628147011998326992200066392875374713135236421589265126204072887716578358405219646054105435443642166562244565042999010256586927279142752931172082793937751326106052881235373451068372939893580871243869385934389175713376300720319760816604464683937725806909237297523486702916910426369262090199605204121024077648190316014085863558427609537086558164273995349346546314504040199528537252004957805254656251154109252437991326262713609099402902262062836752132305065183934057450112099341464918433323646569371725914489324159006242020612885732926133596808726500045628284557574596592120530341310111827501306961509835515632004310784601906565493806542525229161991819959602752327702249855738824899882707465936355768582560518068964285376850772012220347920993936179268206590142165615925306737944568949070853263568196831861772268249911472615732035807646298116244013316737892788689229032593349861797021994981925739617673075834417098559222170171825712777534491508205278430904619460835217402005838672849709411023266953921445461066215006410674740207009189911951376466904481267253691537162290791385403937560077835153374167747942100384002308951850994548779039346122220865060160500351776264831611153325587705073541279249909859373473787081194253055121436979749914951860535920403830235716352727630874693219622190064260886183676103346002255477477813641012691906569686495012688376296907233961276287223041141813610060264044030035996988919945827397624114613744804059697062576764723766065541618574690527229238228275186799156983390747671146103022776606020061246876477728819096791613354019881402757992174167678799231603963569492851513633647219540611171767387372555728522940054361785176502307544693869307873499110352182532929726044553210797887711449898870911511237250604238753734841257086064069052058452122754533848008205302450456517669518576913200042816758054924811780519832646032445792829730129105318385636821206215531288668564956512613892261367064093953334570526986959692350353094224543865278677673027540402702246384483553239914751363441044050092330361271496081355490531539021002299595756583705381261965683144286057956696622154721695620870013727768536960840704833325132793112232507148630206951245395003735723346807094656483089209801534878705633491092366057554050864111521441481434630437273271045027768661953107858323334857840297160925215326092558932655600672124359464255065996771770388445396181632879614460817789272171836908880126778207430106422524634807454300476492885553409062185153654355474125476152769772667769772777058315801412185688011705028365275543214803488004442979998062157904564161957212784508928489806426497427090579129069217807298769477975112447305991406050629946894280931034216416629935614828130998870745292716048433630818404126469637925843094185442216359084576146078558562473814931427078266215185541603870206876980461747400808324343665382354555109449498431093494759944672673665352517662706772194183191977196378015702169933675083760057163454643671776723387588643405644871566964321041282595645349841388412890420682047007615596916843038999348366793542549210328113363184722592305554383058206941675629992013373175489122037230349072681068534454035993561823576312837767640631013125335212141994611869350833176587852047112364331226765129964171325217513553261867681942338790365468908001827135283584888444111761234101179918709236507184857856221021104009776994453121795022479578069506532965940383987369907240797679040826794007618729547835963492793904576973661643405359792219285870574957481696694062334272619733518136626063735982575552496509807260123668283605928341855848026958413772558970883789942910549800331113884603401939166122186696058491571485733568286149500019097591125218800396419762163559375743718011480559442298730418196808085647265713547612831629200449880315402105530597076666362749328308916880932359290081787411985738317192616728834918402429721290434965526942726402559641463525914348400675867690350382320572934132981593533044446496829441367323442158380761694831219333119819061096142952201536170298575105594326461468505452684975764807808009221335811378197749271768545075538328768874474591593731162470601091244609829424841287520224462594477638749491997840446829257360968534549843266536862844489365704111817793806441616531223600214918768769467398407517176307516849856359201486892943105940202457969622924566644881967576294349535326382171613395757790766370764569570259738800438415805894336137106551859987600754924187211714889295221737721146081154344982665479872580056674724051122007383459271575727715218589946948117940644466399432370044291140747218180224825837736017346685300744985564715420036123593397312914458591522887408719508708632218837288262822884631843717261903305777147651564143822306791847386039147683108141358275755853643597721650028277803713422869688787349795096031108899196143386664068450697420787700280509367203387232629637856038653216432348815557557018469089074647879122436375556668678067610544955017260791142930831285761254481944449473244819093795369008206384631678225064809531810406570254327604385703505922818919878065865412184299217273720955103242251079718077833042609086794273428955735559252723805511440438001239041687716445180226491681641927401106451622431101700056691121733189423400547959684669804298017362570406733282129962153684881404102194463424646220745575643960452985313071409084608499653767803793201899140865814662175319337665970114330608625009829566917638846056762972931464911493704624469351984039534449135141193667933301936617663652555149174982307987072280860859626112660504289296966535652516688885572112276802772743708917389639772257564890533401038855931125679991516589025016486961427207005916056166159702451989051832969278935550303934681219761582183980483960562523091462638447386296039848924386187298507775928792722068554807210497817653286210187476766897248841139560349480376727036316921007350834073865261684507482496448597428134936480372426116704266870831925040997615319076855770327421785010006441984124207396400139603601583810565928413684574119102736420274163723488214524101347716529603128408658419787951116511529827814620379139855006399960326591248525308493690313130100799977191362230866011099929142871249388541612038020411340188887219693477904497527454288072803509305828754420755134816660927879353566521255620139988249628478726214432362853676502591450468377635282587652139156480972141929675549384375582600253168536356731379262475878049445944183429172756988376226261846365452743497662411138451305481449836311789784489732076719508784158618879692955819733250699951402601511675529750575437810242238957925786562128432731202200716730574069286869363930186765958251326499145950260917069347519408975357464016830811798846452473618956056479426358070562563281189269663026479535951097127659136233180866921535788607812759910537171402204506186075374866306350591483916467656723205714516886170790984695932236724946737583099607042589220481550799132752088583781117685214269334786921895240622657921043620348852926267984013953216458791151579050460579710838983371864038024417511347226472547010794793996953554669619726763255229914654933499663234185951450360980344092212206712567698723427940708857070474293173329188523896721971353924492426178641188637790962814486917869468177591717150669111480020759432012061969637795103227089029566085562225452602610460736131368869009281721068198618553780982018471154163630326265699283424155023600978046417108525537612728905335045506135684143775854429677977014660294387687225115363801191758154028120818255606485410787933598921064427244898618961629413418001295130683638609294100083136673372153008352696235737175330738653338204842190308186449184093723944033405244909554558016406460761581010301767488475017661908692946098769201691202181688291040870709560951470416921147027413390052253340834812870353031023919699978597413908593605433599697075604460134242453682496098772581311024732798562072126572499003468293886872304895562253204463602639854225258416464324271611419817802482595563544907219226583863662663750835944314877635156145710745528016159677048442714194435183275698407552677926411261765250615965235457187956673170913319358761628255920783080185206890151504713340386100310055914817852110384754542933389188444120517943969970194112695119526564919594189975418393234647424290702718875223534393673633663200307232747037407123982562024662651974090199762452056198557625760008708173083288344381831070054514493545885422678578551915372292379555494333410174420169600090696415612732297770221217951868376359082255128816470021992348864043959153018464004714321186360622527011541122283802778538911098490201342741014121559769965438877197485376431158229838533123071751132961904559007938064276695819014842627991221792947987348901868471676503827328552059082984529806259250352128451925927986593506132961946796252373972565584157853744567558998032405492186962888490332560851455344391660226257775512916200772796852629387937530454181080729285891989715381797343496187232927614747850192611450413274873242970583408471112333746274617274626582415324271059322506255302314738759251724787322881491455915605036334575424233779160374952502493022351481961381162563911415610326844958072508273431765944054098269765269344579863479709743124498271933113863873159636361218623497261409556079920628316999420072054811525353393946076850019909886553861433495781650089961649079678142901148387645682174914075623767618453775144031475411206760160726460556859257799322070337333398916369504346690694828436629980037414527627716547623825546170883189810868806847853705536480469350958818025360529740793538676511195079373282083146268960071075175520614433784114549950136432446328193346389050936545714506900864483440180428363390513578157273973334537284263372174065775771079830517555721036795976901889958494130195999573017901240193908681356585539661941371794487632079868800371607303220547423572266896801882123424391885984168972277652194032493227314793669234004848976059037958094696041754279613782553781223947646147832926976545162290281701100437846038756544151739433960048915318817576650500951697402415644771293656614253949368884230517400129920556854289853897942669956777027089146513736892206104415481662156804219838476730871787590279209175900695273456682026513373111518000181434120962601658629821076663523361774007837783423709152644063054071807843358061072961105550020415131696373046849213356837265400307509829089364612047891114753037049893952833457824082817386441322710002968311940203323456420826473276233830294639378998375836554559919340866235090967961134004867027123176526663710778725111860354037554487418693519733656621772359229396776463251562023487570113795712096237723431370212031004965152111976013176419408203437348512852602913334915125083119802850177855710725373149139215709105130965059885999931560863655477403551898166733535880048214665099741433761182777723351910741217572841592580872591315074606025634903777263373914461377038021318347447301113032670296917335047701632106616227830027269283365584011791419447808748253360714403296252285775009808599609040936312635621328162071453406104224112083010008587264252112262480142647519426184325853386753874054743491072710049754281159466017136122590440158991600229827801796035194080046513534752698777609527839984368086908989197839693532179980139135442552717910225397010810632143048511378291498511381969143043497500189980681644412123273328307192824362406733196554692677851193152775113446468905504248113361434984604849051258345683266441528489713972376040328212660253516693914082049947320486021627759791771234751097502403078935759937715095021751693555827072533911892334070223832077585802137174778378778391015234132098489423459613692340497998279304144463162707214796117456975719681239291913740982925805561955207434243295982898980529233366415419256367380689494201471241340525072204061794355252555225008748790086568314542835167750542294803274783044056438581591952666758282929705226127628711040134801787224801789684052407924360582742467443076721645270313451354167649668901274786801010295133862698649748212118629040337691568576240699296372493097201628707200189835423690364149270236961938547372480329855045112089192879829874467864129159417531675602533435310626745254507114181483239880607297140234725520713490798398982355268723950909365667878992383712578976248755990443228895388377317348941122757071410959790047919301046740750411435381782464630795989555638991884773781341347070246747362112048986226991888517456251732519341352038115863350123913054441910073628447567514161050410973505852762044489190978901984315485280533985777844313933883994310444465669244550885946314081751220331390681596592510546858013133838152176418210433429788826119630443111388796258746090226130900849975430395771243230616906262919403921439740270894777663702488155499322458825979020631257436910946393252806241642476868495455324938017639371615636847859823715902385421265840615367228607131702674740131145261063765383390315921943469817605358380310612887852051546933639241088467632009567089718367490578163085158138161966882222047570437590614338040725853862083565176998426774523195824182683698270160237414938363496629351576854061397342746470899685618170160551104880971554859118617189668025973541705423985135560018720335079060946421271143993196046527424050882225359773481519135438571253258540493946010865793798058620143366078825219717809025817370870916460452727977153509910340736425020386386718220522879694458387652947951048660717390229327455426785669776865939923416834122274663015062155320502655341460995249356050854921756549134830958906536175693817637473644183378974229700703545206663170929607591989627732423090252397443861014263098687733913882518684316501027964911497737582888913450341148865948670215492101084328080783428089417298008983297536940644969903125399863919581601468995220880662285408414864274786281975546629278814621607171381880180840572084715868906836919393381864278454537956719272397972364651667592011057995663962598535512763558768140213409829016296873429850792471846056874828331381259161962476156902875901072733103299140623864608333378638257926302391590003557609032477281338887339178096966601469615031754226751125993315529674213336300222964906480934582008181061802100227664580400278213336758573019011371754672763059044353131319036092489097246427928455549913490005180295707082919052556781889913899625138662319380053611346224294610248954072404857123256628888931722116432947816190554868054943441034090680716088028227959686950133643814268252170472870863010137301155236861416908375675747637239763185757038109443390564564468524183028148107998376918512127201935044041804604721626939445788377090105974693219720558114078775989772072009689382249303236830515862657281114637996983137517937623215111252349734305240622105244234353732905655163406669506165892878218707756794176080712973781335187117931650033155523822487730653444179453415395202424449703410120874072188109388268167512042299404948179449472732894770111574139441228455521828424922240658752689172272780607116754046973008037039618787796694882555614674384392570115829546661358678671897661297311267200072971553613027503556167817765442287442114729881614802705243806817653573275578602505847084013208837932816008769081300492491473682517035382219619039014999523495387105997351143478292339499187936608692301375596368532373806703591144243268561512109404259582639301678017128669239283231057658851714020211196957064799814031505633045141564414623163763809904402816256917576489142569714163598439317433270237812336938043012892626375382667795034169334323607500248175741808750388475094939454896209740485442635637164995949920980884294790363666297526003243856352945844728944547166209297495496616877414120882130477022816116456044007236351581149729739218966737382647204722642221242016560150284971306332795814302516013694825567014780935790889657134926158161346901806965089556310121218491805847922720691871696316330044858020102860657858591269974637661741463934159569539554203314628026518951167938074573315759846086173702687867602943677780500244673391332431669880354073232388281847501051641331189537036488422690270478052742490603492082954755054003457160184072574536938145531175354210726557835615499874447480427323457880061873149341566046352979779455075359304795687209316724536547208381685855606043801977030764246083489876101345709394877002946175792061952549255757109038525171488525265671045349813419803390641529876343695420256080277614421914318921393908834543131769685101840103844472348948869520981943531906506555354617335814045544837884752526253949665869992058417652780125341033896469818642430034146791380619028059607854888010789705516946215228773090104467462497979992627120951684779568482583341402266477210843362437593741610536734041954738964197895425335036301861400951534766961476255651873823292468547356935802896011536791787303553159378363082248615177770541577576561759358512016692943111138863582159667618830326104164651714846979385422621687161400122378213779774131268977266712992025922017408770076956283473932201088159356286281928563571893384958850603853158179760679479840878360975960149733420572704603521790605647603285569276273495182203236144112584182426247712012035776388895974318232827871314608053533574494297621796789034568169889553518504478325616380709476951699086247100019748809205009521943632378719764870339223811540363475488626845956159755193765410115014067001226927474393888589943859730245414801061235908036274585288493563251585384383242493252666087588908318700709100237377106576985056433928854337658342596750653715005333514489908293887737352051459333049626531415141386124437935885070944688045486975358170212908490787347806814366323322819415827345671356443171537967818058195852464840084032909981943781718177302317003989733050495387356116261023999433259780126893432605584710278764901070923443884634011735556865903585244919370181041626208504299258697435817098133894045934471937493877624232409852832762266604942385129709453245586252103600829286649724174919141988966129558076770979594795306013119159011773943104209049079424448868513086844493705909026006120649425744710353547657859242708130410618546219881830090634588187038755856274911587375421064667951346487586771543838018521348281915812462599335160198935595167968932852205824799421034512715877163345222995418839680448835529753361286837225935390079201666941339091168758803988828869216002373257361588207163516271332810518187602104852180675526648673908900907195138058626735124312215691637902277328705410842037841525683288718046987952513073266340278519059417338920358540395677035611329354482585628287610610698229721420961993509331312171187891078766872044548876089410174798647137882462153955933333275562009439580434537919782280590395959927436913793778664940964048777841748336432684026282932406260081908081804390914556351936856063045089142289645219987798849347477729132797266027658401667890136490508741142126861969862044126965282981087045479861559545338021201155646979976785738920186243599326777689454060508218838227909833627167124490026761178498264377033002081844590009717235204331994708242098771514449751017055643029542821819670009202515615844174205933658148134902693111517093872260026458630561325605792560927332265579346280805683443921373688405650434307396574061017779370141424615493070741360805442100295600095663588977899267630517718781943706761498217564186590116160865408635391513039201316805769034172596453692350806417446562351523929050409479953184074862151210561833854566176652606393713658802521666223576132201941701372664966073252010771947931265282763302413805164907174565964853748354669194523580315301969160480994606814904037819829732360930087135760798621425422096419004367905479049930078372421581954535418371129368658430553842717628035279128821129308351575656599944741788438381565148434229858704245592434693295232821803508333726283791830216591836181554217157448465778420134329982594566884558266171979012180849480332448787258183774805522268151011371745368417870280274452442905474518234674919564188551244421337783521423865979925988203287085109338386829906571994614906290257427686038850511032638544540419184958866538545040571323629681069146814847869659166861842756798460041868762298055562963045953227923051616721591968675849523635298935788507746081537321454642984792310511676357749494622952569497660359473962430995343310404994209677883827002714478494069037073249106444151696053256560586778757417472110827435774315194060757983563629143326397812218946287447798119807225646714664054850131009656786314880090303749338875364183165134982546694673316118123364854397649325026179549357204305402182974871251107404011611405899911093062492312813116340549262571356721818628932786138833718028535056503591952741400869510926167541476792668032109237467087213606278332922386413619594121339278036118276324106004740971111048140003623342714514483334641675466354699731494756643423659493496845884551524150756376605086632827424794136062876041290644913828519456402643153225858624043141838669590633245063000392213192647625962691510904457695301444054618037857503036686212462278639752746667870121003392984873375014475600322100622358029343774955032037012738468163061026570300872275462966796880890587127676361066225722352229739206443093524327228100859973095132528630601105497915644791845004618046762408928925680912930592960642357021061524646205023248966593987324933967376952023991760898474571843531936646529125848064480196520162838795189499336759241485626136995945307287254532463291529110128763770605570609531377527751867923292134955245133089867969165129073841302167573238637575820080363575728002754490327953079900799442541108725693188014667935595834676432868876966610097395749967836593397846346959948950610490383647409504695226063858046758073069912290474089879166872117147527644711604401952718169508289733537148530928937046384420893299771125856840846608339934045689026787516008775461267988015465856522061210953490796707365539702576199431376639960606061106406959330828171876426043573425361756943784848495250108266488395159700490598380812105221111091943323951136051446459834210799058082093716464523127704023160072138543723461267260997870385657091998507595634613248460188409850194287687902268734556500519121546544063829253851276317663922050938345204300773017029940362615434001322763910912988327863920412300445551684054889809080779174636092439334912641164240093880746356607262336695842764583698268734815881961058571835767462009650526065929263548291499045768307210893245857073701660717398194485028842603963660746031184786225831056580870870305567595861341700745402965687634774176431051751036732869245558582082372038601781739405175130437994868822320044378043103170921034261674998000073016094814586374488778522273076330495383944345382770608760763542098445008306247630253572781032783461766970544287155315340016497076657195985041748199087201490875686037783591994719343352772947285537925787684832301101859365800717291186967617655053775030293033830706448912811412025506150896411007623824574488655182581058140345320124754723269087547507078577659732542844459353044992070014538748948226556442223696365544194225441338212225477497535494624827680533336983284156138692363443358553868471111430498248398991803165458638289353799130535222833430137953372954016257623228081138499491876144141322933767106563492528814528239506209022357876684650116660097382753660405446941653422239052108314585847035529352219928272760574821266065291385530345549744551470344939486863429459658431024190785923680224560763936784166270518555178702904073557304620639692453307795782245949710420188043000183881429008173039450507342787013124466860092778581811040911511729374873627887874907465285565434748886831064110051023020875107768918781525622735251550379532444857787277617001964853703555167655209119339343762866284619844026295252183678522367475108809781507098978413086245881522660963551401874495836926917799047120726494905737264286005211403581231076006699518536124862746756375896225299116496066876508261734178484789337295056739007878617925351440621045366250640463728815698232317500596261080921955211150859302955654967538862612972339914628358476048627627027309739202001432248707582337354915246085608210328882974183906478869923273691360048837436615223517058437705545210815513361262142911815615301758882573594892507108879262128641392443309383797333867806131795237315266773820858024701433527009243803266951742119507670884326346442749127558907746863582162166042741315170212458586056233631493164646913946562497471741958354218607748711057338458433689939645913740603382159352243594751626239188685307822821763983237306180204246560477527943104796189724299533029792497481684052893791044947004590864991872727345413508101983881864673609392571930511968645601855782450218231065889437986522432050677379966196955472440585922417953006820451795370043472451762893566770508490213107736625751697335527462302943031203596260953423574397249659211010657817826108745318874803187430823573699195156340957162700992444929749105489851519658664740148225106335367949737142510229341882585117371994499115097583746130105505064197721531929354875371191630262030328588658528480193509225875775597425276584011721342323648084027143356367542046375182552524944329657043861387865901965738802868401894087672816714137033661732650120578653915780703088714261519075001492576112927675193096728453971160213606303090542243966320674323582797889332324405779199278484633339777737655901870574806828678347965624146102899508487399692970750432753029972872297327934442988646412725348160603779707298299173029296308695801996312413304939350493325412355071054461182591141116454534710329881047844067780138077131465400099386306481266614330858206811395838319169545558259426895769841428893743467084107946318932539106963955780706021245974898293564613560788983472419979478564362042094613412387613198865352358312996862268948608408456655606876954501274486631405054735351746873009806322780468912246821460806727627708402402266155485024008952891657117617439020337584877842911289623247059191874691042005848326140677333751027195653994697162517248312230633919328707983800748485726516123434933273356664473358556430235280883924348278760886164943289399166399210488307847777048045728491456303353265070029588906265915498509407972767567129795010098229476228961891591441520032283878773485130979081019129267227103778898053964156362364169154985768408398468861684375407065121039062506128107663799047908879674778069738473170475253442156390387201238806323688037017949308954900776331523063548374256816653361606641980030188287123767481898330246836371488309259283375902278942588060087286038859168849730693948020511221766359138251524278670094406942355120201568377778851824670025651708509249623747726813694284350062938814429987905301056217375459182679973217735029368928065210025396268807498092643458011655715886700443503976505323478287327368840863540002740676783821963522226539290939807367391364082898722017776747168118195856133721583119054682936083236976113450281757830202934845982925000895682630271263295866292147653142233351793093387951357095346377183684092444422096319331295620305575517340067973740614162107923633423805646850092037167152642556371853889571416419772387422610596667396997173168169415435095283193556417705668622215217991151355639707143312893657553844648326201206424338016955862698561022460646069330793847858814367407000599769703649019273328826135329363112403650698652160638987250267238087403396744397830258296894256896741864336134979475245526291426522842419243083388103580053787023999542172113686550275341362211693140694669513186928102574795985605145005021715913317751609957865551981886193211282110709442287240442481153406055895958355815232012184605820563592699303478851132068626627588771446035996656108430725696500563064489187599466596772847171539573612108180841547273142661748933134174632662354222072600146012701206934639520564445543291662986660783089068118790090815295063626782075614388815781351134695366303878412092346942868730839320432333872775496805210302821544324723388845215343727250128589747691460808314404125868181540049187772287869801853454537006526655649170915429522756709222217474112062720656622989806032891672068743654948246108697367225547404812889242471854323605753411672850757552057131156697954584887398742228135887985840783135060548290551482785294891121905383195624228719484759407859398047901094194070671764439032730712135887385049993638838205501683402777496070276844880281912220636888636811043569529300652195528261526991271637277388418993287130563464688227398288763198645709836308917786487086676185485680047672552675414742851028145807403152992197814557756843681110185317498167016426647884090262682824448258027532094549915104518517716546311804904567985713257528117913656278158111288816562285876030875974963849435275676612168959261485030785362045274507752950631012480341804584059432926079854435620093708091821523920371790678121992280496069738238743312626730306795943960954957189577217915597300588693646845576676092450906088202212235719254536715191834872587423919410890444115959932760044506556206461164655665487594247369252336955993030355095817626176231849561906494839673002037763874369343999829430209147073618947932692762445186560239559053705128978163455423320114975994896278424327483788032701418676952621180975006405149755889650293004867605208010491537885413909424531691719987628941277221129464568294860281493181560249677887949813777216229359437811004448060797672429276249510784153446429150842764520002042769470698041775832209097020291657347251582904630910359037842977572651720877244740952267166306005469716387943171196873484688738186656751279298575016363411314627530499019135646823804329970695770150789337728658035712790913767420805655493624646 diff --git a/vendor/github.com/klauspost/cpuid/LICENSE b/vendor/github.com/klauspost/cpuid/LICENSE new file mode 100644 index 0000000..5cec7ee --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Klaus Post + +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/klauspost/cpuid/README.md b/vendor/github.com/klauspost/cpuid/README.md new file mode 100644 index 0000000..b2b6bee --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/README.md @@ -0,0 +1,145 @@ +# cpuid +Package cpuid provides information about the CPU running the current program. + +CPU features are detected on startup, and kept for fast access through the life of the application. +Currently x86 / x64 (AMD64) is supported, and no external C (cgo) code is used, which should make the library very easy to use. + +You can access the CPU information by accessing the shared CPU variable of the cpuid library. + +Package home: https://github.com/klauspost/cpuid + +[![GoDoc][1]][2] [![Build Status][3]][4] + +[1]: https://godoc.org/github.com/klauspost/cpuid?status.svg +[2]: https://godoc.org/github.com/klauspost/cpuid +[3]: https://travis-ci.org/klauspost/cpuid.svg +[4]: https://travis-ci.org/klauspost/cpuid + +# features +## CPU Instructions +* **CMOV** (i686 CMOV) +* **NX** (NX (No-Execute) bit) +* **AMD3DNOW** (AMD 3DNOW) +* **AMD3DNOWEXT** (AMD 3DNowExt) +* **MMX** (standard MMX) +* **MMXEXT** (SSE integer functions or AMD MMX ext) +* **SSE** (SSE functions) +* **SSE2** (P4 SSE functions) +* **SSE3** (Prescott SSE3 functions) +* **SSSE3** (Conroe SSSE3 functions) +* **SSE4** (Penryn SSE4.1 functions) +* **SSE4A** (AMD Barcelona microarchitecture SSE4a instructions) +* **SSE42** (Nehalem SSE4.2 functions) +* **AVX** (AVX functions) +* **AVX2** (AVX2 functions) +* **FMA3** (Intel FMA 3) +* **FMA4** (Bulldozer FMA4 functions) +* **XOP** (Bulldozer XOP functions) +* **F16C** (Half-precision floating-point conversion) +* **BMI1** (Bit Manipulation Instruction Set 1) +* **BMI2** (Bit Manipulation Instruction Set 2) +* **TBM** (AMD Trailing Bit Manipulation) +* **LZCNT** (LZCNT instruction) +* **POPCNT** (POPCNT instruction) +* **AESNI** (Advanced Encryption Standard New Instructions) +* **CLMUL** (Carry-less Multiplication) +* **HTT** (Hyperthreading (enabled)) +* **HLE** (Hardware Lock Elision) +* **RTM** (Restricted Transactional Memory) +* **RDRAND** (RDRAND instruction is available) +* **RDSEED** (RDSEED instruction is available) +* **ADX** (Intel ADX (Multi-Precision Add-Carry Instruction Extensions)) +* **SHA** (Intel SHA Extensions) +* **AVX512F** (AVX-512 Foundation) +* **AVX512DQ** (AVX-512 Doubleword and Quadword Instructions) +* **AVX512IFMA** (AVX-512 Integer Fused Multiply-Add Instructions) +* **AVX512PF** (AVX-512 Prefetch Instructions) +* **AVX512ER** (AVX-512 Exponential and Reciprocal Instructions) +* **AVX512CD** (AVX-512 Conflict Detection Instructions) +* **AVX512BW** (AVX-512 Byte and Word Instructions) +* **AVX512VL** (AVX-512 Vector Length Extensions) +* **AVX512VBMI** (AVX-512 Vector Bit Manipulation Instructions) +* **MPX** (Intel MPX (Memory Protection Extensions)) +* **ERMS** (Enhanced REP MOVSB/STOSB) +* **RDTSCP** (RDTSCP Instruction) +* **CX16** (CMPXCHG16B Instruction) +* **SGX** (Software Guard Extensions, with activation details) + +## Performance +* **RDTSCP()** Returns current cycle count. Can be used for benchmarking. +* **SSE2SLOW** (SSE2 is supported, but usually not faster) +* **SSE3SLOW** (SSE3 is supported, but usually not faster) +* **ATOM** (Atom processor, some SSSE3 instructions are slower) +* **Cache line** (Probable size of a cache line). +* **L1, L2, L3 Cache size** on newer Intel/AMD CPUs. + +## Cpu Vendor/VM +* **Intel** +* **AMD** +* **VIA** +* **Transmeta** +* **NSC** +* **KVM** (Kernel-based Virtual Machine) +* **MSVM** (Microsoft Hyper-V or Windows Virtual PC) +* **VMware** +* **XenHVM** + +# installing + +```go get github.com/klauspost/cpuid``` + +# example + +```Go +package main + +import ( + "fmt" + "github.com/klauspost/cpuid" +) + +func main() { + // Print basic CPU information: + fmt.Println("Name:", cpuid.CPU.BrandName) + fmt.Println("PhysicalCores:", cpuid.CPU.PhysicalCores) + fmt.Println("ThreadsPerCore:", cpuid.CPU.ThreadsPerCore) + fmt.Println("LogicalCores:", cpuid.CPU.LogicalCores) + fmt.Println("Family", cpuid.CPU.Family, "Model:", cpuid.CPU.Model) + fmt.Println("Features:", cpuid.CPU.Features) + fmt.Println("Cacheline bytes:", cpuid.CPU.CacheLine) + fmt.Println("L1 Data Cache:", cpuid.CPU.Cache.L1D, "bytes") + fmt.Println("L1 Instruction Cache:", cpuid.CPU.Cache.L1D, "bytes") + fmt.Println("L2 Cache:", cpuid.CPU.Cache.L2, "bytes") + fmt.Println("L3 Cache:", cpuid.CPU.Cache.L3, "bytes") + + // Test if we have a specific feature: + if cpuid.CPU.SSE() { + fmt.Println("We have Streaming SIMD Extensions") + } +} +``` + +Sample output: +``` +>go run main.go +Name: Intel(R) Core(TM) i5-2540M CPU @ 2.60GHz +PhysicalCores: 2 +ThreadsPerCore: 2 +LogicalCores: 4 +Family 6 Model: 42 +Features: CMOV,MMX,MMXEXT,SSE,SSE2,SSE3,SSSE3,SSE4.1,SSE4.2,AVX,AESNI,CLMUL +Cacheline bytes: 64 +We have Streaming SIMD Extensions +``` + +# private package + +In the "private" folder you can find an autogenerated version of the library you can include in your own packages. + +For this purpose all exports are removed, and functions and constants are lowercased. + +This is not a recommended way of using the library, but provided for convenience, if it is difficult for you to use external packages. + +# license + +This code is published under an MIT license. See LICENSE file for more information. diff --git a/vendor/github.com/klauspost/cpuid/cpuid.go b/vendor/github.com/klauspost/cpuid/cpuid.go new file mode 100644 index 0000000..9230ca5 --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/cpuid.go @@ -0,0 +1,1022 @@ +// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. + +// Package cpuid provides information about the CPU running the current program. +// +// CPU features are detected on startup, and kept for fast access through the life of the application. +// Currently x86 / x64 (AMD64) is supported. +// +// You can access the CPU information by accessing the shared CPU variable of the cpuid library. +// +// Package home: https://github.com/klauspost/cpuid +package cpuid + +import "strings" + +// Vendor is a representation of a CPU vendor. +type Vendor int + +const ( + Other Vendor = iota + Intel + AMD + VIA + Transmeta + NSC + KVM // Kernel-based Virtual Machine + MSVM // Microsoft Hyper-V or Windows Virtual PC + VMware + XenHVM +) + +const ( + CMOV = 1 << iota // i686 CMOV + NX // NX (No-Execute) bit + AMD3DNOW // AMD 3DNOW + AMD3DNOWEXT // AMD 3DNowExt + MMX // standard MMX + MMXEXT // SSE integer functions or AMD MMX ext + SSE // SSE functions + SSE2 // P4 SSE functions + SSE3 // Prescott SSE3 functions + SSSE3 // Conroe SSSE3 functions + SSE4 // Penryn SSE4.1 functions + SSE4A // AMD Barcelona microarchitecture SSE4a instructions + SSE42 // Nehalem SSE4.2 functions + AVX // AVX functions + AVX2 // AVX2 functions + FMA3 // Intel FMA 3 + FMA4 // Bulldozer FMA4 functions + XOP // Bulldozer XOP functions + F16C // Half-precision floating-point conversion + BMI1 // Bit Manipulation Instruction Set 1 + BMI2 // Bit Manipulation Instruction Set 2 + TBM // AMD Trailing Bit Manipulation + LZCNT // LZCNT instruction + POPCNT // POPCNT instruction + AESNI // Advanced Encryption Standard New Instructions + CLMUL // Carry-less Multiplication + HTT // Hyperthreading (enabled) + HLE // Hardware Lock Elision + RTM // Restricted Transactional Memory + RDRAND // RDRAND instruction is available + RDSEED // RDSEED instruction is available + ADX // Intel ADX (Multi-Precision Add-Carry Instruction Extensions) + SHA // Intel SHA Extensions + AVX512F // AVX-512 Foundation + AVX512DQ // AVX-512 Doubleword and Quadword Instructions + AVX512IFMA // AVX-512 Integer Fused Multiply-Add Instructions + AVX512PF // AVX-512 Prefetch Instructions + AVX512ER // AVX-512 Exponential and Reciprocal Instructions + AVX512CD // AVX-512 Conflict Detection Instructions + AVX512BW // AVX-512 Byte and Word Instructions + AVX512VL // AVX-512 Vector Length Extensions + AVX512VBMI // AVX-512 Vector Bit Manipulation Instructions + MPX // Intel MPX (Memory Protection Extensions) + ERMS // Enhanced REP MOVSB/STOSB + RDTSCP // RDTSCP Instruction + CX16 // CMPXCHG16B Instruction + SGX // Software Guard Extensions + + // Performance indicators + SSE2SLOW // SSE2 is supported, but usually not faster + SSE3SLOW // SSE3 is supported, but usually not faster + ATOM // Atom processor, some SSSE3 instructions are slower +) + +var flagNames = map[Flags]string{ + CMOV: "CMOV", // i686 CMOV + NX: "NX", // NX (No-Execute) bit + AMD3DNOW: "AMD3DNOW", // AMD 3DNOW + AMD3DNOWEXT: "AMD3DNOWEXT", // AMD 3DNowExt + MMX: "MMX", // Standard MMX + MMXEXT: "MMXEXT", // SSE integer functions or AMD MMX ext + SSE: "SSE", // SSE functions + SSE2: "SSE2", // P4 SSE2 functions + SSE3: "SSE3", // Prescott SSE3 functions + SSSE3: "SSSE3", // Conroe SSSE3 functions + SSE4: "SSE4.1", // Penryn SSE4.1 functions + SSE4A: "SSE4A", // AMD Barcelona microarchitecture SSE4a instructions + SSE42: "SSE4.2", // Nehalem SSE4.2 functions + AVX: "AVX", // AVX functions + AVX2: "AVX2", // AVX functions + FMA3: "FMA3", // Intel FMA 3 + FMA4: "FMA4", // Bulldozer FMA4 functions + XOP: "XOP", // Bulldozer XOP functions + F16C: "F16C", // Half-precision floating-point conversion + BMI1: "BMI1", // Bit Manipulation Instruction Set 1 + BMI2: "BMI2", // Bit Manipulation Instruction Set 2 + TBM: "TBM", // AMD Trailing Bit Manipulation + LZCNT: "LZCNT", // LZCNT instruction + POPCNT: "POPCNT", // POPCNT instruction + AESNI: "AESNI", // Advanced Encryption Standard New Instructions + CLMUL: "CLMUL", // Carry-less Multiplication + HTT: "HTT", // Hyperthreading (enabled) + HLE: "HLE", // Hardware Lock Elision + RTM: "RTM", // Restricted Transactional Memory + RDRAND: "RDRAND", // RDRAND instruction is available + RDSEED: "RDSEED", // RDSEED instruction is available + ADX: "ADX", // Intel ADX (Multi-Precision Add-Carry Instruction Extensions) + SHA: "SHA", // Intel SHA Extensions + AVX512F: "AVX512F", // AVX-512 Foundation + AVX512DQ: "AVX512DQ", // AVX-512 Doubleword and Quadword Instructions + AVX512IFMA: "AVX512IFMA", // AVX-512 Integer Fused Multiply-Add Instructions + AVX512PF: "AVX512PF", // AVX-512 Prefetch Instructions + AVX512ER: "AVX512ER", // AVX-512 Exponential and Reciprocal Instructions + AVX512CD: "AVX512CD", // AVX-512 Conflict Detection Instructions + AVX512BW: "AVX512BW", // AVX-512 Byte and Word Instructions + AVX512VL: "AVX512VL", // AVX-512 Vector Length Extensions + AVX512VBMI: "AVX512VBMI", // AVX-512 Vector Bit Manipulation Instructions + MPX: "MPX", // Intel MPX (Memory Protection Extensions) + ERMS: "ERMS", // Enhanced REP MOVSB/STOSB + RDTSCP: "RDTSCP", // RDTSCP Instruction + CX16: "CX16", // CMPXCHG16B Instruction + SGX: "SGX", // Software Guard Extensions + + // Performance indicators + SSE2SLOW: "SSE2SLOW", // SSE2 supported, but usually not faster + SSE3SLOW: "SSE3SLOW", // SSE3 supported, but usually not faster + ATOM: "ATOM", // Atom processor, some SSSE3 instructions are slower + +} + +// CPUInfo contains information about the detected system CPU. +type CPUInfo struct { + BrandName string // Brand name reported by the CPU + VendorID Vendor // Comparable CPU vendor ID + Features Flags // Features of the CPU + PhysicalCores int // Number of physical processor cores in your CPU. Will be 0 if undetectable. + ThreadsPerCore int // Number of threads per physical core. Will be 1 if undetectable. + LogicalCores int // Number of physical cores times threads that can run on each core through the use of hyperthreading. Will be 0 if undetectable. + Family int // CPU family number + Model int // CPU model number + CacheLine int // Cache line size in bytes. Will be 0 if undetectable. + Cache struct { + L1I int // L1 Instruction Cache (per core or shared). Will be -1 if undetected + L1D int // L1 Data Cache (per core or shared). Will be -1 if undetected + L2 int // L2 Cache (per core or shared). Will be -1 if undetected + L3 int // L3 Instruction Cache (per core or shared). Will be -1 if undetected + } + SGX SGXSupport + maxFunc uint32 + maxExFunc uint32 +} + +var cpuid func(op uint32) (eax, ebx, ecx, edx uint32) +var cpuidex func(op, op2 uint32) (eax, ebx, ecx, edx uint32) +var xgetbv func(index uint32) (eax, edx uint32) +var rdtscpAsm func() (eax, ebx, ecx, edx uint32) + +// CPU contains information about the CPU as detected on startup, +// or when Detect last was called. +// +// Use this as the primary entry point to you data, +// this way queries are +var CPU CPUInfo + +func init() { + initCPU() + Detect() +} + +// Detect will re-detect current CPU info. +// This will replace the content of the exported CPU variable. +// +// Unless you expect the CPU to change while you are running your program +// you should not need to call this function. +// If you call this, you must ensure that no other goroutine is accessing the +// exported CPU variable. +func Detect() { + CPU.maxFunc = maxFunctionID() + CPU.maxExFunc = maxExtendedFunction() + CPU.BrandName = brandName() + CPU.CacheLine = cacheLine() + CPU.Family, CPU.Model = familyModel() + CPU.Features = support() + CPU.SGX = sgx(CPU.Features&SGX != 0) + CPU.ThreadsPerCore = threadsPerCore() + CPU.LogicalCores = logicalCores() + CPU.PhysicalCores = physicalCores() + CPU.VendorID = vendorID() + CPU.cacheSize() +} + +// Generated here: http://play.golang.org/p/BxFH2Gdc0G + +// Cmov indicates support of CMOV instructions +func (c CPUInfo) Cmov() bool { + return c.Features&CMOV != 0 +} + +// Amd3dnow indicates support of AMD 3DNOW! instructions +func (c CPUInfo) Amd3dnow() bool { + return c.Features&AMD3DNOW != 0 +} + +// Amd3dnowExt indicates support of AMD 3DNOW! Extended instructions +func (c CPUInfo) Amd3dnowExt() bool { + return c.Features&AMD3DNOWEXT != 0 +} + +// MMX indicates support of MMX instructions +func (c CPUInfo) MMX() bool { + return c.Features&MMX != 0 +} + +// MMXExt indicates support of MMXEXT instructions +// (SSE integer functions or AMD MMX ext) +func (c CPUInfo) MMXExt() bool { + return c.Features&MMXEXT != 0 +} + +// SSE indicates support of SSE instructions +func (c CPUInfo) SSE() bool { + return c.Features&SSE != 0 +} + +// SSE2 indicates support of SSE 2 instructions +func (c CPUInfo) SSE2() bool { + return c.Features&SSE2 != 0 +} + +// SSE3 indicates support of SSE 3 instructions +func (c CPUInfo) SSE3() bool { + return c.Features&SSE3 != 0 +} + +// SSSE3 indicates support of SSSE 3 instructions +func (c CPUInfo) SSSE3() bool { + return c.Features&SSSE3 != 0 +} + +// SSE4 indicates support of SSE 4 (also called SSE 4.1) instructions +func (c CPUInfo) SSE4() bool { + return c.Features&SSE4 != 0 +} + +// SSE42 indicates support of SSE4.2 instructions +func (c CPUInfo) SSE42() bool { + return c.Features&SSE42 != 0 +} + +// AVX indicates support of AVX instructions +// and operating system support of AVX instructions +func (c CPUInfo) AVX() bool { + return c.Features&AVX != 0 +} + +// AVX2 indicates support of AVX2 instructions +func (c CPUInfo) AVX2() bool { + return c.Features&AVX2 != 0 +} + +// FMA3 indicates support of FMA3 instructions +func (c CPUInfo) FMA3() bool { + return c.Features&FMA3 != 0 +} + +// FMA4 indicates support of FMA4 instructions +func (c CPUInfo) FMA4() bool { + return c.Features&FMA4 != 0 +} + +// XOP indicates support of XOP instructions +func (c CPUInfo) XOP() bool { + return c.Features&XOP != 0 +} + +// F16C indicates support of F16C instructions +func (c CPUInfo) F16C() bool { + return c.Features&F16C != 0 +} + +// BMI1 indicates support of BMI1 instructions +func (c CPUInfo) BMI1() bool { + return c.Features&BMI1 != 0 +} + +// BMI2 indicates support of BMI2 instructions +func (c CPUInfo) BMI2() bool { + return c.Features&BMI2 != 0 +} + +// TBM indicates support of TBM instructions +// (AMD Trailing Bit Manipulation) +func (c CPUInfo) TBM() bool { + return c.Features&TBM != 0 +} + +// Lzcnt indicates support of LZCNT instruction +func (c CPUInfo) Lzcnt() bool { + return c.Features&LZCNT != 0 +} + +// Popcnt indicates support of POPCNT instruction +func (c CPUInfo) Popcnt() bool { + return c.Features&POPCNT != 0 +} + +// HTT indicates the processor has Hyperthreading enabled +func (c CPUInfo) HTT() bool { + return c.Features&HTT != 0 +} + +// SSE2Slow indicates that SSE2 may be slow on this processor +func (c CPUInfo) SSE2Slow() bool { + return c.Features&SSE2SLOW != 0 +} + +// SSE3Slow indicates that SSE3 may be slow on this processor +func (c CPUInfo) SSE3Slow() bool { + return c.Features&SSE3SLOW != 0 +} + +// AesNi indicates support of AES-NI instructions +// (Advanced Encryption Standard New Instructions) +func (c CPUInfo) AesNi() bool { + return c.Features&AESNI != 0 +} + +// Clmul indicates support of CLMUL instructions +// (Carry-less Multiplication) +func (c CPUInfo) Clmul() bool { + return c.Features&CLMUL != 0 +} + +// NX indicates support of NX (No-Execute) bit +func (c CPUInfo) NX() bool { + return c.Features&NX != 0 +} + +// SSE4A indicates support of AMD Barcelona microarchitecture SSE4a instructions +func (c CPUInfo) SSE4A() bool { + return c.Features&SSE4A != 0 +} + +// HLE indicates support of Hardware Lock Elision +func (c CPUInfo) HLE() bool { + return c.Features&HLE != 0 +} + +// RTM indicates support of Restricted Transactional Memory +func (c CPUInfo) RTM() bool { + return c.Features&RTM != 0 +} + +// Rdrand indicates support of RDRAND instruction is available +func (c CPUInfo) Rdrand() bool { + return c.Features&RDRAND != 0 +} + +// Rdseed indicates support of RDSEED instruction is available +func (c CPUInfo) Rdseed() bool { + return c.Features&RDSEED != 0 +} + +// ADX indicates support of Intel ADX (Multi-Precision Add-Carry Instruction Extensions) +func (c CPUInfo) ADX() bool { + return c.Features&ADX != 0 +} + +// SHA indicates support of Intel SHA Extensions +func (c CPUInfo) SHA() bool { + return c.Features&SHA != 0 +} + +// AVX512F indicates support of AVX-512 Foundation +func (c CPUInfo) AVX512F() bool { + return c.Features&AVX512F != 0 +} + +// AVX512DQ indicates support of AVX-512 Doubleword and Quadword Instructions +func (c CPUInfo) AVX512DQ() bool { + return c.Features&AVX512DQ != 0 +} + +// AVX512IFMA indicates support of AVX-512 Integer Fused Multiply-Add Instructions +func (c CPUInfo) AVX512IFMA() bool { + return c.Features&AVX512IFMA != 0 +} + +// AVX512PF indicates support of AVX-512 Prefetch Instructions +func (c CPUInfo) AVX512PF() bool { + return c.Features&AVX512PF != 0 +} + +// AVX512ER indicates support of AVX-512 Exponential and Reciprocal Instructions +func (c CPUInfo) AVX512ER() bool { + return c.Features&AVX512ER != 0 +} + +// AVX512CD indicates support of AVX-512 Conflict Detection Instructions +func (c CPUInfo) AVX512CD() bool { + return c.Features&AVX512CD != 0 +} + +// AVX512BW indicates support of AVX-512 Byte and Word Instructions +func (c CPUInfo) AVX512BW() bool { + return c.Features&AVX512BW != 0 +} + +// AVX512VL indicates support of AVX-512 Vector Length Extensions +func (c CPUInfo) AVX512VL() bool { + return c.Features&AVX512VL != 0 +} + +// AVX512VBMI indicates support of AVX-512 Vector Bit Manipulation Instructions +func (c CPUInfo) AVX512VBMI() bool { + return c.Features&AVX512VBMI != 0 +} + +// MPX indicates support of Intel MPX (Memory Protection Extensions) +func (c CPUInfo) MPX() bool { + return c.Features&MPX != 0 +} + +// ERMS indicates support of Enhanced REP MOVSB/STOSB +func (c CPUInfo) ERMS() bool { + return c.Features&ERMS != 0 +} + +func (c CPUInfo) RDTSCP() bool { + return c.Features&RDTSCP != 0 +} + +func (c CPUInfo) CX16() bool { + return c.Features&CX16 != 0 +} + +// Atom indicates an Atom processor +func (c CPUInfo) Atom() bool { + return c.Features&ATOM != 0 +} + +// Intel returns true if vendor is recognized as Intel +func (c CPUInfo) Intel() bool { + return c.VendorID == Intel +} + +// AMD returns true if vendor is recognized as AMD +func (c CPUInfo) AMD() bool { + return c.VendorID == AMD +} + +// Transmeta returns true if vendor is recognized as Transmeta +func (c CPUInfo) Transmeta() bool { + return c.VendorID == Transmeta +} + +// NSC returns true if vendor is recognized as National Semiconductor +func (c CPUInfo) NSC() bool { + return c.VendorID == NSC +} + +// VIA returns true if vendor is recognized as VIA +func (c CPUInfo) VIA() bool { + return c.VendorID == VIA +} + +// RTCounter returns the 64-bit time-stamp counter +// Uses the RDTSCP instruction. The value 0 is returned +// if the CPU does not support the instruction. +func (c CPUInfo) RTCounter() uint64 { + if !c.RDTSCP() { + return 0 + } + a, _, _, d := rdtscpAsm() + return uint64(a) | (uint64(d) << 32) +} + +// Ia32TscAux returns the IA32_TSC_AUX part of the RDTSCP. +// This variable is OS dependent, but on Linux contains information +// about the current cpu/core the code is running on. +// If the RDTSCP instruction isn't supported on the CPU, the value 0 is returned. +func (c CPUInfo) Ia32TscAux() uint32 { + if !c.RDTSCP() { + return 0 + } + _, _, ecx, _ := rdtscpAsm() + return ecx +} + +// LogicalCPU will return the Logical CPU the code is currently executing on. +// This is likely to change when the OS re-schedules the running thread +// to another CPU. +// If the current core cannot be detected, -1 will be returned. +func (c CPUInfo) LogicalCPU() int { + if c.maxFunc < 1 { + return -1 + } + _, ebx, _, _ := cpuid(1) + return int(ebx >> 24) +} + +// VM Will return true if the cpu id indicates we are in +// a virtual machine. This is only a hint, and will very likely +// have many false negatives. +func (c CPUInfo) VM() bool { + switch c.VendorID { + case MSVM, KVM, VMware, XenHVM: + return true + } + return false +} + +// Flags contains detected cpu features and caracteristics +type Flags uint64 + +// String returns a string representation of the detected +// CPU features. +func (f Flags) String() string { + return strings.Join(f.Strings(), ",") +} + +// Strings returns and array of the detected features. +func (f Flags) Strings() []string { + s := support() + r := make([]string, 0, 20) + for i := uint(0); i < 64; i++ { + key := Flags(1 << i) + val := flagNames[key] + if s&key != 0 { + r = append(r, val) + } + } + return r +} + +func maxExtendedFunction() uint32 { + eax, _, _, _ := cpuid(0x80000000) + return eax +} + +func maxFunctionID() uint32 { + a, _, _, _ := cpuid(0) + return a +} + +func brandName() string { + if maxExtendedFunction() >= 0x80000004 { + v := make([]uint32, 0, 48) + for i := uint32(0); i < 3; i++ { + a, b, c, d := cpuid(0x80000002 + i) + v = append(v, a, b, c, d) + } + return strings.Trim(string(valAsString(v...)), " ") + } + return "unknown" +} + +func threadsPerCore() int { + mfi := maxFunctionID() + if mfi < 0x4 || vendorID() != Intel { + return 1 + } + + if mfi < 0xb { + _, b, _, d := cpuid(1) + if (d & (1 << 28)) != 0 { + // v will contain logical core count + v := (b >> 16) & 255 + if v > 1 { + a4, _, _, _ := cpuid(4) + // physical cores + v2 := (a4 >> 26) + 1 + if v2 > 0 { + return int(v) / int(v2) + } + } + } + return 1 + } + _, b, _, _ := cpuidex(0xb, 0) + if b&0xffff == 0 { + return 1 + } + return int(b & 0xffff) +} + +func logicalCores() int { + mfi := maxFunctionID() + switch vendorID() { + case Intel: + // Use this on old Intel processors + if mfi < 0xb { + if mfi < 1 { + return 0 + } + // CPUID.1:EBX[23:16] represents the maximum number of addressable IDs (initial APIC ID) + // that can be assigned to logical processors in a physical package. + // The value may not be the same as the number of logical processors that are present in the hardware of a physical package. + _, ebx, _, _ := cpuid(1) + logical := (ebx >> 16) & 0xff + return int(logical) + } + _, b, _, _ := cpuidex(0xb, 1) + return int(b & 0xffff) + case AMD: + _, b, _, _ := cpuid(1) + return int((b >> 16) & 0xff) + default: + return 0 + } +} + +func familyModel() (int, int) { + if maxFunctionID() < 0x1 { + return 0, 0 + } + eax, _, _, _ := cpuid(1) + family := ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff) + model := ((eax >> 4) & 0xf) + ((eax >> 12) & 0xf0) + return int(family), int(model) +} + +func physicalCores() int { + switch vendorID() { + case Intel: + return logicalCores() / threadsPerCore() + case AMD: + if maxExtendedFunction() >= 0x80000008 { + _, _, c, _ := cpuid(0x80000008) + return int(c&0xff) + 1 + } + } + return 0 +} + +// Except from http://en.wikipedia.org/wiki/CPUID#EAX.3D0:_Get_vendor_ID +var vendorMapping = map[string]Vendor{ + "AMDisbetter!": AMD, + "AuthenticAMD": AMD, + "CentaurHauls": VIA, + "GenuineIntel": Intel, + "TransmetaCPU": Transmeta, + "GenuineTMx86": Transmeta, + "Geode by NSC": NSC, + "VIA VIA VIA ": VIA, + "KVMKVMKVMKVM": KVM, + "Microsoft Hv": MSVM, + "VMwareVMware": VMware, + "XenVMMXenVMM": XenHVM, +} + +func vendorID() Vendor { + _, b, c, d := cpuid(0) + v := valAsString(b, d, c) + vend, ok := vendorMapping[string(v)] + if !ok { + return Other + } + return vend +} + +func cacheLine() int { + if maxFunctionID() < 0x1 { + return 0 + } + + _, ebx, _, _ := cpuid(1) + cache := (ebx & 0xff00) >> 5 // cflush size + if cache == 0 && maxExtendedFunction() >= 0x80000006 { + _, _, ecx, _ := cpuid(0x80000006) + cache = ecx & 0xff // cacheline size + } + // TODO: Read from Cache and TLB Information + return int(cache) +} + +func (c *CPUInfo) cacheSize() { + c.Cache.L1D = -1 + c.Cache.L1I = -1 + c.Cache.L2 = -1 + c.Cache.L3 = -1 + vendor := vendorID() + switch vendor { + case Intel: + if maxFunctionID() < 4 { + return + } + for i := uint32(0); ; i++ { + eax, ebx, ecx, _ := cpuidex(4, i) + cacheType := eax & 15 + if cacheType == 0 { + break + } + cacheLevel := (eax >> 5) & 7 + coherency := int(ebx&0xfff) + 1 + partitions := int((ebx>>12)&0x3ff) + 1 + associativity := int((ebx>>22)&0x3ff) + 1 + sets := int(ecx) + 1 + size := associativity * partitions * coherency * sets + switch cacheLevel { + case 1: + if cacheType == 1 { + // 1 = Data Cache + c.Cache.L1D = size + } else if cacheType == 2 { + // 2 = Instruction Cache + c.Cache.L1I = size + } else { + if c.Cache.L1D < 0 { + c.Cache.L1I = size + } + if c.Cache.L1I < 0 { + c.Cache.L1I = size + } + } + case 2: + c.Cache.L2 = size + case 3: + c.Cache.L3 = size + } + } + case AMD: + // Untested. + if maxExtendedFunction() < 0x80000005 { + return + } + _, _, ecx, edx := cpuid(0x80000005) + c.Cache.L1D = int(((ecx >> 24) & 0xFF) * 1024) + c.Cache.L1I = int(((edx >> 24) & 0xFF) * 1024) + + if maxExtendedFunction() < 0x80000006 { + return + } + _, _, ecx, _ = cpuid(0x80000006) + c.Cache.L2 = int(((ecx >> 16) & 0xFFFF) * 1024) + } + + return +} + +type SGXSupport struct { + Available bool + SGX1Supported bool + SGX2Supported bool + MaxEnclaveSizeNot64 int64 + MaxEnclaveSize64 int64 +} + +func sgx(available bool) (rval SGXSupport) { + rval.Available = available + + if !available { + return + } + + a, _, _, d := cpuidex(0x12, 0) + rval.SGX1Supported = a&0x01 != 0 + rval.SGX2Supported = a&0x02 != 0 + rval.MaxEnclaveSizeNot64 = 1 << (d & 0xFF) // pow 2 + rval.MaxEnclaveSize64 = 1 << ((d >> 8) & 0xFF) // pow 2 + + return +} + +func support() Flags { + mfi := maxFunctionID() + vend := vendorID() + if mfi < 0x1 { + return 0 + } + rval := uint64(0) + _, _, c, d := cpuid(1) + if (d & (1 << 15)) != 0 { + rval |= CMOV + } + if (d & (1 << 23)) != 0 { + rval |= MMX + } + if (d & (1 << 25)) != 0 { + rval |= MMXEXT + } + if (d & (1 << 25)) != 0 { + rval |= SSE + } + if (d & (1 << 26)) != 0 { + rval |= SSE2 + } + if (c & 1) != 0 { + rval |= SSE3 + } + if (c & 0x00000200) != 0 { + rval |= SSSE3 + } + if (c & 0x00080000) != 0 { + rval |= SSE4 + } + if (c & 0x00100000) != 0 { + rval |= SSE42 + } + if (c & (1 << 25)) != 0 { + rval |= AESNI + } + if (c & (1 << 1)) != 0 { + rval |= CLMUL + } + if c&(1<<23) != 0 { + rval |= POPCNT + } + if c&(1<<30) != 0 { + rval |= RDRAND + } + if c&(1<<29) != 0 { + rval |= F16C + } + if c&(1<<13) != 0 { + rval |= CX16 + } + if vend == Intel && (d&(1<<28)) != 0 && mfi >= 4 { + if threadsPerCore() > 1 { + rval |= HTT + } + } + + // Check XGETBV, OXSAVE and AVX bits + if c&(1<<26) != 0 && c&(1<<27) != 0 && c&(1<<28) != 0 { + // Check for OS support + eax, _ := xgetbv(0) + if (eax & 0x6) == 0x6 { + rval |= AVX + if (c & 0x00001000) != 0 { + rval |= FMA3 + } + } + } + + // Check AVX2, AVX2 requires OS support, but BMI1/2 don't. + if mfi >= 7 { + _, ebx, ecx, _ := cpuidex(7, 0) + if (rval&AVX) != 0 && (ebx&0x00000020) != 0 { + rval |= AVX2 + } + if (ebx & 0x00000008) != 0 { + rval |= BMI1 + if (ebx & 0x00000100) != 0 { + rval |= BMI2 + } + } + if ebx&(1<<2) != 0 { + rval |= SGX + } + if ebx&(1<<4) != 0 { + rval |= HLE + } + if ebx&(1<<9) != 0 { + rval |= ERMS + } + if ebx&(1<<11) != 0 { + rval |= RTM + } + if ebx&(1<<14) != 0 { + rval |= MPX + } + if ebx&(1<<18) != 0 { + rval |= RDSEED + } + if ebx&(1<<19) != 0 { + rval |= ADX + } + if ebx&(1<<29) != 0 { + rval |= SHA + } + + // Only detect AVX-512 features if XGETBV is supported + if c&((1<<26)|(1<<27)) == (1<<26)|(1<<27) { + // Check for OS support + eax, _ := xgetbv(0) + + // Verify that XCR0[7:5] = ‘111b’ (OPMASK state, upper 256-bit of ZMM0-ZMM15 and + // ZMM16-ZMM31 state are enabled by OS) + /// and that XCR0[2:1] = ‘11b’ (XMM state and YMM state are enabled by OS). + if (eax>>5)&7 == 7 && (eax>>1)&3 == 3 { + if ebx&(1<<16) != 0 { + rval |= AVX512F + } + if ebx&(1<<17) != 0 { + rval |= AVX512DQ + } + if ebx&(1<<21) != 0 { + rval |= AVX512IFMA + } + if ebx&(1<<26) != 0 { + rval |= AVX512PF + } + if ebx&(1<<27) != 0 { + rval |= AVX512ER + } + if ebx&(1<<28) != 0 { + rval |= AVX512CD + } + if ebx&(1<<30) != 0 { + rval |= AVX512BW + } + if ebx&(1<<31) != 0 { + rval |= AVX512VL + } + // ecx + if ecx&(1<<1) != 0 { + rval |= AVX512VBMI + } + } + } + } + + if maxExtendedFunction() >= 0x80000001 { + _, _, c, d := cpuid(0x80000001) + if (c & (1 << 5)) != 0 { + rval |= LZCNT + rval |= POPCNT + } + if (d & (1 << 31)) != 0 { + rval |= AMD3DNOW + } + if (d & (1 << 30)) != 0 { + rval |= AMD3DNOWEXT + } + if (d & (1 << 23)) != 0 { + rval |= MMX + } + if (d & (1 << 22)) != 0 { + rval |= MMXEXT + } + if (c & (1 << 6)) != 0 { + rval |= SSE4A + } + if d&(1<<20) != 0 { + rval |= NX + } + if d&(1<<27) != 0 { + rval |= RDTSCP + } + + /* Allow for selectively disabling SSE2 functions on AMD processors + with SSE2 support but not SSE4a. This includes Athlon64, some + Opteron, and some Sempron processors. MMX, SSE, or 3DNow! are faster + than SSE2 often enough to utilize this special-case flag. + AV_CPU_FLAG_SSE2 and AV_CPU_FLAG_SSE2SLOW are both set in this case + so that SSE2 is used unless explicitly disabled by checking + AV_CPU_FLAG_SSE2SLOW. */ + if vendorID() != Intel && + rval&SSE2 != 0 && (c&0x00000040) == 0 { + rval |= SSE2SLOW + } + + /* XOP and FMA4 use the AVX instruction coding scheme, so they can't be + * used unless the OS has AVX support. */ + if (rval & AVX) != 0 { + if (c & 0x00000800) != 0 { + rval |= XOP + } + if (c & 0x00010000) != 0 { + rval |= FMA4 + } + } + + if vendorID() == Intel { + family, model := familyModel() + if family == 6 && (model == 9 || model == 13 || model == 14) { + /* 6/9 (pentium-m "banias"), 6/13 (pentium-m "dothan"), and + * 6/14 (core1 "yonah") theoretically support sse2, but it's + * usually slower than mmx. */ + if (rval & SSE2) != 0 { + rval |= SSE2SLOW + } + if (rval & SSE3) != 0 { + rval |= SSE3SLOW + } + } + /* The Atom processor has SSSE3 support, which is useful in many cases, + * but sometimes the SSSE3 version is slower than the SSE2 equivalent + * on the Atom, but is generally faster on other processors supporting + * SSSE3. This flag allows for selectively disabling certain SSSE3 + * functions on the Atom. */ + if family == 6 && model == 28 { + rval |= ATOM + } + } + } + return Flags(rval) +} + +func valAsString(values ...uint32) []byte { + r := make([]byte, 4*len(values)) + for i, v := range values { + dst := r[i*4:] + dst[0] = byte(v & 0xff) + dst[1] = byte((v >> 8) & 0xff) + dst[2] = byte((v >> 16) & 0xff) + dst[3] = byte((v >> 24) & 0xff) + switch { + case dst[0] == 0: + return r[:i*4] + case dst[1] == 0: + return r[:i*4+1] + case dst[2] == 0: + return r[:i*4+2] + case dst[3] == 0: + return r[:i*4+3] + } + } + return r +} diff --git a/vendor/github.com/klauspost/cpuid/cpuid_386.s b/vendor/github.com/klauspost/cpuid/cpuid_386.s new file mode 100644 index 0000000..4d73171 --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/cpuid_386.s @@ -0,0 +1,42 @@ +// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. + +// +build 386,!gccgo + +// func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32) +TEXT ·asmCpuid(SB), 7, $0 + XORL CX, CX + MOVL op+0(FP), AX + CPUID + MOVL AX, eax+4(FP) + MOVL BX, ebx+8(FP) + MOVL CX, ecx+12(FP) + MOVL DX, edx+16(FP) + RET + +// func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32) +TEXT ·asmCpuidex(SB), 7, $0 + MOVL op+0(FP), AX + MOVL op2+4(FP), CX + CPUID + MOVL AX, eax+8(FP) + MOVL BX, ebx+12(FP) + MOVL CX, ecx+16(FP) + MOVL DX, edx+20(FP) + RET + +// func xgetbv(index uint32) (eax, edx uint32) +TEXT ·asmXgetbv(SB), 7, $0 + MOVL index+0(FP), CX + BYTE $0x0f; BYTE $0x01; BYTE $0xd0 // XGETBV + MOVL AX, eax+4(FP) + MOVL DX, edx+8(FP) + RET + +// func asmRdtscpAsm() (eax, ebx, ecx, edx uint32) +TEXT ·asmRdtscpAsm(SB), 7, $0 + BYTE $0x0F; BYTE $0x01; BYTE $0xF9 // RDTSCP + MOVL AX, eax+0(FP) + MOVL BX, ebx+4(FP) + MOVL CX, ecx+8(FP) + MOVL DX, edx+12(FP) + RET diff --git a/vendor/github.com/klauspost/cpuid/cpuid_amd64.s b/vendor/github.com/klauspost/cpuid/cpuid_amd64.s new file mode 100644 index 0000000..3c1d60e --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/cpuid_amd64.s @@ -0,0 +1,42 @@ +// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. + +//+build amd64,!gccgo + +// func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32) +TEXT ·asmCpuid(SB), 7, $0 + XORQ CX, CX + MOVL op+0(FP), AX + CPUID + MOVL AX, eax+8(FP) + MOVL BX, ebx+12(FP) + MOVL CX, ecx+16(FP) + MOVL DX, edx+20(FP) + RET + +// func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32) +TEXT ·asmCpuidex(SB), 7, $0 + MOVL op+0(FP), AX + MOVL op2+4(FP), CX + CPUID + MOVL AX, eax+8(FP) + MOVL BX, ebx+12(FP) + MOVL CX, ecx+16(FP) + MOVL DX, edx+20(FP) + RET + +// func asmXgetbv(index uint32) (eax, edx uint32) +TEXT ·asmXgetbv(SB), 7, $0 + MOVL index+0(FP), CX + BYTE $0x0f; BYTE $0x01; BYTE $0xd0 // XGETBV + MOVL AX, eax+8(FP) + MOVL DX, edx+12(FP) + RET + +// func asmRdtscpAsm() (eax, ebx, ecx, edx uint32) +TEXT ·asmRdtscpAsm(SB), 7, $0 + BYTE $0x0F; BYTE $0x01; BYTE $0xF9 // RDTSCP + MOVL AX, eax+0(FP) + MOVL BX, ebx+4(FP) + MOVL CX, ecx+8(FP) + MOVL DX, edx+12(FP) + RET diff --git a/vendor/github.com/klauspost/cpuid/cpuid_test.go b/vendor/github.com/klauspost/cpuid/cpuid_test.go new file mode 100644 index 0000000..54d2cbc --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/cpuid_test.go @@ -0,0 +1,727 @@ +// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. + +package cpuid + +import ( + "fmt" + "testing" +) + +// There is no real way to test a CPU identifier, since results will +// obviously differ on each machine. +func TestCPUID(t *testing.T) { + n := maxFunctionID() + t.Logf("Max Function:0x%x\n", n) + n = maxExtendedFunction() + t.Logf("Max Extended Function:0x%x\n", n) + t.Log("Name:", CPU.BrandName) + t.Log("PhysicalCores:", CPU.PhysicalCores) + t.Log("ThreadsPerCore:", CPU.ThreadsPerCore) + t.Log("LogicalCores:", CPU.LogicalCores) + t.Log("Family", CPU.Family, "Model:", CPU.Model) + t.Log("Features:", CPU.Features) + t.Log("Cacheline bytes:", CPU.CacheLine) + t.Log("L1 Instruction Cache:", CPU.Cache.L1I, "bytes") + t.Log("L1 Data Cache:", CPU.Cache.L1D, "bytes") + t.Log("L2 Cache:", CPU.Cache.L2, "bytes") + t.Log("L3 Cache:", CPU.Cache.L3, "bytes") + + if CPU.SSE2() { + t.Log("We have SSE2") + } +} + +func TestDumpCPUID(t *testing.T) { + n := int(maxFunctionID()) + for i := 0; i <= n; i++ { + a, b, c, d := cpuidex(uint32(i), 0) + t.Logf("CPUID %08x: %08x-%08x-%08x-%08x", i, a, b, c, d) + ex := uint32(1) + for { + a2, b2, c2, d2 := cpuidex(uint32(i), ex) + if a2 == a && b2 == b && d2 == d || ex > 50 || a2 == 0 { + break + } + t.Logf("CPUID %08x: %08x-%08x-%08x-%08x", i, a2, b2, c2, d2) + a, b, c, d = a2, b2, c2, d2 + ex++ + } + } + n2 := maxExtendedFunction() + for i := uint32(0x80000000); i <= n2; i++ { + a, b, c, d := cpuid(i) + t.Logf("CPUID %08x: %08x-%08x-%08x-%08x", i, a, b, c, d) + } +} + +func Example() { + // Print basic CPU information: + fmt.Println("Name:", CPU.BrandName) + fmt.Println("PhysicalCores:", CPU.PhysicalCores) + fmt.Println("ThreadsPerCore:", CPU.ThreadsPerCore) + fmt.Println("LogicalCores:", CPU.LogicalCores) + fmt.Println("Family", CPU.Family, "Model:", CPU.Model) + fmt.Println("Features:", CPU.Features) + fmt.Println("Cacheline bytes:", CPU.CacheLine) + + // Test if we have a specific feature: + if CPU.SSE() { + fmt.Println("We have Streaming SIMD Extensions") + } +} + +func TestBrandNameZero(t *testing.T) { + if len(CPU.BrandName) > 0 { + // Cut out last byte + last := []byte(CPU.BrandName[len(CPU.BrandName)-1:]) + if last[0] == 0 { + t.Fatal("last byte was zero") + } else if last[0] == 32 { + t.Fatal("whitespace wasn't trimmed") + } + } +} + +// Generated here: http://play.golang.org/p/mko-0tFt0Q + +// TestCmov tests Cmov() function +func TestCmov(t *testing.T) { + got := CPU.Cmov() + expected := CPU.Features&CMOV == CMOV + if got != expected { + t.Fatalf("Cmov: expected %v, got %v", expected, got) + } + t.Log("CMOV Support:", got) +} + +// TestAmd3dnow tests Amd3dnow() function +func TestAmd3dnow(t *testing.T) { + got := CPU.Amd3dnow() + expected := CPU.Features&AMD3DNOW == AMD3DNOW + if got != expected { + t.Fatalf("Amd3dnow: expected %v, got %v", expected, got) + } + t.Log("AMD3DNOW Support:", got) +} + +// TestAmd3dnowExt tests Amd3dnowExt() function +func TestAmd3dnowExt(t *testing.T) { + got := CPU.Amd3dnowExt() + expected := CPU.Features&AMD3DNOWEXT == AMD3DNOWEXT + if got != expected { + t.Fatalf("Amd3dnowExt: expected %v, got %v", expected, got) + } + t.Log("AMD3DNOWEXT Support:", got) +} + +// TestMMX tests MMX() function +func TestMMX(t *testing.T) { + got := CPU.MMX() + expected := CPU.Features&MMX == MMX + if got != expected { + t.Fatalf("MMX: expected %v, got %v", expected, got) + } + t.Log("MMX Support:", got) +} + +// TestMMXext tests MMXext() function +func TestMMXext(t *testing.T) { + got := CPU.MMXExt() + expected := CPU.Features&MMXEXT == MMXEXT + if got != expected { + t.Fatalf("MMXExt: expected %v, got %v", expected, got) + } + t.Log("MMXEXT Support:", got) +} + +// TestSSE tests SSE() function +func TestSSE(t *testing.T) { + got := CPU.SSE() + expected := CPU.Features&SSE == SSE + if got != expected { + t.Fatalf("SSE: expected %v, got %v", expected, got) + } + t.Log("SSE Support:", got) +} + +// TestSSE2 tests SSE2() function +func TestSSE2(t *testing.T) { + got := CPU.SSE2() + expected := CPU.Features&SSE2 == SSE2 + if got != expected { + t.Fatalf("SSE2: expected %v, got %v", expected, got) + } + t.Log("SSE2 Support:", got) +} + +// TestSSE3 tests SSE3() function +func TestSSE3(t *testing.T) { + got := CPU.SSE3() + expected := CPU.Features&SSE3 == SSE3 + if got != expected { + t.Fatalf("SSE3: expected %v, got %v", expected, got) + } + t.Log("SSE3 Support:", got) +} + +// TestSSSE3 tests SSSE3() function +func TestSSSE3(t *testing.T) { + got := CPU.SSSE3() + expected := CPU.Features&SSSE3 == SSSE3 + if got != expected { + t.Fatalf("SSSE3: expected %v, got %v", expected, got) + } + t.Log("SSSE3 Support:", got) +} + +// TestSSE4 tests SSE4() function +func TestSSE4(t *testing.T) { + got := CPU.SSE4() + expected := CPU.Features&SSE4 == SSE4 + if got != expected { + t.Fatalf("SSE4: expected %v, got %v", expected, got) + } + t.Log("SSE4 Support:", got) +} + +// TestSSE42 tests SSE42() function +func TestSSE42(t *testing.T) { + got := CPU.SSE42() + expected := CPU.Features&SSE42 == SSE42 + if got != expected { + t.Fatalf("SSE42: expected %v, got %v", expected, got) + } + t.Log("SSE42 Support:", got) +} + +// TestAVX tests AVX() function +func TestAVX(t *testing.T) { + got := CPU.AVX() + expected := CPU.Features&AVX == AVX + if got != expected { + t.Fatalf("AVX: expected %v, got %v", expected, got) + } + t.Log("AVX Support:", got) +} + +// TestAVX2 tests AVX2() function +func TestAVX2(t *testing.T) { + got := CPU.AVX2() + expected := CPU.Features&AVX2 == AVX2 + if got != expected { + t.Fatalf("AVX2: expected %v, got %v", expected, got) + } + t.Log("AVX2 Support:", got) +} + +// TestFMA3 tests FMA3() function +func TestFMA3(t *testing.T) { + got := CPU.FMA3() + expected := CPU.Features&FMA3 == FMA3 + if got != expected { + t.Fatalf("FMA3: expected %v, got %v", expected, got) + } + t.Log("FMA3 Support:", got) +} + +// TestFMA4 tests FMA4() function +func TestFMA4(t *testing.T) { + got := CPU.FMA4() + expected := CPU.Features&FMA4 == FMA4 + if got != expected { + t.Fatalf("FMA4: expected %v, got %v", expected, got) + } + t.Log("FMA4 Support:", got) +} + +// TestXOP tests XOP() function +func TestXOP(t *testing.T) { + got := CPU.XOP() + expected := CPU.Features&XOP == XOP + if got != expected { + t.Fatalf("XOP: expected %v, got %v", expected, got) + } + t.Log("XOP Support:", got) +} + +// TestF16C tests F16C() function +func TestF16C(t *testing.T) { + got := CPU.F16C() + expected := CPU.Features&F16C == F16C + if got != expected { + t.Fatalf("F16C: expected %v, got %v", expected, got) + } + t.Log("F16C Support:", got) +} + +// TestCX16 tests CX16() function +func TestCX16(t *testing.T) { + got := CPU.CX16() + expected := CPU.Features&CX16 == CX16 + if got != expected { + t.Fatalf("CX16: expected %v, got %v", expected, got) + } + t.Log("CX16 Support:", got) +} + +// TestSGX tests SGX() function +func TestSGX(t *testing.T) { + got := CPU.SGX.Available + expected := CPU.Features&SGX == SGX + if got != expected { + t.Fatalf("SGX: expected %v, got %v", expected, got) + } + t.Log("SGX Support:", got) +} + +// TestBMI1 tests BMI1() function +func TestBMI1(t *testing.T) { + got := CPU.BMI1() + expected := CPU.Features&BMI1 == BMI1 + if got != expected { + t.Fatalf("BMI1: expected %v, got %v", expected, got) + } + t.Log("BMI1 Support:", got) +} + +// TestBMI2 tests BMI2() function +func TestBMI2(t *testing.T) { + got := CPU.BMI2() + expected := CPU.Features&BMI2 == BMI2 + if got != expected { + t.Fatalf("BMI2: expected %v, got %v", expected, got) + } + t.Log("BMI2 Support:", got) +} + +// TestTBM tests TBM() function +func TestTBM(t *testing.T) { + got := CPU.TBM() + expected := CPU.Features&TBM == TBM + if got != expected { + t.Fatalf("TBM: expected %v, got %v", expected, got) + } + t.Log("TBM Support:", got) +} + +// TestLzcnt tests Lzcnt() function +func TestLzcnt(t *testing.T) { + got := CPU.Lzcnt() + expected := CPU.Features&LZCNT == LZCNT + if got != expected { + t.Fatalf("Lzcnt: expected %v, got %v", expected, got) + } + t.Log("LZCNT Support:", got) +} + +// TestLzcnt tests Lzcnt() function +func TestPopcnt(t *testing.T) { + got := CPU.Popcnt() + expected := CPU.Features&POPCNT == POPCNT + if got != expected { + t.Fatalf("Popcnt: expected %v, got %v", expected, got) + } + t.Log("POPCNT Support:", got) +} + +// TestAesNi tests AesNi() function +func TestAesNi(t *testing.T) { + got := CPU.AesNi() + expected := CPU.Features&AESNI == AESNI + if got != expected { + t.Fatalf("AesNi: expected %v, got %v", expected, got) + } + t.Log("AESNI Support:", got) +} + +// TestHTT tests HTT() function +func TestHTT(t *testing.T) { + got := CPU.HTT() + expected := CPU.Features&HTT == HTT + if got != expected { + t.Fatalf("HTT: expected %v, got %v", expected, got) + } + t.Log("HTT Support:", got) +} + +// TestClmul tests Clmul() function +func TestClmul(t *testing.T) { + got := CPU.Clmul() + expected := CPU.Features&CLMUL == CLMUL + if got != expected { + t.Fatalf("Clmul: expected %v, got %v", expected, got) + } + t.Log("CLMUL Support:", got) +} + +// TestSSE2Slow tests SSE2Slow() function +func TestSSE2Slow(t *testing.T) { + got := CPU.SSE2Slow() + expected := CPU.Features&SSE2SLOW == SSE2SLOW + if got != expected { + t.Fatalf("SSE2Slow: expected %v, got %v", expected, got) + } + t.Log("SSE2SLOW Support:", got) +} + +// TestSSE3Slow tests SSE3slow() function +func TestSSE3Slow(t *testing.T) { + got := CPU.SSE3Slow() + expected := CPU.Features&SSE3SLOW == SSE3SLOW + if got != expected { + t.Fatalf("SSE3slow: expected %v, got %v", expected, got) + } + t.Log("SSE3SLOW Support:", got) +} + +// TestAtom tests Atom() function +func TestAtom(t *testing.T) { + got := CPU.Atom() + expected := CPU.Features&ATOM == ATOM + if got != expected { + t.Fatalf("Atom: expected %v, got %v", expected, got) + } + t.Log("ATOM Support:", got) +} + +// TestNX tests NX() function (NX (No-Execute) bit) +func TestNX(t *testing.T) { + got := CPU.NX() + expected := CPU.Features&NX == NX + if got != expected { + t.Fatalf("NX: expected %v, got %v", expected, got) + } + t.Log("NX Support:", got) +} + +// TestSSE4A tests SSE4A() function (AMD Barcelona microarchitecture SSE4a instructions) +func TestSSE4A(t *testing.T) { + got := CPU.SSE4A() + expected := CPU.Features&SSE4A == SSE4A + if got != expected { + t.Fatalf("SSE4A: expected %v, got %v", expected, got) + } + t.Log("SSE4A Support:", got) +} + +// TestHLE tests HLE() function (Hardware Lock Elision) +func TestHLE(t *testing.T) { + got := CPU.HLE() + expected := CPU.Features&HLE == HLE + if got != expected { + t.Fatalf("HLE: expected %v, got %v", expected, got) + } + t.Log("HLE Support:", got) +} + +// TestRTM tests RTM() function (Restricted Transactional Memory) +func TestRTM(t *testing.T) { + got := CPU.RTM() + expected := CPU.Features&RTM == RTM + if got != expected { + t.Fatalf("RTM: expected %v, got %v", expected, got) + } + t.Log("RTM Support:", got) +} + +// TestRdrand tests RDRAND() function (RDRAND instruction is available) +func TestRdrand(t *testing.T) { + got := CPU.Rdrand() + expected := CPU.Features&RDRAND == RDRAND + if got != expected { + t.Fatalf("Rdrand: expected %v, got %v", expected, got) + } + t.Log("Rdrand Support:", got) +} + +// TestRdseed tests RDSEED() function (RDSEED instruction is available) +func TestRdseed(t *testing.T) { + got := CPU.Rdseed() + expected := CPU.Features&RDSEED == RDSEED + if got != expected { + t.Fatalf("Rdseed: expected %v, got %v", expected, got) + } + t.Log("Rdseed Support:", got) +} + +// TestADX tests ADX() function (Intel ADX (Multi-Precision Add-Carry Instruction Extensions)) +func TestADX(t *testing.T) { + got := CPU.ADX() + expected := CPU.Features&ADX == ADX + if got != expected { + t.Fatalf("ADX: expected %v, got %v", expected, got) + } + t.Log("ADX Support:", got) +} + +// TestSHA tests SHA() function (Intel SHA Extensions) +func TestSHA(t *testing.T) { + got := CPU.SHA() + expected := CPU.Features&SHA == SHA + if got != expected { + t.Fatalf("SHA: expected %v, got %v", expected, got) + } + t.Log("SHA Support:", got) +} + +// TestAVX512F tests AVX512F() function (AVX-512 Foundation) +func TestAVX512F(t *testing.T) { + got := CPU.AVX512F() + expected := CPU.Features&AVX512F == AVX512F + if got != expected { + t.Fatalf("AVX512F: expected %v, got %v", expected, got) + } + t.Log("AVX512F Support:", got) +} + +// TestAVX512DQ tests AVX512DQ() function (AVX-512 Doubleword and Quadword Instructions) +func TestAVX512DQ(t *testing.T) { + got := CPU.AVX512DQ() + expected := CPU.Features&AVX512DQ == AVX512DQ + if got != expected { + t.Fatalf("AVX512DQ: expected %v, got %v", expected, got) + } + t.Log("AVX512DQ Support:", got) +} + +// TestAVX512IFMA tests AVX512IFMA() function (AVX-512 Integer Fused Multiply-Add Instructions) +func TestAVX512IFMA(t *testing.T) { + got := CPU.AVX512IFMA() + expected := CPU.Features&AVX512IFMA == AVX512IFMA + if got != expected { + t.Fatalf("AVX512IFMA: expected %v, got %v", expected, got) + } + t.Log("AVX512IFMA Support:", got) +} + +// TestAVX512PF tests AVX512PF() function (AVX-512 Prefetch Instructions) +func TestAVX512PF(t *testing.T) { + got := CPU.AVX512PF() + expected := CPU.Features&AVX512PF == AVX512PF + if got != expected { + t.Fatalf("AVX512PF: expected %v, got %v", expected, got) + } + t.Log("AVX512PF Support:", got) +} + +// TestAVX512ER tests AVX512ER() function (AVX-512 Exponential and Reciprocal Instructions) +func TestAVX512ER(t *testing.T) { + got := CPU.AVX512ER() + expected := CPU.Features&AVX512ER == AVX512ER + if got != expected { + t.Fatalf("AVX512ER: expected %v, got %v", expected, got) + } + t.Log("AVX512ER Support:", got) +} + +// TestAVX512CD tests AVX512CD() function (AVX-512 Conflict Detection Instructions) +func TestAVX512CD(t *testing.T) { + got := CPU.AVX512CD() + expected := CPU.Features&AVX512CD == AVX512CD + if got != expected { + t.Fatalf("AVX512CD: expected %v, got %v", expected, got) + } + t.Log("AVX512CD Support:", got) +} + +// TestAVX512BW tests AVX512BW() function (AVX-512 Byte and Word Instructions) +func TestAVX512BW(t *testing.T) { + got := CPU.AVX512BW() + expected := CPU.Features&AVX512BW == AVX512BW + if got != expected { + t.Fatalf("AVX512BW: expected %v, got %v", expected, got) + } + t.Log("AVX512BW Support:", got) +} + +// TestAVX512VL tests AVX512VL() function (AVX-512 Vector Length Extensions) +func TestAVX512VL(t *testing.T) { + got := CPU.AVX512VL() + expected := CPU.Features&AVX512VL == AVX512VL + if got != expected { + t.Fatalf("AVX512VL: expected %v, got %v", expected, got) + } + t.Log("AVX512VL Support:", got) +} + +// TestAVX512VL tests AVX512VBMI() function (AVX-512 Vector Bit Manipulation Instructions) +func TestAVX512VBMI(t *testing.T) { + got := CPU.AVX512VBMI() + expected := CPU.Features&AVX512VBMI == AVX512VBMI + if got != expected { + t.Fatalf("AVX512VBMI: expected %v, got %v", expected, got) + } + t.Log("AVX512VBMI Support:", got) +} + +// TestMPX tests MPX() function (Intel MPX (Memory Protection Extensions)) +func TestMPX(t *testing.T) { + got := CPU.MPX() + expected := CPU.Features&MPX == MPX + if got != expected { + t.Fatalf("MPX: expected %v, got %v", expected, got) + } + t.Log("MPX Support:", got) +} + +// TestERMS tests ERMS() function (Enhanced REP MOVSB/STOSB) +func TestERMS(t *testing.T) { + got := CPU.ERMS() + expected := CPU.Features&ERMS == ERMS + if got != expected { + t.Fatalf("ERMS: expected %v, got %v", expected, got) + } + t.Log("ERMS Support:", got) +} + +// TestVendor writes the detected vendor. Will be 0 if unknown +func TestVendor(t *testing.T) { + t.Log("Vendor ID:", CPU.VendorID) +} + +// Intel returns true if vendor is recognized as Intel +func TestIntel(t *testing.T) { + got := CPU.Intel() + expected := CPU.VendorID == Intel + if got != expected { + t.Fatalf("TestIntel: expected %v, got %v", expected, got) + } + t.Log("TestIntel:", got) +} + +// AMD returns true if vendor is recognized as AMD +func TestAMD(t *testing.T) { + got := CPU.AMD() + expected := CPU.VendorID == AMD + if got != expected { + t.Fatalf("TestAMD: expected %v, got %v", expected, got) + } + t.Log("TestAMD:", got) +} + +// Transmeta returns true if vendor is recognized as Transmeta +func TestTransmeta(t *testing.T) { + got := CPU.Transmeta() + expected := CPU.VendorID == Transmeta + if got != expected { + t.Fatalf("TestTransmeta: expected %v, got %v", expected, got) + } + t.Log("TestTransmeta:", got) +} + +// NSC returns true if vendor is recognized as National Semiconductor +func TestNSC(t *testing.T) { + got := CPU.NSC() + expected := CPU.VendorID == NSC + if got != expected { + t.Fatalf("TestNSC: expected %v, got %v", expected, got) + } + t.Log("TestNSC:", got) +} + +// VIA returns true if vendor is recognized as VIA +func TestVIA(t *testing.T) { + got := CPU.VIA() + expected := CPU.VendorID == VIA + if got != expected { + t.Fatalf("TestVIA: expected %v, got %v", expected, got) + } + t.Log("TestVIA:", got) +} + +// Test VM function +func TestVM(t *testing.T) { + t.Log("Vendor ID:", CPU.VM()) +} + +// Test RTCounter function +func TestRtCounter(t *testing.T) { + a := CPU.RTCounter() + b := CPU.RTCounter() + t.Log("CPU Counter:", a, b, b-a) +} + +// Prints the value of Ia32TscAux() +func TestIa32TscAux(t *testing.T) { + ecx := CPU.Ia32TscAux() + t.Logf("Ia32TscAux:0x%x\n", ecx) + if ecx != 0 { + chip := (ecx & 0xFFF000) >> 12 + core := ecx & 0xFFF + t.Log("Likely chip, core:", chip, core) + } +} + +func TestThreadsPerCoreNZ(t *testing.T) { + if CPU.ThreadsPerCore == 0 { + t.Fatal("threads per core is zero") + } +} + +// Prints the value of LogicalCPU() +func TestLogicalCPU(t *testing.T) { + t.Log("Currently executing on cpu:", CPU.LogicalCPU()) +} + +func TestMaxFunction(t *testing.T) { + expect := maxFunctionID() + if CPU.maxFunc != expect { + t.Fatal("Max function does not match, expected", expect, "but got", CPU.maxFunc) + } + expect = maxExtendedFunction() + if CPU.maxExFunc != expect { + t.Fatal("Max Extended function does not match, expected", expect, "but got", CPU.maxFunc) + } +} + +// This example will calculate the chip/core number on Linux +// Linux encodes numa id (<<12) and core id (8bit) into TSC_AUX. +func ExampleCPUInfo_Ia32TscAux(t *testing.T) { + ecx := CPU.Ia32TscAux() + if ecx == 0 { + fmt.Println("Unknown CPU ID") + return + } + chip := (ecx & 0xFFF000) >> 12 + core := ecx & 0xFFF + fmt.Println("Chip, Core:", chip, core) +} + +/* +func TestPhysical(t *testing.T) { + var test16 = "CPUID 00000000: 0000000d-756e6547-6c65746e-49656e69 \nCPUID 00000001: 000206d7-03200800-1fbee3ff-bfebfbff \nCPUID 00000002: 76035a01-00f0b2ff-00000000-00ca0000 \nCPUID 00000003: 00000000-00000000-00000000-00000000 \nCPUID 00000004: 3c004121-01c0003f-0000003f-00000000 \nCPUID 00000004: 3c004122-01c0003f-0000003f-00000000 \nCPUID 00000004: 3c004143-01c0003f-000001ff-00000000 \nCPUID 00000004: 3c07c163-04c0003f-00003fff-00000006 \nCPUID 00000005: 00000040-00000040-00000003-00021120 \nCPUID 00000006: 00000075-00000002-00000009-00000000 \nCPUID 00000007: 00000000-00000000-00000000-00000000 \nCPUID 00000008: 00000000-00000000-00000000-00000000 \nCPUID 00000009: 00000001-00000000-00000000-00000000 \nCPUID 0000000a: 07300403-00000000-00000000-00000603 \nCPUID 0000000b: 00000000-00000000-00000003-00000003 \nCPUID 0000000b: 00000005-00000010-00000201-00000003 \nCPUID 0000000c: 00000000-00000000-00000000-00000000 \nCPUID 0000000d: 00000007-00000340-00000340-00000000 \nCPUID 0000000d: 00000001-00000000-00000000-00000000 \nCPUID 0000000d: 00000100-00000240-00000000-00000000 \nCPUID 80000000: 80000008-00000000-00000000-00000000 \nCPUID 80000001: 00000000-00000000-00000001-2c100800 \nCPUID 80000002: 20202020-49202020-6c65746e-20295228 \nCPUID 80000003: 6e6f6558-20295228-20555043-322d3545 \nCPUID 80000004: 20303636-20402030-30322e32-007a4847 \nCPUID 80000005: 00000000-00000000-00000000-00000000 \nCPUID 80000006: 00000000-00000000-01006040-00000000 \nCPUID 80000007: 00000000-00000000-00000000-00000100 \nCPUID 80000008: 0000302e-00000000-00000000-00000000" + restore := mockCPU([]byte(test16)) + Detect() + t.Log("Name:", CPU.BrandName) + n := maxFunctionID() + t.Logf("Max Function:0x%x\n", n) + n = maxExtendedFunction() + t.Logf("Max Extended Function:0x%x\n", n) + t.Log("PhysicalCores:", CPU.PhysicalCores) + t.Log("ThreadsPerCore:", CPU.ThreadsPerCore) + t.Log("LogicalCores:", CPU.LogicalCores) + t.Log("Family", CPU.Family, "Model:", CPU.Model) + t.Log("Features:", CPU.Features) + t.Log("Cacheline bytes:", CPU.CacheLine) + t.Log("L1 Instruction Cache:", CPU.Cache.L1I, "bytes") + t.Log("L1 Data Cache:", CPU.Cache.L1D, "bytes") + t.Log("L2 Cache:", CPU.Cache.L2, "bytes") + t.Log("L3 Cache:", CPU.Cache.L3, "bytes") + if CPU.LogicalCores > 0 && CPU.PhysicalCores > 0 { + if CPU.LogicalCores != CPU.PhysicalCores*CPU.ThreadsPerCore { + t.Fatalf("Core count mismatch, LogicalCores (%d) != PhysicalCores (%d) * CPU.ThreadsPerCore (%d)", + CPU.LogicalCores, CPU.PhysicalCores, CPU.ThreadsPerCore) + } + } + + if CPU.ThreadsPerCore > 1 && !CPU.HTT() { + t.Fatalf("Hyperthreading not detected") + } + if CPU.ThreadsPerCore == 1 && CPU.HTT() { + t.Fatalf("Hyperthreading detected, but only 1 Thread per core") + } + restore() + Detect() + TestCPUID(t) +} +*/ diff --git a/vendor/github.com/klauspost/cpuid/detect_intel.go b/vendor/github.com/klauspost/cpuid/detect_intel.go new file mode 100644 index 0000000..a5f04dd --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/detect_intel.go @@ -0,0 +1,17 @@ +// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. + +// +build 386,!gccgo amd64,!gccgo + +package cpuid + +func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32) +func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32) +func asmXgetbv(index uint32) (eax, edx uint32) +func asmRdtscpAsm() (eax, ebx, ecx, edx uint32) + +func initCPU() { + cpuid = asmCpuid + cpuidex = asmCpuidex + xgetbv = asmXgetbv + rdtscpAsm = asmRdtscpAsm +} diff --git a/vendor/github.com/klauspost/cpuid/detect_ref.go b/vendor/github.com/klauspost/cpuid/detect_ref.go new file mode 100644 index 0000000..909c5d9 --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/detect_ref.go @@ -0,0 +1,23 @@ +// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. + +// +build !amd64,!386 gccgo + +package cpuid + +func initCPU() { + cpuid = func(op uint32) (eax, ebx, ecx, edx uint32) { + return 0, 0, 0, 0 + } + + cpuidex = func(op, op2 uint32) (eax, ebx, ecx, edx uint32) { + return 0, 0, 0, 0 + } + + xgetbv = func(index uint32) (eax, edx uint32) { + return 0, 0 + } + + rdtscpAsm = func() (eax, ebx, ecx, edx uint32) { + return 0, 0, 0, 0 + } +} diff --git a/vendor/github.com/klauspost/cpuid/generate.go b/vendor/github.com/klauspost/cpuid/generate.go new file mode 100644 index 0000000..c060b81 --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/generate.go @@ -0,0 +1,3 @@ +package cpuid + +//go:generate go run private-gen.go diff --git a/vendor/github.com/klauspost/cpuid/mockcpu_test.go b/vendor/github.com/klauspost/cpuid/mockcpu_test.go new file mode 100644 index 0000000..f15173f --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/mockcpu_test.go @@ -0,0 +1,209 @@ +package cpuid + +import ( + "archive/zip" + "fmt" + "io/ioutil" + "sort" + "strings" + "testing" +) + +type fakecpuid map[uint32][][]uint32 + +type idfuncs struct { + cpuid func(op uint32) (eax, ebx, ecx, edx uint32) + cpuidex func(op, op2 uint32) (eax, ebx, ecx, edx uint32) + xgetbv func(index uint32) (eax, edx uint32) +} + +func (f fakecpuid) String() string { + var out = make([]string, 0, len(f)) + for key, val := range f { + for _, v := range val { + out = append(out, fmt.Sprintf("CPUID %08x: [%08x, %08x, %08x, %08x]", key, v[0], v[1], v[2], v[3])) + } + } + sorter := sort.StringSlice(out) + sort.Sort(&sorter) + return strings.Join(sorter, "\n") +} + +func mockCPU(def []byte) func() { + lines := strings.Split(string(def), "\n") + anyfound := false + fakeID := make(fakecpuid) + for _, line := range lines { + line = strings.Trim(line, "\r\t ") + if !strings.HasPrefix(line, "CPUID") { + continue + } + // Only collect for first cpu + if strings.HasPrefix(line, "CPUID 00000000") { + if anyfound { + break + } + } + if !strings.Contains(line, "-") { + //continue + } + items := strings.Split(line, ":") + if len(items) < 2 { + if len(line) == 51 || len(line) == 50 { + items = []string{line[0:14], line[15:]} + } else { + items = strings.Split(line, "\t") + if len(items) != 2 { + //fmt.Println("not found:", line, "len:", len(line)) + continue + } + } + } + items = items[0:2] + vals := strings.Trim(items[1], "\r\n ") + + var idV uint32 + n, err := fmt.Sscanf(items[0], "CPUID %x", &idV) + if err != nil || n != 1 { + continue + } + existing, ok := fakeID[idV] + if !ok { + existing = make([][]uint32, 0) + } + + values := make([]uint32, 4) + n, err = fmt.Sscanf(vals, "%x-%x-%x-%x", &values[0], &values[1], &values[2], &values[3]) + if n != 4 || err != nil { + n, err = fmt.Sscanf(vals, "%x %x %x %x", &values[0], &values[1], &values[2], &values[3]) + if n != 4 || err != nil { + //fmt.Println("scanned", vals, "got", n, "Err:", err) + continue + } + } + + existing = append(existing, values) + fakeID[idV] = existing + anyfound = true + } + + restorer := func(f idfuncs) func() { + return func() { + cpuid = f.cpuid + cpuidex = f.cpuidex + xgetbv = f.xgetbv + } + }(idfuncs{cpuid: cpuid, cpuidex: cpuidex, xgetbv: xgetbv}) + + cpuid = func(op uint32) (eax, ebx, ecx, edx uint32) { + if op == 0x80000000 || op == 0 { + var ok bool + _, ok = fakeID[op] + if !ok { + return 0, 0, 0, 0 + } + } + first, ok := fakeID[op] + if !ok { + if op > maxFunctionID() { + panic(fmt.Sprintf("Base not found: %v, request:%#v\n", fakeID, op)) + } else { + // we have some entries missing + return 0, 0, 0, 0 + } + } + theid := first[0] + return theid[0], theid[1], theid[2], theid[3] + } + cpuidex = func(op, op2 uint32) (eax, ebx, ecx, edx uint32) { + if op == 0x80000000 { + var ok bool + _, ok = fakeID[op] + if !ok { + return 0, 0, 0, 0 + } + } + first, ok := fakeID[op] + if !ok { + if op > maxExtendedFunction() { + panic(fmt.Sprintf("Extended not found Info: %v, request:%#v, %#v\n", fakeID, op, op2)) + } else { + // we have some entries missing + return 0, 0, 0, 0 + } + } + if int(op2) >= len(first) { + //fmt.Printf("Extended not found Info: %v, request:%#v, %#v\n", fakeID, op, op2) + return 0, 0, 0, 0 + } + theid := first[op2] + return theid[0], theid[1], theid[2], theid[3] + } + xgetbv = func(index uint32) (eax, edx uint32) { + first, ok := fakeID[1] + if !ok { + panic(fmt.Sprintf("XGETBV not supported %v", fakeID)) + } + second := first[0] + // ECX bit 26 must be set + if (second[2] & 1 << 26) == 0 { + panic(fmt.Sprintf("XGETBV not supported %v", fakeID)) + } + // We don't have any data to return, unfortunately + return 0, 0 + } + return restorer +} + +func TestMocks(t *testing.T) { + zr, err := zip.OpenReader("testdata/cpuid_data.zip") + if err != nil { + t.Skip("No testdata:", err) + } + defer zr.Close() + for _, f := range zr.File { + rc, err := f.Open() + if err != nil { + t.Fatal(err) + } + content, err := ioutil.ReadAll(rc) + if err != nil { + t.Fatal(err) + } + rc.Close() + t.Log("Opening", f.FileInfo().Name()) + restore := mockCPU(content) + Detect() + t.Log("Name:", CPU.BrandName) + n := maxFunctionID() + t.Logf("Max Function:0x%x\n", n) + n = maxExtendedFunction() + t.Logf("Max Extended Function:0x%x\n", n) + t.Log("PhysicalCores:", CPU.PhysicalCores) + t.Log("ThreadsPerCore:", CPU.ThreadsPerCore) + t.Log("LogicalCores:", CPU.LogicalCores) + t.Log("Family", CPU.Family, "Model:", CPU.Model) + t.Log("Features:", CPU.Features) + t.Log("Cacheline bytes:", CPU.CacheLine) + t.Log("L1 Instruction Cache:", CPU.Cache.L1I, "bytes") + t.Log("L1 Data Cache:", CPU.Cache.L1D, "bytes") + t.Log("L2 Cache:", CPU.Cache.L2, "bytes") + t.Log("L3 Cache:", CPU.Cache.L3, "bytes") + if CPU.LogicalCores > 0 && CPU.PhysicalCores > 0 { + if CPU.LogicalCores != CPU.PhysicalCores*CPU.ThreadsPerCore { + t.Fatalf("Core count mismatch, LogicalCores (%d) != PhysicalCores (%d) * CPU.ThreadsPerCore (%d)", + CPU.LogicalCores, CPU.PhysicalCores, CPU.ThreadsPerCore) + } + } + + if CPU.ThreadsPerCore > 1 && !CPU.HTT() { + t.Fatalf("Hyperthreading not detected") + } + if CPU.ThreadsPerCore == 1 && CPU.HTT() { + t.Fatalf("Hyperthreading detected, but only 1 Thread per core") + } + restore() + } + Detect() + +} diff --git a/vendor/github.com/klauspost/cpuid/private-gen.go b/vendor/github.com/klauspost/cpuid/private-gen.go new file mode 100644 index 0000000..437333d --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/private-gen.go @@ -0,0 +1,476 @@ +// +build ignore + +package main + +import ( + "bytes" + "fmt" + "go/ast" + "go/parser" + "go/printer" + "go/token" + "io" + "io/ioutil" + "log" + "os" + "reflect" + "strings" + "unicode" + "unicode/utf8" +) + +var inFiles = []string{"cpuid.go", "cpuid_test.go"} +var copyFiles = []string{"cpuid_amd64.s", "cpuid_386.s", "detect_ref.go", "detect_intel.go"} +var fileSet = token.NewFileSet() +var reWrites = []rewrite{ + initRewrite("CPUInfo -> cpuInfo"), + initRewrite("Vendor -> vendor"), + initRewrite("Flags -> flags"), + initRewrite("Detect -> detect"), + initRewrite("CPU -> cpu"), +} +var excludeNames = map[string]bool{"string": true, "join": true, "trim": true, + // cpuid_test.go + "t": true, "println": true, "logf": true, "log": true, "fatalf": true, "fatal": true, +} + +var excludePrefixes = []string{"test", "benchmark"} + +func main() { + Package := "private" + parserMode := parser.ParseComments + exported := make(map[string]rewrite) + for _, file := range inFiles { + in, err := os.Open(file) + if err != nil { + log.Fatalf("opening input", err) + } + + src, err := ioutil.ReadAll(in) + if err != nil { + log.Fatalf("reading input", err) + } + + astfile, err := parser.ParseFile(fileSet, file, src, parserMode) + if err != nil { + log.Fatalf("parsing input", err) + } + + for _, rw := range reWrites { + astfile = rw(astfile) + } + + // Inspect the AST and print all identifiers and literals. + var startDecl token.Pos + var endDecl token.Pos + ast.Inspect(astfile, func(n ast.Node) bool { + var s string + switch x := n.(type) { + case *ast.Ident: + if x.IsExported() { + t := strings.ToLower(x.Name) + for _, pre := range excludePrefixes { + if strings.HasPrefix(t, pre) { + return true + } + } + if excludeNames[t] != true { + //if x.Pos() > startDecl && x.Pos() < endDecl { + exported[x.Name] = initRewrite(x.Name + " -> " + t) + } + } + + case *ast.GenDecl: + if x.Tok == token.CONST && x.Lparen > 0 { + startDecl = x.Lparen + endDecl = x.Rparen + // fmt.Printf("Decl:%s -> %s\n", fileSet.Position(startDecl), fileSet.Position(endDecl)) + } + } + if s != "" { + fmt.Printf("%s:\t%s\n", fileSet.Position(n.Pos()), s) + } + return true + }) + + for _, rw := range exported { + astfile = rw(astfile) + } + + var buf bytes.Buffer + + printer.Fprint(&buf, fileSet, astfile) + + // Remove package documentation and insert information + s := buf.String() + ind := strings.Index(buf.String(), "\npackage cpuid") + s = s[ind:] + s = "// Generated, DO NOT EDIT,\n" + + "// but copy it to your own project and rename the package.\n" + + "// See more at http://github.com/klauspost/cpuid\n" + + s + + outputName := Package + string(os.PathSeparator) + file + + err = ioutil.WriteFile(outputName, []byte(s), 0644) + if err != nil { + log.Fatalf("writing output: %s", err) + } + log.Println("Generated", outputName) + } + + for _, file := range copyFiles { + dst := "" + if strings.HasPrefix(file, "cpuid") { + dst = Package + string(os.PathSeparator) + file + } else { + dst = Package + string(os.PathSeparator) + "cpuid_" + file + } + err := copyFile(file, dst) + if err != nil { + log.Fatalf("copying file: %s", err) + } + log.Println("Copied", dst) + } +} + +// CopyFile copies a file from src to dst. If src and dst files exist, and are +// the same, then return success. Copy the file contents from src to dst. +func copyFile(src, dst string) (err error) { + sfi, err := os.Stat(src) + if err != nil { + return + } + if !sfi.Mode().IsRegular() { + // cannot copy non-regular files (e.g., directories, + // symlinks, devices, etc.) + return fmt.Errorf("CopyFile: non-regular source file %s (%q)", sfi.Name(), sfi.Mode().String()) + } + dfi, err := os.Stat(dst) + if err != nil { + if !os.IsNotExist(err) { + return + } + } else { + if !(dfi.Mode().IsRegular()) { + return fmt.Errorf("CopyFile: non-regular destination file %s (%q)", dfi.Name(), dfi.Mode().String()) + } + if os.SameFile(sfi, dfi) { + return + } + } + err = copyFileContents(src, dst) + return +} + +// copyFileContents copies the contents of the file named src to the file named +// by dst. The file will be created if it does not already exist. If the +// destination file exists, all it's contents will be replaced by the contents +// of the source file. +func copyFileContents(src, dst string) (err error) { + in, err := os.Open(src) + if err != nil { + return + } + defer in.Close() + out, err := os.Create(dst) + if err != nil { + return + } + defer func() { + cerr := out.Close() + if err == nil { + err = cerr + } + }() + if _, err = io.Copy(out, in); err != nil { + return + } + err = out.Sync() + return +} + +type rewrite func(*ast.File) *ast.File + +// Mostly copied from gofmt +func initRewrite(rewriteRule string) rewrite { + f := strings.Split(rewriteRule, "->") + if len(f) != 2 { + fmt.Fprintf(os.Stderr, "rewrite rule must be of the form 'pattern -> replacement'\n") + os.Exit(2) + } + pattern := parseExpr(f[0], "pattern") + replace := parseExpr(f[1], "replacement") + return func(p *ast.File) *ast.File { return rewriteFile(pattern, replace, p) } +} + +// parseExpr parses s as an expression. +// It might make sense to expand this to allow statement patterns, +// but there are problems with preserving formatting and also +// with what a wildcard for a statement looks like. +func parseExpr(s, what string) ast.Expr { + x, err := parser.ParseExpr(s) + if err != nil { + fmt.Fprintf(os.Stderr, "parsing %s %s at %s\n", what, s, err) + os.Exit(2) + } + return x +} + +// Keep this function for debugging. +/* +func dump(msg string, val reflect.Value) { + fmt.Printf("%s:\n", msg) + ast.Print(fileSet, val.Interface()) + fmt.Println() +} +*/ + +// rewriteFile applies the rewrite rule 'pattern -> replace' to an entire file. +func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File { + cmap := ast.NewCommentMap(fileSet, p, p.Comments) + m := make(map[string]reflect.Value) + pat := reflect.ValueOf(pattern) + repl := reflect.ValueOf(replace) + + var rewriteVal func(val reflect.Value) reflect.Value + rewriteVal = func(val reflect.Value) reflect.Value { + // don't bother if val is invalid to start with + if !val.IsValid() { + return reflect.Value{} + } + for k := range m { + delete(m, k) + } + val = apply(rewriteVal, val) + if match(m, pat, val) { + val = subst(m, repl, reflect.ValueOf(val.Interface().(ast.Node).Pos())) + } + return val + } + + r := apply(rewriteVal, reflect.ValueOf(p)).Interface().(*ast.File) + r.Comments = cmap.Filter(r).Comments() // recreate comments list + return r +} + +// set is a wrapper for x.Set(y); it protects the caller from panics if x cannot be changed to y. +func set(x, y reflect.Value) { + // don't bother if x cannot be set or y is invalid + if !x.CanSet() || !y.IsValid() { + return + } + defer func() { + if x := recover(); x != nil { + if s, ok := x.(string); ok && + (strings.Contains(s, "type mismatch") || strings.Contains(s, "not assignable")) { + // x cannot be set to y - ignore this rewrite + return + } + panic(x) + } + }() + x.Set(y) +} + +// Values/types for special cases. +var ( + objectPtrNil = reflect.ValueOf((*ast.Object)(nil)) + scopePtrNil = reflect.ValueOf((*ast.Scope)(nil)) + + identType = reflect.TypeOf((*ast.Ident)(nil)) + objectPtrType = reflect.TypeOf((*ast.Object)(nil)) + positionType = reflect.TypeOf(token.NoPos) + callExprType = reflect.TypeOf((*ast.CallExpr)(nil)) + scopePtrType = reflect.TypeOf((*ast.Scope)(nil)) +) + +// apply replaces each AST field x in val with f(x), returning val. +// To avoid extra conversions, f operates on the reflect.Value form. +func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value { + if !val.IsValid() { + return reflect.Value{} + } + + // *ast.Objects introduce cycles and are likely incorrect after + // rewrite; don't follow them but replace with nil instead + if val.Type() == objectPtrType { + return objectPtrNil + } + + // similarly for scopes: they are likely incorrect after a rewrite; + // replace them with nil + if val.Type() == scopePtrType { + return scopePtrNil + } + + switch v := reflect.Indirect(val); v.Kind() { + case reflect.Slice: + for i := 0; i < v.Len(); i++ { + e := v.Index(i) + set(e, f(e)) + } + case reflect.Struct: + for i := 0; i < v.NumField(); i++ { + e := v.Field(i) + set(e, f(e)) + } + case reflect.Interface: + e := v.Elem() + set(v, f(e)) + } + return val +} + +func isWildcard(s string) bool { + rune, size := utf8.DecodeRuneInString(s) + return size == len(s) && unicode.IsLower(rune) +} + +// match returns true if pattern matches val, +// recording wildcard submatches in m. +// If m == nil, match checks whether pattern == val. +func match(m map[string]reflect.Value, pattern, val reflect.Value) bool { + // Wildcard matches any expression. If it appears multiple + // times in the pattern, it must match the same expression + // each time. + if m != nil && pattern.IsValid() && pattern.Type() == identType { + name := pattern.Interface().(*ast.Ident).Name + if isWildcard(name) && val.IsValid() { + // wildcards only match valid (non-nil) expressions. + if _, ok := val.Interface().(ast.Expr); ok && !val.IsNil() { + if old, ok := m[name]; ok { + return match(nil, old, val) + } + m[name] = val + return true + } + } + } + + // Otherwise, pattern and val must match recursively. + if !pattern.IsValid() || !val.IsValid() { + return !pattern.IsValid() && !val.IsValid() + } + if pattern.Type() != val.Type() { + return false + } + + // Special cases. + switch pattern.Type() { + case identType: + // For identifiers, only the names need to match + // (and none of the other *ast.Object information). + // This is a common case, handle it all here instead + // of recursing down any further via reflection. + p := pattern.Interface().(*ast.Ident) + v := val.Interface().(*ast.Ident) + return p == nil && v == nil || p != nil && v != nil && p.Name == v.Name + case objectPtrType, positionType: + // object pointers and token positions always match + return true + case callExprType: + // For calls, the Ellipsis fields (token.Position) must + // match since that is how f(x) and f(x...) are different. + // Check them here but fall through for the remaining fields. + p := pattern.Interface().(*ast.CallExpr) + v := val.Interface().(*ast.CallExpr) + if p.Ellipsis.IsValid() != v.Ellipsis.IsValid() { + return false + } + } + + p := reflect.Indirect(pattern) + v := reflect.Indirect(val) + if !p.IsValid() || !v.IsValid() { + return !p.IsValid() && !v.IsValid() + } + + switch p.Kind() { + case reflect.Slice: + if p.Len() != v.Len() { + return false + } + for i := 0; i < p.Len(); i++ { + if !match(m, p.Index(i), v.Index(i)) { + return false + } + } + return true + + case reflect.Struct: + for i := 0; i < p.NumField(); i++ { + if !match(m, p.Field(i), v.Field(i)) { + return false + } + } + return true + + case reflect.Interface: + return match(m, p.Elem(), v.Elem()) + } + + // Handle token integers, etc. + return p.Interface() == v.Interface() +} + +// subst returns a copy of pattern with values from m substituted in place +// of wildcards and pos used as the position of tokens from the pattern. +// if m == nil, subst returns a copy of pattern and doesn't change the line +// number information. +func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value) reflect.Value { + if !pattern.IsValid() { + return reflect.Value{} + } + + // Wildcard gets replaced with map value. + if m != nil && pattern.Type() == identType { + name := pattern.Interface().(*ast.Ident).Name + if isWildcard(name) { + if old, ok := m[name]; ok { + return subst(nil, old, reflect.Value{}) + } + } + } + + if pos.IsValid() && pattern.Type() == positionType { + // use new position only if old position was valid in the first place + if old := pattern.Interface().(token.Pos); !old.IsValid() { + return pattern + } + return pos + } + + // Otherwise copy. + switch p := pattern; p.Kind() { + case reflect.Slice: + v := reflect.MakeSlice(p.Type(), p.Len(), p.Len()) + for i := 0; i < p.Len(); i++ { + v.Index(i).Set(subst(m, p.Index(i), pos)) + } + return v + + case reflect.Struct: + v := reflect.New(p.Type()).Elem() + for i := 0; i < p.NumField(); i++ { + v.Field(i).Set(subst(m, p.Field(i), pos)) + } + return v + + case reflect.Ptr: + v := reflect.New(p.Type()).Elem() + if elem := p.Elem(); elem.IsValid() { + v.Set(subst(m, elem, pos).Addr()) + } + return v + + case reflect.Interface: + v := reflect.New(p.Type()).Elem() + if elem := p.Elem(); elem.IsValid() { + v.Set(subst(m, elem, pos)) + } + return v + } + + return pattern +} diff --git a/vendor/github.com/klauspost/cpuid/private/README.md b/vendor/github.com/klauspost/cpuid/private/README.md new file mode 100644 index 0000000..57a68f8 --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/private/README.md @@ -0,0 +1,6 @@ +# cpuid private + +This is a specially converted of the cpuid package, so it can be included in +a package without exporting anything. + +Package home: https://github.com/klauspost/cpuid diff --git a/vendor/github.com/klauspost/cpuid/private/cpuid.go b/vendor/github.com/klauspost/cpuid/private/cpuid.go new file mode 100644 index 0000000..be99cb0 --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/private/cpuid.go @@ -0,0 +1,987 @@ +// Generated, DO NOT EDIT, +// but copy it to your own project and rename the package. +// See more at http://github.com/klauspost/cpuid + +package cpuid + +import ( + "strings" +) + +// Vendor is a representation of a CPU vendor. +type vendor int + +const ( + other vendor = iota + intel + amd + via + transmeta + nsc + kvm // Kernel-based Virtual Machine + msvm // Microsoft Hyper-V or Windows Virtual PC + vmware + xenhvm +) + +const ( + cmov = 1 << iota // i686 CMOV + nx // NX (No-Execute) bit + amd3dnow // AMD 3DNOW + amd3dnowext // AMD 3DNowExt + mmx // standard MMX + mmxext // SSE integer functions or AMD MMX ext + sse // SSE functions + sse2 // P4 SSE functions + sse3 // Prescott SSE3 functions + ssse3 // Conroe SSSE3 functions + sse4 // Penryn SSE4.1 functions + sse4a // AMD Barcelona microarchitecture SSE4a instructions + sse42 // Nehalem SSE4.2 functions + avx // AVX functions + avx2 // AVX2 functions + fma3 // Intel FMA 3 + fma4 // Bulldozer FMA4 functions + xop // Bulldozer XOP functions + f16c // Half-precision floating-point conversion + bmi1 // Bit Manipulation Instruction Set 1 + bmi2 // Bit Manipulation Instruction Set 2 + tbm // AMD Trailing Bit Manipulation + lzcnt // LZCNT instruction + popcnt // POPCNT instruction + aesni // Advanced Encryption Standard New Instructions + clmul // Carry-less Multiplication + htt // Hyperthreading (enabled) + hle // Hardware Lock Elision + rtm // Restricted Transactional Memory + rdrand // RDRAND instruction is available + rdseed // RDSEED instruction is available + adx // Intel ADX (Multi-Precision Add-Carry Instruction Extensions) + sha // Intel SHA Extensions + avx512f // AVX-512 Foundation + avx512dq // AVX-512 Doubleword and Quadword Instructions + avx512ifma // AVX-512 Integer Fused Multiply-Add Instructions + avx512pf // AVX-512 Prefetch Instructions + avx512er // AVX-512 Exponential and Reciprocal Instructions + avx512cd // AVX-512 Conflict Detection Instructions + avx512bw // AVX-512 Byte and Word Instructions + avx512vl // AVX-512 Vector Length Extensions + avx512vbmi // AVX-512 Vector Bit Manipulation Instructions + mpx // Intel MPX (Memory Protection Extensions) + erms // Enhanced REP MOVSB/STOSB + rdtscp // RDTSCP Instruction + cx16 // CMPXCHG16B Instruction + + // Performance indicators + sse2slow // SSE2 is supported, but usually not faster + sse3slow // SSE3 is supported, but usually not faster + atom // Atom processor, some SSSE3 instructions are slower +) + +var flagNames = map[flags]string{ + cmov: "CMOV", // i686 CMOV + nx: "NX", // NX (No-Execute) bit + amd3dnow: "AMD3DNOW", // AMD 3DNOW + amd3dnowext: "AMD3DNOWEXT", // AMD 3DNowExt + mmx: "MMX", // Standard MMX + mmxext: "MMXEXT", // SSE integer functions or AMD MMX ext + sse: "SSE", // SSE functions + sse2: "SSE2", // P4 SSE2 functions + sse3: "SSE3", // Prescott SSE3 functions + ssse3: "SSSE3", // Conroe SSSE3 functions + sse4: "SSE4.1", // Penryn SSE4.1 functions + sse4a: "SSE4A", // AMD Barcelona microarchitecture SSE4a instructions + sse42: "SSE4.2", // Nehalem SSE4.2 functions + avx: "AVX", // AVX functions + avx2: "AVX2", // AVX functions + fma3: "FMA3", // Intel FMA 3 + fma4: "FMA4", // Bulldozer FMA4 functions + xop: "XOP", // Bulldozer XOP functions + f16c: "F16C", // Half-precision floating-point conversion + bmi1: "BMI1", // Bit Manipulation Instruction Set 1 + bmi2: "BMI2", // Bit Manipulation Instruction Set 2 + tbm: "TBM", // AMD Trailing Bit Manipulation + lzcnt: "LZCNT", // LZCNT instruction + popcnt: "POPCNT", // POPCNT instruction + aesni: "AESNI", // Advanced Encryption Standard New Instructions + clmul: "CLMUL", // Carry-less Multiplication + htt: "HTT", // Hyperthreading (enabled) + hle: "HLE", // Hardware Lock Elision + rtm: "RTM", // Restricted Transactional Memory + rdrand: "RDRAND", // RDRAND instruction is available + rdseed: "RDSEED", // RDSEED instruction is available + adx: "ADX", // Intel ADX (Multi-Precision Add-Carry Instruction Extensions) + sha: "SHA", // Intel SHA Extensions + avx512f: "AVX512F", // AVX-512 Foundation + avx512dq: "AVX512DQ", // AVX-512 Doubleword and Quadword Instructions + avx512ifma: "AVX512IFMA", // AVX-512 Integer Fused Multiply-Add Instructions + avx512pf: "AVX512PF", // AVX-512 Prefetch Instructions + avx512er: "AVX512ER", // AVX-512 Exponential and Reciprocal Instructions + avx512cd: "AVX512CD", // AVX-512 Conflict Detection Instructions + avx512bw: "AVX512BW", // AVX-512 Byte and Word Instructions + avx512vl: "AVX512VL", // AVX-512 Vector Length Extensions + avx512vbmi: "AVX512VBMI", // AVX-512 Vector Bit Manipulation Instructions + mpx: "MPX", // Intel MPX (Memory Protection Extensions) + erms: "ERMS", // Enhanced REP MOVSB/STOSB + rdtscp: "RDTSCP", // RDTSCP Instruction + cx16: "CX16", // CMPXCHG16B Instruction + + // Performance indicators + sse2slow: "SSE2SLOW", // SSE2 supported, but usually not faster + sse3slow: "SSE3SLOW", // SSE3 supported, but usually not faster + atom: "ATOM", // Atom processor, some SSSE3 instructions are slower + +} + +// CPUInfo contains information about the detected system CPU. +type cpuInfo struct { + brandname string // Brand name reported by the CPU + vendorid vendor // Comparable CPU vendor ID + features flags // Features of the CPU + physicalcores int // Number of physical processor cores in your CPU. Will be 0 if undetectable. + threadspercore int // Number of threads per physical core. Will be 1 if undetectable. + logicalcores int // Number of physical cores times threads that can run on each core through the use of hyperthreading. Will be 0 if undetectable. + family int // CPU family number + model int // CPU model number + cacheline int // Cache line size in bytes. Will be 0 if undetectable. + cache struct { + l1i int // L1 Instruction Cache (per core or shared). Will be -1 if undetected + l1d int // L1 Data Cache (per core or shared). Will be -1 if undetected + l2 int // L2 Cache (per core or shared). Will be -1 if undetected + l3 int // L3 Instruction Cache (per core or shared). Will be -1 if undetected + } + maxFunc uint32 + maxExFunc uint32 +} + +var cpuid func(op uint32) (eax, ebx, ecx, edx uint32) +var cpuidex func(op, op2 uint32) (eax, ebx, ecx, edx uint32) +var xgetbv func(index uint32) (eax, edx uint32) +var rdtscpAsm func() (eax, ebx, ecx, edx uint32) + +// CPU contains information about the CPU as detected on startup, +// or when Detect last was called. +// +// Use this as the primary entry point to you data, +// this way queries are +var cpu cpuInfo + +func init() { + initCPU() + detect() +} + +// Detect will re-detect current CPU info. +// This will replace the content of the exported CPU variable. +// +// Unless you expect the CPU to change while you are running your program +// you should not need to call this function. +// If you call this, you must ensure that no other goroutine is accessing the +// exported CPU variable. +func detect() { + cpu.maxFunc = maxFunctionID() + cpu.maxExFunc = maxExtendedFunction() + cpu.brandname = brandName() + cpu.cacheline = cacheLine() + cpu.family, cpu.model = familyModel() + cpu.features = support() + cpu.threadspercore = threadsPerCore() + cpu.logicalcores = logicalCores() + cpu.physicalcores = physicalCores() + cpu.vendorid = vendorID() + cpu.cacheSize() +} + +// Generated here: http://play.golang.org/p/BxFH2Gdc0G + +// Cmov indicates support of CMOV instructions +func (c cpuInfo) cmov() bool { + return c.features&cmov != 0 +} + +// Amd3dnow indicates support of AMD 3DNOW! instructions +func (c cpuInfo) amd3dnow() bool { + return c.features&amd3dnow != 0 +} + +// Amd3dnowExt indicates support of AMD 3DNOW! Extended instructions +func (c cpuInfo) amd3dnowext() bool { + return c.features&amd3dnowext != 0 +} + +// MMX indicates support of MMX instructions +func (c cpuInfo) mmx() bool { + return c.features&mmx != 0 +} + +// MMXExt indicates support of MMXEXT instructions +// (SSE integer functions or AMD MMX ext) +func (c cpuInfo) mmxext() bool { + return c.features&mmxext != 0 +} + +// SSE indicates support of SSE instructions +func (c cpuInfo) sse() bool { + return c.features&sse != 0 +} + +// SSE2 indicates support of SSE 2 instructions +func (c cpuInfo) sse2() bool { + return c.features&sse2 != 0 +} + +// SSE3 indicates support of SSE 3 instructions +func (c cpuInfo) sse3() bool { + return c.features&sse3 != 0 +} + +// SSSE3 indicates support of SSSE 3 instructions +func (c cpuInfo) ssse3() bool { + return c.features&ssse3 != 0 +} + +// SSE4 indicates support of SSE 4 (also called SSE 4.1) instructions +func (c cpuInfo) sse4() bool { + return c.features&sse4 != 0 +} + +// SSE42 indicates support of SSE4.2 instructions +func (c cpuInfo) sse42() bool { + return c.features&sse42 != 0 +} + +// AVX indicates support of AVX instructions +// and operating system support of AVX instructions +func (c cpuInfo) avx() bool { + return c.features&avx != 0 +} + +// AVX2 indicates support of AVX2 instructions +func (c cpuInfo) avx2() bool { + return c.features&avx2 != 0 +} + +// FMA3 indicates support of FMA3 instructions +func (c cpuInfo) fma3() bool { + return c.features&fma3 != 0 +} + +// FMA4 indicates support of FMA4 instructions +func (c cpuInfo) fma4() bool { + return c.features&fma4 != 0 +} + +// XOP indicates support of XOP instructions +func (c cpuInfo) xop() bool { + return c.features&xop != 0 +} + +// F16C indicates support of F16C instructions +func (c cpuInfo) f16c() bool { + return c.features&f16c != 0 +} + +// BMI1 indicates support of BMI1 instructions +func (c cpuInfo) bmi1() bool { + return c.features&bmi1 != 0 +} + +// BMI2 indicates support of BMI2 instructions +func (c cpuInfo) bmi2() bool { + return c.features&bmi2 != 0 +} + +// TBM indicates support of TBM instructions +// (AMD Trailing Bit Manipulation) +func (c cpuInfo) tbm() bool { + return c.features&tbm != 0 +} + +// Lzcnt indicates support of LZCNT instruction +func (c cpuInfo) lzcnt() bool { + return c.features&lzcnt != 0 +} + +// Popcnt indicates support of POPCNT instruction +func (c cpuInfo) popcnt() bool { + return c.features&popcnt != 0 +} + +// HTT indicates the processor has Hyperthreading enabled +func (c cpuInfo) htt() bool { + return c.features&htt != 0 +} + +// SSE2Slow indicates that SSE2 may be slow on this processor +func (c cpuInfo) sse2slow() bool { + return c.features&sse2slow != 0 +} + +// SSE3Slow indicates that SSE3 may be slow on this processor +func (c cpuInfo) sse3slow() bool { + return c.features&sse3slow != 0 +} + +// AesNi indicates support of AES-NI instructions +// (Advanced Encryption Standard New Instructions) +func (c cpuInfo) aesni() bool { + return c.features&aesni != 0 +} + +// Clmul indicates support of CLMUL instructions +// (Carry-less Multiplication) +func (c cpuInfo) clmul() bool { + return c.features&clmul != 0 +} + +// NX indicates support of NX (No-Execute) bit +func (c cpuInfo) nx() bool { + return c.features&nx != 0 +} + +// SSE4A indicates support of AMD Barcelona microarchitecture SSE4a instructions +func (c cpuInfo) sse4a() bool { + return c.features&sse4a != 0 +} + +// HLE indicates support of Hardware Lock Elision +func (c cpuInfo) hle() bool { + return c.features&hle != 0 +} + +// RTM indicates support of Restricted Transactional Memory +func (c cpuInfo) rtm() bool { + return c.features&rtm != 0 +} + +// Rdrand indicates support of RDRAND instruction is available +func (c cpuInfo) rdrand() bool { + return c.features&rdrand != 0 +} + +// Rdseed indicates support of RDSEED instruction is available +func (c cpuInfo) rdseed() bool { + return c.features&rdseed != 0 +} + +// ADX indicates support of Intel ADX (Multi-Precision Add-Carry Instruction Extensions) +func (c cpuInfo) adx() bool { + return c.features&adx != 0 +} + +// SHA indicates support of Intel SHA Extensions +func (c cpuInfo) sha() bool { + return c.features&sha != 0 +} + +// AVX512F indicates support of AVX-512 Foundation +func (c cpuInfo) avx512f() bool { + return c.features&avx512f != 0 +} + +// AVX512DQ indicates support of AVX-512 Doubleword and Quadword Instructions +func (c cpuInfo) avx512dq() bool { + return c.features&avx512dq != 0 +} + +// AVX512IFMA indicates support of AVX-512 Integer Fused Multiply-Add Instructions +func (c cpuInfo) avx512ifma() bool { + return c.features&avx512ifma != 0 +} + +// AVX512PF indicates support of AVX-512 Prefetch Instructions +func (c cpuInfo) avx512pf() bool { + return c.features&avx512pf != 0 +} + +// AVX512ER indicates support of AVX-512 Exponential and Reciprocal Instructions +func (c cpuInfo) avx512er() bool { + return c.features&avx512er != 0 +} + +// AVX512CD indicates support of AVX-512 Conflict Detection Instructions +func (c cpuInfo) avx512cd() bool { + return c.features&avx512cd != 0 +} + +// AVX512BW indicates support of AVX-512 Byte and Word Instructions +func (c cpuInfo) avx512bw() bool { + return c.features&avx512bw != 0 +} + +// AVX512VL indicates support of AVX-512 Vector Length Extensions +func (c cpuInfo) avx512vl() bool { + return c.features&avx512vl != 0 +} + +// AVX512VBMI indicates support of AVX-512 Vector Bit Manipulation Instructions +func (c cpuInfo) avx512vbmi() bool { + return c.features&avx512vbmi != 0 +} + +// MPX indicates support of Intel MPX (Memory Protection Extensions) +func (c cpuInfo) mpx() bool { + return c.features&mpx != 0 +} + +// ERMS indicates support of Enhanced REP MOVSB/STOSB +func (c cpuInfo) erms() bool { + return c.features&erms != 0 +} + +func (c cpuInfo) rdtscp() bool { + return c.features&rdtscp != 0 +} + +func (c cpuInfo) cx16() bool { + return c.features&cx16 != 0 +} + +// Atom indicates an Atom processor +func (c cpuInfo) atom() bool { + return c.features&atom != 0 +} + +// Intel returns true if vendor is recognized as Intel +func (c cpuInfo) intel() bool { + return c.vendorid == intel +} + +// AMD returns true if vendor is recognized as AMD +func (c cpuInfo) amd() bool { + return c.vendorid == amd +} + +// Transmeta returns true if vendor is recognized as Transmeta +func (c cpuInfo) transmeta() bool { + return c.vendorid == transmeta +} + +// NSC returns true if vendor is recognized as National Semiconductor +func (c cpuInfo) nsc() bool { + return c.vendorid == nsc +} + +// VIA returns true if vendor is recognized as VIA +func (c cpuInfo) via() bool { + return c.vendorid == via +} + +// RTCounter returns the 64-bit time-stamp counter +// Uses the RDTSCP instruction. The value 0 is returned +// if the CPU does not support the instruction. +func (c cpuInfo) rtcounter() uint64 { + if !c.rdtscp() { + return 0 + } + a, _, _, d := rdtscpAsm() + return uint64(a) | (uint64(d) << 32) +} + +// Ia32TscAux returns the IA32_TSC_AUX part of the RDTSCP. +// This variable is OS dependent, but on Linux contains information +// about the current cpu/core the code is running on. +// If the RDTSCP instruction isn't supported on the CPU, the value 0 is returned. +func (c cpuInfo) ia32tscaux() uint32 { + if !c.rdtscp() { + return 0 + } + _, _, ecx, _ := rdtscpAsm() + return ecx +} + +// LogicalCPU will return the Logical CPU the code is currently executing on. +// This is likely to change when the OS re-schedules the running thread +// to another CPU. +// If the current core cannot be detected, -1 will be returned. +func (c cpuInfo) logicalcpu() int { + if c.maxFunc < 1 { + return -1 + } + _, ebx, _, _ := cpuid(1) + return int(ebx >> 24) +} + +// VM Will return true if the cpu id indicates we are in +// a virtual machine. This is only a hint, and will very likely +// have many false negatives. +func (c cpuInfo) vm() bool { + switch c.vendorid { + case msvm, kvm, vmware, xenhvm: + return true + } + return false +} + +// Flags contains detected cpu features and caracteristics +type flags uint64 + +// String returns a string representation of the detected +// CPU features. +func (f flags) String() string { + return strings.Join(f.strings(), ",") +} + +// Strings returns and array of the detected features. +func (f flags) strings() []string { + s := support() + r := make([]string, 0, 20) + for i := uint(0); i < 64; i++ { + key := flags(1 << i) + val := flagNames[key] + if s&key != 0 { + r = append(r, val) + } + } + return r +} + +func maxExtendedFunction() uint32 { + eax, _, _, _ := cpuid(0x80000000) + return eax +} + +func maxFunctionID() uint32 { + a, _, _, _ := cpuid(0) + return a +} + +func brandName() string { + if maxExtendedFunction() >= 0x80000004 { + v := make([]uint32, 0, 48) + for i := uint32(0); i < 3; i++ { + a, b, c, d := cpuid(0x80000002 + i) + v = append(v, a, b, c, d) + } + return strings.Trim(string(valAsString(v...)), " ") + } + return "unknown" +} + +func threadsPerCore() int { + mfi := maxFunctionID() + if mfi < 0x4 || vendorID() != intel { + return 1 + } + + if mfi < 0xb { + _, b, _, d := cpuid(1) + if (d & (1 << 28)) != 0 { + // v will contain logical core count + v := (b >> 16) & 255 + if v > 1 { + a4, _, _, _ := cpuid(4) + // physical cores + v2 := (a4 >> 26) + 1 + if v2 > 0 { + return int(v) / int(v2) + } + } + } + return 1 + } + _, b, _, _ := cpuidex(0xb, 0) + if b&0xffff == 0 { + return 1 + } + return int(b & 0xffff) +} + +func logicalCores() int { + mfi := maxFunctionID() + switch vendorID() { + case intel: + // Use this on old Intel processors + if mfi < 0xb { + if mfi < 1 { + return 0 + } + // CPUID.1:EBX[23:16] represents the maximum number of addressable IDs (initial APIC ID) + // that can be assigned to logical processors in a physical package. + // The value may not be the same as the number of logical processors that are present in the hardware of a physical package. + _, ebx, _, _ := cpuid(1) + logical := (ebx >> 16) & 0xff + return int(logical) + } + _, b, _, _ := cpuidex(0xb, 1) + return int(b & 0xffff) + case amd: + _, b, _, _ := cpuid(1) + return int((b >> 16) & 0xff) + default: + return 0 + } +} + +func familyModel() (int, int) { + if maxFunctionID() < 0x1 { + return 0, 0 + } + eax, _, _, _ := cpuid(1) + family := ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff) + model := ((eax >> 4) & 0xf) + ((eax >> 12) & 0xf0) + return int(family), int(model) +} + +func physicalCores() int { + switch vendorID() { + case intel: + return logicalCores() / threadsPerCore() + case amd: + if maxExtendedFunction() >= 0x80000008 { + _, _, c, _ := cpuid(0x80000008) + return int(c&0xff) + 1 + } + } + return 0 +} + +// Except from http://en.wikipedia.org/wiki/CPUID#EAX.3D0:_Get_vendor_ID +var vendorMapping = map[string]vendor{ + "AMDisbetter!": amd, + "AuthenticAMD": amd, + "CentaurHauls": via, + "GenuineIntel": intel, + "TransmetaCPU": transmeta, + "GenuineTMx86": transmeta, + "Geode by NSC": nsc, + "VIA VIA VIA ": via, + "KVMKVMKVMKVM": kvm, + "Microsoft Hv": msvm, + "VMwareVMware": vmware, + "XenVMMXenVMM": xenhvm, +} + +func vendorID() vendor { + _, b, c, d := cpuid(0) + v := valAsString(b, d, c) + vend, ok := vendorMapping[string(v)] + if !ok { + return other + } + return vend +} + +func cacheLine() int { + if maxFunctionID() < 0x1 { + return 0 + } + + _, ebx, _, _ := cpuid(1) + cache := (ebx & 0xff00) >> 5 // cflush size + if cache == 0 && maxExtendedFunction() >= 0x80000006 { + _, _, ecx, _ := cpuid(0x80000006) + cache = ecx & 0xff // cacheline size + } + // TODO: Read from Cache and TLB Information + return int(cache) +} + +func (c *cpuInfo) cacheSize() { + c.cache.l1d = -1 + c.cache.l1i = -1 + c.cache.l2 = -1 + c.cache.l3 = -1 + vendor := vendorID() + switch vendor { + case intel: + if maxFunctionID() < 4 { + return + } + for i := uint32(0); ; i++ { + eax, ebx, ecx, _ := cpuidex(4, i) + cacheType := eax & 15 + if cacheType == 0 { + break + } + cacheLevel := (eax >> 5) & 7 + coherency := int(ebx&0xfff) + 1 + partitions := int((ebx>>12)&0x3ff) + 1 + associativity := int((ebx>>22)&0x3ff) + 1 + sets := int(ecx) + 1 + size := associativity * partitions * coherency * sets + switch cacheLevel { + case 1: + if cacheType == 1 { + // 1 = Data Cache + c.cache.l1d = size + } else if cacheType == 2 { + // 2 = Instruction Cache + c.cache.l1i = size + } else { + if c.cache.l1d < 0 { + c.cache.l1i = size + } + if c.cache.l1i < 0 { + c.cache.l1i = size + } + } + case 2: + c.cache.l2 = size + case 3: + c.cache.l3 = size + } + } + case amd: + // Untested. + if maxExtendedFunction() < 0x80000005 { + return + } + _, _, ecx, edx := cpuid(0x80000005) + c.cache.l1d = int(((ecx >> 24) & 0xFF) * 1024) + c.cache.l1i = int(((edx >> 24) & 0xFF) * 1024) + + if maxExtendedFunction() < 0x80000006 { + return + } + _, _, ecx, _ = cpuid(0x80000006) + c.cache.l2 = int(((ecx >> 16) & 0xFFFF) * 1024) + } + + return +} + +func support() flags { + mfi := maxFunctionID() + vend := vendorID() + if mfi < 0x1 { + return 0 + } + rval := uint64(0) + _, _, c, d := cpuid(1) + if (d & (1 << 15)) != 0 { + rval |= cmov + } + if (d & (1 << 23)) != 0 { + rval |= mmx + } + if (d & (1 << 25)) != 0 { + rval |= mmxext + } + if (d & (1 << 25)) != 0 { + rval |= sse + } + if (d & (1 << 26)) != 0 { + rval |= sse2 + } + if (c & 1) != 0 { + rval |= sse3 + } + if (c & 0x00000200) != 0 { + rval |= ssse3 + } + if (c & 0x00080000) != 0 { + rval |= sse4 + } + if (c & 0x00100000) != 0 { + rval |= sse42 + } + if (c & (1 << 25)) != 0 { + rval |= aesni + } + if (c & (1 << 1)) != 0 { + rval |= clmul + } + if c&(1<<23) != 0 { + rval |= popcnt + } + if c&(1<<30) != 0 { + rval |= rdrand + } + if c&(1<<29) != 0 { + rval |= f16c + } + if c&(1<<13) != 0 { + rval |= cx16 + } + if vend == intel && (d&(1<<28)) != 0 && mfi >= 4 { + if threadsPerCore() > 1 { + rval |= htt + } + } + + // Check XGETBV, OXSAVE and AVX bits + if c&(1<<26) != 0 && c&(1<<27) != 0 && c&(1<<28) != 0 { + // Check for OS support + eax, _ := xgetbv(0) + if (eax & 0x6) == 0x6 { + rval |= avx + if (c & 0x00001000) != 0 { + rval |= fma3 + } + } + } + + // Check AVX2, AVX2 requires OS support, but BMI1/2 don't. + if mfi >= 7 { + _, ebx, ecx, _ := cpuidex(7, 0) + if (rval&avx) != 0 && (ebx&0x00000020) != 0 { + rval |= avx2 + } + if (ebx & 0x00000008) != 0 { + rval |= bmi1 + if (ebx & 0x00000100) != 0 { + rval |= bmi2 + } + } + if ebx&(1<<4) != 0 { + rval |= hle + } + if ebx&(1<<9) != 0 { + rval |= erms + } + if ebx&(1<<11) != 0 { + rval |= rtm + } + if ebx&(1<<14) != 0 { + rval |= mpx + } + if ebx&(1<<18) != 0 { + rval |= rdseed + } + if ebx&(1<<19) != 0 { + rval |= adx + } + if ebx&(1<<29) != 0 { + rval |= sha + } + + // Only detect AVX-512 features if XGETBV is supported + if c&((1<<26)|(1<<27)) == (1<<26)|(1<<27) { + // Check for OS support + eax, _ := xgetbv(0) + + // Verify that XCR0[7:5] = ‘111b’ (OPMASK state, upper 256-bit of ZMM0-ZMM15 and + // ZMM16-ZMM31 state are enabled by OS) + /// and that XCR0[2:1] = ‘11b’ (XMM state and YMM state are enabled by OS). + if (eax>>5)&7 == 7 && (eax>>1)&3 == 3 { + if ebx&(1<<16) != 0 { + rval |= avx512f + } + if ebx&(1<<17) != 0 { + rval |= avx512dq + } + if ebx&(1<<21) != 0 { + rval |= avx512ifma + } + if ebx&(1<<26) != 0 { + rval |= avx512pf + } + if ebx&(1<<27) != 0 { + rval |= avx512er + } + if ebx&(1<<28) != 0 { + rval |= avx512cd + } + if ebx&(1<<30) != 0 { + rval |= avx512bw + } + if ebx&(1<<31) != 0 { + rval |= avx512vl + } + // ecx + if ecx&(1<<1) != 0 { + rval |= avx512vbmi + } + } + } + } + + if maxExtendedFunction() >= 0x80000001 { + _, _, c, d := cpuid(0x80000001) + if (c & (1 << 5)) != 0 { + rval |= lzcnt + rval |= popcnt + } + if (d & (1 << 31)) != 0 { + rval |= amd3dnow + } + if (d & (1 << 30)) != 0 { + rval |= amd3dnowext + } + if (d & (1 << 23)) != 0 { + rval |= mmx + } + if (d & (1 << 22)) != 0 { + rval |= mmxext + } + if (c & (1 << 6)) != 0 { + rval |= sse4a + } + if d&(1<<20) != 0 { + rval |= nx + } + if d&(1<<27) != 0 { + rval |= rdtscp + } + + /* Allow for selectively disabling SSE2 functions on AMD processors + with SSE2 support but not SSE4a. This includes Athlon64, some + Opteron, and some Sempron processors. MMX, SSE, or 3DNow! are faster + than SSE2 often enough to utilize this special-case flag. + AV_CPU_FLAG_SSE2 and AV_CPU_FLAG_SSE2SLOW are both set in this case + so that SSE2 is used unless explicitly disabled by checking + AV_CPU_FLAG_SSE2SLOW. */ + if vendorID() != intel && + rval&sse2 != 0 && (c&0x00000040) == 0 { + rval |= sse2slow + } + + /* XOP and FMA4 use the AVX instruction coding scheme, so they can't be + * used unless the OS has AVX support. */ + if (rval & avx) != 0 { + if (c & 0x00000800) != 0 { + rval |= xop + } + if (c & 0x00010000) != 0 { + rval |= fma4 + } + } + + if vendorID() == intel { + family, model := familyModel() + if family == 6 && (model == 9 || model == 13 || model == 14) { + /* 6/9 (pentium-m "banias"), 6/13 (pentium-m "dothan"), and + * 6/14 (core1 "yonah") theoretically support sse2, but it's + * usually slower than mmx. */ + if (rval & sse2) != 0 { + rval |= sse2slow + } + if (rval & sse3) != 0 { + rval |= sse3slow + } + } + /* The Atom processor has SSSE3 support, which is useful in many cases, + * but sometimes the SSSE3 version is slower than the SSE2 equivalent + * on the Atom, but is generally faster on other processors supporting + * SSSE3. This flag allows for selectively disabling certain SSSE3 + * functions on the Atom. */ + if family == 6 && model == 28 { + rval |= atom + } + } + } + return flags(rval) +} + +func valAsString(values ...uint32) []byte { + r := make([]byte, 4*len(values)) + for i, v := range values { + dst := r[i*4:] + dst[0] = byte(v & 0xff) + dst[1] = byte((v >> 8) & 0xff) + dst[2] = byte((v >> 16) & 0xff) + dst[3] = byte((v >> 24) & 0xff) + switch { + case dst[0] == 0: + return r[:i*4] + case dst[1] == 0: + return r[:i*4+1] + case dst[2] == 0: + return r[:i*4+2] + case dst[3] == 0: + return r[:i*4+3] + } + } + return r +} diff --git a/vendor/github.com/klauspost/cpuid/private/cpuid_386.s b/vendor/github.com/klauspost/cpuid/private/cpuid_386.s new file mode 100644 index 0000000..4d73171 --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/private/cpuid_386.s @@ -0,0 +1,42 @@ +// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. + +// +build 386,!gccgo + +// func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32) +TEXT ·asmCpuid(SB), 7, $0 + XORL CX, CX + MOVL op+0(FP), AX + CPUID + MOVL AX, eax+4(FP) + MOVL BX, ebx+8(FP) + MOVL CX, ecx+12(FP) + MOVL DX, edx+16(FP) + RET + +// func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32) +TEXT ·asmCpuidex(SB), 7, $0 + MOVL op+0(FP), AX + MOVL op2+4(FP), CX + CPUID + MOVL AX, eax+8(FP) + MOVL BX, ebx+12(FP) + MOVL CX, ecx+16(FP) + MOVL DX, edx+20(FP) + RET + +// func xgetbv(index uint32) (eax, edx uint32) +TEXT ·asmXgetbv(SB), 7, $0 + MOVL index+0(FP), CX + BYTE $0x0f; BYTE $0x01; BYTE $0xd0 // XGETBV + MOVL AX, eax+4(FP) + MOVL DX, edx+8(FP) + RET + +// func asmRdtscpAsm() (eax, ebx, ecx, edx uint32) +TEXT ·asmRdtscpAsm(SB), 7, $0 + BYTE $0x0F; BYTE $0x01; BYTE $0xF9 // RDTSCP + MOVL AX, eax+0(FP) + MOVL BX, ebx+4(FP) + MOVL CX, ecx+8(FP) + MOVL DX, edx+12(FP) + RET diff --git a/vendor/github.com/klauspost/cpuid/private/cpuid_amd64.s b/vendor/github.com/klauspost/cpuid/private/cpuid_amd64.s new file mode 100644 index 0000000..3c1d60e --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/private/cpuid_amd64.s @@ -0,0 +1,42 @@ +// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. + +//+build amd64,!gccgo + +// func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32) +TEXT ·asmCpuid(SB), 7, $0 + XORQ CX, CX + MOVL op+0(FP), AX + CPUID + MOVL AX, eax+8(FP) + MOVL BX, ebx+12(FP) + MOVL CX, ecx+16(FP) + MOVL DX, edx+20(FP) + RET + +// func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32) +TEXT ·asmCpuidex(SB), 7, $0 + MOVL op+0(FP), AX + MOVL op2+4(FP), CX + CPUID + MOVL AX, eax+8(FP) + MOVL BX, ebx+12(FP) + MOVL CX, ecx+16(FP) + MOVL DX, edx+20(FP) + RET + +// func asmXgetbv(index uint32) (eax, edx uint32) +TEXT ·asmXgetbv(SB), 7, $0 + MOVL index+0(FP), CX + BYTE $0x0f; BYTE $0x01; BYTE $0xd0 // XGETBV + MOVL AX, eax+8(FP) + MOVL DX, edx+12(FP) + RET + +// func asmRdtscpAsm() (eax, ebx, ecx, edx uint32) +TEXT ·asmRdtscpAsm(SB), 7, $0 + BYTE $0x0F; BYTE $0x01; BYTE $0xF9 // RDTSCP + MOVL AX, eax+0(FP) + MOVL BX, ebx+4(FP) + MOVL CX, ecx+8(FP) + MOVL DX, edx+12(FP) + RET diff --git a/vendor/github.com/klauspost/cpuid/private/cpuid_detect_intel.go b/vendor/github.com/klauspost/cpuid/private/cpuid_detect_intel.go new file mode 100644 index 0000000..a5f04dd --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/private/cpuid_detect_intel.go @@ -0,0 +1,17 @@ +// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. + +// +build 386,!gccgo amd64,!gccgo + +package cpuid + +func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32) +func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32) +func asmXgetbv(index uint32) (eax, edx uint32) +func asmRdtscpAsm() (eax, ebx, ecx, edx uint32) + +func initCPU() { + cpuid = asmCpuid + cpuidex = asmCpuidex + xgetbv = asmXgetbv + rdtscpAsm = asmRdtscpAsm +} diff --git a/vendor/github.com/klauspost/cpuid/private/cpuid_detect_ref.go b/vendor/github.com/klauspost/cpuid/private/cpuid_detect_ref.go new file mode 100644 index 0000000..909c5d9 --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/private/cpuid_detect_ref.go @@ -0,0 +1,23 @@ +// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. + +// +build !amd64,!386 gccgo + +package cpuid + +func initCPU() { + cpuid = func(op uint32) (eax, ebx, ecx, edx uint32) { + return 0, 0, 0, 0 + } + + cpuidex = func(op, op2 uint32) (eax, ebx, ecx, edx uint32) { + return 0, 0, 0, 0 + } + + xgetbv = func(index uint32) (eax, edx uint32) { + return 0, 0 + } + + rdtscpAsm = func() (eax, ebx, ecx, edx uint32) { + return 0, 0, 0, 0 + } +} diff --git a/vendor/github.com/klauspost/cpuid/private/cpuid_test.go b/vendor/github.com/klauspost/cpuid/private/cpuid_test.go new file mode 100644 index 0000000..04c26e0 --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/private/cpuid_test.go @@ -0,0 +1,719 @@ +// Generated, DO NOT EDIT, +// but copy it to your own project and rename the package. +// See more at http://github.com/klauspost/cpuid + +package cpuid + +import ( + "fmt" + "testing" +) + +// There is no real way to test a CPU identifier, since results will +// obviously differ on each machine. +func TestCPUID(t *testing.T) { + n := maxFunctionID() + t.Logf("Max Function:0x%x\n", n) + n = maxExtendedFunction() + t.Logf("Max Extended Function:0x%x\n", n) + t.Log("Name:", cpu.brandname) + t.Log("PhysicalCores:", cpu.physicalcores) + t.Log("ThreadsPerCore:", cpu.threadspercore) + t.Log("LogicalCores:", cpu.logicalcores) + t.Log("Family", cpu.family, "Model:", cpu.model) + t.Log("Features:", cpu.features) + t.Log("Cacheline bytes:", cpu.cacheline) + t.Log("L1 Instruction Cache:", cpu.cache.l1i, "bytes") + t.Log("L1 Data Cache:", cpu.cache.l1d, "bytes") + t.Log("L2 Cache:", cpu.cache.l2, "bytes") + t.Log("L3 Cache:", cpu.cache.l3, "bytes") + + if cpu.sse2() { + t.Log("We have SSE2") + } +} + +func TestDumpCPUID(t *testing.T) { + n := int(maxFunctionID()) + for i := 0; i <= n; i++ { + a, b, c, d := cpuidex(uint32(i), 0) + t.Logf("CPUID %08x: %08x-%08x-%08x-%08x", i, a, b, c, d) + ex := uint32(1) + for { + a2, b2, c2, d2 := cpuidex(uint32(i), ex) + if a2 == a && b2 == b && d2 == d || ex > 50 || a2 == 0 { + break + } + t.Logf("CPUID %08x: %08x-%08x-%08x-%08x", i, a2, b2, c2, d2) + a, b, c, d = a2, b2, c2, d2 + ex++ + } + } + n2 := maxExtendedFunction() + for i := uint32(0x80000000); i <= n2; i++ { + a, b, c, d := cpuid(i) + t.Logf("CPUID %08x: %08x-%08x-%08x-%08x", i, a, b, c, d) + } +} + +func example() { + // Print basic CPU information: + fmt.Println("Name:", cpu.brandname) + fmt.Println("PhysicalCores:", cpu.physicalcores) + fmt.Println("ThreadsPerCore:", cpu.threadspercore) + fmt.Println("LogicalCores:", cpu.logicalcores) + fmt.Println("Family", cpu.family, "Model:", cpu.model) + fmt.Println("Features:", cpu.features) + fmt.Println("Cacheline bytes:", cpu.cacheline) + + // Test if we have a specific feature: + if cpu.sse() { + fmt.Println("We have Streaming SIMD Extensions") + } +} + +func TestBrandNameZero(t *testing.T) { + if len(cpu.brandname) > 0 { + // Cut out last byte + last := []byte(cpu.brandname[len(cpu.brandname)-1:]) + if last[0] == 0 { + t.Fatal("last byte was zero") + } else if last[0] == 32 { + t.Fatal("whitespace wasn't trimmed") + } + } +} + +// Generated here: http://play.golang.org/p/mko-0tFt0Q + +// TestCmov tests Cmov() function +func TestCmov(t *testing.T) { + got := cpu.cmov() + expected := cpu.features&cmov == cmov + if got != expected { + t.Fatalf("Cmov: expected %v, got %v", expected, got) + } + t.Log("CMOV Support:", got) +} + +// TestAmd3dnow tests Amd3dnow() function +func TestAmd3dnow(t *testing.T) { + got := cpu.amd3dnow() + expected := cpu.features&amd3dnow == amd3dnow + if got != expected { + t.Fatalf("Amd3dnow: expected %v, got %v", expected, got) + } + t.Log("AMD3DNOW Support:", got) +} + +// TestAmd3dnowExt tests Amd3dnowExt() function +func TestAmd3dnowExt(t *testing.T) { + got := cpu.amd3dnowext() + expected := cpu.features&amd3dnowext == amd3dnowext + if got != expected { + t.Fatalf("Amd3dnowExt: expected %v, got %v", expected, got) + } + t.Log("AMD3DNOWEXT Support:", got) +} + +// TestMMX tests MMX() function +func TestMMX(t *testing.T) { + got := cpu.mmx() + expected := cpu.features&mmx == mmx + if got != expected { + t.Fatalf("MMX: expected %v, got %v", expected, got) + } + t.Log("MMX Support:", got) +} + +// TestMMXext tests MMXext() function +func TestMMXext(t *testing.T) { + got := cpu.mmxext() + expected := cpu.features&mmxext == mmxext + if got != expected { + t.Fatalf("MMXExt: expected %v, got %v", expected, got) + } + t.Log("MMXEXT Support:", got) +} + +// TestSSE tests SSE() function +func TestSSE(t *testing.T) { + got := cpu.sse() + expected := cpu.features&sse == sse + if got != expected { + t.Fatalf("SSE: expected %v, got %v", expected, got) + } + t.Log("SSE Support:", got) +} + +// TestSSE2 tests SSE2() function +func TestSSE2(t *testing.T) { + got := cpu.sse2() + expected := cpu.features&sse2 == sse2 + if got != expected { + t.Fatalf("SSE2: expected %v, got %v", expected, got) + } + t.Log("SSE2 Support:", got) +} + +// TestSSE3 tests SSE3() function +func TestSSE3(t *testing.T) { + got := cpu.sse3() + expected := cpu.features&sse3 == sse3 + if got != expected { + t.Fatalf("SSE3: expected %v, got %v", expected, got) + } + t.Log("SSE3 Support:", got) +} + +// TestSSSE3 tests SSSE3() function +func TestSSSE3(t *testing.T) { + got := cpu.ssse3() + expected := cpu.features&ssse3 == ssse3 + if got != expected { + t.Fatalf("SSSE3: expected %v, got %v", expected, got) + } + t.Log("SSSE3 Support:", got) +} + +// TestSSE4 tests SSE4() function +func TestSSE4(t *testing.T) { + got := cpu.sse4() + expected := cpu.features&sse4 == sse4 + if got != expected { + t.Fatalf("SSE4: expected %v, got %v", expected, got) + } + t.Log("SSE4 Support:", got) +} + +// TestSSE42 tests SSE42() function +func TestSSE42(t *testing.T) { + got := cpu.sse42() + expected := cpu.features&sse42 == sse42 + if got != expected { + t.Fatalf("SSE42: expected %v, got %v", expected, got) + } + t.Log("SSE42 Support:", got) +} + +// TestAVX tests AVX() function +func TestAVX(t *testing.T) { + got := cpu.avx() + expected := cpu.features&avx == avx + if got != expected { + t.Fatalf("AVX: expected %v, got %v", expected, got) + } + t.Log("AVX Support:", got) +} + +// TestAVX2 tests AVX2() function +func TestAVX2(t *testing.T) { + got := cpu.avx2() + expected := cpu.features&avx2 == avx2 + if got != expected { + t.Fatalf("AVX2: expected %v, got %v", expected, got) + } + t.Log("AVX2 Support:", got) +} + +// TestFMA3 tests FMA3() function +func TestFMA3(t *testing.T) { + got := cpu.fma3() + expected := cpu.features&fma3 == fma3 + if got != expected { + t.Fatalf("FMA3: expected %v, got %v", expected, got) + } + t.Log("FMA3 Support:", got) +} + +// TestFMA4 tests FMA4() function +func TestFMA4(t *testing.T) { + got := cpu.fma4() + expected := cpu.features&fma4 == fma4 + if got != expected { + t.Fatalf("FMA4: expected %v, got %v", expected, got) + } + t.Log("FMA4 Support:", got) +} + +// TestXOP tests XOP() function +func TestXOP(t *testing.T) { + got := cpu.xop() + expected := cpu.features&xop == xop + if got != expected { + t.Fatalf("XOP: expected %v, got %v", expected, got) + } + t.Log("XOP Support:", got) +} + +// TestF16C tests F16C() function +func TestF16C(t *testing.T) { + got := cpu.f16c() + expected := cpu.features&f16c == f16c + if got != expected { + t.Fatalf("F16C: expected %v, got %v", expected, got) + } + t.Log("F16C Support:", got) +} + +// TestCX16 tests CX16() function +func TestCX16(t *testing.T) { + got := cpu.cx16() + expected := cpu.features&cx16 == cx16 + if got != expected { + t.Fatalf("CX16: expected %v, got %v", expected, got) + } + t.Log("CX16 Support:", got) +} + +// TestBMI1 tests BMI1() function +func TestBMI1(t *testing.T) { + got := cpu.bmi1() + expected := cpu.features&bmi1 == bmi1 + if got != expected { + t.Fatalf("BMI1: expected %v, got %v", expected, got) + } + t.Log("BMI1 Support:", got) +} + +// TestBMI2 tests BMI2() function +func TestBMI2(t *testing.T) { + got := cpu.bmi2() + expected := cpu.features&bmi2 == bmi2 + if got != expected { + t.Fatalf("BMI2: expected %v, got %v", expected, got) + } + t.Log("BMI2 Support:", got) +} + +// TestTBM tests TBM() function +func TestTBM(t *testing.T) { + got := cpu.tbm() + expected := cpu.features&tbm == tbm + if got != expected { + t.Fatalf("TBM: expected %v, got %v", expected, got) + } + t.Log("TBM Support:", got) +} + +// TestLzcnt tests Lzcnt() function +func TestLzcnt(t *testing.T) { + got := cpu.lzcnt() + expected := cpu.features&lzcnt == lzcnt + if got != expected { + t.Fatalf("Lzcnt: expected %v, got %v", expected, got) + } + t.Log("LZCNT Support:", got) +} + +// TestLzcnt tests Lzcnt() function +func TestPopcnt(t *testing.T) { + got := cpu.popcnt() + expected := cpu.features&popcnt == popcnt + if got != expected { + t.Fatalf("Popcnt: expected %v, got %v", expected, got) + } + t.Log("POPCNT Support:", got) +} + +// TestAesNi tests AesNi() function +func TestAesNi(t *testing.T) { + got := cpu.aesni() + expected := cpu.features&aesni == aesni + if got != expected { + t.Fatalf("AesNi: expected %v, got %v", expected, got) + } + t.Log("AESNI Support:", got) +} + +// TestHTT tests HTT() function +func TestHTT(t *testing.T) { + got := cpu.htt() + expected := cpu.features&htt == htt + if got != expected { + t.Fatalf("HTT: expected %v, got %v", expected, got) + } + t.Log("HTT Support:", got) +} + +// TestClmul tests Clmul() function +func TestClmul(t *testing.T) { + got := cpu.clmul() + expected := cpu.features&clmul == clmul + if got != expected { + t.Fatalf("Clmul: expected %v, got %v", expected, got) + } + t.Log("CLMUL Support:", got) +} + +// TestSSE2Slow tests SSE2Slow() function +func TestSSE2Slow(t *testing.T) { + got := cpu.sse2slow() + expected := cpu.features&sse2slow == sse2slow + if got != expected { + t.Fatalf("SSE2Slow: expected %v, got %v", expected, got) + } + t.Log("SSE2SLOW Support:", got) +} + +// TestSSE3Slow tests SSE3slow() function +func TestSSE3Slow(t *testing.T) { + got := cpu.sse3slow() + expected := cpu.features&sse3slow == sse3slow + if got != expected { + t.Fatalf("SSE3slow: expected %v, got %v", expected, got) + } + t.Log("SSE3SLOW Support:", got) +} + +// TestAtom tests Atom() function +func TestAtom(t *testing.T) { + got := cpu.atom() + expected := cpu.features&atom == atom + if got != expected { + t.Fatalf("Atom: expected %v, got %v", expected, got) + } + t.Log("ATOM Support:", got) +} + +// TestNX tests NX() function (NX (No-Execute) bit) +func TestNX(t *testing.T) { + got := cpu.nx() + expected := cpu.features&nx == nx + if got != expected { + t.Fatalf("NX: expected %v, got %v", expected, got) + } + t.Log("NX Support:", got) +} + +// TestSSE4A tests SSE4A() function (AMD Barcelona microarchitecture SSE4a instructions) +func TestSSE4A(t *testing.T) { + got := cpu.sse4a() + expected := cpu.features&sse4a == sse4a + if got != expected { + t.Fatalf("SSE4A: expected %v, got %v", expected, got) + } + t.Log("SSE4A Support:", got) +} + +// TestHLE tests HLE() function (Hardware Lock Elision) +func TestHLE(t *testing.T) { + got := cpu.hle() + expected := cpu.features&hle == hle + if got != expected { + t.Fatalf("HLE: expected %v, got %v", expected, got) + } + t.Log("HLE Support:", got) +} + +// TestRTM tests RTM() function (Restricted Transactional Memory) +func TestRTM(t *testing.T) { + got := cpu.rtm() + expected := cpu.features&rtm == rtm + if got != expected { + t.Fatalf("RTM: expected %v, got %v", expected, got) + } + t.Log("RTM Support:", got) +} + +// TestRdrand tests RDRAND() function (RDRAND instruction is available) +func TestRdrand(t *testing.T) { + got := cpu.rdrand() + expected := cpu.features&rdrand == rdrand + if got != expected { + t.Fatalf("Rdrand: expected %v, got %v", expected, got) + } + t.Log("Rdrand Support:", got) +} + +// TestRdseed tests RDSEED() function (RDSEED instruction is available) +func TestRdseed(t *testing.T) { + got := cpu.rdseed() + expected := cpu.features&rdseed == rdseed + if got != expected { + t.Fatalf("Rdseed: expected %v, got %v", expected, got) + } + t.Log("Rdseed Support:", got) +} + +// TestADX tests ADX() function (Intel ADX (Multi-Precision Add-Carry Instruction Extensions)) +func TestADX(t *testing.T) { + got := cpu.adx() + expected := cpu.features&adx == adx + if got != expected { + t.Fatalf("ADX: expected %v, got %v", expected, got) + } + t.Log("ADX Support:", got) +} + +// TestSHA tests SHA() function (Intel SHA Extensions) +func TestSHA(t *testing.T) { + got := cpu.sha() + expected := cpu.features&sha == sha + if got != expected { + t.Fatalf("SHA: expected %v, got %v", expected, got) + } + t.Log("SHA Support:", got) +} + +// TestAVX512F tests AVX512F() function (AVX-512 Foundation) +func TestAVX512F(t *testing.T) { + got := cpu.avx512f() + expected := cpu.features&avx512f == avx512f + if got != expected { + t.Fatalf("AVX512F: expected %v, got %v", expected, got) + } + t.Log("AVX512F Support:", got) +} + +// TestAVX512DQ tests AVX512DQ() function (AVX-512 Doubleword and Quadword Instructions) +func TestAVX512DQ(t *testing.T) { + got := cpu.avx512dq() + expected := cpu.features&avx512dq == avx512dq + if got != expected { + t.Fatalf("AVX512DQ: expected %v, got %v", expected, got) + } + t.Log("AVX512DQ Support:", got) +} + +// TestAVX512IFMA tests AVX512IFMA() function (AVX-512 Integer Fused Multiply-Add Instructions) +func TestAVX512IFMA(t *testing.T) { + got := cpu.avx512ifma() + expected := cpu.features&avx512ifma == avx512ifma + if got != expected { + t.Fatalf("AVX512IFMA: expected %v, got %v", expected, got) + } + t.Log("AVX512IFMA Support:", got) +} + +// TestAVX512PF tests AVX512PF() function (AVX-512 Prefetch Instructions) +func TestAVX512PF(t *testing.T) { + got := cpu.avx512pf() + expected := cpu.features&avx512pf == avx512pf + if got != expected { + t.Fatalf("AVX512PF: expected %v, got %v", expected, got) + } + t.Log("AVX512PF Support:", got) +} + +// TestAVX512ER tests AVX512ER() function (AVX-512 Exponential and Reciprocal Instructions) +func TestAVX512ER(t *testing.T) { + got := cpu.avx512er() + expected := cpu.features&avx512er == avx512er + if got != expected { + t.Fatalf("AVX512ER: expected %v, got %v", expected, got) + } + t.Log("AVX512ER Support:", got) +} + +// TestAVX512CD tests AVX512CD() function (AVX-512 Conflict Detection Instructions) +func TestAVX512CD(t *testing.T) { + got := cpu.avx512cd() + expected := cpu.features&avx512cd == avx512cd + if got != expected { + t.Fatalf("AVX512CD: expected %v, got %v", expected, got) + } + t.Log("AVX512CD Support:", got) +} + +// TestAVX512BW tests AVX512BW() function (AVX-512 Byte and Word Instructions) +func TestAVX512BW(t *testing.T) { + got := cpu.avx512bw() + expected := cpu.features&avx512bw == avx512bw + if got != expected { + t.Fatalf("AVX512BW: expected %v, got %v", expected, got) + } + t.Log("AVX512BW Support:", got) +} + +// TestAVX512VL tests AVX512VL() function (AVX-512 Vector Length Extensions) +func TestAVX512VL(t *testing.T) { + got := cpu.avx512vl() + expected := cpu.features&avx512vl == avx512vl + if got != expected { + t.Fatalf("AVX512VL: expected %v, got %v", expected, got) + } + t.Log("AVX512VL Support:", got) +} + +// TestAVX512VL tests AVX512VBMI() function (AVX-512 Vector Bit Manipulation Instructions) +func TestAVX512VBMI(t *testing.T) { + got := cpu.avx512vbmi() + expected := cpu.features&avx512vbmi == avx512vbmi + if got != expected { + t.Fatalf("AVX512VBMI: expected %v, got %v", expected, got) + } + t.Log("AVX512VBMI Support:", got) +} + +// TestMPX tests MPX() function (Intel MPX (Memory Protection Extensions)) +func TestMPX(t *testing.T) { + got := cpu.mpx() + expected := cpu.features&mpx == mpx + if got != expected { + t.Fatalf("MPX: expected %v, got %v", expected, got) + } + t.Log("MPX Support:", got) +} + +// TestERMS tests ERMS() function (Enhanced REP MOVSB/STOSB) +func TestERMS(t *testing.T) { + got := cpu.erms() + expected := cpu.features&erms == erms + if got != expected { + t.Fatalf("ERMS: expected %v, got %v", expected, got) + } + t.Log("ERMS Support:", got) +} + +// TestVendor writes the detected vendor. Will be 0 if unknown +func TestVendor(t *testing.T) { + t.Log("Vendor ID:", cpu.vendorid) +} + +// Intel returns true if vendor is recognized as Intel +func TestIntel(t *testing.T) { + got := cpu.intel() + expected := cpu.vendorid == intel + if got != expected { + t.Fatalf("TestIntel: expected %v, got %v", expected, got) + } + t.Log("TestIntel:", got) +} + +// AMD returns true if vendor is recognized as AMD +func TestAMD(t *testing.T) { + got := cpu.amd() + expected := cpu.vendorid == amd + if got != expected { + t.Fatalf("TestAMD: expected %v, got %v", expected, got) + } + t.Log("TestAMD:", got) +} + +// Transmeta returns true if vendor is recognized as Transmeta +func TestTransmeta(t *testing.T) { + got := cpu.transmeta() + expected := cpu.vendorid == transmeta + if got != expected { + t.Fatalf("TestTransmeta: expected %v, got %v", expected, got) + } + t.Log("TestTransmeta:", got) +} + +// NSC returns true if vendor is recognized as National Semiconductor +func TestNSC(t *testing.T) { + got := cpu.nsc() + expected := cpu.vendorid == nsc + if got != expected { + t.Fatalf("TestNSC: expected %v, got %v", expected, got) + } + t.Log("TestNSC:", got) +} + +// VIA returns true if vendor is recognized as VIA +func TestVIA(t *testing.T) { + got := cpu.via() + expected := cpu.vendorid == via + if got != expected { + t.Fatalf("TestVIA: expected %v, got %v", expected, got) + } + t.Log("TestVIA:", got) +} + +// Test VM function +func TestVM(t *testing.T) { + t.Log("Vendor ID:", cpu.vm()) +} + +// Test RTCounter function +func TestRtCounter(t *testing.T) { + a := cpu.rtcounter() + b := cpu.rtcounter() + t.Log("CPU Counter:", a, b, b-a) +} + +// Prints the value of Ia32TscAux() +func TestIa32TscAux(t *testing.T) { + ecx := cpu.ia32tscaux() + t.Logf("Ia32TscAux:0x%x\n", ecx) + if ecx != 0 { + chip := (ecx & 0xFFF000) >> 12 + core := ecx & 0xFFF + t.Log("Likely chip, core:", chip, core) + } +} + +func TestThreadsPerCoreNZ(t *testing.T) { + if cpu.threadspercore == 0 { + t.Fatal("threads per core is zero") + } +} + +// Prints the value of LogicalCPU() +func TestLogicalCPU(t *testing.T) { + t.Log("Currently executing on cpu:", cpu.logicalcpu()) +} + +func TestMaxFunction(t *testing.T) { + expect := maxFunctionID() + if cpu.maxFunc != expect { + t.Fatal("Max function does not match, expected", expect, "but got", cpu.maxFunc) + } + expect = maxExtendedFunction() + if cpu.maxExFunc != expect { + t.Fatal("Max Extended function does not match, expected", expect, "but got", cpu.maxFunc) + } +} + +// This example will calculate the chip/core number on Linux +// Linux encodes numa id (<<12) and core id (8bit) into TSC_AUX. +func examplecpuinfo_ia32tscaux(t *testing.T) { + ecx := cpu.ia32tscaux() + if ecx == 0 { + fmt.Println("Unknown CPU ID") + return + } + chip := (ecx & 0xFFF000) >> 12 + core := ecx & 0xFFF + fmt.Println("Chip, Core:", chip, core) +} + +/* +func TestPhysical(t *testing.T) { + var test16 = "CPUID 00000000: 0000000d-756e6547-6c65746e-49656e69 \nCPUID 00000001: 000206d7-03200800-1fbee3ff-bfebfbff \nCPUID 00000002: 76035a01-00f0b2ff-00000000-00ca0000 \nCPUID 00000003: 00000000-00000000-00000000-00000000 \nCPUID 00000004: 3c004121-01c0003f-0000003f-00000000 \nCPUID 00000004: 3c004122-01c0003f-0000003f-00000000 \nCPUID 00000004: 3c004143-01c0003f-000001ff-00000000 \nCPUID 00000004: 3c07c163-04c0003f-00003fff-00000006 \nCPUID 00000005: 00000040-00000040-00000003-00021120 \nCPUID 00000006: 00000075-00000002-00000009-00000000 \nCPUID 00000007: 00000000-00000000-00000000-00000000 \nCPUID 00000008: 00000000-00000000-00000000-00000000 \nCPUID 00000009: 00000001-00000000-00000000-00000000 \nCPUID 0000000a: 07300403-00000000-00000000-00000603 \nCPUID 0000000b: 00000000-00000000-00000003-00000003 \nCPUID 0000000b: 00000005-00000010-00000201-00000003 \nCPUID 0000000c: 00000000-00000000-00000000-00000000 \nCPUID 0000000d: 00000007-00000340-00000340-00000000 \nCPUID 0000000d: 00000001-00000000-00000000-00000000 \nCPUID 0000000d: 00000100-00000240-00000000-00000000 \nCPUID 80000000: 80000008-00000000-00000000-00000000 \nCPUID 80000001: 00000000-00000000-00000001-2c100800 \nCPUID 80000002: 20202020-49202020-6c65746e-20295228 \nCPUID 80000003: 6e6f6558-20295228-20555043-322d3545 \nCPUID 80000004: 20303636-20402030-30322e32-007a4847 \nCPUID 80000005: 00000000-00000000-00000000-00000000 \nCPUID 80000006: 00000000-00000000-01006040-00000000 \nCPUID 80000007: 00000000-00000000-00000000-00000100 \nCPUID 80000008: 0000302e-00000000-00000000-00000000" + restore := mockCPU([]byte(test16)) + Detect() + t.Log("Name:", CPU.BrandName) + n := maxFunctionID() + t.Logf("Max Function:0x%x\n", n) + n = maxExtendedFunction() + t.Logf("Max Extended Function:0x%x\n", n) + t.Log("PhysicalCores:", CPU.PhysicalCores) + t.Log("ThreadsPerCore:", CPU.ThreadsPerCore) + t.Log("LogicalCores:", CPU.LogicalCores) + t.Log("Family", CPU.Family, "Model:", CPU.Model) + t.Log("Features:", CPU.Features) + t.Log("Cacheline bytes:", CPU.CacheLine) + t.Log("L1 Instruction Cache:", CPU.Cache.L1I, "bytes") + t.Log("L1 Data Cache:", CPU.Cache.L1D, "bytes") + t.Log("L2 Cache:", CPU.Cache.L2, "bytes") + t.Log("L3 Cache:", CPU.Cache.L3, "bytes") + if CPU.LogicalCores > 0 && CPU.PhysicalCores > 0 { + if CPU.LogicalCores != CPU.PhysicalCores*CPU.ThreadsPerCore { + t.Fatalf("Core count mismatch, LogicalCores (%d) != PhysicalCores (%d) * CPU.ThreadsPerCore (%d)", + CPU.LogicalCores, CPU.PhysicalCores, CPU.ThreadsPerCore) + } + } + + if CPU.ThreadsPerCore > 1 && !CPU.HTT() { + t.Fatalf("Hyperthreading not detected") + } + if CPU.ThreadsPerCore == 1 && CPU.HTT() { + t.Fatalf("Hyperthreading detected, but only 1 Thread per core") + } + restore() + Detect() + TestCPUID(t) +} +*/ diff --git a/vendor/github.com/klauspost/cpuid/testdata/cpuid_data.zip b/vendor/github.com/klauspost/cpuid/testdata/cpuid_data.zip new file mode 100644 index 0000000000000000000000000000000000000000..509fd710335a56cfce207ad0ee744242601bf9ae GIT binary patch literal 201312 zcmZ^Kb8w{V_H}IA_9U4&9ox2@Ol)f=w(W^++qP}nnq+43^||-{>O1G$bGxeFs{W^| zo_DXc_S$$9WxydYKtMoXfL{<0a|bPW4NwpeMKBN$65wwkR~HL2I~Pk6AvsYd;D?=w z$v}qPKtxeZN|e#X!$nVV$!UuT#kc1cSx3Ah0d?FmEnTW0LtCdCGpM_pMUI#2bI6v6 zH5(vsAT6@f7>sdUU}4UsajGIIvHrUd1birb2fX*Y!$AfIi(}ZV3mZ0T##Bwsi#4id zv59uKZN7FP=WCNM$S3-;5U8h~U+-E7v0=L>!@QMkwJk3XiSMXB*c>UuhTbdg8^6Ab z$qzd8=r1;4Qc-BAE(^UFuT5Wr)fiPx4nP^vk*d-WJ*A2?w-D;uc9qW+A4kN?C>_zPO`FF~1x zzDxWgD9ZmcD9nEkN_`F!O1F84`)a!|x@x)8<`zSuF+)&KyorJV*c8FB4`=+=FVk$$ z5{EcvC3o50AFn1l%}qlc35m;#B!NEye`NpI;%i0HBW?qTjW&Nhj8b>Dwk~D>pF!09 z{H#|f71cXa<*WHcj1zPAo40!d0a0Av%M+I-qLKT{d+05nVUVHk8Bw#_+XmpSt1LWC zHma(*X)@?ALfY1qGu7mZBRr(+h)a`N7BfhC$hq1zsnUtcdL2F^CHrSPQGU#TB)Mp7 zeN|P+X#N4iqaL4Z7nn!a%$v4Vul8=DwL8 zhh)=)2Lcdk(INVD{m6I1=K*2I1-El3UmebIawM=nM*0`G->&7qH&q5twxzXS1Rm?2 zP(&TW^L|t~iQnw98fLu#?p#K;Z&Eh<^|z;;c&-LidobLiK>XsV4>Yv zVn`A&hUeuW=uIISGQb`+`Sp+-@ENT)u?xlRRj(JOZ~GXMz>T?x@_EddF0rPL=h!EC z_>J+ljXI-=A-j+&a=vpdM_Ohwof__09mZSPoE*0(U5TnDsR+Gj!LpIjlGHQZw@uX` z!_n<^%Ec3Yc_U0UVQ^Tud@SyxDjk>Fs=%Mm_3#<(Go<1-)OMuB-rubu&vjMJ<+F&m}2$a0sMp&<)ER)=wU^ z-}7ZAJ3p35UM)uwcy-3Ke_|KvcE|nhL4)-RIzot<2$SIQK6emBxf45uVJtmuJ>)?{ z?4`T_xSs8_jDXdq_fX%}NKIBCATtNSIx*2j*P)bLW}GM-@WJHrv~IY8$3 z8TNlLnDSvNweLBv&JMH^4V~v?(_^Zl33``6>-^*Z64Lw^Mn84hJi$hef~oR|U3#J! z-o-|*d5#4Khf6|6AWajlfSP3tS93~K*IXcB8FC1VG;$OR$Gi}?I(N3H)+m_qz~y*w zd4gl}>ywKkxG=f|os_YP;P=vjaE4cch)RdaVXc>A7Q*2#ptx|kjj^EB0xPV9#AoYH#PgpzX zit~__I1x8@q}CfG}|fux#xozDv>#3pZve3RdIMSGYgCNhRWKQv4dIB&3@ znK{n!@y0SdSx4e*cMHC3?b-4F&LFhsb#jL8kuRP|p;mmolheZDCQuZ!*jqXSEiFOq zK&(6Idq^JX!J#*5;!%txV^+wQHW`&$aXfZNV#(3{H>_}U!?pGSvC{v)bb{rtSOMxp z!T}SCkN#UImw3mZTS|I5sw#gl`H89L*~Lsm!8mi1CEK}MEY0a2SWNO5UfJ|+`D7Gg zEaFW@;}_GBmp%YJ;peN*garMB@Q`qIB+QeaK8=K&B+H*iW@hH_AW@i-?kR+V6ieU@x-@v7PJW5oD-j>?_xp#DV>yO^53iC91VH7ZG1pPNx|8vivI+Y7;G^*N zT#D7X-=ls6kM4b%`^FRRND_I36A%`k=EOk^REn~&AwdVBAt%vp^f|{c$@mh~U+?#; zfY+QJ?7JE<`fF%rATBTrRiO+%UoZFZUsh<7H;ntZ4sJG8L~T$iQ(LW-&a};sk;{S} zDFw4$B4i*C$j{k3{ zqE%K>GJ#TYLh##YzJh=>C`ihEW82$+P`%j^6ne0^Ce}16V_h~;pKh268np3cW8*4Yul3oAv6{;@%C>^^pms-FkKGJ34zCLJdb!rl z7$PInyB5PevD`1_YFmyX39EOd39GWUMNk)e8S5spyrw|Xbcv4RQ7e9(0Cq`k{*JdP zF-WA$5BrRek~)#*dTK##Lpy>s`8aQ0=1Nj+(EeB1>H7L!RP$m0JL-uZYB_Im8PO*V zU)&0stZ8#;mk(Fwl%qq7;4VJ-;IpV ztW|W>c8{R?8BO|XHSHOX`HE3r5_$WUHX`O|vJOEnBb8jtbj0xlG!5ed(`IO2N&{(% z7|xln>$poQr#in&%5%}N_?Gv6PhsN@ImD+7>@<+1EKQ)3zMPTX{wxht3pzK!%Av9e z3vg6f?kw~ufSKHN-Le7&Cy4kO+w^&uCj_fRAjbpXs2hq<{p4DK!m4^?>tkmOK9`>K zO&x@L7{l`v|E;d1;=v{<<3rzM_t`2OqXn?<%9sqSSJ!2DI+ir_XJ7fFhmA5q#7g4_zDcjOi$xyWzk+l4>vrbVbqbsw3?=>af` zKUph_Hl%iXvVhNK`x-uKMr2G{!kbH!pESH^!f&i1uhk!bpRl4McAaB{hBs=nCz+?> zq{Y;`O$9!$82-zE_EjQWRB*oC}eLZt~8VA#b8GTMF^SHO&tT@dlf*jQb^6v9_HsnRPRR>hK{9ae!3rC ze-TJI5G~1RtvL~B)mRz&ZT+{E*2Wf^85MTZ&!uq|?~vGCPn8|`a50;282bo1T3MzH zm&chV2+rx8MOqN{GRQ6wS=H!IG#E7G^M$=)ddsZ!_zai?=cEDa% zd)(Mt&=fLLsck*#hmt4+O;TRf_MLW&6fqcf-E{g)5UsX2+AFvPb?aY%%;n`yli0z8 zmwXyHi(d*M`r9|I^llZoJ-O7f64DW^NI!ppPf_ak@6%f-8{2FSmYI#cfeKjPsbB`& zLic%@c}cO194bCcitbcM1Hs1WW`Z(0hQ>Ytsse@dPdE~JCHsIVxX14H7uP5KSseKGtVeN& zK<8*cF_|>ODhX?WIIy+*5Unp)RN5=~>cBFpTtdPXtn64Xb6FGmT{0N$qbi{wS-XcO zo|eQe2OKR5kkmjaO50aBq(>3f3&Hw~9xm^nyLp`C&H^grAu;dtS!iJk$K?9Ezq9l<~zQ4#K zE2YF}I$SS|XG={-f&xEjGT{fw;!63 zVg;FgD;i=+Hd$d@+`0(`sPM8frx>@Xx6)TI!3G5kXMAvOzQ9ct}Owf*gwLS7;U(}I-RsSqLnix z#t-@)jpSsW)9SEPGniLe61=>YltbKq-=SgZ%@p4&qcE?AU5pG({Wj9 zbUi2&@A}eSiac!EL-5VGigSH@+Ux|Iwm6hepanRIZ`;azD!X&fq~i++B5hmb63TjD zqz)jRi`Uf@{(u!dS5x9DIm1aypzMIarBpdP>w&~v24PPhv`>$UDtmxO&jwp(U?UkT z>w_>5j+$%KaEUKOQ zpF_F*m(R{V8f$rP88kb-0a_%517Si9F@b%noov z*+s9RB*Lr}h#}_EAL(s3TGVp07POfP|g z>~riLMKY`ziF!?@|AK4pd_#?ro*ZG5#e!}qjYkL%XG1k{w-W$I7buY%)hf%ah{ar8H1Cq;2Ya&8D@>%IuJ>Sf<+l zQ!*VFXuA@HGE}qvgS!8-T}Ci2KU;v>wgs%)DE~?0gjftD%TLqNM;0x z7ynHoMiPrLhOwM2lVjZa396SK>D!+PvS5RTrE*HqDKD`tuKjn%iK_Wj3uVGiMdI-m zV;&(r-9O_V<9-^|gZdNJ3RT6bFRPTBpB27Jl>OGjyMf1|_c*Odm{MW#0;sfdSB1#% zt|2T_FtG4?CXQ2ivZ&^la3Lg6%DkqThcupYhCi@9e&X+S*82{SGcf9S$3_lqM6aiVwiUB5j>a)^(TZ%cs zlUy5X#_9XUFeejFk&}gM8I7+YMMYaPy#Ysu`$MKlZ6GQAtrnq5`i0!=`(oQmj@yyL zjN>TeEd()-(E{}(J0}Im!{n94QiTolQWLkXzT2#xX~6~lFtye?$tRAgM;%HxV4a`0 zzO`o84;3y%_U{e$e(KC_bpS+7!x1+R7~RC$CeH%`4N?fm^oEjmk@m8nH{+uu6&%-+ z_KC*Y>ZBb)HXyOfRP2)}T2$#|&XwjdUL=bWd{oPfk~*QK7oqWFPXsYa7!y0?TP48H z$NXRlNBOR|$eD=?<7AsLC?jG7Wa~cG57eG-e>kJHNG*!F0MH^N*DTz`p3(BMJwMD{c_IIK!qw|UnTZgQ&B0uK z^pf&hJV<Sb)d%<5tRYj()-V{`{9o>$sa z#ANet(7%Gp5R`NT6$q;2{|PE!3xtE^Z=g~Ef{GjC4^ROz3us6&{GwN&R^)-Gs?0)c z2$C}R#;{?W#tTH%*15VcIzeyq#E?R{*O(!NSfCX;=nhf>(i6 z&LH)KuL+KoTip=!DnmTkbF$ot6JO6Smit%9TL43GwmtzOHR$&4TfNwTk&pUYEg_=! zH#rfV16&`ydQ^8v%&7G+Wjw`9o-pr#`?v-kvUe)F`GZAxMk=?0BC%?>dCI$7i-`8p z<3VB~|%9P~SXhy^YZq3{cbb-_h)&^r%59I7<0#SU^OpWP^)PD&Uw)1Qt(4>r8# z1AOBRWa`+c*e03AqD)k2apevggT!u5%#?>p)OQIU`DjhWxBhT@PU0d>D6&@q`&DB~ zr7_}~0^TzC7qyH$U7c}S`T}0%1>u;RS{Q8JcOQy^r3I1|EGp1^(#C7!hds(vcbGpx zHl7JKC?o3Dh{aNCX(h~AA{Vdl-AydUjkZ5IFTDPz{r-Ov?PRvCoDP)cMW94e{ewhv zFa!H4oCZQp=Js}fQmQyUxB(^v@fYEnU3eJ&vHHWx=ufB1ML>ntK|6^>K!w@9e-u1; zf3Sjma51buKNm|^ZKBno!q>gBJo>u9#p_?E*i#=o&MfLu@;r^;mZ#!QC~y^pGsB%w zDCa(=X65Fq=r0ImZ8}sRJkd8cHq_s6k|-YgM6O61@U52w5~32GfKZ2L zy!RU{7|ccU1LR)`lgSAiL;)mB1duTQcsQ1S9S%qs7yJKzxZot9;gLoO{!kg>X>=B4 z_e6=2UhVGAbk>K9rO<^j#o^%Vf;OVyXaOUfPLI8u+y`k^OOdcl7*JXQ_Kvit=9REy z&v8ANR*5Q+IXL#BnjoxK_K`Ik=~3_1jiAmoq5POkejqnXu9t+Qv|ue3j84bKIU z7i?ItZ3fFif8t+=BT<^rT_E+i5zDq&nbTk)ke0^v0}LxBqYBKSUW_9HRTqW%z45N9JD=Z2?yssZgq$B z2|*r8DvI(Y@-Re-O%eg0g%NZxj9Dix!+r1%DXvgTvQF0X9-R=P9MMBQ_C9|N^dDmq zPA&``CwM4^XrgqIUCHjES5@EsE`&xWpz;kaIVklOmL}D9+M{gsCm$@Mp^98F9sGFc za1`pJYLr3{`VJOY9o0z<95y;d3A@_{pkHT!H~g$jaYQnCvB)MpxqgE3eH!IqQCv45b(0m!@t}Pkb-DaP(YA_fptwVA{oPqNPVjLz9sDQiL zaM^_*jjhpU*+tU${P-1GjZon)oNZy>U?CU8x9OBpq`r27K4nFAD%Zy(b6u#HihDe- z!l+l&kk}7TQR_s3>qBu^5rKUEz z+=Z$T-qs$8pE+dXbN*6oK39Fw3(5tGu&#pG(b7pDBQ?3e`ayoZ&91P}TIsv`!1luk z4-wBGWk(%?d8VjZ1U5ejDv1fdE?h=yG^+!pEjog+%1(%vCqq;T|6W^Jr|yHqvqtK= zqmV1T<0g)tn11szO7l=VLlhNW*UFP#^i80-mc0#rjlY${Ic)2N$FAy^;r=ERSzYKW?2N)i{V!Czg@*(J+7b_kkwrTVL`xT=3K%U?nXXM&^ z_`4Bxy|Sd;HXegXT4ba2dHK#e{9olvAq0EIJQV}G1VTT&P>OT4YEZ>vtR_+r_;&Ep#Bw)s{bgr1SUr{K<;i zMd$4}GriXPRT)j~bzfLJbFPj~_lu83f693E6EgY=-Q#tGWZ(1@rP42k6nKsFXk6?q zC1&>si*%v&H1(UKD@S6g7H$j@+&HAahT8T_ldJ&yNY~)J>cpBcw9zg{IXKNE%V1kGm2n*!`w?6hRoB~Q{~q!n|2v#GvlCAabCks+GJO?*$59kBKQ zXFNibE>*YrsxXLYGj2-aoL3V~M{Y6E8dh%Xc>TAA=L10#4KEOGkdXgF)&3Z{a2hBY z+1T4!+WjekMkgKBZ}6goe0UGP)S9_`F`KAAFqRx5fP4I;ad1vyhgg<}(4v0;qE$mKMzv$RjT+CZpfQ5W!TI6()c)|mjbSzR;;fRxq8LA z8f7x^KbSJb^1>8e%^jTI#Rx(p>HNyV3Ra5q=2{8-W5R}fV!aqCv5FcMV4dlgpK0)! z+($&0tF+sv#dlwk?47ISx~a}aKcEwOTI17cXaPAOp`nz+?GAOAMQc>I^hK)# z)r*BOznm%h`(G80qhnjE8mM#*WM# z9`oMMa7xZ{&8o6p(38E2p@-?Hi#8|YOZGwdSaF}jHod;loYWnq#TgGQJdVw#peJdQJshoC2wgA=6HSd7{Ez5xI7J08vgFTlcT=A2{`UyD zliR;t{x;|S203uV4?HeBkaZ0IbmTwA41b8cy_3DGxrMQl*`HND=_qA`8zcAwxpRQF zpkYvbQwOFEfMa35_CzzAVTI%MCVc>4EA^YXUwij4zNqx|_m^&vA~3tH@@Z&mZfnjQ zE?9)GAOOtbx;*o25fRj92(r^l5@yi7aI9p|-H%)$6Vp|J7Y*D#dBn5j%ZwO7>(Iqkjp|g<7^}R#2pi7I;#-?CgkZ2KmP2LRI`e}_@OEGV{k>JoFb(8D)@ZUkob6y zoNxEXXq1-$q5Nc){L&~J>70kNEk|z4)sN8)4}{xVy!C>ivk#P5s&4G8yPMo0vD<)N z1vqFZeI~9|-HKU@^(?ynlsJwCt^q8Q%BkAil+q1Z7YGC9Jx`6Q@@Zi~O4rP4ope*N zaxzcw1YN2%>;&yrSJZHTprY0q8pFW6|5Vr_$jW{Ki8A&TCc3L1nl#KllwbzN9DLj- zs^i}BLof6ds*u79GRrnbq3X!^AvSa)4rFy%WB$T~*h>srnqngj&1HMA{(6yo=#+%ci`9glmwrl+4Lf>St*b3AqV`nZ-4=GA?-i z!%v)Q-{3KSP~Q^Jv|MC47M%V<>M}VkV^S(JpDvLnw4B+%M_y!y3HBNoVCZ<_d=@_BLbKBPktI9%(N@{Fs z>Ji}Ncuyt;$OD%uKQpO%q83Ym?yQqHs5Gc-cyf=M**Gyl|DN4>^7dUdCye1vOJuAp zQ=XQuDx<*hzS+UQB8Wq}K-oCUZBNLnv`5~Rt53}-S{!+kNDo+GhpxaU@=(j6`V8tE zWO(qz%sT{u1gi2@$zCO%M?aljPp{nL^wcqBFHyfK^Wc$iQ`Bdm)^C-0olG~;Z^|ZB zbEdvSA(pNoq!qiduukQ8dY@WbcXvmrXwS;m`hw=g*F$?h9Eg~%>dit^p?loOxxpRI0x@bg))7CaBGRwmx9uSMsIN z+}!=$mm3Zom;ER7>1ECY4P3nyQV0v&lN~M_x0W+iKbAY;@hXB&6mzVRJj1pt&P$tb zUyy=MlWaCCsB4)fdViX(2ur*-&zL0QSX)A4%t{SeJQqo6m5t*bikval3xT-qwa%LW zS(wY`v{M2=(ngk39w^eBxEHQx-{A3X!l8O%l^jBw@M$zk00}8mJ&rJh5eF<|#w#w` zKt`0cpdNICwbZoU`T(}9oi$ll9KJbs*E5G#M{R|;ky823O_3t`EWzbt!~K?^n~Ty& z#ZOu*p1+!Bq}je}Yq~G+W~u7$z_Y+6jV|>_Q}&_KgEeJWPhD!yeV|W>oK^r-+A41p zvc+qw^T{eB*2+HqjlTaYsn*F9p#D&P@&Bd#LjRIMVIwD(zcePM<=_IDP(t>6^V~-v z!5&h_POGh;+b@cNoeA=ce4(;xehT}XsGAvUxZ1D2dN@nt=H$#qYM* zdw6Hy`)}4ftECUT9NvDdKhVj{;RPP-p1KYlv$Yr3hG>o;mUMc!5_ zu_Qi!Ywtk~+F48kj|&d_&l5p$HX#EUfPsjOk-LSFt?i#@%-JbR2@e1u<5ZH}Pt8=z z8D#4B#SWODQiP7?D7JUkiG1FY_h)}Yq?F0{@)Js3foL`D7?wt|7);8%7F=7ltXEAK zGt({FB!Uws7&&D>zB$bBNbOVoaB34gG>?5=_}+ zzcV)1d^9fBTJuAgGeazSSm{E(<3*wOukEq=YzIr^h8cjc>lrM$FiokoDM+Y1Ih1~3 z)kC>fJoU_48lNaDx5FN?skmgQ53e@-bgJgnHhEHzy&ESAeYHH-SsBq$S-&y6pqA~O zv~TTA?iOKgF7OS}&Zpbsb=UgzDPbwPTAVLpPj>3YPECCav%Pkrqhi=g|0rGSMBMml zW=XcE5&XMG!)HMzrlV08Eyjqgbq4pU8|RKAYb0A4Ehf8`OBCz{d>DB49#C?kQI(hwjvot4NamlqUyzli{4_Bn744$!%-L$<|6Xq78_;Qk+iucuruuRNp%m8 z3Dr4EXRZ1Mqd)l@^Rb}DKe70al(Iq5Izo!AW8T5XT?9&SDZAj_>GlO%H)8P7DbG+c zW{9*uLWbG8#fErad}HV5=TC5=bvmp{^2j(Gwfr^cp zskzzTiE))`8@VosGO`2zHIx>z6&M(1K%Q1urkRYpIoMB=3vE&!j6q` zSTfuS2!kJZ2U5q!&h$0?7ftmwbB`n~BHIOm?nUxn`aLgkwkuk3Y|guWFQ-#oLufgc z7Q1oy{Q-6K0blLu7aR_@cR0172jfD7IYUd;t@34w`1|$V8u_C0hf_ZDz*Z$cf{L?Z z^IyWHC&xqXfdEMRZQjuBWC4DHomG2E1du;yJHw8w7)pc^Mk`Zz2Zin$rxMib5qrkK zZ2GlpX%6kMi!Rie%uK3wI%FQmHbR5Be+y$hZT7K1m772z8gjg|flT@K{JQ%B5*e)F zny>vd9jq01{XL*|)tu$i*j)GOXk%Fay+gEU@Hb+LdL$pO%S^Ji;CnRT^pg!)O3-5c zz^NnWLKfda#q^p7xgL!wlp4b<$TK);OLm1(P7qF8akaOM&ZKewZ+2?taKH!Un|v>mzGe%ZYKa ziPm^obe?7Oueuw~xFu0;uT3v8iVNYwdF_#d>gQ0&eo+6X@yXc0I(p-`G@GU5ewWAW~4yOko#q5y+s|_4J&kNw+|EBxKl+-@(*Of@tDY zF0zD%r6|zC%9$xdBNv7wkFA@{zYD1&TGCXmd>^|`2vfqg*o4e*@!w>OTYV`H!olRmNJwq z^z%A^+_(eYI{Bw!L7e?xDdV5Hk)2{>4YX+?J<#{Wb_lt_G+9T9l{iprbzN8))f8H| zQJ}+0==L#*Yw|1CD>D&RSzkW6U}bSq^I9%N5A(5@_{t9O4?=fksIgUPiE3SrY+f{785 zKz9hrV~4o|8G_>KFN!Vc=HJN}_a;D7KLEYwq<|8Q19=#?KMH`84*>f@g$K*s4O0Ao zJNZb*@JX-pRgnqyVsG^$hTTjFXL$~0PMXTK+qO8_(4qhvZ9h7QoO5mVRM^C|0^Zqr z$TPn{_+#^e*E0Zl7tWqS5@%@to$6~)@b;w(YGy@?Jh`lkdhvVx&O7*Dy`pNZQ0y_# zD<%U==Ko%$VrCK-0eVG%frh1>iG`W7%U_JstdLz069VL{Z_&0tyyjaS;YjVLAjvJ) zg?EFZL?b~4Iy5JW$ez&yYOU^WfeXKtjOV1$PK&V&Nwo?p^!mEes+66b-?@*Xu(qIi zpGQ9BhVDCO>TJXl%XM4!%pGdTRl5*)B-4Gc-LWw>3#j<3O=yK}sapq!_Z2MVQ&TJ$ z&U2d19*~RCC$=&j_=Ds?2B6O$JPD@mMcuPCLfwc|F~7xuMHNZ_$lsR=5gth?dK2|I zl6gk(foe=)*z>J~`5uKBl}%z6O^7{U8O91U2}OuD01!YCz!u;Hp#_l)bFXvyw`)*- z3mM9L|9M^iy~qfBUE=?GUBJGcnUn3G+IrcuP5$6Qz<2dp3Y~l#%(^{VTYTF3p*%Uc z%rc3N*!{bN!Ki_KgSxnMC;~q*y=gcPBioo6;lqPZxD&V`1#_W*xe7^!>I8ImZh zRx9ZDh#7%y+Htn`Hb8qHB2K<|)aHRgufQVM+w2VxbBr5<(9D5QRc)?FA16PGmRHmx z4_+McJ~xG$o5=kNg~(Dmm1_hQjTRO!lqHlPlp&NNlp_=`L>YK4VuAG6`WLLETn80+ z*?AAuT}h|_poHA$9l4)QjX5=u1w^lgpi_r7FauYxFI{!} zr4)Lw=mRN*v>dl$WU*t!tc04N7?Dk!{b)OlJFdEP!RO)~P zvZOzrr2F4mfEY1n(O)I|DQH3CkoC{~O1B{vcD)Rw zne#6wP~ho>9(gdYaoOD`D<`V-x~F>%^w*R3%q$d3Pq!HhHDhLLFiv6=XiQlZBcN6} zxa3s6bz}A&Daw;ZQN`81R<^qL$yw5J5SpG^P-?Pfgdt;z@^)FZTl1h!#6L9~yM!V_ z*yK$HKzMkwt}yQMT&ZWXP*=Bv>HOmMys@!+JovFiBS*DV(ixJuku6JgmXEN@ogQU( z>8Hck9wM|=AZn@Lp{z(2gacC!Q0k^uEj&aLUHL9i9wSas!L+#0)rvjBUZ^2oE%8+2 zF#j%ZCs>^Y2!Hjv;UR_h%Zrp%-SJ}J$uab@L_x2{VKG2-BOwAYS7tp7pgET!#X-Y_ zpH_Sd7Y&j2vVleer73HT;1lO<_Hm3wkI{9W-sIMbJwT!W4>MVOrgEH|-4-QbDKuVM z3tqJP9tRU*VIP2?q*I!+?%#=cO3l-;wt%!h`k0gQJ1OzQI?FAu7Ix7Z>?u<)kV=YoHT1UV zbqq}KV;oEn8FE(<1nEDI8+s54>=OsOYw_pZCfD*t^y$E7FwOJ?Ktx<_>?wt>s5W&& zieb-rI77H0sA5P&uDG0{(a!nX66mt&^J>DRGP?Qk`~2iQ_ARNy*$-vOiq@ZY8N8t~ zta@qmb>{U)Y{EOT_e$w4Is$)daUvxRDf9qc%O23R{I>uBnI!@oECBu(Ec{J?Qcm0& z#DQ~#j?IBW&Z_C!=wO$14a)acnl6W1ZL&NXzl$Y_is-m|*9Mnk-(saPub*J7TaBK2 zO}CkR&aLjP?wgAbR1BOPx1>2k)OTmNx({`Ob>w9Mg6?N~`neT0sC?hL=iUTId}M=p z#1AadDS7!rsh7;U@Q1Q^I&`d7k%+s$i#n7~n5k%xJ5Z3x6739>z}fkeeT7mb`)agy z6Ul4qzIM z)LWsv*}A%Z+GS7Gec7$zaI`Y)kUUNHD*g4s_gvvIm=Xg zg*a#NaD`o71>=nRkR1h8xTW@a>c*|5##g9{PYGwuRrnizh_3lH4^No&7-Y(_!tH=f zR-~8+c$kdFc0cO)ChrJF5dL2?4Npy0N;^aa7d(bVz6JanT{$xso;gKB+*imBFXhEz z@eDOSX+>gRjpSEl=a3#by^-R_kE;Jzx{~-~>1yVPC1oFSbWL4+79m*Di}SRc1UA7G zyo^7g9_|S#e$krDGs2F1h~D_Kgz!1I*hP9P4LL0Yx$2lE6(c1^88vxo4+t|c1uK}p zX_FCSVgS<^jo3<1A*e{mXTi=JqJ)*3P7qk)1c+oU$pl3<_`PE3&=;Q1!cNp^C1GDk zi|@t-Yr+q^MZ6}xL6xzLC6_u@4iPN}Uqo^ZVK9*V^GOwXA*7)Mk&yheNKpvE>PS(D z!NN)72*BDzNS>Hz>IR_uNfnQHsiK@6wqiNzuvVr?0*NiK#JGm~K`1!|&;Npbxj)Mk+wa%L)ye5*_rll_?XN$y&Y53G*ib z4O#!sedMfknAo=qoU{mHZJ!i#Dc`7_F)|s-K@|>L%t&5KqH!x<#X++-5e^5G!RSq! zdSg!%2y6;d@`L))OshR=E*tY@;EE*?X5_eeNUom?xs?_NRV6c0QIk4uZADxW89JVz zS!m;q>~jS7=vmft`dMe+nCFmGQ>8ncR`2gUQN7&NYuTWhE>&aabDF>~CZTwFF$XYa zY#S@uPs8C;L6m9p%8g}VHsUzt$Yz%i`+6^>5)K0TRMc@t0dymCiK3`te6TBO8J!C9 zBy(JO35ue8u;sgHKh>z;VZ0cOO17M}!$@7X^%ol5y?EI0!8}DszQJH1`1g}4vVpKT z!k8lYpQ3~z`oE%#;{8DcJ_x7Z$Pw#%0Yjy>j{KBw?om7#uws!;kU9!1Km9t-vMH#t?zb8DNbG8)Y%<#QiuNx$d z>B=uHD=)^N80>RuiSDZlyb|17Xs{lUf>HHDb{Lb^kL7#F{J6d}YAnRH-&0Rj(>}!P zwEjSV9_Ulk;!V1%fAB}1vvnbyvfoX_ks?qUxr#{K@0ukSsXSnc)nBM@Dy|RbF+ei9e+Vw>ZfR>e?Z+yb z*7XWUt=dnXR-=L*_F5^&J2v0CuJDt4>ZUy3rb|OhcL)2(=^`6@3|bFgX&GwLx=Xw0 z#{kFf5q$ougF}vnYn%Kfnql?D^2_NMD-SB|v>}JL2^O|K*7pydz#qI;RLhf{W4=WF z^wTRZj>gg#jIAN%>L&du+gUcOWo9Yc zmcJ`|(_~VF(I`50;~?2|%lyI(V41$@4dVEHH>d}ab(z{F=fO?jLfO#QvEXF$v)ZHN z-TbQ(Z=qBcyUq{d7X|+5def%oJ&x)5j=fwRM!S$5tt81A%xZEPRN>R^<|R1cOXtaig0}IC`CByp)fkUbj`!06fGyF!Z`W9Fd2q3!uT_!hu1<1xIb&X z^x+*%w~_v7gdbcl%9I(^E%o|xO&m=)@9Fo$Q;fU z2?BTcZqJ@5;yv-t8tqY6O_QP|vaaey7gm5*sK3$*+x3C*8d&m;0W0MHrWHFd+5C%E z3Qjg=Ms|PNNYDOTc`QY+!P+5QyQs(6^`RyWHQtynxtLPv(Kmsd!_U97;a7FNqe8}P zR+SZ&j!#WX!D*IWgfwt5@i~R4vcC((3-=bssRzcYAog0}i+4uVHe=D66rRF{-=YPP z&JR|GozSQ!w*<24wt$oZi}-egc@{Qe%`;i5vVMw&C>Cows6Hx46AA3HcpALHbY01B6E^Cd2IP;54KkPi*|z$>3DnnzyKMxZ6p;d@=)afxIR3Bx z6Lzw6Ha4>RQ;PmWiw-z|)gRPP;^I?EAvu#*QfaK&z^6VtKLE@=n`Z8*&=O0Xww4p6 zC+CKNfpP?J94gep-H1Jb!Z$m~TJw0%L}FQEuq&kDs*c6}bDb|;zBqBC+^0Oj_B%N7 ze&{Qs{?32|b1I-Dfq`UJjwKtSU6OO|$<^QjJTsEZd6R2hzDwHUomCez_NXkv*X_fz zWY6OV%2gsS{U^i;HHe8XiTIwhyL_3T1!1*bFW9<@Sv+8bxG}>N<6NsYz}>Fm;IQHRx;M>YoF`TQ|Bf8;eJTXovn-Ms&ch3tX;P(m+Jj| zILRm)fm^A5W8PbkdB5P!`u`Yv3$Qqn?R^+`8{FN4yF0<%3GNVrySoN=2*F*0Lx2z% z+zArgJ-GXS*v;PEdw=&n-}lteUEOu2rs?WFbv+-(es!WgeMZioZu|K*`XTb=6PP*cDyfQuH7BrP$8F zN*76=o3#(T{yLfSkx}LhT;4kCMywIMh3Bg6y$5ghW$OIKCN^)=v(?J>{#(N|C7sNz zqY|IElEv&T&$h*f)A+6V@clx6eV^7xp?nFiY6l|GNHlVEbtiJ1>i91%Fld5)#H`@r zs0q0-wgd-Wfe6V5WHnk|k)=1tvMX9C6K%85$@J*3fR`xri$LSKjDZQ8j4rGZc8Dm4 z!FWb9j(`@_PrSt9Oc8}U+fd@Plz*M31hFSi>Pha6-{cVBWUlP zY_z|o7c!$S?j=@DUf%Y1+#&}g%$UFp)_8ny6+*~KRx|?0GuC)qNM2J?UKpo-k(F=3 z>h8W6mpfp&FWX?byWkGQV81t~{wM)6_bA7gYMR___Z#Zg82Y@(K0K!qy(lZ~YvA`_~j7a%LEe|@2%Q>~(Z+BLx0x4Z@5G66SEyKlbP zCt0@4EoN7vdo!?O!R3t|+8Qd+`2Pn`H%_NYa`GE_q5|#zJt`76NDch~smNP@F#eml zm_4Cl6C#2Hv-V0hhlY@$P6GN?#0GX=y|T@-XHsU5gDBCcb5|cT?+zd8kz3}DSOKM3 z+E@?(YcX9BDGdFF&TmhmE>d9tsGq}t6UdwQ6FyON8-b6~=L!#@l>VP7h45{aO24x; zo>NBJLvFgUTTQZ5!yT$rTIs`n_}E9I&Nrn~fv}gK#H0!CC@2rJ7&n&R*V3 z2GPMS!Ez0=KTN?J#y({z(;d-~cd{sBKs_HiUe80esw{ea_`+dQ&IUL~f=D1f}Mqs^N!H9rOa*6>^C2bj5_ z%+K#ySn%9?0(yL@>2{)8@en_}eT+fLoanS-UKqw|Pv-o{@o|`whaH-3XKW;ZuWHiD zbP-CNokOq2hBmTc&`Ic>xNvRv6GNo!6>&x_|Cbwr5h_n1)C~BNO>B7z4(hJEmdfD7$UG1;R6TupFHH`#1Rdc5^Luzs`wV4*_SX8xT zjqf-VChfncLrsyZOIxs6b(dkr;=!f$E!)Y1B2sK*>0s@POm9X$Vm>oR;7BTriKmXi zdL1c*gx+lwR}7Prh5!z5f70zV1xHl5`OXprb zJ;>wOnYEb?>`8bO`6|x2O|A+pA`h%RziV)ua$XZoH=QgBT1x%pUSpMTGOl zohaa`pFDs!%{fAT!D;41^0ESsd)F$44){Y|lg|lih1Q6Ug&_WzR=hnlp~iU1chNOi zgc{*$=fE`a=rD?cJegx!T?4MxLf?UT!-iQcVKCPjEgl@A={;@&iOjA%br(qC@4-Ug zUJ&&@3~zsenN}*CSbul7=~QwfLi;VQ2qP9t=lvD!0rMTc_Jd)5? zK)c_iJ~HrzfxqhzL-)HtMu9k1ksoJ(IX0J=_d-Z?fWevD3CrCWnnY?p16MB$9Og7V zeV(2spTO<|wr{C7=TCR5t`SemLccpbRu)%F*C5krjl@DAD{F-=lZ?z=P8Gp|K^QCJ z?ae6aZP)t`1j}EN#4Z{1T2hex7w7$t*Aj$afnG~dOY?uel1DnbPW3#PPbYZaf}6O9 zoi)&Ei3olkaCm#0-(rTl>JQC*_5(!0_m$Z)s#3cj=Q`W*dh8Ug9r%QICR?Z4&f?vR z3cn7uCAqLG70eu?bi@QP2iF_%iO1b3cg4dUCq#Mc^sIBFA63MP^ims2nYFRlcD z_7MNkVUBLD(8is1D7~7^Q1IxJRDJMupW0xcok4zeD#DtndC^R;2JnnWJn46mbk__*gKSgac#6hg>dFF;G6xQQk`GQi zJ1|^yPRVq$C_2p`H7R>QS3VkiC7>ghQNCY1Y4bIi|1`tr6Kx*zcQ7c@!pr>C3LGXC ztv8W~AqMu9&u=dpeL6E}92+XBJ>WB$X>^%3Kb&#hv*}XDO+zjdF^w;N9qI1=()z(M zh<8_rCdhbwK@Y0iCShQv0T+yi2Ml*e8eC7_))F(eyH+yam8OfEh7tWxtj>)Rr6mQ7 zpOm)|jgMkQFvI~Rl+;^o-Z&z7!cu|klP(-Wo0E>#Px3YFrn1_h8Zb3wrI1BRYcgB3 zPSVtsTwp9}s8zyk@U*kdRd>87E_xSVUH~r`boXJQ0=f-Nwy7fcGO?4}8!2E}IL&<*~{TN+CLB8)`;ObmP)4n?a^6Fhm2 zVw)kCH7;WJO3t8MA3TUG@<&npQ;OoiGx*;^uSJT*mV5GJNepS$v(F^Q9<7l$dshVt zZBeQA?J=cb@1C07PTaVNNc0q<%s<rz zE=%lj-$OjRU>x~|V-~`|q<6wbT(Z7Ch}f;^B#g&h?3XNUNgHYNxDwA273}&J3LN+X z`ixqjCdmp$#^;LhExuG^dVj_(KEJRP@sT?H=ywRL59U~clI*PuLmWfV>Zx-9eNGuv zlCvjI|KTX{TC~>-f~LZiBmb8fV}HEZAV&%GV#~Sy(?mI%k&^|ApuwzltP!<~d^e2q z11`(6K_4%9yi}x9v#am}C&e6+MAl&M4-eF>Yj3*SJ(R|qfzB-;&$=m*#->wj&g6ne__ zc3l*N32i9_*Kj{ zN+vo%QsY`ha5FVZU+>&jX2n5gXH$} zxH$=*I!@t)T@_gSjY7|p>^qmXJXgcT{HZ+W!YN!)H7I@Z0muk|D4{62D848*XbjQ` zH1=2y;8>*ze@6FRqItp|{bk>ePhxt6`@UbBzi)wcHulT4lIaoAzk8~?l6}Y`AjWB@ z;QumsK#Yd}ZtxssDcNtl#qB$h_6aZZk|{*;-Ho$EQbmOkSSTe^fQ+Hf6Vx7~be#J+ zozA$ZwECq3mt|gI78YnsXnq;x`Pox&{O5i4$Km&}#4b%yQ)Zz;n%`Xbm&f!|g)G0D z@Q1?;_@ACU?IZc_2!aceTah5U61(t=XNNFvW@S~m1z5%1lu~#rS2i56wLM_y(%rNbk2{rSmPq?LI-Bh|;Vtp&KD{X#>lX51@F?!{MM>XDPsLhrH2KHz0*gX^sO3=V72(=*(J1C?Hi#LZ=KVY!Tg5TM{3bJKZI_d z?EMjj&8iEW>@5{5uJ)94z%mS?{<35Syj_@60y9$rZ-sJ=rnTmdsnbHWLyfT1_P)j& zFf=g9jx@Ux?G0`St90l=3brYy6#`^Kv^Fa!ySgf8_91-+J2D~pQ>Pc8{nRck(uNa- zaL;oqtRo@Q9ONY$aMHB7zQgd=3%MyJIP^`c3(xmY7px$yJej6<+ijgbVCN6g$}M2H zBhuja>C*0{VX~a^4aZQoi;_LSh4fEVk&t$nU9s|ZL=qZ+6C%-;8W`~2GR;tRga@0E z>tKgNQYah=K9ui?2)%ejoB62F>qhW;Dr=w_gMEb`7ZM1gzidrobvp8k1YUnJ>jubk z@SlO_D>uX=vD-c47T^Z(FBLfuN@RalMM@?QsOYx(Lu2P#qf3^Q_kDuEe8C-A!!9PL zIQdDrDx{ZxkDT-_1GhFT)o<6~!QP#Z%d;_(Q1GoQ89}jemSO={u_Hm!YG0vlI$Q&5 z0vGi{ALw83AV~VrN4b!0Mv%1FXSPBE{R>v%>rG@we_{Ede)Ek2dZJolyf(V-ztU#{ z_xQjW6d2>+51 zlY5mCpn@-=%KKMZ$BTDh>yWy+=hfZjd&enELDXw~3$MRaJWn3M40|P&4_jZqzh`Ar z7kgoaC&kD9X^%I{u4GTmmB!G}OAlq}MqviFl(GOF4LF|$M)zh)I6nE^cEFt??Aoy$ zp}RlUw{qI~G&of`H^^{Ecwb3~aP;e@5UnmCC|a7c8aCuBbJ13aSUNj9c}A7Ca3VQM zm;O-W4sLY&i~6kU`kX4xXz!QlWf@P#ZL4EKnWDkC7Gh4-wbfIQ}&8Kp|7?EUk>K|8`i9vgVvFxIkoF&I0$J zmlm|qVrZ)62nh!UQ;1SwjMV65%F`$3m&SOiqbWH4lL0vV{N23Tn*pCsqA30Sg4r>~ zgJ?f}C+TG#eOvE{CYAO@m~Ji?awWrkizufHu_W|ozN*X~C=3mk7d2rljPSFz4S$zz zelOunw{3}&?8_QvCn9tHHr>2E4YwL(G>xla&-#+^iPV?C<72SvlE}ycG+g%?6qZ1^ zud6HF;mO}QS%7g-zHOUbIgBUH0_Q!$2_%@qu%^PT5gUUhy!g-W(I;3R)cf<%h-fVM zkh_OvU8X5~XKj6O#u7b*8{eHt;l% z=26KCI@LNYs^0YPC6LJ6iQ9d22=d!YhvZ{7hDN2velh8~s4mD{|D&FA7#E6B; zrxLY=xRGemZ;jot(tt*z0toIANI-%$hVnQV9Qd! zlwgtgUI%Wik^!G!YX4(P$gfqsc}~8Z#c}Js?seC86G={k^?@dJ8z`*DsMl5pU(&s+ zd@vt%O{~lui%O+wzN>s?Y~&nkBI2b(JrVEn5bUX^)pKRAP6nka^rs@+yiv zC`orY6WEu(*+}Y?_fd^j`d1pS>Z0+^xHZGh`8&M}RC;DR8)OvvJ2gY(Y?yDTY5VB@ zE7?H{Wv4|d^>6(6S8{%HN@qwdRMcDYue7VV_QN;h*5&W27=>2VeU6Dqz9+OISwu!! z9int6(cTQ?Tp!V~yv!E>y_>RzQ7Ce{m8E-q(y=vI(6{GSwC70(DctC!wQn zePZwDBRBW@DNH9AHJfzm3ntBr{NsBb)}*q?r(fbH>VXs7n>s8xoCGib0i9{?J-~>8 z3{z|n3;O@e#`%Xj5;wNBwRZkzID?}Zg;(Pg`nPdfkyCx#!ft`E)Oz-;_ z(=G%G0($GP*wAX_@S%V4GNfkrjt%QvvkKdkt$y%licjed4Rai-R)i%`BpnS*6cWw~ zWSmxi_{eG!T6hB0CRiD75pS;CN(xy8vj@}od4=t)g`%TLAr5?xRxv#sU$i9s($cG{ zghpGl*i*qCT3sPiiP$Vy1SW^?V81Mxx;79~w*hXTKsNAGqvqAd!lZ_mhJah)oR=3M z3J!)bH~p3&};83@sCd$B$;uh z=NcKKu<+UWJ1i!WMN5#PpiIorEaT1oxW+-!@!U*N#^A9Vy4+zJl$G$#lceL-vQ?T` z!^w=N4>;$Op;9=+`W`OpubJl>rbnoMw@}XmJz{M^Ey0cTKU{?09fP#_`+uNuM>F4L zfh-^wp+4wD`82<)OE_bY^2(x_=#)Arj&wuA*S~VHS9Ugqla#hlneW2|=b*?Pck>Om zsr$|8?dAFX>Eo3C2x^;iXFDIizJam3%kp4#lo_ve)KFo0K^?qK&NOv&=th-E7bmEB zVBiMeM3g?AuLXPOb@SouIjGQbaDsq_^gvJaMeMp$*|P*n6$wRzr=g~^oM5hEV;Of@ z%b+yRrdlBdzhYXwsQoQ#Ii^;ba#5kIbxM@RP`P@!YOCy3z0&|&Usr#b(n}hl@Z4$M z&u<#hi*dlyHwgob=#vSnM9(w&1ccQX zlK&5^=68EZnA@3~{G%7w@qfSh7VT+u?S!QW41P3ooI|5o54G%ZK`_s@xYyDocP=g z=jmwYQ1|;`X1D#~p5JF21Perx>d)$_HEWNALhz?kw0>c0LUdONdV!W*008#4M@X9K zARMEJlHy+s3i%3OD{I)U!soxr7MznYYmTn4#pP(|aGD9@0qfKcT@wYlBHqW1%zLw; ztOcex{fgiW0OmK!qE|xMyyx(1W=eKiR;&bHI2r);Z=22dKNwy~KBog!baS4iYz;k< zi_g6HLl-0pHQc6D|TU^Y%+?yG?xw;j&Gf^mySWx(^iypftOyHZC9lbZeM3vmR3j~q!G zY~G2qbiz@Ye8T?6nVLIUEY$l1i!TU>S96-?XIi&-Eyq&=cUi((lZZ>DGrCwRphq`U zB)!5V$(DO_@;5o_FP-5U)9Pjl((z1${{w~ir_NB8x<#QA)?I-)=mMd0+h` zhAef$OHy?#nMu2B?%-R*_?T_I_`?PUE5#<7*BV2*-aLQaAh8hQL!n?=B}83C6e%Kn zZFmq58@r@TG2o>IB?P(^=CUr7vZQc@u3W6#!F(@ zbq*WYb*~3xh&nCb{@4wG&Yu1U7OyM~JJJc#?-v;VL%+XOM*-iqWIfe+{M zTE^}mu~>E7dj?7A+tryg2G$&pIs(p-)jmSqYZj%iU zE;C>>D9Fkpa)WRIN~xCu7G(KTPLH)(393c2ZW_a$*aNMyc8pbQ;4A=8GwF57Y8pTE7ZZeU5gT-`eTjaM#BJ z?0{X!*38Wx6oE?w;!Lftc{P>|9p%?Cjks<**~=Qt_ar?cSkyCXb>%N^)R0sg3B?@- z&(c&V5l^Gf0Y;`~u6gy<7gf`W}z()l02-7(DKD?s6 zL0}1l!Ww&y44Fgh{54DA9>BtTMO=<|$$7*15=3wU&a@^^UcSf61Dps1}v(Ks@RpK9QI*$XB}X zpBmkaBylyo@IJl|Lpq)}Lc$53&MNumzU&X8NXn9U^qWsVf509lJ*I*F4Ci(|eLw$m zW9w({e^swgG^}vrM>aCb{6=pHdz)>PnP&7!^vwecYMg5Q2Ltm%fgjsYzchLl9gIS2 zXEL=&WC*hcYKbT%4(S2mXq2uJ3ur&yl!$ry#EGkiqfM5Jxv3!LqmX@xrsWNht_$aY z?ZFP|g#6AG;)}A5pqd$QNO6_)dG$sAs|$FP}r3t(!@c>!{GvH4fg6fjZrrVA``>Ldb9aG460Y_thr51hCDvm^d0r0U0AUHf2aUG z6NKJIkP5&Cq4xiW-t_7m{Z;{L#-KPM|D-pi?%ExKrcJ*Pobr!cV|#@wBsW#8ypG3F zVfIZLG^ZrrU%rubR7we8fgE?|$rOhZR~7!&qeRVIH{TE-oMqUSZMVyk6XPVPv$ggn z!api*^E(=oS)6H{7jbx3a@!*O2!~+wN~eCUA^2e=v08h$TZv@K>8X?lr(kxK)|YR{ zHM=mH<63Js6u9Yw0yRUbf!h^ovC(PBcw>sthS8x0S4lT?2H(mUmu?P8v>ihwW6ib`!&R5{-EYeuLIAL9ZaO`BKOKa1aUb5;5FZfU&7IIO9xTTqkl1{ zqP&59N51lw5{Ep{?2Sk#g;UyF4gm6JqmZxfp(G`|f4YKKCq@8efO9bpX>VC<-KY_= z2NDu7b~G1hq5xqd&g4{05=&7$PT%PqTd1fK4@k6@5(GA{Dwn1Kfb^eyBKQr}Fg zE5Wl8EnPn)4$mlB>(4aT4Vl%?EuSlUuZiG)ZC#=ohPo*(2Db5=pWxLGS3Lxq@^BSY z(kgV;`}0&63;MJP57T%(&TDmH@?G~eCJ>=?XRE*X=viDiTAbH(8H`o85xs-s)}y#e z1Uh1QMj)flVnh$QLRk|{DiqeKu^0%vX`aUJW$so0L`n5TlPmTixUp+Ts-Mulooa&(b z9S0`dw`gL!0)oE5ulFh`j)aimq-~Guex+Sse;E_N`2t0wYRv$WM^4>A+JKD4JC=`n%tg97=E9S-=Utn)-@;sh_N%(UF0v`{RcsYAfW!669}gD z*83m0$ZNP9Q136}>|$(Z;%fW1p{56zsViW)%*K0OuOvWMJyC-$J#3TV>b3X+U*`9e z-_aaH$enO;K_sNZaF)*!m=h|2DPcTH9-fdpC5rP=sc+Wf1snw#+F0_v>j6tG4cF8W#}Z}us0FgXIVbI#(9kRaU+;05X&yZ1OIaTB-U{a-%Nq6H*-R9KfYnaR+(98 zfZMUFN$8#D%!%)x;!25-#IkOyAJTg+Uri2=XzjoT@} zS$o*HBc~*NuamiO1k#4Y}}LzGk8X z1Bv2xM`_!LosM!fnZ)K23=D?w_k<+ zMQaZvWy)>y^c7eGKFF${8Bn(p=yja0%0ty%XH3Lq^*_|}<(=!rg5l!FPIQTsYsk7-7Jt*Tzy^Qhs8Z_(z=i1+h@V|T-Zk_G^LR}Bb`B;m*r_K=WN z15{i>@a8))#^i?r*hGwSiQv!}Y6fbA?IMNp+{gpvEul+K+z#fF3?}D9% zBZVhOy6jfNxzf2oAa)lJ#P2EuF}y(hF7{IM3BMc&Ct}uQ?>*0)t>;3=9N8sNM7CDX} zR6?190m}U@9+MHWe3f}Eesimr=)?4J(r>}r$~9-XbI-Lu1Xskf_A#MyP=C1rf*tKO31UhPnbKn04xV1P-1 zK|w)jM|fAZS}02QQBUl$kX7ZnkwGeedx^6~@nF=TMn!l7jykNo?GcVL8g`5Qqa##8 z*4o)U4`+>K&^tjkM<7F|D}fc}x)%~hyyaZ=inNZxX*2`W!2*q0LBw@#2kwzMJsX}2 z3^*RC5rOerzfb!kW)Orpq5(W;q+eE4UY;Fz)8Km}G5JR6Cxo)C?>hHm4Is}vVyMjq zK=CsaUg)hVayx?R0&uZ_Sd>_WSY}w$^aF27wUpH-PHvJXoPpoRC*Ipm?Pkp)IzHp* z+dgj&D)HYaK#_u+%n|gCkC-o+%4hwkDhZ6>XMKEU5mEvhfH)6e7UYJ4>mNA^;xo`H zBfzZ4-z60o_Q(;la)%V#EX52|NeHiO=Kbq=?Va4~Kq$cJbi?TV$x7k#5^hF@NM<1%&<`!~A7$ zCiWVOi?Hm!ME-m=a9@{i0QGVT#+G)T;`Xji|1feZXC`fcq-f9+H)1cw{zhxDu?5HP zFxV%WJ1<}Si=cGo@u$L!Ap_-3B|0SP{CxeJ2<}54D5$0qsc4MR6R0Z_8Z0IiempEP z1Nlw5=rIDYph)_Ls>EQ1mtPG;yskTNWm4r&jN<5YG@3Y8nj}MdUrK? zZQo`!-Yyy79YJ4mCuxqh$>bAqSWm@3T+`^n;vbn?sVVxxX1WM6=X)%?DG;oOV~4py z6M=xL{m4SGd^62119qK-7Enh)nn$Ga?C)vo3@9py;EBO9;$2j`!aQR|iyOBRgUFiL z$gsZ3-4V@#&46STh!CXpP`)HR%iR(^5Sf}MF7MSDPlHWc3!AT!9Z{zTIxtYXRh zh;y#=;Hn5kiUuY!f-bBag_1-_Kc>Pj$)}L_3KzBfd!6{#ExP z_87+Br*~U^ON(JMIsSE;LGO<%`x6!EW&G=B9OB;nd8G_y>wxCpsL4P#yWQ{0h!53z zg;f45IQhF`p}#Bk>HiCD8R$m+_veo`P`@q~WMzeL{109A8jTC|{DDHxg62Z}ZDX0K ze77rL!EBcr5+1Q(j+D?253wDN!PFEbpjZD{I#mvv#s`k|YapHLXl~AEl6)pSVLRjI z^Xf>x@Qb5S9UZj&sgXf((mrLv2Bo#2!zmhZ_g9wD(~SkDFGQBEF^p<1eDiFdalZQr zTM6?PhVyN9^`X%s#~IbQ4VGdrK)mvSrmsMvuFG zO%D*{aT7c56oW`8wo{y9n9_jPJQQ`E;3Q6sr6EOjsKkbK$FAlzGz6#GJGPscBLqEY z2ROhYU!k4fDX%9pA96^mh?)6rQs0Eue}k?0y~^Xsm`tIE_!F^~VD*!q1SV;5yWo^w zW1@`5={pUU>LI-oK534P)Y*|oldW#~nTszN6J*6wj!eJN7{`z zC>2cR&E7VXE}a;_pc9642SP|w>T=&WpS+7Nw}9Z)Yaq>p*hh^JZ9>Q;16hmIzeK7J z40P6gByRMYy|tNIK1EjEuw5XQyN_!ut0~7a^rZJ;#hY)BbbAa&LZqZiLTfBj6zGFf zCvt%2L6nIGT1-t@iTAym3G$$>WLrrr0x-I340q6+5{ssWLJWc-#8>1aXVjL|rB;G< z=RiTPK|qPHoQPeYMv~?BnYG>#*)NPwN9QgMAJ$m2w!rZnm$$x59-{Z*f9zmE z=_!X%W3CJ{F8|(!Q*506zV;y06L*#~-P?FM^l-Iz<|w9R(4UdJ=C17`w6J0$!SihY z-I>4>D9pD!Z8&{<_e6`gdzPD>en*u-8gqqt=V$mWL=RzML=4f*^ueQEOC1#|FmuXf zdSX{Wh?c5ayfd==>@8oEt{I9pR#{hT2|dBYBl=1yr0b7j6A`7s7lqH)eo3~? zRhTME1+5dO&m9Rf50!NFL!!E7cMuCYYUYe5b#&?E(aV)pb-HOf5M#iOBc|^fDs^9J z*&`l~5g5jxjLRv(j3YMIY!dQnRHh@03`1@JP?A@0K?o^9NBm-U_m(^p<8iHqyZ$R6 zxcuA3@HN=Ui^lSkpO*)Y``r(@PCvMs4orA7>&^v+Rjysjm*1e#U-P>xz;-mQKr<`A zVE)VeE;dk~`WmzywD_=;leL9~^*@wa_Jo2B5EL`!72!XHhEi$*A^h9@VaILzPc^Db zGGhH1#xU?uackqu9#7AA3xwAhvA{xJnW%0`@~m2zsYHp2zVSGIAdzP-G@94YULFmL znFH4zsWN_CalNyDJOKzkx0U{hjaGDL@qm znuuP!8+d~F_x@n>(IdVd)E{_&R#o^vlh@fn_YTw-$bnXlkheAdXJBY~RSnRZteB6e zOL=K@MsP3l7?m;gBe$}td41}20xtLZgPT!+>A1Fc;=YevmP|uDC{yY11by0;ZGq9=2jywQnyHI#|NE>m%uB8d^Ob;KLaP z7C%fc^e+Z&`c$4)lfRJT5XLr#)#ENim$3#kav*s;@C!7jwgg(^G9UQRM3&j^l3)y- z<9lbtBRM5-;Rx{r0uzpg2 zIc=|j{CTM6_hb}+O2Tz-ykAn4gCTXpQ@O692@N!(YEf3zWZTI2n6X)vg~mA&scH~6 zS&XtP>_RjQcQUx^d97E>Tx)1bQyO8S$%VCYQK9Xvp~Zr<$kJ2{xZ*GW`Thc?I(MYs zxXN+3aTLzOz+J_J%VY*{V?O&H%O&+la&gL(xbGvn;3GxB2L>wmH|1C>=wA!td%AFk z)Sk{*(Led%zVRuhyguRX{^mAnBa?|4(LMM6MA^MUzEA|BW1+9@>)}cD`8DDwlKJu? zRwMmK3#i>q4o%CDJ%keb=z7^?o{Fl;(uP@rm~PqjnK~@?fLfwD2ry(6)%5_dcCkZE zW2|nl{0*oB2i5=&6tgi>WE*8LlAtZ_PYzJ6Y~HQiGa>WNoAVT4xmcEvO=P7Xemb~c z>tzTAE!CS8BY)LKW2rU9K{Q3OVo=WLxGV?0tB^p%&$rq)dm}0zGBDhC0A7d_)5OnQ zLXI4iiWy*Te6|@$t40hVE^Rs_=`sZdRVv3CLK#ChCo2_GtS!Qz7lgtyzsU~~Od`T0 zj&(90BuKv2R5GTn%gt9sCmvV>E`6JN+(Q2%YkPJx0F^X`-Vl<)$I}pgKkCTc?;U{6Wsd z_mnUG6dBZ#Y)@1PA72mWq^lG3K;`Ez+=-s5loufJ*TcWXYsfu4U2*!|!{#6}F`I`` zSM>VFvM~EMtyW%?wvkL>i#u3|!^$8x4boA1mI6JQM@(DzDNg(zRW2r55z~&B1l_$k z7!NDX49`c|PkLYGUOcYmCB?@~+K4CLKW%MZRS!Ni?Js+4ofx!vUQM+we(BBW>M0>s zdOPvXw($YIX;IrVpc;5Z+0}}mQwJjg#vurQOds-@QX*1OW#$0R3;oAoktu` zma!IjO9>95AUqK#x)9T3bl>(_HLKjjhuk|p1vY`lraOEk4ltkV4{>avx^{|XM{Fvp zwAgHrvIyH$YLr|mOR7Biwt0k~Ro`XP(qhJR=;bk3Mwy4I{L;1gwT)<=nlV*dOgkGY z#-15to_C4Ym@HwO*EOFvSFZev%^c`>;kv17bBVx6sIM9=BW3^}p`lC7NO#adbod!6 z&VvHYoeD0QK4^Kl(z$uO#MJ+3*LnTA_1(<|bfwhjFf#Ak6FNGfR-dE(@KKuG>SY1< zhklnsS}yT=A@{4XB5(IZQo;0daq=dK14>~s7-T4G)55SG;Kype-wVq8)n{b2eD$FN z`Rslm7S{h6Xy63tJ(gELjKfgO-o(`SA1gM3*gt>HVf4;BnZSX2jLeY#RaFh+by#%r zLa*(d#>+@fD2XKrTDh;6PqqcYD|*IBNh`8kIx!csi| z35{gG+0z-?$B*H4bGF#+9G8i;r8i^iJRaq@}QT#d=W0lO1{F{crBe~PJXrINh zHvmdjw^fQ8PN(lzW_2s&3c96HDHnnXMt&x~!D9(pKdtntb3XJcKJ0r^I~h{M1&l|N z1DU;{9cm2_zz<~7A3a~3UwJl;)uRdWxZA>*@U zE8=myvaS+DK7yt;CL$fMNwb%lfw*C#Al{Ww@CuuiwlYxM#loLovpsK?ROl_jLP;X|G|0V$6TUy zSRWaGl5tn~0q#zI3n#gxyGo+)L*1JS01E{ozKJI?V<-mH`+BsUXvRJ4ru8g7U)8of zwbZudeZ9JxaX>6F6;z}vOyra*$}P`UO^na1v`#Y#EtLYWh=Fy{?uA2Ga0EJ8S8-OL z<#3b9qhg_>Mp3AS*aXPuanwh4=CKvKXO?Em)QD+#iM;87h_nc-N~+mUarXMSJ}OF@ zz@HM&;0#4!HkfFVD92Hp#ycI9Fe0MRBiI4&gug#oOl##RO5%lxp-bF`|7`$fQY`yiNXg2JTzyM*yn&_73FVPK< zD?AyT2y2c?Pdx20(HFb`$QaE}nBg4sS59h}-cn7HQ()q3ea*a7P_O>S`ZkOon{Orm zf42ksKigqhw&#_5=>6TD)}x@SD`S2>=dzlW=u{DkBrl@*;KB5VTZNr<6eNTg1Y!@h zA=f9c-RHAAV{L&C1_rCbT=pl?i${GMVJE3`S`Y7d^oIGUWU1cAf=F+{P6)|umDbrN z!5$I-78r0e%#Y%MaC{qjUWcRjl>JE}yWude%PJDlW|YW>+maW!B@G07%erISq%2J1MivJ6tqc(+&*41zDU64Fe! zENC~$+2@ZE!JsR@igw+HDpF{H_etVn9nL46Z;zWE;;UcNid^p23!FLgE1^|Hb*{X_ zPc}k65Tsf5o>&uokIDvX;(_K3LP}0auRtLH27~Khu}}{LthPmcB`uOl>zb&yQEd`; zGe5m|svc~me$AZw&ur2BX?p#of>>_{HVi>+A^X2n5ZkNi_18P`&!+hP+7vKrU)T7d z+G%S~$AA6$Rm^S5x26C^A_}ayfByMlA(vpGJ0Kul%t-peygR4s<@EBL$8EgE{v^k+ zh9qbC=vcyC+&$~CVxO7NZ+VBsY61ij<&lyX#P{X;VlUg+plKw7nL>em4C2FNDL_pg zHVW1W_E-sV@Ul|A%yp3nnm~#uiT^w=fvCQ7SsWQAw?A5{fC^mn69$@L|LnVE?_ewG zPd_F!iRvyWj3)&~lxDF}aAw(fMdDoz24zxX73G>@GqqKX>)7Re8u3 zf=Sq9i{N!)PxgXhU&%p6!i@g~Tix?9H31Rw3a+#~A0z90n>nb`UO7V+{>bnV zv%PNq1K#KjBeJS?FwA%{EGoXB)uHH)2ox$gstIZoF(q-bfV3d3xAIx;O7O9u6%ToR zy_Lyu=9X}&jP84c88^MOEgN&7c8kSP)0_zxEUVrnvsmNa>dL zAktyjH^d45^h*o+`jj_COA2&<2-+dqxMS8*=HHX zNczdUGas5^uA=RtC1XpZbUEFEpy?~_h@2<$!&8;cFg;DhlT0y^77a28=O{IlIDrZY zU64Oi%;qV?$qW3{4zCJVM-XsWvn$w?I6B|n?B^V}yQ@;VSvSJ%@bv5gT3@9dcHG6I zY#f=?2d;O9cXN-N^&YbpmWD4@v1)}gaPPB$xr`Eh&O;DJoU_n|1e=nZFH^s&t*F^d zLwE!xmaaHi(a)=h8kp~-a80DTmSQJfridmAq$;9>9gL9kuJP?;81sSZf`XO_--(J# zsy`8<4_RBY0HBDG-`e_mm47Cd#F;k@V&&WDz9MRjWlJB9OD23;+gMdaR4N@STg34DQorT&^Af1FtR3QEK8aHs6 zTKOA1M`D{@|A4n~X=QHyOXQ&i$xP{@`L=W>l@1_h@@;KN9aX{@8C=@YnJmsO+HMMrOAsT^(o+s7(U@D z%uh}1OqvqPJB|5u`k}0{P#rm2-9b|Vw7%%m;(PUGSsxRsX}fpihb#E{Tj89MNfdv3ZjC{d5@t8nV2ays-u^O(w_mmso(6vwNeIUR&cYFJ ztDOm_xv?;-O+ig*ioWNa9&e%C8Xs5;_7wKmPx%~XvvaKr!-#h|kjof+9cUw*A4co~ zId2b~bM5t$w<)LPauD*1mrjvdlz#i8Sl{>rAW904-FxVKhC+DKf!~2qiBkNugZ{l z2XlnyVx~-qMiI;tOc~4(%n&RK;|Vi^WP^9PR1!ei6|-cQ|3zuyA*oMDa!IP@VHymp z_8JR2pjuPOs+}_g{wLTTrxVl~I~z6`h$i9m7$*;Z&sT;5^&F-L?}!oOYN`D4^mxg{ z5y6d*9!S3H5 zW&^Fo!}GDjo$$HFInV6BKOG+WB<*%O{}I(2T*{4774!fpfqIbt`T)JI$;rxTsB8Se z#N5l8OZ*=l2!>SR66tBRRzvA|g6Jk;JlAgfXAcPo#BycrX$=2E?pw&Pgdd(`)IWI7 zZ!g!)IQ#{IhbNaA1!CjuYZL>N`-<%qarud|uOpg+&EP0#4#sk=ZH)2wztZRcIW@WT zWTpM{L@Vl=2jAs7G=%oa8s}+Z<<_oNVc$~hRMJFw6e$P1wJr0~NjH~O%*5A-acQu| z3e0~gf||kCnYe&PVALyN;nWuw_Vc-kLUXts0G!)R@Arpt=&=8GZk2&G20|2tCr^ftp6tJ`J@Qk!DSr*HN(+5m9&!XFd1{j zU|YIRK|^deDjDiVh@IMja{{sW(|f{;b-d&qg1ZkBi`@3ljl0>qmIkH5D#z1ba>sMN zN1wvk-Tyzv-T}O_rRg7yZDV3%VrydCwr$%^Cf3B9*tVTa%!zGJc=tKq|NYLK`M>u* zH@os=?X|jVb#~Y8u2uLIcQM+OX{;)jcdA1A^HmX=4WGf5dBYr+3VK!G_2cF=W?hV9pzYC4=D4~F z`aWCDG=2-$H<*FtAr98cPv=X-KCT7B9FR}$4Y_hh-W?xAM&K?vA;1aRIg5EU>}ebJo@{zWx-`<3+AD@6Dp+> zB2vof7rV)94YgmCl2KI36LR0CKyn71KU$zmZjW_5@rl8Z&*ovk8TIu+0S^0q15fA8tikMQ9#Rhm^5Ph~E?^`(+RgIBd7ru(5`lJ@yt8I5ed~U)oz3<;TW2-g zXF%hheXriR7YL|@VO}uEU~qE%@@s;&tnI?igbTzg_mm$Y7AE8~8F8KSg9CY#87BLO zBNaY%%4CQHGWWgD1I?|UT~gFqecW2LUn0s{+3nA`e1n|#~b#$0u5h>-dypanBGMN1xA2ok*{Pd^x{4idV@tBf4lqztb0*Dj z-z`89@T1K0lT6D&c`ySz0c928FC0kb5B8c5=Y*>u37+}{(w3<#Y5eBENeA7A8N|z~ z!Vi62--Pu`sqe8Z3civN#k|Il9^BEtx_U)w4<^J^t}lNdLw!GWN80d_ug8jd&WGtV zh-|5wuwU9VVPcFD6`q>Fxy-cBGMs6TD|H{ee$<33l_i|dOmPs9pIw`f+DcQMDn+Lv zn)*HW0VZ90%lfcR`+)9i>)2ibmJS5J7q~OsRuM!vU1PT{latCQ8DSf3X>lc}GhM27 zLezQ@liFLohfx3u4A5F$F_Tz`?l>F&{(cSAdljnC`Q6k}P)LS12M{Mze-Ip@avo)o;1 zSpRGmC0RqDG0RF!pp8wLH0qT#0Euf5pwSk%4Z-Fk-C@NLE3|HOuVH(AO z-$cn2unUV@CRDise27-)vVFg`pkawpnoT1pg9e$Ck)e>ZL2`q9LYj% zv_X3n2#SZWS(4w$*BMrYeLaUatuMF0jg~A>w3@xCwJpx8vUnbsV~ELmVw9nNahF88 zh`ad$QknX~D0ZX?s!od1N}XrRGJ%2xL8LD;b(NyX5xBE?%&^g8w!=8VqUa0kWRwS= z0-Pv2(Vy8%-jpNX*JA4UU4{)MaUgCzbJS4h0()?s1tsCqI$hQ+t1}6jEvo~~T1I1g1R%!;%7VW8`LrisPVk`}z$8dJaplRJ<@A%B^ zN5A-UQ^xRuus~Wpl1ousqUX!3C!}Qn8w~QTwXIqS>&2UO&T2$F7ZHi2`{23_*VxJ8 zd(AO$hfh`_&coiWSgGJo&AyV6)EyLw2=mUgmnV8-v8Ql@z^tNuD-#0H?aP5(&I!Y% zW{vp!>p&iSa99xTl}3ZnGl~O43@x1?az4*bD;VOqeDys)-wzvf9oHZX8GtTf?-027 z)nC2MSx)E@CS;tT*`%(k_O3U(y_)+bM2_l%Dz=gu>Ng; zLI=@$0+dFaLdpD4mVqJy00RmQUD#aK7=68NdQHNYxr_v_HSU6dEW)I5JfZ{Xk&@GTlSOX0J8a-*_1(`!9`zl^)N#k#Hy@r?E~kJ&x2bKq zB`N%6MK>>_X4$V>;Q>HUz7~b8+u0v}313rIX15VoB~=UEbw4&gsE;sEoN17qNsfYZ zp)>v=T!B=mwlJ^_DX@*-PeXGN9r10go5Ez|F2(0Ap$Jri$;|vi-;nM!iOmBy1p_xF z!8(yy1W^B%oCRmr{GBL{(gQbz0ym|=I{&!@Xal(F6_E@53WpgKq7uAvY+Ye~YriDPBtVgE)1K~pcvLd?!l*lo#J&*=;-0IbD-=nHn+ z&c}8J-(lFjp82o<4 zJoFuoD@O@_a>i={@NwjIL;rKTzixe(nr8*)^Ey6bgXLL9=&bjiIRh2*8@&ZdYWdEZ zA>rgrBjss9=V=B0b`j8U!xGS3Eqtakc!pQNJXrKMx)7SOq0U2oMgUY(C%VfZWDz9! zjjG9lMUT3Ip*oY1Jf#5ak$9Yjr5Qmhvrf7I1_UF`KId7H#re-=VPb(rX=g$wgerN{HXAo{f3hqtv4{6W~ zni>X3!yO*;ou=WD+n;>t7+Hj>r6y(oT)+Iu)okWhmZf>9Eu+vSS?D|Yzhq@{MlbYT z$Vx{`3`tl3O~!<2W*9;aZWE$z^T2OFUNo7?>Pl1QvK#05;B{phGx{(N0PTG8ba3bR z==kB_r~Ovk@K$(dKwH#Z1L_*7vkUYIEo=yygGx3A)?PsyhkdKKg%#f)a!_a&+Fg-{ zRo5SLP-++6U8#f2HO;^luHE9y|C`|w2N2|7o&$(%q|z>kHd^Wsd<&Irj6tXgkZWr; zuw0KstyKpQ=3w46#5!8ZfB}GAQ7vdTTJsRFy8;i3Y)|G+8RJ9^QzW3{GSwyyVoz^P z<`AmA;u#KokBEbL2Qd2}l>^R}fCJ!e6#aG!se^5RN@t==MQ&+2D?h*Fk5G}nk4;R# z>jd&2AJeR~DUf%zoDH#vi9s!1+;U!SB4+azm2~!+Go8nLtn`&PPTG|_A8a4Ezm2c1 zuu*{*LpFbeAKjX%pb8@Jrd7&_X;~F)w#ZC?`wmX)c)nUco2+JnJ?%EizdKq{p0 zoFY@VpI@8wi&iLM!yg8EoYskYbi#2oDJj`0{e+DPl92RH!!&?Yi!ME-PBx{LRH-uvFKPEWNZ!w2C@(6_Y0B$`^<`yO(<~>5~6mO-EqX1V#jv1y)ROO5bcd+ z$WR0`XK+PI?3vM&DmhdHk3(-Q>$cvf8=oGV%sON2x{qO~*fyzYFb^OHgEpO8e(?_A z&8D{?&+rbd=zH)_i=B2dx^(#wJd&g4ANj{%@w{GHvkZbspchas50ZH|^Pl?n%&PeP zVMsEk~fo*H-I+*nB

{*ybR9B)?&xU?7p=~nJQp&dDlzrsm2%0kKR*Ku= zyUG}W?W+OSp{})Yu>fRhPfqgP!3iRIDA3pwoGPeT{w!wK={0E@m0MG8+E)_Te#+_% z7SFnKl+9y4>AxypgR>e5pyY=V#hkw4yV^!hdgw(vB87{Z1F<4E9IL&SMWtoultbJU zk-aEYZUiJI8WLG3)L46c(!Y3!x6v^byh#|b`~XiLdR(sHMt3;<3R*C$28j_BKps$> zm+!?E&f_->+Ru&P{Y@J02o58%Lgm4JewOq{z4n7aaJ^$t1TE)2`dLx51v$2Y`k4?~ z2&3$=t#;54uXNuT@m_x$qhm{;1x6HV;i<mEVgx%_N+st>OO6n%kkvc>smaB_5dXWSM5_5vvdX@U#ya2m&FIpmZM^RgY<`C3)nvyrHI3APia;42V=F7Ck#y%Gez!JU*gInYLnmDlD z416M^T>oJ+K`6<;ouZm&c?#Lp65|b`yELu)IjK`!V#wGu%0YF^sP=Wl!ackB-mV^k z;6)H%hl%GCRqGYj2B1Rc3n=0SZDPXzz)x~D&Mo%u68cq)+AXvn`MNuOoBhG^ko$$# z{6auV#H3vWzSa?Y?>@Cg)*#+c92paUI}@O$|{z)zn(XF)#c2LGNHg+ z0mZtypr;%w`_zK%(^9Rpj94&H;I}400XVE>euxoGW#zfA@ajJseA9ryAiYIsva3tI zvkU8@0Z>&`4XsQ5j(CyT&hD8A7C&w(0xkZq?p7PFwqKG^Aq`cx@@%Op& zL5_&jydz#SA3Wf2z^;J6(%@L0dL3Q=bg1M~`Le$Daa%E{@^w%JK8l7mcCeNMV|YjXQg)OrzxTd|!C+T^)y8NR!Dwcswf&7N zptn1C)LQQjPE?$=gPO5}TK^8hU$^_4?ceuSt7+-qIjn1;uWP9`aESYTOtFJB>g$LA z-rmMhVZ>2kI2efkGuZ$1?g$(N#UPm7sejzu&g{0jt#f-gGvL&t6ZQ-vNatZ?;Txci zRAEy6r7l)0JH$nhNy#?4yk~?v$cDYK^oGF!pikVsP2pJ5nPcSx$x8~bYs00zL^`aHLhd(vZ1Y7 zW!kB3_uNlzKbJQK4g15bz6Jp!cY2k46NDJ06+U;Fj&1L3+(A^GuZ3Jh(jMj_c zE->nOaXs`_piLDkNxeOsDk=$Yi3SVE9Z%&yO#SMlOISQ8HreVF!yhO-RSYXeCyx6S zX%vRE7?$WO|CCu_7Bw>_WxoM-ZC@V;w}0Jts;?`ftS~KAoSeu+Vp4e-OAt2>)%dlT zmkvo13VmSTHJ=_a@@4v6kUCW{;^gB{+4xGz#u8jmj~@yXis;k`3F=gEuV2A<=(yX0 ztKU|)o_*7K3Xyv)acU?t&K||N@Q7n%;Vq+W5&Mz-XK@QCN4y(qi=aD$Mpf@ducsN* zcuW%=|HJK zEN*}-)(fQ*hvPo|3U}weF;Rv$^ur-~V)c9Rh1_!VaesQ=U7CJ@_1*n7m^z))q@Kn;m1xYc0nvNw0~!9>KIsahf{4e} z2SEaXYD%R4=u%u|dZ2bKnz^WXYu=|!M$w`2x_ni<&RQuiYp|j#D=J(}7>hJaLQ73b zN=iveo|jkDRje$`FKp^U30>#G>kedJn8myUZIA6@`jY#8P6KdjUMP(FLITyP6?Huw zMdeIgMLeHgyfxZcFRB=za8YvnmwfEMBA#=@4KYVwcd(zHz)n?ExM!<8tzJ^1n(QS1sw_P2=?(03vYzWH&qL1t zj2{D@ot8Vc7hz&>cJ>%FADDN%y5{y=!5Fh>$zgi_t!BLH*HfA+{gVR2`gmVShUjUB zag7dSldS1MWIQ5uG#Qb7^A|?e6!Tovn;G0?=#qtzt&x6?JdOE!UBN+C`niDn+p7?0 zp7yBhM{pXL?2QY(OS7gbX;%%hF)p<8eIIhJ?;7cru*`Gv+ijTWUERm}v)hV0SIZ-4 zzF)k4)Tn6lc~YO0O)QugYZZ# zuW9-9Uhkz5TlYVQ^taTnDN)UODq3ccjiS`vb-M}R@VnO(D)$sBq5=9_c`eN^!ATYYGMBA_2OFz6ElWCvVJt3(zt0+&$;77#IzO!8{{KZ&}J1}^12M6Rzd zMGn%7;hs|kq#!EclYJs^@CQNatOka=3^BjuPhRR?yE1mecOq0YKy*wxRVEi!dEzgd zgVHR!k!zrj4He3pm(D>M1x)sLc9Uyq=1jz^HLDld*BJ# zd%y_6kgVK%gQ8j2;b%(Gs9f$MbNdrBhU*9mHITg<(2v|YbU@N2kR>0N> z5c7}>7YUbPD-@C!7^HdeCC@DT?(&;vw&fc)*CEwks{=BIe{9)>{L3m7Y7Nj#feDTO z&#$#mz^3XveboPl7+d0muU_>ju60y4}c)u;7X)4);O|ZKo<9^shG#&1= zkox4dBMsxm@EKcITJLahGpZBQi~d3PtaI6`_R;VXaKgd>@O}c;gYg57-t?~%f3yJf zvL*@M>uec|8Whx}^$o>@{qL>%ysk?+TACQ0cY5~-CW0I`S36JPJ3V?ht{VuZ--V2{ ziWSpMQ!ISbrA)Fl4t|*^P)DWjujuMoe_cZ)=m|P|J0YBYC}xu~GHP!|D7mn{v~gvV zrAPmu--_n*TxJkb#&7HF{#t!uU191~jJEUjR|~=;{=qjMT-pGR>*{nyu0sa~Z}Vo& zXO&3xSW;QAWM9JkhEEoQvcij20$B}(s1obqTHp?(qDi5hQR4~&KK8^4F2X8eJ7Z9- z%#!z@L|;)YGQ$<${_pDP>dl;*OMNTK3XSQttR4G_gpp`o%kT71uC zUH(C;C^OfR8(}V7pq!|K)85dMTQrGWDNt5Cn| z>E{HF)4P}~sL61oSdw7cJ3dm{Dh&q|LS}>y5xO-kw#ST0-Nnsu*T?$GO-5}nJhZZe z3!P(EckXeurWa3b;4CILfffmOO(om@f`v(IM9a5#T{bMBBRC^t!!-Rm$JKc0-uydC zqR@x;dm{+GKY)jVgLXE)19rP^_Wu&+$;SM@+LDw3KvDV)B3fB-scw}4$*1JCU&5}5 zWNw#zHa!Xo??(Y6NR*+Mw(ZMv%RsckXS2rrv+oiw0gYGQ$IE=aMfCfEtqk{BLBsUe z5TMTUMKL%RRyahOMH=O~pFsdg*C95V8`m7Dtnzctl>#RxMgKe^u?egCw~Kxa6~Gxj2^Oib4V7^6mP>Y$08kdn;v1-;=Vt&2yt1jeLsd?j4;a{2^<|`OQp~~+R*%>W`9Xhw4o+P{rHuDb+ zAUosFKt@a#ZZPblC%(TAC7glsiVq0k{0Tkm+igt1U}w1Hu#`}oQPCsBcB1Q&8N#2n2*C=hs5@Hl=kIP`#6kSedRLLsJ47uUR$s zk$a~xIn%|sIBAZz1Bk@e?Yr*B1{NNHm;7)Qzq%hL>sB1HBKmUlo)M|Fl}{SxLFmIe zCcw%9V6(p|!&3--`0kev)PB;QzM;`Ose9%GDKBt3o_ejDijxXmxF6!m5I@D^?k7$6 z=re9?2r=Sr6rET_ywDU2Vw0i+X5b;bZ@AJlARYasz)3xhP?!-*^azP3{unTUV>luU z)QMOJ>6z~nzZM!<(0}W5pnMk)>XYk0VE%)juGoBt8cXQLAbhbc67g;?^9`3I1An=j zD#=>il8dsWphiZjY%IdoPW`8~dPphlg0PSh6idUbF1JNbVGjx8X_vpw=}|DRHS8f; z^jA@;`GSV2pr$4*eW^`5)i@1 zu%x=7S6?dObt&OFC^x{*x?3qlKi{!jfXY1c&+*BxfD+#Ylp+>B^S2=m_z=!P*7*=F zLEiY}%FB^qne><_Jr3u}@E*^3X)d8A?;p#zXY=Huiw~oy`ezNL)Pb^=#1KPABeyJ@ z&;Yp#NlQxfG&`2@Ak+c^nzPp-@)72h=?oTndqXI9U4HbV*IPBhzXl7pkeiJ&GxD{! z=yVdDL{&Vw-?bsp=4A6?_7Cp7558J+`YCqO(T?99j;{`GmJ|El!w=@hVA5z4462+r z*iDv?!&mjZ!%%pE{XC31Ce@Sn3#Bi{yd7M@G}FuSad`OsKFM-LFy@~(A%1p1Ko}OpB!9w7ItonJF3+y7dK_`5(+TL7sH;SIhmubxL zli9_(=*!@40!(^8jQ6J3vniThLA1z|FMD#D-M>7w*;fSZGWdMF%{cw+&2)Lc=K*Ig zG>h#-Ri~PbTOwb)UH)_#7C%wf^`S1ALqg~09;BeE@t+3+fa&QZ^jVu|M3+cJ$|=Eo zmSSQnj^3r3k{EkdN-&HqS>C0(Fo!9^L-!{omsA|%3Mr6Ex!SZYOWW;d9c_~~Dolu_ zJ(o8ir8+SeQzekwKAI&nFExzBPsC&%0&;hinJ~|-WZG%xY5)aigi~18*okt|mYSc? z{5&GU3c<-ZHz+y@q-HsWFr!eQJjrH6GbtG}3c=c~FgGR4ik}vnA-SMkz_zF`$&j9V zfWx}4W~uDF5Fhz#vaXWcQh+NwJ!aW6f3FSoe4^fbV4XA)J=y|Eh$Ph1_&ayq6iZl4 znu3D$z|}oS8g3@X@aJZrAmLj9q1TcQ$dIQTUU0H=QUtuUH@v?~oBp}p5rlb^M)IQo( zdD~QSSRd)W-zeN)Ik;Tzw7P4V!=7eI$rZ^#=BSRZJ<OxcJMA{v= zm5Uj=d;BWZqz#7RgejH{3hRE8tW*Y7pl(1h&y95Vb-`g^c(uZbG~Bx1e)&&A)_-tO z!4O|1&H>he8}k45bO+e){>H3f)f2NbHgGlgeaFk16H8d*hXbE!oWt`5R`v--$ohsY zzn^^jR=rbP$ABGao*>s<29lEV(N(SI;K`F!o@{Bi7zyzCTWTkt%vabpdjE0{a~D(D z{s!%z2U@r`ufl-Z%=dDJAFrLjKaB}&0igkr%*-TDnLC~LEQs;$u=o(}y zMhgHSXYV&|JlMYj=2Z9}iF3J{%zEC7-}=D_opWzpL_s{ikEdV6iffhlKO0CxRgdjxO)K))u zokNMA*(^Co?cI1AQ%aD^J)WNofX%tHul*OD5*UDCfq2EfhZTlLi$EQ*FV%I&N<({Q z&R2zlwn@|NqFvn)Tz7A9H2?zz0|RPmKZVqO`1R*9k|=fNHaU4uX^mudjQ%fa5!uaV zHh;FeA^(R$I?iD$%ty5_em@B~{xz}ohY#if;;W4SKuOa5Z%PvTf8ycU^rQ?7Eo}d# zBrPNq@T2*}z4mJ~i=)zS);K6CXe4qMqH=+tF+JQz!BPDnUz%$4FQS)ewz&q*#8ogr`;PS| z-Lo74{-Mp&dHsxXoMI&sUd`i`*y&fM9omk~$}?3|HbpcxdWTvoU$^?*+ z&k$Xjv6@uL`hcLvndmeGUyd1-?CpYeC^?H$a4Sh4VLh7C&P~SMe2={?HCCHdY;>}+ zYZLbmRMXcZhnyWCCwvxPC}A{G)kfy`Zyb^Gp#v~X7Jf%0SuyIxYx?RKnWs}5Fo0+5 zuFYD*sM&3OkFU|l8eXe6^A3~u^}`bnoRz)Cv`2)C)t`Um)H{wlAcf`~sV@7Ib>HOr zf%fXv2U$LJ$1s{mDp0S+qQ+l94zoqr?a&1J?K-N#JAT$oKq<9U8Uyj5%}C7(J#{$s zZNs`#cjXrzjD)Id7>h=gFH4j$#T)Q440f6oKneJPrx+}onpc8kEZbg*EuC#J*Lnc#LhPaC=QBRH6UfaN;`pBBAZ9>WB5an zAc+vh@}mT>fD}O`k;q5zvx3ARA8k|o`n39H{J@EJje6b;kLnJk<|uc(^LfC(blC13 zj|BkS{E0akascm6?r@cjE@+A`QFTUvLX=fs(&$HFJcjLim0I7;+gg`~4LgF6!kxzv z!37Wekd#`AO>0o>_=GgD%UFEN-6P2$_7V)OTbga_Eaw^&Hwz~ys!>#wm7GC)L#IiD zJqj=o1dRmvj--tqy#FtIPU$2)(2*Z5`xyDAw-v7P5(riER#zfro|#ycyebx*E~$OT zDu*F1w)0+>{0o;SSdN?L@2F*eWO53#JIGS1~aAQ7xIwGXX=C|HN3nfZMOM|)rIT%6^NRzE2r-{p7j0$s$OyDICR!`hvFW9B^33+IC5{STB zjF>7^zyFNw%v9=Qo8f{{ebEoZEiG95gS9Ob(rF)8{4Tmmr#U9+O!%2gJCv7A8}Xff>I7ex@a(3g6ptVt<}ifmCk-5R0kK~ zyA|w|=Jy~B7**%H+@3%vri+KzG`G~Up={2^oW*&2Asy}SbE}^_K+*Vy8EWW3l%|p- zAEr+{*CE|)>9`mI&O(Z%dv|&xEcunI*_G>|^|2=QxrV?JU+CdR(G-*L;f2H;of?lE zxZju8zWkpGD*w@4t`6Mw$^fYwOyd6~6yX2bhJH&XH&*P8{mU>-a*YUpP)&wn4X*jj zj#4K%k2K5wBl$ai#{l#Nh%mq~t)~Y{WU}CfMKbMI2o%;$EPMB{S}=8o_}&)jZwnpD~n{BNcS{#R{rl1=2K(IikNV!C`$dyFnZN;##AR`i#qt=ZU3yngzpUR1(|eGfE09 z{x}#!i13;DBH4a)etP&>UKC`N^6L(9Z+7-_%<^>Tt=GfQ+Trmu>W%maDkF+YYYB-+ z|ALw+i1hoo1Vm#jvG>3aMEjA}Qcvbq61~-unAnY8w^|xmINk+5$2;Z%c;XZt4T*hp zNCc@A)s8C7rG0MSab~(tJnxBji96u#Y6ugYT`^(STH5Z?N)0!N#yplRGP_pigt^x= zoi!KL`)T(C3W`jgAP)A0RA0)*kZ@a*Z<~E?wQaS<@~srRRzO1Vamys$&)6pJ8Nh+I8`QOd2}WGdBp8fF@o|2=1-yFD-BoE}Iq@*&o00 zd_}v@nT%GN&kql730Vq-QbtJkI)uO8a^xJBz);MEz)-BOEfFHwXXt;<0GHQyvDdGU zhzMHsoUck4)peL}w|~H}Y=8w8EV|Cp)kp(FR&l!IR0baYqv5Rg>5Rjct}_m-tY{CU zVR6g5;~P~}Ag+l#>~{9sQw7(9!q3{7HFJDV%rQ*DB8*Qxsheg#Y^J_Z)_r^Tyy_o= zFS;#){`J7Hr70m-gHTLW?4b!XCD(fEMEVMNd|PLpH=0VIAU6ZON=^GfB8e0N%jz^G zvT!L(9i!pO8$l?OULr_on((m>S>)pKekELlVEs6chBP`Qs`l1g)QGR~Rt*{OU)Q zbtY)KOtV}MQ%xyXTmVs?20u}3C#&L~ZKHp*pLWHh*EPVL+UW4OoIYdpdmRy*jT%{B zyr6Yeudjdfe*gBN0^^$ZPGOYdxAJS~dr**@7riS6J>T@lX!K6|PYgcM?r)Huzrxa1 zz&y!{DL)!M$ z$bj^)DHB^g4fCvXZ-w$07b0U?z-I_%hOg<7lViOVL;9)#ic_GArZ|LY+ZB|=%y@t0 zos@k`cQlOwfn06GhUsKdGBGwatoL-jBfM;XI-=57GE^0lBNh0E$!l6E z%rvj)=7x9@r_djia_%CXP7G$;Q7#X6sVv<#y0R;d%^$vX)BMEgXvT_MDE$ehY>K2y zpk*Vxtm!Pqb%cp2(kaGu#EGow)}J&Q-yfTBsS-{DtP8T!j)G8)4@bHP_(()7dE+}t zOunpqZp0TSou>GkSAv8H`M+5-Qk*-MVgKFTUxtxkRCsU5I}(h(cr^Bv$BUZEU;58} zi(lFDYQz%ATFpert(aEgM^mI-jq6GhP(D#TkJgJi^2Uo#LMw9A*`-Q3f&m6i6<}k> zAwm7KKGPU5#(APlX%C7ePzynP5Z3K)nux~RBeJr5-)pi-KmQV^95w!jX?6u_{xf9) zTTb^MkDc7XW}VEApnS2nRRa5DeL51q9jRkaGhESd2rJlnR(E!4_+ z=U_f_l}I;9c(Ws83k_wt0Yxt@;yw}rZX=`jdw;jpYw7geP%6-lN;Z}@T?Ewf&5qn> zEy?-vF4R!~!U3rDPR-xeL>-vkGQVQ>2rQ8U#)Sy_14`1(IG2cjTK?S>B`5DD@?@=A zjilQmGFJ-hGx9ta^)Nc?-4(+1o6}%dy0Vu++`uVhNM&`%IVcBqLrbFj++p9M?y_~d zl%%vsU8dxkU?3p{b%xU7D}QHA;G3($Du`r)n$SkGtY zd991sHUh`g&)Ue;%T)qR4EY^0J0uCvH3WhiXluuMUCkZ)*l@lZ;Up6_I5U;|FxYH@ zz&_v5EIjbErYNLFq;7#Hze-4fH9~2U{P(KAA~QuKZ=ddc96vsZJVd-G38nSG0(HhI z`^5or__|InXZni4e6p4C#UbvF4}9Sf`~A)r^WcFPphSApDPJyCg^&uXpifvzDSR&o z41o;^A^stw7(+-y$N_%1f9T`~JvWjR5-8(8gnN&VP5Fe7OwkREEF@8tr zT&0?l+u3a8OKM{4?eqCdPPgvIlZ9+5_XH!4)Am)su@J)xgXsq?*{MM<$sRUf_vD*X*KKO__kx`vRM7>Odu7X9MUrGmm5^g6^;~Emef-T%)sfu=9JR9w z95u_VFR8{w#k_b{ti{N~?P?@+Y6Z4Kq&-AtQk>U@tcH~kz0S!dauG(*U~tj2WE_Y5 zGd#4olZ2Y|P^R)Yx=Tw<&SLao@bv|#>h$<{$^7zFgl$zsi^Nx@qAP zn8ZPVxy72K!QuiU5zkg0X@O+;Ci}Ukv|q1Z*V-TH{n&(xKTlvAKH4}HqmYOBLs2I3 z>zF6eN7`ppBKgZh5AqK@A68hpz&fB%PF)ztc8X4FjquBuVEd=Km1$z7YKGIi%WYBa zi^8k4i&7^mTUID)6d)T%jtE5G$UKMR|W z$0xYgHH02CI)sqJ5=K!r{Zsb{JSX$mM;;}m|ccB;kj}#KZ0rf^8$v@=4 zhY=D1E6ry4-JdW~t}3930EkBE?>~T}7vOxcNKpt8F_XxA%HQZ{`5aTk3_=9-ujcKDY|6d|0WMb=V;NmE5;9~8>0Qg~LVboKzuoW`5uoq(c zMeD-ts4*&8(pK*LncD5@GwtN_fqM3|5%7Nhw8x`#GnPSgL`@;bt zcit4ok|oD^Yayb))f^dE`*Ny<(bt0>(TIRz@-#K+dY41uRnXl&_>K7!iu@KrZdTJ& zVmL|%#9)vaN5s;tgj>3!t?pr2f{i-OIE(Y>;%DQ`6l(0)%7rO8p_8kK`EzV;*@ZfW zcA^q7$Iz57oc-}eE<(wV0NqAR@FR#N{)NLL+~mtCwB-&yflYxW=e+m3c3}Hfz zx-t&UA3M>Yxi2^XQ){C#V-poAp?m(TF9{4=m{>M18XBxh?^RrVm!3qXVi6>BntKX>x(I-T_~@Hrw8z zn`W3!JmiZK7TZ~`vPWP}j@@3#J`Qwz`h*Lj>ZM?7)I%y4EPNPoZsOYJaB>5?F@O2)O6)A^ThJ&o6v)kl)O;oc3RDvf<>6Mb zK)9fsA)sF|4KmQ|H{G3OmYQxFQg77sirWNvVE>UR z7DPSHS8-c-a+6!(_;vi5n93uW{+gOvInuhh*XX*W7yhig0nY&s;mPVpJX+?ekB(CP z;!Lef*8{Nb_cFa0rm*YgItQ*;nVN0G zu+}CcoZz+;zAH`{Xf#fB=FC!^G$gnVVwcV+b#LSpwB#Y22GpGR8*d`O^c!!E4GU-)I821 zrHy6dL}5+0pv*=+Q3IdU0ipdovIJw);gKdx5PAW`FvA#w5tzgMn0h{ zD>2jjFHWPQQKqS*d=rr^JZQcOrcCALyx5re6Xe3!2a$?vlM&*ZZ0!Oskxis=LF9cY zp(i`Byz`B-73fwhcGcWq?$yPB>J&ridz4oq%UIolsr_gMMW|=#~F2^ALB|; zxNP+h7-sV|WefGKA@B#wg%C@^Pln1u=T6uh=tbknBMP!G*IFVrF~V^Uj<#;Z_(%g9 zDpkGaF660e5CUv<+T)B^1xa^Qt>pOygfqLtM$^dG;{qJ$6?_Zs;Y89n{M7amd+OAk zFuYS`CB$msUnK9MN4%yZIv%4(lEZn$2FeNXk$)8(TDW>Zr|c=jV=}eh9ICOeX2}nO zns^?U{|Zaec)N;RPBlt@)f!v=5@hFJD^)9GIW%@Dp4Ar_t(YG1oKt8?ax}_-IHtYy zXVnrSMfIQW0O5)Ge_eV6{v$j>Y=162Ce?qbEw-Z{2IEIZ-o})}qeiB|iC!KKR^PX0 ztE=-$_^HN1MK{wkHzH6A%9J?b|CXV{b99}##!A}ODd9rTEy0i6?zx{E{|{yF9Nkyi z^$*9kZQHhO+l}osjcq55?KV!@ps~@|Nn_i7zny#LnVH@*&+mEvIBR8PCF@-K?9b-4 z5rn(cRc2}unNJIwZ=;X>)U&qqar3J`Z&8r^obZkGaNqJ$*p6p>bnDFg?Wrnsp|kOq zX2>w%WB4F6$2)qXU?blHU;~sEQ2TakbHi?-ZPU7hZF$SB1t%#lPU>f>f03x0dX*jw@FA>rq6-!Jh)gvHS>KKDQ+2T0TX?51bBWT!@o z66K>}FN!LS$et{tK`ir)xqlDFeC88|9{@1&{Z}3IKQLku`Ku1{vsnfV5C<$}KJN$8 z2@j%s;DnRfj)q7?Nuz(Pv097$Qfg!1L1QGU7!>#;+O<+ zy?`%yXxfJ9g=aKUbL<|?6EuC|8=`-2Twku@o_-1QsJ4NFw#sZE zEOa5?XDxaHt?U$>f^CAu07Do11g)ObXLf$bh0b^yPOKC8!W$apYD1ni&=srsyH%uj zeGKwi?ijDpUzO|VWMkdHa8rxF$%)DqzM&tCH@zRo^!y}Bm+Lv>!N2SbLRh&AI@F=n zcrCC>5g%V$DIK6OmF<%J@12;1K2j3?qKcMgeS z6(sa>!rdIdVviJHyF+QoV!~|PWQk-Ps^~z?`!>iJ6IwH{b+SUBM%(&@Uo6?!w~#U|BBBmh|y@7xE8bu z>1Yp>x9cNetRB-%;vh4~a6L=4?DYNb6GHx&f!bFJj~oebS4#j0`kC7K)&Jq(U@{bC z7dBKiwsSN8%gVRxcv+ZkKx*eM&|?rB$6(@m!q#nTJO zuCqVs`MC)9pXmVv1^-BoFboJYoH&4DQ`7qHdG3itaLI0z4-Aj>H zDpv4LL0*+s*GB;qnrlrJn)bwpyY28IQ{=fCdTCw^E_W=lpyqe!auw~Dk8kamf0u50 zENkcp06i%GN)PM*fu2N;hlu(H(jVh7ci$r66!xJC(O^TGy?l3?2d+Bg+OoN&2hlmx zH7+A}A&B7_X|ogw6KzqHsMi-o9aAcc(X?giK&kU(L5sNGL&(xoDn8P;|Kcz`fWp}O0mzvG!0n&nHxAC9 z>ly~1cxh4P0yr=xW>Pa+~_NCO`<3E7)74%9gbg#LIsAOJ<80^lTppzWf$Dg`= zWvls8Zl3s6++s_b1DwDxXglvv!gXX$ezqhA_a1fnx`vGtVy7S_?^ ziMnk(q58{C9AoO9E{$xUtkMr?S6pSRYojqFk6*bixzF)T2z(Jai$*YAe8-h2M;6G6 zBTZv61Rk57*h>ye#z$zi?ba1EBD84c$LO0^tAuHzdaRVL*i8LN^S~5x7NOQJZx&V0m%R z{LuB8CQ|~?At5?;hgw%o=UIOob*Uv0%`n>2AZ^N~qgq0I-tt_aqS;}-E1pQ8BGaI0 zRiB2ekf_Yn;kLg}Wu`e8!pjOY)mXNJmJ905nfjJ&r$+IK5KTFuWuW=exN^4j=6AvT z*_KuunmC~k)Q7kZ9GhyDn)76Ks51xj&YN)T##*hvD>HuYAW~cF9 z2i?wW*6m1%wx6B`BOs5?T07ZayG1Kh;ls=P<{S<0t0=em!FZ(qi8(Nm(BZkwV$E#z zhgmQ0Uzp+dMB$YIASMi;G=EP0{4b*h*zqRHt|e!vU~Xw{XJ!1CD~s${W`rIhIPpD= zL;Mzha$H-}Ih0U)eebu*WT|)#^)e*^k=LNyoU5xFExaZ!533lWIt+9Kq@Z0YnNExs z9s7BF@$4xve|kf5tTk$>(&H^_c6?=eT=ty;)3ndYk`xLBc?Bii;D0UoBlC$IIBL2IuLDC-Cx@H*~YSgbLDRXtcH6n-IOzxMjCZj;JIhjVdV| zYRTj*qN3Cuh`s4BGWl-2p|=Af96@r8v{6}wg#3!x%f`FH#vPLaj3?HwJOzV_N1B3a;c$ z@MG_~fbh6LJMb1$vpl*{w8ZNJj2zQHfrSwjzPfBi;PG!Pj63bk0W3EP$Gy8_df_q3 z2NxMX#Q2ES;cLU@%#L3yxJx?E>`&gL0Bj%N`sW{H>!Kk9Bj|#6lZE>is9fg!0p42iKuv1&m^`{Nl!dPw`F#w)2ekwn9}qJXG{~cKyK@N8 zK1B}kf5D%US9D|Ch9JMFH;Dd$Te zWi;47KB!>GEaE`*tU9E==R?xx;_;pg8Hg*C?r9gmlU{{0Q{gP8(UmK6rO$NMP`?PCx6w=TrwDqlYbF zQS1uBSyRqJo5fzoE2EeYlSczve=+f=Vxhc>mCzplUtJKQt;Ci8s<9${Hp0F zgBHuPm+eR)wwu^WRWdH)#R@a-Pro2C$xVTf<7SHDocO>%maece{{!%f0`8;Lva^Zz|fdK%}R`#F(5icdLbC}- zUIRUEfnk_8s(SP3?3x!J6T!=9!uqC?~WTY`3L5ATYHiiNgw*%%Lt?6){ccNPH&BV=I)RM;+T zaR&5+5pdyAmuv_)vF!$G>sJ#*(;0QXKoQQ%clBINBohjCQbfGZC~#u#iN$chUh>;u zKYpAFzk!J&!}~{(hB!g8cE2ZUIoI1&F|%a?pT`c@0%Bk%qcNFD7PoCd%M4RBnR5}{ zt$h&ceLCCD5WNx|W$Ovf?i3<3;Oy=pHcmSgpL34N;?yE&A96-zi!BHkJP=cu=|~c0 z&WDIcU|O1dBs{jR4{h|88<9Dve=4TN%M2~4#9v}NP>K_IKcO^=<%$>1>nd?!hndMh z?fzZ+a-0f~)OAkVe@lMw7tu*lKojADC*laOy+rP-Z)x{Rv9|}yprn~Q)U3YT1{VO@ z`80v;fVE8M^8lyYC`d)0Svj1{EJi~+y`-o5$B3gpoS=&e+ZkQ}S{?rltztie;eSG_ z&CguQi~YGD5}Z*GjZ`Y#VgT@m2#7@GL=L!qpe<^|-Gywz)vtzv(h=cXMXvL;Tw;4G zKCVoGB^?2cwt$>^;}2f89iC5D-)EL71Q+<3z!!OREh;6?MJTb#3GamHT36gmw9#8# z1)5i=&necxAZ-I(DS64gJVENMRS`?~-v|tI$+_my_|yd}A3fY4Yr>GUR^HsQwP)Ss z4PBRpWZWg!a{X5W`Zka7wW?X_JuS#f&gj6S+73CrCU0VF(F7CJ)9%K6*V3wsEkO-0 zgZN?$CP?BPTYwJlLu{A7GE*c&(rOK-wL@=H34PUybf>9hIpc710g5ahK0O1v_vD!@ zHO9O0Ze_fj;=1<_&EGcH=DQn~GdT5YiOr5yU~hyHRnYE#FGEC0w;|9I53w?BMArST z^t(S0K5!p!D6(QV7e;p^2=5RH#L2l06Uw4=g?;2XeF7&q0gu4BJQGGjK)4CcqnwLs zH?^|APsdW;fs|OOkogX4cktl|KLu9+Sor{{*5Vd2{3o&3b2(xEYuIw@P$vGMgz!}a z5+UT0`2%te=cqwHv79z+?hZ8Q1TxYD53~d+)iM!i72kQLbY)U{9Oc|hcPS3wT4eRPRv}KzU{{(B}r-5DvX&0jiW{TvTOMS^=AzR z`-{xx!6MkDjqC)Xd{dNOD=i|0;i%2vRpodD8LSkElz2TfS8ofP@W1D~Eb&;al z+LXyFz^EnxjO#zDO9_DEsvvAA?PC0QuXRc}GMEVt;>TS`dygJbJcX4?n7MFeh%YY2 z?W^WuYAqL-YcJY{=CfttgZDGTdM@F^#U1OqW3`VWY5IPFGFCLZ?hH_3w2mWHm6WW% zdlYmnxEcW@mMp=rTBN8NvOFKLM#CHiRUy;TF_Pwt;UXeJUo2P`co9Zfs-(9$WozIR zI-8!bskjU@wiTlIcC1Qnc+OOp0zyd87B~@H_)sASa_|IrYZvJUVHPppQ1Nsn5G?Gb zAMq;={WvL&K=}z6rbedKQApim58DQn!^c(B0jLZw!F_3Twg!j*|Xs`(j8D{MIYJA zk}J3TL~c%TMZyoV3BN-D=D#6?Xm%5^t5NE1O;4nqkaZ2lWUT8)j9x+|E98v_?u`dr z8~}#~vLrf(uDn*Sx)}5x@#Aftm$)__j8`xUpp6ric{ukN4N33|KSc)idHACk)F(*( z=x0t}I zgruNZCu_^g%o48-(P*2Dc{~EAR6f`t>n{j2TGsGV2Hqw9u84I3Y{+;<8%+?3^9yqu zzvn#u(2a-tTQop`;tFf%e}g8#?^6)@Z)m3KJ1jAwg`Uyg2;y0BR;x{K#gQRQ6@jCw z6{)C)Xe5>BYt7JC5xYXWo_u&Y_7{gTuV(6Q>pe3iBt&qMn*Gq3O+9?T$GEX~ID9dA zG3mzaM|V9MCyYDQdQE{J`-9xl$(Fenh{qy7E{=zSQ1NS8+S)S2911-{#G^Ehu3MSDKU@mO zVUBd8x#O5$h8SRAdS|4pnfTydkG8djIoQLxL$19yH7H?FwPF2=al74H!ap4q=EV$p zR5uo<2&7ywQm}gO+WD0W|ENmm1$K_LvflQ&&9iCmA6Bg%!6xUf`2JhDpx@Z^|8_){dxBn-7^PA}O(dCUC4 z4GvO0($RVB4eGah38s)h(-}LV6_K?%L$QozDoWpqEni|nwMKCZ7Hvmd@@)nV%lNv#hLWl2Ms2J?|tI)NDxG5ZGlx2PK65K zvtavd`%nV#ygCycDakx$vB*Ut?LlDtV){W9y=;iI_fp?af=7|Q8rN>IAfji!6m8sNsmTj?)7dowjtfmLg7EWH{i z!qaG{tnX0nQDu=|+klY?SvL-4Qrtx63i6H~pA&B9C>_c~}#1X=q57lFYz?^ao(SK~vbqiO+Ed@DoSvrN|Xaw&LIwT9tiJ zGqi*~MLpDjG(Lk9pC}*)`B*IFA1vbH-b(1O6%N@dx z^RN^lYYz@SJ`MZcS>(~NmdbIN$$?^~AE5L0g}++DOTtXdg)~D)He55Cns_m=fz;Zc z05?_E><#Aui*;}T~kz)@9);UAQo#0^)EBaokb=FRVLMLSTmfX%z>~Lv$BidPC!?+uF2s4a?R^dcg@E+ce;6N4grB6 zC^J2-S0C|4>9!X^ZBp*erRHQln0tdM%Q4+*5FLW{?SR^$xrIM;`oyN|>J1R1xdisc zvvz?C>#5M;rOgqYg7)qIo;Qp?1JDAZ9{B)F(&$( zS8~U%99iAUc-azX=LcWMCBigtP?AwD<}Xz;5;KHMcSvR zT{BA4tdXfFsmZIbOV5(c!pxANFVmDS7$&L}{O2!!{tM0Y$0C@Lt7MrY%?KkEss(&$ zmvwU$YxdeXeJ$;DHKVT>6q&|40S`Lq_MzI~7&aU5(l#F3i(LZ8NA*-=u5}Ic;#~x> z-@~3%gF}Oa^S!Y&>DkJ3m{KI@bymJtDuk$bOy|8e17__}<+p(?^$+b9< z^y`8VC&V@Aa|U)Q%-zH-Zq;S|)98D}<-FTNLXg7ja-tf~;ZxmhG%0s;H2O^W<*p~b z#13$tLnDocOSXO4IWKi_gAaRr7NH#0BgS-tQ&F6zQjF=sBZ{A1yjNGw7jX>%?9hJO z7Wqu~{7d1fT;>0ov`%8Z^6`60!kp1g*B;Poy&b(>G6h=Tz!-J^J42nE0fCiX3zx=t2wz%xL623 z3L4auS+?@huSdS;;3Z9^bEO;{8(He$6(+(W_omML$`7WSWz1h%_D#P5mDka1)J0|` zPF#Ap!R~JAsElvE+8NxyMIXaHx65Rv)tHTc^tNbz!iFlYVe^4MBi92dCZwQoaY`)} zPj2nzkQ3-+NV$iTm2LH%{UWV3<)l2VY*0jTQ-Q$tI2zV+J@VD&R5r__I=xk~4<29A z0;)RmssylITV$L|6#mGg4HdudJ#ar(ZO3fvxQ+A@c%{);J-q*&t`n~U!zSX6F+IhN zMG>!Wt!5b?%j$tx`zEaIk;3%ccBKgCZQr*9q2R>9_(>tA0Pr-rcs03Nr3zgn0ykvO z?8_(-7{L5m5>P3fXM@2E5dxJCzPEnD;O}<(5tlXHJC`#xZOU(1@+f5LfZ;17XmmtU zax(q1^x+?X@6zP!hB_4@TWf?C^0nn|RADIY>BHeAV{_I~zX3-3mJNTm6sNPR>iJsE zS-(=WlYMwwA-y`~ThDIldl{4-Vh3p4;jlMUsirT;{QzLLI8kPy;)%x6ScUumKx-f!qI zY!SsG!SReB#hu2S5!E>de!@;2-AyITM$P3CH6|XlvCwC=7313*F*db{fn-C zEEFdg)0gmTxba1o%@bcdaZ)B*kc%r$I61DMcL?g_o95()MTwKCTKXX|CSXo&cD{ww zz0vc$scMZvlMgb)btvpE3Vevr~4Yt^i{m`8p5%Vj%*p==fgZWNC_tOMG z5H_z}QH%n|oVn;vY{uF)?vjr$+NtCNJpS+_QxvLck65Y@dzUb4<)q&fhDAyx@xDzsnVURf@yt9f^nHUr+8T^fIt;KNYM)7JShf`-ux z{Bs)aG*iqMDvv+{Hb`W-`RP8_jP9XE=sKtHcq=}ZoD<6Wj8t)^I((mPRNQi;mrl=) zz;uU^SI|QSenMV5TnI3oPAGWe4o4{Fm~_oX%Q_wS zX0w|<#+c@KvP=en93c^}`eN->C<@m$7M8~na#;7_*3dMtq94RBSV^)@lv`XYKm zW3W07vQ9u5MEUJL{#}uN=a*54Pq67Jt$c;znC?N3HhJO+_?b|14TC#!-Za-yQn@ud zA+Ljo_$FSlVf^zRfYKOM%IhFMiuZQL2U)MgLWt=tFBgeBBJL|Y&di$=jPc?bO8nFl z3rR+~@LP-6r@&kBKa7gd4xR#<;_G@6pes1&t-wq*)Vx$P`hO4U|6r2jhjxN8fB-E6 z81=KvQqtVP%$&%?i%3CL^bZ~T+wTk|wEzhcC3R^r23Jqlm`VAcH67qT0QW&{LPYXO zX)`C!{=A%k#Tg1tJZ><7`XQZ=jGw2kZqgmvzWHPZ=V=)q7A@8>bZ>)`z_l7EP@N1W zTN!4D{*dB^ml7D{6vz_*<3yu3$ULUpjD3wvBk>)GA~pEt$C2WXj6vV6G6;^~g0J+c z>@)$YGRldb-Y1k;^~65t$lq18eC{Zu#z@?We55;FsZzKL4mTeEt(R>E>!sy)U-b`S z9pUTbYXC&9{u{CE%!Ypu`|>ZL)@P%mq*Uacc^E2ri=0aL3+CqkP`l#GW050u3M#i{mQR1p zxc2mfwcw<8-B_#;sSIY>H>RcXDEr0=ty@;uJe+VaIyDkfS52gwH}fQ^4`y3sys6z4 z(auD>mz(k2=qzPJ^&$fTCw&1!8;)28Ou2$8!8?>DCCOYG z$r4srb>!iuz+;4B0l%46{}^^TK3XnT=+5Dtca(nFcvCnsZ;3#nDs9~`o1oVI(ugoU zXW}Kee>V?&qWe_b0Gh1<4>918G`DxNvN!*^kID8Ys@b@h4B5E;(ya1J55vrFJq&vD zql=?6fQAP3`Q9lwGK-;+kb)tkilN?aAxxU!A*S6OkY8@_(zXxm_yO;;2Ruao@LqOi zPD3TY-Q*u)^nZG7d0r>r#bZbnV>93NFfCAUdcF_A7s3DX>QmrNdjkNAe`;Hje|j|w zU>q_#+h0~a>MPBrW(gtr582kv_#Z^<*Z z&utx&vndO#(meR<^k9!>I_Stp=PGI5b*>lGX-uv@E^*;28w*oF6O43;`L`>=zXMW- zot;*0 zfXxzTA7XFgZVe->DWtv}3j>BP1#t#7pZ(yf1D(HRnde{fi*8H5%jMUN-TASce?l2> zf)h_Jd^YQoes0w$ZS=a9JqvX-oJkx4XF#l}me$+_3*spta286)EVI3PUP*QAR^1G9 z^zm}Bg57eTQjaDd)_mrh_$<4^bc=q*^#=Ebw+u`%cw`By$S3LnjV|YHc!KFU-{#|w zkKuT<&U1qakim$yK#rN=joPRxw4588+2#SEuO6W@Sg+dA3lWJuGvcL%dU?L338s zH$@A%koF7^4R~X_+=M#~*fS4Ed$ibG%}vbe=B2Yi>n&Pr(BCIcQX46JdHXwWhOXSb zfBKRR|0+46zw$Sloe1^e5D>9 zD<vs$Nex!MP1V4;5v4qb0#aN zI$W49uBQ#N`msmVAlVB&H752>%Y8N5yunA2-&5MNk;GVgCw)G9V32mWwsiBwQJK1R9!FPT`3#)o&~TkSQcBp} znW$!@5{l;x3p{Nf^*hI0`LY5&t5^w`Fz6i2H#au^oFa!eU0v(kC?q;0?rx1V02s zVRd}{#+2yVSAs-VEz@)&(naBt8W2%9u9UXrN9ex`BEqhtus?vuT>r*nHdcTj0xJFf z$9^`ds5`F+A-!m(oPIY>mVvU+V`c45o@(W-b?kI~4DW$@A@$_SQ+I)Z9ORNmMcBI` zR98-+Pes6r(1nx8_xQeiaB|ueQ|J?F@2vq;PZeGso@`r_XV~@7ddEnMN#G_J6cu>#C=sGNi+af0@!pgGcdn7&(?{;X^zkOYlX3 z8Hz_gC!t8B&{DUf=JgbKU_GCM zm3xXEQNWZ`=qN<;sGz=NS(q_-J2vxv{>baomd#q$-ec_ibQbdGXU@xzL0hp;rZ&|R zrHlc_3-z$;)$d;4yiXKfP1xNr%J2xkN~NBBJixI9E@7 z-ac-R8^S*}&LSq=@xlZH-DTQTb5?)&#Rc&g9o*#uxE@x3=jT?2U%f7NE`W^wdoAZ5Kn^1#2G;%@H9rxSo87C_dB=pRnO@zV$U zi|e4VsPF6%s(o?e#vG zlL}oiBygfn{@e6fmD$$>x^gD0p3Sk%zRew4u4~9-IK9IVroQMKURAV7_t$%;KKvlg zbI3I&ETkhf^NebP9?)8aW$okD$|QUdR0&^OPwf60kp!n~|MDFk&*09ar&32R#Ml4` zO_&R^UAe|SS{w%wtM>1%~ojci6KnNsAAgN%V^?lFE`+BgwS zks1SrJ=!N(u*z28v`i5kZn^f5Vg#KW;913`_Bl07n|k(`bgZAL-6XK|&yKqU66=4@ zC**RK2n$fej3rd@!F;7~&is%yyf;7Q{8jIj;xgJY&a;>NbX_d@-fYw7?Re-#(A)d+ z61=SwUK4xR@HGQ`Sf<3ZEGBEm#Mqsf*e;UOO4Y(l>v$e(ArI%8(zU*x|q$^8m+Sd+@AyJkbmYr z_b=T4OXWC!oe2ZZrYW5Zdxv}hx1@sk!Tx~_l;RV}DsUGhEGf3#`w&DbT7yWK4iC=e zPwQVlP>tl9ZDB(YUkhHxJvpp*VYBO-EC~ZK)3_gbN0Sg1x3;ocL!~aV(jTT5F@GeN zMp*Aj#Y!HL{@Ch~h8ip$EW~J?(+z^4O!a9%DeV%DinylP3p~!-5%|+x3#ugeyV<(? z@4gTTig?y;!Obv~s0^VlBIxsjsb$GCU#xL_qAElg-Z#(M7S{{}6V&KgMbt@fC|NSp zR9j1M_p`3K@-~vow`ed`jFEAEs}R`b(bml~YahZF#qWs|KmWYD!5@#jmA4 zP}7_fGAcSW<6UNxfu z2VrHGK?_wo>O*wK#34mgy{){MjdGll3G$HxN!kKg-GQJ_-D_OV?HWN3GlEyK(x>NA zi1d#V#G^6M!3(SQ8JhzxGBPpTUtZFvGCg|4Vl#Tzal}7BGj_qepFiR9`$e$xw{iW| z0RmkJc>c)+;P}l2P!#)9so2Ri0)sNaWy%WP`v)#YG?U2fyeU$XrVCGb`f4cvou$S_ z_!tYgP47P}(9e|eSAY1T?yqnaBmq6Y+ua^EwJaoVQMh;vSR6<-C?)k~X{ts?14Q|E zo8{}nsiOA#p?;Q?{HpUfSOGSR#ZVTY?~GmlQVeZ33OJe&6i_Em6DX*d0QAOTei#>CIMDq z36aNv{xU5!Aceo5%viyqdm11K$pA_CSxx$1Cj%rq04Ec5aJRC5=jvep=V$X(Rd4!P zA&7WvJiL!5oltAZyKtM5;g%)6IhUXhm_V-?*%R`RPz4K`fi-du=D^IjsfKZ0{K1NI zDQ3@$XQa<0CIIrK`6cZ|^Ycc!2i;UYh6{10N&_zNu;rT1rPc-x9Bib3m zIDYCTspVnt0vA@T%&FoTn#$$8-XZ2OSv+%gfO^tzXt6$yWM=H>$^d_t)-${=lANJZ zN7Z1{sY+Mh3l%?AdXFXuQJ7&H49x}|Cl?TskopZ@i&a46P!?pBJZyd|I@!)Cs^>x( zat=%zJbe~R6w}`6(oN_^eNjr2)YzzY7_E`7bjVoYsQS)gXMY2Ks`EI;k2Gn=+rRW~ zPbB-a6CVyiOfKSUFtW@m4Gc6T!uoP(p(f)j+B+v@la6Lj94&PdpC6X(;?ncyq9dG- z$xio01EtREpqJ)xgq}6hws4QW`V7RaXuD@BBB%Sy0)2~L&vE#Rl$O@r^3}dLDm;yR zgWr7&Luct0j{QcHJefh0tkNutUxNMFkFJ-xtzSI!%Xi+Ar|-)Kz3P+p&k%oyMgi5N z=??%j904Zse}RUWxr?crtEIWipU_xU`x`V;Yw^5CL8?WdVVAzhl+cmA=~a1 zyi!tQ*h~$t5Y@bl=CRuido2($HD`w@B5&^)r>K+vVZUt8T2=KTCq`c1b}6Z5ghA$j zO%Q7>gZl1APBR4Ughc%!Vj-(3kx-|fEgXpYcK7f4?T=)x?vG8EX8?$i{|&@|_DX<$ zlQ*|Fb1=2CclZ;;zDe>9nLWXnj9CV}6auCQTP!5Fk6`1-mx#@E1%TiXT%#-U0bZ4Di8Ds7&x1mF|KcG}F1tGDb zanA?(0McRiPlPS?Zjj?bs}pt>@x@hm7X5=BUWu1&F`sGaB9jSU`#`zBXQic-CCNnS zn9f3s6SRkMy-seA5fWLnt<@J*fWu(FhPEkia|F2!!WgO+->Q71Don;R4+AO*yug=| z(ZLi1S>eCL%z4{&el_o}@MTbV3whk3zZCsgQ>DF0$)ZO*Qdd;wt5vrhf{z6CK7a}H z#MlLG&|T>LLLJ>Ibw_rN-sqV^$u19DLF|b&TT!gdv{XH%+5-irw8UqP)|ODno_dR< z#bb)0WN8fM2;u0sL=h9z369XjpsEDjwKYs7=fE94wMQuB~F5GT&&3ZDamCbw!|EXv==Qay69 z&-iymsHN^)|8wR|&c6Yi1CTWRM-2TnUXhvy%(?kF^yc3Z#-pQZfOrL^=X>|U*wh%j zd=j!!Qf)v&Kz;x*hx|AM1q22~D9kV3PEQaTkqY2g*?{Ng<@bM?Zw}#~M-#L1{Hy8y z|9LFs|JSi3em~V8LI-=jrSSp~x;22%{cJM*uTuevN!NShkN3 zuiVfB)+fO3dK%i)G@i#KJzb79sXM}T1rx$hu9BQ=i``MYx06^;?m(;t^&3Y0;@(+| zY5cf>{O$uylKoPehpl2qKH+^GY_0nXw>P~T)-t{tdSfnHF3RuZft~Q;Iz^#0asic) zkncL7+RtXD`Ak#FUq=rE&GlKz9}bcudOmNv6iGyitB+7r-{?SpZXM-5m#oq8#THKd zu7N*c+$UE5&T3VP0sSf=iUPF_|C1!gGx@ZvAr6t9fKzP67@9?51f^1Poq!)$ODpC? z!85}Q%u&|tlM2S0|0piQh-hkETl)^LnL*-?m$$XZLM@+6@nt0o@mo6g?-lX{P#ZcKSmtmt9k|f?1h{H zIHv!(a{T+{%+E&U|H06o2=Yy`ivnovfpy4Bdg*1;eV+PYRC#JeIJTt*ih z5&Zho>Yu-Scs#Y{i%CWx>KQ!~RIJi5Rdh7^?H=C+H$$N$shUb5a91DUJrQIb=>@@B z%_-5Uqa0#tRl)R7;>C8G&S%~^NY#O_R;@fLDPI}7Zjnho(1q%&*}i=+{+`L0A8B4= z-X?Q|S3va9sk+{_ z-oH5S8JrCKJV6kYkMB~`;Ca_M#7?5pl=$*Zd-B=_3=EA~kR%fmLF%tX)K6+-Hn8df(xmj$k)Vbm#{IJ0M2 zG@@ue+ZeIbLpBS36r8odc#1j^nHfS8)H9<21uJc4r#oBqO^%MEAmbI9TS8A2&b0P# zK;9i&X#&@lQsLJ{@59rhh*1`DO51n=`q@g7kTg`-TkNK$Ce&`k@&gaWj7=V&alX+v z>;5DU?lSXM7u@B@g}2cI^jo@bOv1B0YCb}pbpQo@u>FgI9)L8&DekzhFhp z*xvrHJx;6f;&p&2Ktl8Ryk#^tnh`qm+?LAe8LXpz=RGR|%w#>7Ox>zU1}b>#gI87# z->st~d|m=pO13439Q41rwKEemTkKIkEMOrnao^)!_M+AS%lfGAYOcNv0v2 zD$B}fC(|IOMuV=7twzjeUc$Od^pq*f%VHUhCFiCoPjzOLF4~r=LP>BQaUm%{OFug- zgVJz7&Tx?mQQ3Z zA7sly1HQrNqEk95nt(PPypcw(SR*N7hj>5eOoGIggBEaukzWl95lkly)JnhE*V?>o zSIVjNi6?5ODeQed4xuVa`jq(VZY_RyeX^|vzGISqpe=21Z4G`m*07jp?+MM)E8>Q6 z>tyxOXWpn&S7xiMMjofhj9ia#9UJF3Af@4v^xtc5{;&b+et@CcfV+}IfDQQBM*3ei zfa^E;6?JfQGh?JkpLO)d_&y+DZ`M;?k}-Qo#~C}C{WCpFayAwb||{~ zCl&L0xgD()v)lWyuKwof4`YYo6oPuDr;w(#Kv9kWG_a{4GWwE7wNBHG*_EN5LT!k-29ZGZID|T_9b)^pFS?!GeMOv{R zkj?qDF4Efr^MD|}xdVINGZkZ5ruE&F|9GH}C424tP_v2Ylf~esnl()}zO?f}WO}w= zJ2g25c7RLPFeKjr?Pe3<nTJwwxN4Nye=>!FopIGzKa6jyHheHHI*+qOun{1=r%v?ZP zqTh_xc5H6)0W+NG z)T`PV<=jf6Se`xi<(CkHZwgH2XV2>hz!>~9m;e`}fQIXT0F!=_TUwzIT<4p?69TuU zC#$DsNXYc;@Rw23=~P}UF0+&Ab-3h{hVmWqZ}SQ@_usVf3{K{1JWEYn1X%Xd8Bd*FZxYU)}jyK%;uE-^HNk;$m<9`x&JC zbt@^CMH@kVSp_T|*cF5qJ&vWtemrbjb+wdZc+pH-!oLRy1`6_A7mIa!lebmA)BEDDTSz`tN|YlfcUjQyRgB5Qg83tsEWi}R63%{$9N z6$?kX8q80H<1dU&hlV^mV8=1hog2pReGS3SYj~$J5#RemaoFC--zpY7X@FuyEJqT1 zey9J??>`RvAG*i4#wI=+pnISo{>2_}0~~gFLlI+pE91YUEn<@O9RSM_LeEHd{?jS* zuAhTLYzZ7`pC*M`rp{Vr7FJ?4IYP)H&-(7@ov0L1bp!Sg-r|H$2b{!7OBio?MHL;5 z=e|Zs(t%m|aJ7v43&ALH8?5GrHz=cR|HbHLFRNUk;myY2`cNQP|j)_@Rn2Vk2b+{L`0qp`9lIPBKQ zcvRXuY4+<)$`AwLCUG9449XkTa`!#sk5pO)KDjp|-){du#=bGSvTfVCV%s*VVy9y4 z*jB~1Q?YH^R>ih$TNS%vRFZF>i}%hw@7&hDHrJmy*KYgAY-5bohx*`h(jI@~qiLej zU2<|zQf{=ETVpk(JG1$@xT}Ud%wMI~iMU=C;ZpC*`8mCW{0AOI5@ogVtWl6v#3>5e znO0pw2=&F*;Avg;YAVyYO4?ZY7Zt5``cAd#eJPVQFL^_j7EAs!W!`HQMIQg+Xg2kI zoSnVOvNks_T~S6%$oEp=lzy^Kx@L{^eQT1O>ubFP9=XR!{L6SA4^}wssVBz6PLbFe zw-IYfWTX~4Y$O!NRt?8#z*3p$0&cX3{1vhrsT0|D%oG3+5h~|J$6rSk0G_IFeyy{A zcXE%37dAAczEEO1fWouizhNBSa3}JPmL{1pm&83efXk1%)Zk z5OoWL#srKXr-kAuJmwY%)_PO3{XijfTrqHM`Q;8l(>htMSw6d{$BxJbr__Lv+cYE| zB8vFN^B zx1(t1I5yoa;Fe9ANZ7kwMro|}Z5UJxY{)yKCh6pjW!SQQ|AnMMdnw@O9}(_ipi%tW zfbu^jT*=JX>OX?EQL+DI*Lald6sFf3t&Jk6gAgkG2fYS5D)bkn3qPv6oI8>({%Ws2 zE=w{{$Ml6TKT&7Obb*d!?hnu3;*LoR+?@Jp5H*Na$-hzhn8Xt)VDam`O}XU(`sh}3 zbEjn69`35A;Xr#t|bE;!mx$-R@4cQli6^| zKhHJVff?#d`kH0X*8R03ShU13&=IK0P*DHHl@tQTr&)BBo%OBsoy`9fp1w%ZidYjs zAKr%O?)U3D_a}24-v@nzzW)4`%U6|1+gk_u8G;{t7FDV^mC6bwGKdj_po3(@%FycG zzhOAuSNzD3hiv3NQ)+yv@D7(DW6>xXgr+2P!RFJaxmdp(|Ls5cy5C;z*J?^!wYVFL z*$yW!H)2;qUEXFDzg9`I)Dnfy%jAD>GY-ASS$8@JpIm3w#9Wr4n3VpU8%{}=NKh;y zohHYub_B}qQr~55x>$^}Y@n4^vKm34CAUebUU9Tw^_=-BgRFR8;_<7W`R53+8FT@> zBe_o;-K!-!o5n=85Su18uisspw~N9itURvlJ}8ZoDMBcHJ<^I|*6c4abL3_;(OaWK z1N*hfg?3xM0YYEV2V%Z`@GTyFua^>iTm0~hUGxZi4a+3|ykkRTH|SaZaB@ z=0+%S>pX%X9cIlmZi9Wigy%rcB=Sp;Jy2^(7u_lRD2Ig@%3RP>VjMM&Vg7X^v+qy$89xQZmDW^XXqI z`fmsJvW07D94NU=K*^>0I{*ye{Np18uyr!i|C8KiB^@ngvLgrkv~Ttos$D1ugDRF) z4Rosc-+M_R!r_IlFGA({&bDc3r53ntnX|I~c(s#i)Lva6;9=!9mCgR@R%9K$?#c1m z6SA-BK-cOGmi;TL2M;K$d8fB5RKhA)>rZnMVdSCGi=py(P!j-8-p>z)f-UTFiQy?n-SMe!1&LBpKFO^)8kOUX zy*lbvGU-uFrkz`w>DyO4`G9X%i{83R!*HlkgE`ghT?FAeNIPw(Q9pxdyn|`mZ&|)| zXG{A~4m@Mmbr441YzT zY>5>*h{uV@282+FN{P{Tj|rej!U%%w0Tc+!p(RHa`SN}>J+5`M1N8+R2({_iAEiNo zw!$?*03y*XW-P%<05E(ZguGkD-8rvZk>l>BUD}}Xfmlwj(`Va*fAV!>b|A{fH9*3Rz0;b3D>}YrIG8rLp+Xl%2;RuURx(5UibF;mrVux$ zw`}xCB6(^z!rjE#+}WIen%;rea!C*Rm$@f45kWs25j4JhFDSH3o?41ff-L>;`Z@wP zIQtIR;W!AFoJ^wG2YA!mZ6(3rB*C^ej(Q}?xzTidnV)@Gi9#|S&6f%E%9BH8P7}U8 zTt+}()})7P7IO>4mwmj(?pfB^+oo>0I%VA@%U31sOw;Fc`wQv}9u5dQoP{0*{i>?? zyFC#74$ldqy)W>sj*S5RziBnCE8 zo4A6hXLsO4d3m!+r=r}HI463n;sS9N)jp@ zpiA7-Gh4&BggvqQhj39&BGjM0p`yU(I-sBtLUUl<0h|<21OdUYvpCqZ3Icuioa#u+ z%O0dABD8lxG*tH!?sN_THPEdg4jX80std&YR(C*C-6EB+D$eR)vqZ4Y9{Zjf`euMq zvT+u+wCp3l&%tI-&I`tC%E?HSwt8i@zAft(wCJ}yN0hGJx z;Yq!DqP&IOnaM5i)Z8=efav>8r=p_RQw@j(10stUKu0}Dr?ckMDft{?NQlsaFZ&;f z;Fn?sLU!_AYrKEt3W?u)oVRKxlU22xhyB)_yAdVtQZvGWxFJFx)kTw7Bn>_v7O9Y0 zM?c3t6A~_@N-=@9afRoDU;c#NI{Te5eY##EKVpBa(r;&fRa;+=TSA7e`W+VDJ1etS zB0ZDp(2B%#WN|wFV+TR{V*)Sreb{#A<4;dkfiNd4)@TQ#+fmRc9S={i3f1T8F)G8L zOzK|Jr-`>=YpqB6Ctatf8XJSj>fzc(&;j;7QR_gD`?6zVi`}5G^fR*A7D3GI(j(_s zS7_S&cs(PvPG|ZY*RX>EEL%YSj1oXJKcbX9UkC>UotMF$8*8vHmnd`&5p^gYP4vVa z59S-OLecmscG9Atzs>A~N4Qhlx~Cxl`ENdOZt;aOakn$MxDvdbI$JU_D>6_Zr+bz1 zy`+u9V^{Hfn8x&EbCCqq_iK7av6o3E?st=7+ufCkD(R}t_7VzeQh*7U+}QK!-1q-X zo+!(wz(oMn-URl)sr^4bgMU%`tmFgtpPc9dA6Q$v^h!x`R$n8UERmA+ad^ts+^Ou_ zq9f$Gh9;Yj7inRo;2I{c zl&D61Dc)f57-#*L5V6kOlCnIgJy+6Bi4|piWYcT!Nsh9utUMVbJUr~368(6u zFV9mutBE^28a^rIVQ|ua!s6necF>+Q@mnF}m=DW-R5|F{c(Y*Az|#yw1>pz5VSLy- znC#nJ#7fgXXpOLrtL0+rM~cK^(idzCtM{Y~b~)PKiavE_urW4tJMr3)k%9jq?>(zP-0j zuuyI;nI{Fw^dsL&VooNhu7|eh&rcJqR8RA7DXh_M4b^{;+e2Xu!X%5s;PzfU+-}is zJ`#VNU*~B7hNLmj@4GwT#R^#M;nL`CuwWfkIN)W8`% zR;8(3c0$h&4JI^TislM!3koIPB^Yo@EOp0by+bkeZ$cK@d$8+Y`5B5ju@-8}4Qm#- z!5?Oi;f&nPf3hy#*>>U65D@sCq$L1g4fs4|L-yUu_dJ@S#~NTTi1JfXCC0CICEbY&4Bt@pZ;<4&3mSmSud(v_k6RFU*ch$0_}M zK&Mj~7-}c~J5($BN3oENgYBQsj@tSwcx|I?h_6c~@^0?p|u5Jmm{{R7z<|9bx^ zM=lLOm*S&+qrb3uF*^^aybEbaup__`RF`Z%( z*0s8cTPEe#j&jQ;jwX&vlM@|G0#>F}!E4SIA|6-hkVABP$)K=xyliRA*V_yZJS#}6 zv66{~;!-?wuInp4f6GyuwJU*TULFmJ<1zR{F-WI6=o&SC}a z29egMp@}g&%&2o)@lefD`m@uL{Y25~nU)T6LcX7(F6ktN{&SBXF}dzYDc{G^0XIaEOLBcgjafOlfT z-ngdx#Qrs0wrBFz2}MlAlbVW{^ZB7L){aHih_2cjs<>NrYDWR}YRI7^!O;moQL^Xo z9K^x+#$v1YLe%Z|@u$a@w*~3(KqnK68LuPWNw0HpDUCd-7Uip8%IdYyNAnNGM~a;a zkgNM=M(D&N;s=z&2b3u*EjQtTOHKX!!=X@q+qk6_GV&SdEHyGpRkJVC`L}$icg062 zBAkH*M@Y!8@TBlm*u=fW5)0{QHt<72C!c}Oeo&Gmzc9C}EQs094hoclw%rS0R5h2YDDcrT?VTw<&8yUco*ib$+w zr#a)eGz7Xycy`(sFhNduWaG%Z_2sFV64)%_p%v4~F9qhPM;9vDQzqOA6Z;}8KDM}6 z?e*t9liO>ApG9V#bXY!W7(+rN+Kvw2zC53q1697T2Ex@W+++_h?srkM59ajxP!Hn% z#8}C#`8e^gDAsv-&(uaxa$v*rd2GT6qsw}ZSwhCECTM`tj*8E0Y=?Yum*4AJgZG0U z5E5yv%dI7VG@)QH&KuIhj`Qp7%LU3!J?Exi5-bTvcg##l%>32-s=X%0Bt{`!{#y7q zb3RM{Zms%GBUHIFBR<~;rO1-`QT^7S?16csVMJD#z7A`;d=yooU`4wiW8$Da=7Eg_ zmkBMuksAT*Pt<0g@UCN@4bR2$h@KT1Kxbi5`JTX`A(0hJM}%bhS+Bo>b+w^6o&a&1 zx}PhAeFh~3wzytO*r6uYr&jd*ZtT547Whg8k=deH^~^9Z9T?w9ur_zf6Iek^&2Tj_ zRg!zl@{%Lu4~p1FOBY;~*nC{-nH&)F@A^k^@6X7sq`dy0W9j$lD?P}lSs6fWbl@-b zPhlh*;qifI$e^4B@`4X%`8|S{xQ*l;FzSnDBUa`Mp_Wyu#J}JqFNxhyjO42QbYaVM z>l18@a9NCr2gvd@CtiVIW~ z%A3Nj5MK)ow3aAMt^iN9-_<_}Y9N~>fQjH#jUy(ISeX(*V;jm8&=L|C+Y5nZq*$<& z;@M1vv*Ch~*&_&B=Dia^RoiqC<3{};g>fPmJOZT8-p0cb`W6z5LT3U%lXu{x1wHQh zi=<6Hj8RI^(2Ng5<_Z&(JkqdLglKi@#Xk5$zRN%&P_Qa#9c)v43{zkNCWQiE1Q8P{A{Y}9EKIbnyO>wvi4&S%}C}IUVo|s^G3e# zYVMBKnwoGzD;0+DxFDnK7|6u|E^`wx`I3o6RXb`71E|tn{3gQfK3>UP+|s#6;g~mt zI5|AtH3>FKD;n0T=$ln@HXMcwr1D)UZm_(9Pxuq(gCYvqbbhIuo34torU}n>ha5k9 zriA(%6$o^ZDY$AH?-hXTNpo#_&ZAx@@2B25qB?EG3# zn{I0nghK|m*SmGAKel$4ybi-^Ag)1Xs&-=tx9Ru2JTw+UXhx2OjZZgZx{-d7GsyKQ zd>Vgn^z{%s7_V#lvUy17QVddyt9dc|b|3K4!9^4NT$(*^+2U<>J8S03bk%Fm_eIuI zB$dPlJac}wf z2sRkt0 z_{Q~Pk*2MYJnbN-_Yi$a)SeOUO6D!p_v`oOTm)cl_DoE6-4xbxm!|_StLJg>lLpQ8 zBwKNCyUU^G|1<`(ULEt4z~UN6rvH)x6y?wrwz73Gc5t%&{-*@PMaF^4SqpCP z2iD~-UNQ9%QtM3&xOXFF^q05<_YB;fm9~! z()vVPzLU1HSmUaJ{<4&2q;OuU|%xSU$}CyP}DG@xtfgOY`}8%6Ux(3 zY;?K6=6vCVq+B$u%Gf2JKD@Bm8@-#Ez??7WgSeEb8=P`#^1*CrWK$0BJI=QBX<>wd za;x=NBK$SkcsA(Cq!o?j0!Nr01SEf}GtCJ_=WX$N)j%TTlP;%H<#l}h)}{QWL)3dw zseWnnbI`%Wgrdth+*l{o!rXa4c1O0!c4Nk7HHYu1QnS^o@nR9O=fn4*aih&evjAyA zUxy%0cos9Qywl-EIMhU=7QwjuOO+SW&iwG;qev^u!Peq>9jd`v@D%%T{lnL-^vlDa zR*EtwU{*OM>}iom$zZPWGB?&9y)ww!y@J|!s2C#vNFfxQaRHb#WE4pcx^saB4P-%p zA8u_qd1j1wBBcUukvWtB1v&s*q0pE;)=!ddA6DOl%m2+Wlcf5$Ld@iRgo`B5L~RP6*r3@&oq(1Q$q zeYz}jHG$~!f4B+a%eE_R#Xfw1>Qq7s_!ALiJl|LB(AXMAJ?Zh(5oJg}6Lnn)E@UDB zWN_-1sN8lo43u_BC{(bW5u76)>iRz8*8Oyf4ZS+S05UR*3yo{1!m6VX5Mb=s4=c8}Fw2ZA*yNO!|q{t-{RtAM$ zK;t!$F-5WEkxH+jY~C3_RrX(q^OTcKCR_sIEiU!h4D%I}*3zxSP!}&n#=s>8^35pn zr$t1+?9s#-Ig3~T0D%n{c}^6l6tFM_*iB@41mcVHB4K8h6>&A~$G362&(Ne=VE`-< zI||fhGR^v9&wYQe*a}A+1II{lazqHhy#7=Er|^Y@k58BQkN>gfiapt@j-@xg*` zOdfZe-Y)Pl6YqX$#t*jF*vd#308soBG0sKWe;6DoBaNwScjCUV` zEB2my&zF9LXMG~LWokTUVy9E-bbTc3zjw7=y&O#B<pHMM;^O8<7i1{&(Yzx)T)CWUk2cJWL-;_w6UE3Ff*x5@98fN57+#;hJ7woSt@f- zr_{`FUC9Os06n7PUb$YGK36PO2>E5APo6KF?|eFh!|uDMZ05pF7P$`2e3rJ`KMuTE zk+23``Fbv7;ISf}zvT2J*rA*pREdTxn=6Va8EN%lVK&EI2O2x>l3hY89o_*7(-7u} zqA7+bd-xnpM-V(Y>;iJB@->ZGS13}=mgacDMU^Q5yeTXbue`M|3nK@Das!PcEd7OT zR0gD&*i8g_4rQV51}IdSBok}-#4XB3Dvo>D_n;F?AQ#gT3vhy8lJmVKbd5gJ7ZWT| zJ}5|!mhV^>Ni!s+nci?nHHcQ6$${aBZ%jP?)Rfu^UV7t}Jp=%P2*uAlT*@q6V1 zS79sQwBvo5IN%vR7d`RDGibkH7$=|$BF&RiXbmIfbJB`xOTIa@Q`LF*#xIlF$Bj(r z70E#?M|J?7*IGEb*JQb-jMvjF!m zxRPaoXwFwpy4mvy_*I>tWTM>%Vrx$jS7(sRy#3EUz5^SGIa&lk#qUy>!sNe5nf@TC-kMq=!Q zEbOb8x*{yYq;BT@oEO4x=aBE?BDBvvkIwsg8=}VzQFfYJ;fSOes)5w4e0!4?g;PdI zzanbe2SeisRzUjL?bkzXo3-Ma#A44-Rt5LJ4p1p=2>wPCI>*_wF{KT3LSAlW$_MAR z9$+F!i%U-HX$j>Db@ZO|D%9C@SrXZZK;97Sn2IE?pCZGu@;$Ds(ka5-#fCXw33WI@ zw^jVYbcLbMqb8W|J)*+HA58wd^{c>J2PuVTf@OhMh()? zmqA5qyGZtkQ>$Ihr!Ek0-FjRz_me3^V#wXA#2kxTQ2NRP#*|a-B>OXFS8Lp^9_N#~ z6@A2ATXq1C%jvx+XL*1q*Lu;BL04R z?^^Rq#i*>UO|z9|7|*q$qj{M;1npC{l~_SfEzB3q{t^Zu(r8~861`vVSordRT6#i+ zZTEf7$u=2hUNdg3og;TI8z4l>=5Dp0tFHW>6{w4@C{v2MT1RijUq?sq5TkFcHO^Iy zlR}H=HwS*87L=3u$LQ5QG5a4dHxbl#s@)%sS9$ORh@@Z9&#AQ1IO*S!WnI;MTjyR1 zJ=v|k(`^3%9N;30Xbp=fixo0)IAq|HP7Y^(_pWx4eN2?*r8qTM9tO}!n-4+8F!x3b zuA7|H1;O{6`k3V4cT8yI`b-xZgt0&8xZ;_7J89e`x%@!xqjwute0G0o!r@o%l$GYW zTq5jbttdtk*A*HxO@X4cD@AY62c{4OK@fInD~udhAXEt&*=Z)4PaYjlEy0D#5>KQL zh{Ijt;3ikCi>fgn;N9QM;vricnHLn>6HQkg27;3xqzv}wd;%|p13I+!W4!)4N|NzZ z6y05DVskJvjv&nE;`zz3OSEL0aaH8H3A_j7`wVgZ%jf9063jvHtG42>+8GORFJ57M zj(Js(^PsfLi5{Sm zpT-Vs??KDft5qu!4gO}o8uvS;up@cE5S1-U=)I5}7~OD)4~gWbL4b0EEuNfX4l-|R zn?oy2AKnpW1(n}7b%)w@Y1c3|PkWmoL(cr|rDl<8+UnBw=E&%sHMQfIt!?z;S?vfP zxLD?@<5LGZ-(1wz1$tG~1zHb0sjTktg1Dry)Af5))b;BGo;3W=$;T0f zYb}o-npc{&ly-v-kusVYUSnF}5-44Ck_P(!hK0AbEr9O+UbAa62_IS&hyHWHGbD-9c{Yn9xG5hc|%fKxz?eu?+=Z!9Uo~~?~YkpePvx; zvm%F%1rgcQ9zjlx6Bw9Kc1C0g+utw@{JJ>|O0+~Qe|L|h|$8x5mm8v%VG~fDLILkc2aL+`0)OC-JCTN6kZ=E zD$M2l@(}(8a!%SM(3285{Qfp&ABX}MH3X65AIoqIM@ikc)N*{pEnJGK)3w~Z4Jj5B zpjB`V<|H$4XdG1l9?-voFFZx#WEdyV1D2=92|qao!-r<)D^L3lq`s{Uyz^+}5`)i5 z;hb<6mcg3m;1r1qwHrh)D^SVDOCQB{N%fkt<3|ij9oFfn4TVad41;=k%dZd2WRq6& zaCEAGFe5d%31yOwny2oZKv5#iL>qt*QZvi@fp>$k2l=x4>hR9u0@;5sb|Q3Y&prCt zR|!mdEs^A@5iupk$e} z&0yaVK{0qbg>f_bq9WP{SQc(xVX`KcQtfvd;=4NR9kX>9Nd)BK`~KfIhWQ z9b9YZh#qL>cl}TLZE;SsxPjIv%x-SEa#$iGmqG-eFe$Iq)AS7-LFk2SwnzQLK~26C zp6}n@xK6_+iH*rWW%Hh(*KMO(I8eR6$hX5mC_wKkk%audn&lByD$<>mxW)F0H%7f? zP8_D5E+dYjDza}xkoXB$`2ICQ@hS~CnO;2QrjVBlS%zV;>g zkEIei_%2&(_wP4*z&FzWv+*fWPyhGND1d)3@W&=8+!(^(>-U43!c7>R*4cFT{JD9! zFRCtNs95p%pYa9|F&A=0VCGj2sH}gVc?1qO{%htDO)P$c__|81q4XwB@F#vO`%y=> zD*zO(TwZ+v&F75c2`o5n-ffC<{_D-t-L4U<4^P1O>?R#gbc}7atgrk~v8^mNH$m1z zXmfxOG#SxGGUj4dxhr`5#5#i?|vyw-B&&-%1$Sw1xS-Js-mm0}v{g z34e9O;f;*v*G5T=KHJ3VC6D~@Pl_v5VwR3q18-n18rtseuvc_T9;i@RY7&xEO7VHu zrU`$)Dgv={+J!|*vo}vBuKawKh`yzBAU-6cB6Jj<2>!^<Se~16Q1BiGRC`lX!^t zY(2BiVf)^AlyzjPQ_8P!xlo%sozoj}4Q=znU5q|u64Q({Z90AJ%oBipyhXN_aogPz zo6v>i{TIKCS=wh&4_ITG0i2igcYQIUOu!~9V7llZOiIR1PJc?uMqd@aWNKF8l4j4tUzP68G70p_BqWolamr;#UAu)rg`1G<22LsIA|UyqOfZiyk6cb2 z)Q4L&1NZ{Pc6C~OK4Ga&3-X>LV}ULWML2@c#NQT0Aq+nF-Bl9Snj^tTjg9LaA*)8z zD?XAQB398rCM+Gvk27P}L@pZt!e<<0x2oFcF_hkgW$cp^72=orDT+l{qJeo-X`SX5 z#_jJ?*TPG4<_Uk1GWvbVU&Pk$Em=iH6Mk4=q(Fx*z3DPu)u?OQyw&c2Yg*s&cK_@7 zRme?*I9i2N4Gz|(MrMQdq=hVfeZCYNC7MF$b>m>ce1d1kBj8}P9krJ?JXy^q(IQ5> zu%YF_RPxcpLhUD^I^l&mi+45h2?TRReR7!hFvbK;r zf{1$BvNk^aK@Imd&XPSq^N(uxf!roEt|k!#)18$C2ciBOe5Rwx&}(uAVfeTRPhlL^ z32OL!;&2l{AyTv<6#LO|PPn^}1-XdFn_ZIje|ysckFfBFA?}AEbvB zMr%z~j+d?Qp!Li$>9wR2nXa7xPRWf&8sePdCxL6&sJ_@ooPZkVdE7T{BCidcj;40$4o`{(oDv24)dPX{Q0UA)0& zNnXAv(>IJV4o}KN|7hSEo3lS0{sM{ELiRXtfwYs^fNgOyQIp#b=VRE|pP)ClzOGaW zCK}NIZ_yMxQCRL26I_#(Sv2|OW@X1>Oy4Hj7nZOWMJ~K1(vJrsiv;{tYx!E<)DDJA zD8|B^8}_Z^Gp~5PfkRwziSuvjn}~YW2-9EQxSmH4$n(JFuHKS)Mx1HiXfrqN(TGZT z*sm@*Sk60h26Fm79~Vl;kDI6CrHWRMdfReiEd11Ck*59|`w}>m9qB?ObxVFkw}*j9 za)f0hMN(hHvD!B`+Em-nya`p$s-4BtO=H8%>JYLfo4PYL0nrJ_-iXx3DavX zC0x7W#3mCOQ=2Ga}Ph?7Eq@qBS!wFMz>VW%Exm|G&Q3%rY{&+P)|`vU{oVx zPZ&O@h~vwVPVk8fvXY@#s5x@!h(4kVgNMQ{Ao%ixv+gtz9R{sPD%DuR!)%(8Rb0B7 zUGsqz_5iQk-JnZwh^oaoPD%?{dDdwkSr`vCS?a)_^25$5nD zaAf9yZ;U_1#8dSqspA$G%fKWJ>}Z|q_W2GgWk27nlJr5h@r?B|Z>zuki(l~H&11v8 zoK(p`Q5AvvFE;fLidPNs-7jBD55q?}2V2_#re1l)272dz9~PTX`3^fpA~;4a$T%mi z-avgDj*;L9U(@P7hiDKkM~WX80dFP^6B9r-tZ8u%0-?0~lohK_kts?t-PUKz6Yfel z#Hgz}py4p@eOcF34f*ny8j;m1Hb(_U0`gt0%LSJKFuM<1@6AszK#cAVG z<$z-;m-_-S8;=#wD0sVb3AQw{BN)Az2ib?R6M>X|WqYblY?rJyi6;G?0_FmS z(z6sRyBY?{nq7q_VvcCH{GX`{G?i(Pj%k82QIo0qiiZ{pCKl6tXeZX%>58OqUoHHo zMZ_I>mVe<-bEECTFq&`%Ct5mRU-mgk2TIV@o!*^dT+|#zh%OX=$N!*JJkeKvYlw(& zM2TZ-U8q8?u*fh`zgcImS+h?Yj$}chBU^Q{k$0=s#|}k}V)U<(3bhzW)LiH=t9p++ ztdn!(U-;%ZyMbcW$I9S(he&^xL+?{MzTe$q<=yssi=N>(M&$teghO05&*VaHtw}vC zZpuL;+D2Ko7tSk9?kn0>nm~km6^$CZkT$p+USU?HlF^cglaj{Su?be~n!t)p^(k@N zn<}wU7V)MN!v^y!4YP=?icw0;x480Qlo+txqP_1VdpjcRQN#(UZKN0t@2x+f)FU=^ z3cqz;D{JXf=F`&Fd0+j7$~~WTJ~{v>-jTqzl)vNV5dBZ_{$E23Y^eHU#-i^w*fSE; z!<-Plkp>nwV~^}Pdu(K^k-j`Ew3-aB71eD~;oE(}dAV~(@CZ{^Av$mMI7GB zXudR}8%*=Xq#YxEWq5xVa$0RKc%OC)B8QeMxnb}Sdp|vR9csTI@$Hj-lRCBwsH^l) z>J8IeoOJTZDfh(ft1w4I*E$~oMaL*WFiBdU;`U1!3o&wbxsVBJUwfhAuGkLpke=Hc zJXRAJRZpaDQ{Hb@6l0EsBylAL3O7rg&u{PYM%9OdNz-4gqcS83Vpkd>-{qjFWZhCxbIgV0{8lBjIALb8pGZStTr!h%EpqAAbH5F|`={GYm_8i6^6Pflry=1 zLFSm#9huJ_=EJV_A!MAOm;Q6PW?@c^@#{x2zsLCaB<_+!PGS=6l#Z*l>q**K@kMdx z6bQ#lt$b@YXe;keut_{tSm7c!XlImjyh6vj*b^M)`H(0R?E$th);AmUbq@{{KH;_l zZ)D>awE?j!;;QA}G{$*3%5lTYU-qjt4}T@#rVCSl=asQAdu2hRS{Xa1hRgFo4i{id zGEZALu)F>XeS0Qy&6p8TlGA~h0+<8+KMVt+%s>jyKVb@CV=G{7#Gir)KnR=;oQE9z zQN7U*gcgYX(1o~lHC1tK*ERJpbbja>?JvwV0C=r-p)blyRB}5IBnu+5n56oh`o-4j4maY3G zf}dl-#YA&ReOFh{nKqHCbMBLZBX19O$NV)5a@Gve>Ha?Hf_gH3V_JESH%$d9h0+K1 z_0={l+MnzAnKXMcj2bGk)2@|@7d zMq8B%)eR5zxNey|LQ1GTiUHL5K!j{wu1T$-Dg3ovp0~&k6E?H_wu%`yHbOS7Mywdn zZMgB!OTBu19qgC+4g_Hac-dvOQ_f!|4QDvB;6D*fmCZWF({eXvO9vOT8_DO6+{`V) zC|wr7KZ`6_E!S$VJEs5&5i(gaPD(8sZx07*AQUS_ObB#%3%W6q3P>!1OMuP2%C6uQ zDG$S=bt7iNDxWRP2MhvJJG4||aDzg*H!uS0DNyKmlNv;0nSvK);8|liA!m_ALeiC4 zGupSg{m{O`&Ph|ksp$}G?9+}FRWc$&Qdmhg-XK#scLt{VNJS zNH6%qTZ`G~*HC*2ME0vv)%!+s79TR&a89aibbgxBVSgS8z$imm7TSQcwiCT+_?_as&)|#j0bdu zq$jkU{U}z0B@!$VYj`?S@$(mx4pVh!iL{Cg;OJGda0q>+f#mWiyLbo=P>#PUR&8V6FSz&K)QN075n- zOO7<~F6fGMAPkNRW4tpJ!5bolA7eU`oV~ZOgu}~ZPEqJXSTamRJH#E(x0u#IO}m|f zcMh}Krv^jukDa~Ws9L`7pg^$!Gi;EOF~a3?o8JM>>X{?eN-3ecsSw9QP^jl=eAg-* z>o4`j>BgO)h-OX(sD7?HGsjVmLmY&3ZZFciC!_Lzk7Hvw693TEjr`5`b-XKr&pxY`PqP)v=bWnMe z{@l3co^&Lglm-S$1V6$uLV4wker<~~Wo=XT!Ho#DcE`-UQq2i=3x2D2_Z(B+v?F~e zN*N;xihLV)FvC1Rq)bn92f{Wn(^2%Py?D3oozp)U9NAzzhDWEvGZ!pm00n? zdE{K`&n%;!eTR)A%UDFm!Vnp?Jp(F!cO65@n^qiwg}6MUesP0@%T6(GgklCgCk4M9 z#{v!s;Qi zd@)lzz;s?FLtqdB`OC`r@E%~Im6n${BGTvwEjR+5&lu`YeHvDS)FcD;TKd>+B-0Fssk-L8&rK;+R z$ObzyqLv!Lz}*&H;5E#g%p(}Xd^aiD9U}An={5z{sfMvzA6c)D3Xfd2%KW!+%c0`j z#TZ@>e~fLS7QIs{5*To$Y=ZeyPW->}nf~ym3Ze%FFhLRjzOY)9PA>q)UXN{vT1MqEq!R%XVm@v zd~d$kQOVEV{^s6pd5IWwxU|W?@lCEeR&M^=K_U7Aq!Nr#r#Uj7xF(*ZwO}h*QU~%U zQShNpD9!owz+|K17ivCv$P0A4Ku_=B87OGju_Fx;M-)j(W{PNn-uq9UW0UmS#RD0NvQKym^G_? z#4+#c?gu7Vnn_dDOD^eVth;^8`f$ z&_aVmMRQ6eW1gZL355j7JNdCSGUdQxY^J^$jpt(c&e8tQFIyIYQ)4XbHpf_1l^W=s ziR52cr$E&uCnI}}PmDOheqz(Qo#nAAP^ZuN%}&TefJ3y>#=Cs27W6_g=1)(-lQxgc zMJ)Oq^8zaq9_LKHxaS@bgC%>VyR|i)^IimPt{9j=nu)IOsK);n_DA$~ar@su1C0Rv zU#^!GNR9y%>i=`SSxE;DckDno0d={XXx>T2jvhtCf>s(G-?F)AV+~c^72hd|p8a4X z>Zt0TBRrB}BBypsxORK0zqT@-Tjndk^SQsDDZmiJ{bKVLDo2n$ zECh+35MrHnGho(hrS9xrXAb`?W!fwHy|}KTF}rY*^Ir4w%M9^{h51Hww!NGA(~nYu z8o#2mFCxX}=|Vp#^w64A&FUJee_wrM>b_^b+3LHZo@0S`96Guk&FI zj@62Sw-<%&M>62k9;+r&d-1oS=v9yS#8sp%Ygkc$5NvBa2FEM3CLhtRq|mxh6ePN{ z7+E~(8`@`l>7;ywh|QlQX6(^c7^%)NKX7S_vXYY0`1+D07zAK1-<(=e&{M@06?639 zL*A&>IK(i~+!z~L-H3x~#qQ9Zw9m_-DviMJ>)=H&35Lj}+wD}i>+J95pr8<61&*** z?Hky50&v=v>}FHKFgkmekX!E2+%HaO1vK~-7Ao$3{4zwHG<3&>rV@WCLHt&q`)=k} zb+=H~l==JfLJe(vX33${xLKKRds!6slxfBUBr#>o5sDaF7t=I6ovdgv^_i59V+q^& zh5bd$GV#o$G{$Z{<`fTCz`Kt3RWA*4dKKjwZzr^R#OYINMBlRmx0c4 z(YTxhhPRy${4BALS9IN zHz{5U_{`aF#yGWCFu!X+3Zn7CSDz=PICVF)GV=a5DY>qCU_BVu$`7|9o=e{R!2my$ zh>mn|Lr2b2WimsON$Vp10R zk8qD~E(lmoHjX%Si>;D}99H<8(R@=h?9myL3I&QBBT5CuDzVnHuz%O|f!}S|m_d<2 z6QuuPEB?`yg~LF`>64|MiIL4;0#TUE-6>>#>=)W}MX?IO|J%-u$IGybc+o$?sWa)yib2bU^;vc6{+J8oFXXgLlicZWWF z3t>z!I$F26Fqf~<6G?c3tCMsT*^>QAGQ0pAl z#pb?Vl3ctmgLEc(pmxfKL&xf)WfW&e-e(KSz&~c~EBrB6IyRfN2H09DPUT&(O z&9S5DNB!vOAS*zMP3f70?X4e4NKKhDImg+8MHB_tg^wg)B)wVQ<1557@H&@elfQqZ zvk0ZkwGAr8OGQqb0!;l#RQLsx{0l!czy!~=5M%qO&B`uJXVxbCGc|WJnenH{T{7_- z{rE>~0qs_4sbC?R<@Ln@5~*Bj0?$=`9F)=kyb~8)uoSo9>Mt0BauYuz{77}WOYdG> z$qW}zLy|DkLSD<5747z*RE{IAyimZs&q*f(TZt)YQD6OMz}^TIgWi<>^XV97C5U1d zRs^cIGnR*J3)0Dcnd{n=bA^p>^@BS&#^0#Af?P;WiB`rU&E{`vIFhc8H01q48fYD^ z;b>CXTu!#wgaAc8y)geCxt2cWO!N!^Cmvr_;VDPUGnV`%mz-&;LK;>BEs#$=dHgGB zOD!T3Tf%}QTA406svv84e{30ChxL*O;R@8!UOVrLQBSoY9X36hqw9GxRA3IAv2Zjf z!t(Zs3h6d(DZrIdpu42vg zn5WF>@Q{9KA!2)gP0=F%u~Rgc*U8EQJXS-W;=0mbb8Pqzz=1NMQ%AL}gTQ(Rw_YxK z#CZ&T0-m%0#G&O$EAPaU2Y&4g7Y@LPJXI>StVn%VduQr$kG4AG_R|g1`R>B~iy>tI zOfp?aI~{$Z6$}!TxL_U>X_~%pfKshL`Q)3B^+6Cve279SHijT^5!XvzO$CLCfOYViOqqyiQL>rVQ8;_|O&pY{~ zj~qD!Oel<93`zw2jhN~QCu#hPe26z^q?Tfro>^vIbliGj;sd}r1s{J9Et+(u_On%8 zKY%TLOti#jE(aqTQ+*u+L{q(J~4=U@=Hz?-K8=up)R7j|+=a zi8Fj%#FN}&!IxAC14018QCo`_w8)#bWAyr!!+?-AwdVAC=+@Fm7=-Y#4YCEFvB&qwRrn~%W%RG1 zcveY#6bZI6e~LPUVb~J1e-k&RLN|q}f^-;eAj+(~!$8vcUYEp@aM_8_4TtSuy$E@cCGLR~l%F;j!H@_!2icQ# z9xDf(NTHUYxT%tILSrk9LLx%X+C1yU*Yhh~UGzPCA?Z!D>(dcPLB^{ckRz$^1qaIMCqhC<^+5o(#;F>Ay$2lS&o;UP4Oxh0Da> z29A_yCgW$d=ml@UjgQLSej81_mPG4QnX0yTC9HJBi;d8;5moHwmkdUArm-STa=>SG z9SV)wj!X8xzv|Td5E>akn4=mp>BppyFMZAEj!H-wOEJ z9wcahbRw)&1OCHI3HD-BboG_|)Nh&Z8(NP%)>yIZaq(=?l-`U)B34_~Bq`UGE$70^ zk#NUby0t&2HsaKm!iBHIJZnB3iH!w^E<;~~r)(3Qz>LZwky(!W++l}(?W%hH!m)+Y>SGEBxj={NmA zhhgAJZG4Sa0S1}3dbGI^+!b0K3_6mOep$3>!y#mBs!~$7;tb> ze4JG=Qj6L+Elt|pc#Yy*E9(QDaRb(tc)a{LmSZZB^KcE~^tIk-_8$MP6Iy2t8q^jB z*@9DG8}WGqsWBJZcNsKJvaVk+?yCvpiUO<&KYV!w6n_{|Ji?>Z$J5j|z<2XX6-Otj z${5R@IzaBTdx-T{^R0GDXVJ2SLDV{fn2>;1{Ad!vdNeu)>BcPds*QmWvdy=+C%q7M zA&_7jD;mE5>T_gc>Y&UKaJYS+E(7Z{vk)#Ph}cLQ_L+B5PJwBD5|6y8U_$rkxZOLI zmG6?@z?;EeK?wZw!@mks4|~7Wxjs^^lRB6aa|hOl*j&|JIQDix{H-PyRqYQ567GnP z@^eId{1^>5BBwYYJ==gcaYBl4v>x#3KZo8n_v|Scg}|fuMv(p?23QiGCjTVu{{%-0 zehs*m8U%RvMp;zd(N@d-npBf0PgH%IJs?}-t}01THsCwhLUnG0MZNVdlQYe&2o+(O z`hyPsX=LK>plk4yrX&P`j_7}a?zi(s&DPSz;?E+K|Cd>wvX^rG2mJ-}YF`rVcs!;| zX#Qn^DP7Q!2A3TnB`1TP52Y6t9lN59dCX4_&Vu;i!;_CKaTFyusMW>@phn`JRm9W`h$_`F z&U}m+!!2=prlNT=w#iil#HLc7j4I zuwgUcC+B`F{xdTT{BdVIM=;(A-JQy(TDuCm!?MRjGIQ9nZi#i_!`>vtSES}RUbnlP z{N_7%06fowsU5Eh{`iFu%iACnyiuC$g9Pz#x-U$kYRfj>5EnsRU$lc zb{^jVZ0*?)yhwpwcaDG(9>;u!=sKEFE+7S1j8;EOZ;V3cQA=$U%`zYwLW@lJz$UyD zTSbj(D&4^*beKph>!mO}h7YZY?By+p%xtuv3HJ%qU9f3y{+i)xhU~c@ngq^1+-4O1 z$Zz};VUDT+e`bC>w#N(BCX4vfXP#B=1xRxga=x?{8*!ill`L`<2Fv$2yB)Y_frOZF z?bSHX*)>3IZdZ#O+M7Pw95@ifNcNf`ug{E6D(0u&(B2p(s!N6sUOPn12KF(nuigS| zlb3rNrME3-FT^6!niotloB13c-YX|X`<3q0|wagXPllYbleD;#+c~zpEmcE&hex8xO(xad>!GfQn69eR<c~_bIeDq|F3^ zWT+d>Q1w%J$DFGI@d$g+CNZa1D6)OF8ljX@a|W z51Mf<+3hL(P@lKglGGWk*YHQoGbAzqInt2SIFDaODB6H)E!7^w@J|hrF(jsuLD_mc zK9W{fy1EL0xCUu_zQhi8y8jKC_O$;Eci8ceFAxIPBy!q-Zx2Jlp))G$WhLs#BDWJB z7gTTyXC-?;KG#Jd|NK3og%wi*Qw5j}49O2Cv!aZo$rn?3QwFV|afX3bB1`#ypFahn zNvP8tNr6s;0*MRDF$d20c_5c2S zu;*ASwLx0Y6Z3!VvO(=${(YCNHRlGhJbaj+`|vse<}!5@D|kpe%E5(rFwqrFIma}3 z;)lnBbrs5vY55f6+I(KeaSOh28kN;XG&>Xo6;PdwpSTvd7Erb?wHYM8!*X7Py~b}4 zcSBc@sSjj1S`4Y%eB~@e7}w?JhtY*pEz;;+rJJTsrx^?Scu+QT>5bXJ-I61nR+Z(G zyrYWOgX2_5XQ&oz*z5(#Tmz{IQh(a$$0{@l9>&a_NOKY4CWpe|Ku^9HDK$Sof^YG( z4!|$2%EnJ+S@L48TmuAqy!Yw}-?ih8+J3Py5^6G4AA}89Lc4wHDi!HE$3ayUINk2n zM|2ArQIv=?tNrY(FICQg9M-NAoaXcy9_`Q-SH)#vSTR!7R46 zri(INp>X`uqs`T#Uo2ZB1|scg0$iV?$$c{+^n_g zn*clw3@)K4c_E2NzbTao6-vml*0Ez)5Xqt1lEM#Q47@-eZpg~J`Y34gL%MixwL~A@ zaa6O%m`Sw%Bk=s;+t|`)leQA@h5-v-rjJN_whi$L5%w#dEv`qZ<`Mll!mD@@8*(Gr z1XHjwL9Xo zg!N0%-NY!J`2s#-<%C|DNK%KlP2>yHKs;1qf_I_^B*Rq#H;Jhsc16)jyIDTZ$OHWX z@i&w4D`yRhVBUB*Yu>Oq9o}2js0JnDKV!@qHv2(IT`|b3;xVt1T1ureG3km%KAWRH z=orZDHu@nQtU!Agz_44a+&hnoTM&sIsSTZMF^Oed13tTYzuWN$w}xOe}D-eu&N9Vw1QZVwO}&Zy=3m z8BoAu4Y@J+jTa((y#`-y3QPaEKGvf|?g$OZn=zzyP{AT-Y%xLuUvJ`kit~4Xy47;V zse=H@jrH$E`I20q=C*%&anLAf1}+0fnIu16ZE)!5J* zHG*h=t7E}}Sed_;L7#rUL%GjdDdZ(KnYD(@iDXDcOzu10AAK5m8hNp)&A#+F4#EQ} z6@*O{4A#h%ASoz>5?)C3ENFUvNyxsqJH_UQ6ev=&SyEG%u&Rf;&+SHTY&l75y zLg3M7hm*^JiITT)AysW*Rwo_h1^$wt+K0$j&{oH4P2mI=!wceHK;3dq>=rUK^P2+R zst#ZK&i+atQj6zY|3%B(guV3bdcAXhscDXf7|Xad$*SG?Y5!>iIT=SgeKwsqBH!_Z z-$vCIrU0YG`R5}PkznKz@&bPul3u&-qAF3Oo;I=cf4w+dxThmsdjniQLlMIb)?mR#)+Z zpc>793`g%N;m(yP+w_ZuuRG+k!oZy3;kv9IwVaW$BXKoCKArk`<51h$aP3(xt!{?Q zx}iL#iq2NZ1dr9|FK;wXfN~^E6?A-Gg2!6oK}hr*aPbs-%eE=1^LK6*$I_7K>7uZ_ zYq)WxR4Om##@WM2%G5eGYL!o2t#Q2$zaG{Q&&|C@k3lCXg z8yb;osUV5AX4*O}`GR8TK^es_y7a72AfVVhVP4ZNGf#5}5d~bytskk}l&xh?35?)l zEU|y;&nV!P*jXezi`BEcGF%H|@}vurQqpRI@pW1Znk$pEumtaqE>+%(Qi1}f&m)%` z$|&CDPV$>&KOz%K`~rj13W7hQv&jzmiHi+wkdc}s#i@u%!apv^4rNQBZhcuy@gS|k zus2EGIrw^@;=+CI9u$2PEph+KxVb=m(fR$;Bu`|+9@%V|VKuB}GdKkgIQ*?70R9P3 zl1lSBMpJy;5C>rIv#i1Z+`s6A#$Auh0p7f&9fT;niO~(G!`w?zdxi>N@?&&`ts^Tv zueRyX9I1S1Lu64lSDx^uNKXg6o@cVo`#!Q7M1Iz^cf$`L0a!APdi(5Y{vDZ9=s6TH zAkzjP6#e}-#(YVx-x~;^sjY*vsmEWCnJ8!lA}C_y}Gvm2((Fz1fm91_vz z)a;Xis(_ny%gNy+Tr(I@?;K}rQj$)K=|vH@v%8qD0^lfXA=?IgMOf%HL}KiBUHDf8 zoG18h$nBw9Q@;;-;=E->3pLh@oX`L0??z%WgS-vOxC;hpx_?a!`J*8oh=yO}+$U>8Dy3BBo&c-Diwy89Y59*LST&Ug6QtXdlPZTjH2LNTU0wP5r0^3hkf z#$ZJnrAMIM5^Q5F&=W?lBf6@ZSs37|zM3a!4735SpGH<4E-O@}>R;Km7>0wFeDr~% z&D#z(c?ZA6@k5%Qj7ntLI$?T2)gxTJ6Af8?jJ7UD8O_uE+4FUld%#hVe4vZG&4SFZ z5I)-3SitUqP~cdn?{i_k`!iQw?@$FRl$-TO!w=N;sqmK8s1q~)VPKN)V{#R`L8Jl z>7sw+k%yj3KZhwT7bU~h6AsG6xk-ynll27WNhB5%k{wN3SQ?TZF26nvum*@gStPz^ z;_B6UU0=cb@+toh_qLdnVSL}AbhnB%{E|@#d?8KFg8<=c>em|-ed&c>y->Us z0mK!?RO;)JR|hQ_FOjy=DA)F=eld-3?#?jLtCq^J@YeQbtS~+L)#}NKzD3<)0=_)* zU_+N*D4L6bn%zIXr3g{S^t!HnN*z2_o-f8TsLD5~t>QhX4_c`bts9^A&WV7{xRRgO zXPigN{%!#)Szu3?rub4vZd#pcjq=2Tkoe4+W$rOD)BC9}Q9$;AWZ3?O*Y0*SzjI8&irk zrtictUFbX_oD$ggZjgiZ^Y?{YFI-T$fxzd{DsQpd6}TPu&Jiyb#GM0C`61+dg<}o! z;&hnnKhnuPez4G9gF4N!niHp8oCR>0km`8HQ&D;Mom$&%wgDnrC8dR0J3JgaauRMr~LqT7jq-w1C!;PA_eAk8A(hg*pcvest6%F30Z?R`dxOM;kIe zR&=DKM1cny{;x>MDa`1|?^7-i7@gtscuEVdxDuixwW|n>FYRBMNMn%J6XSd$G*b-& zT@=2Zxkl{C4quYk=)Qxe3btIC%IUYOoQ~u98MJzhe*Ud+Bk5tWT8=yBuRuD+rlr$|q9E_R0%aW5 z49R<$gly}>+dUj794l;ie-a3DkvVT=JI?0S<>2Q|JP!Izi=;QCFHl3Qr0Y@;Reiy` z@8C(s`2*>}TJ*g1yuyR+hmfJ{VwGjSLlG&gF~rBP!&@L6voCeQpbhTDV7|qyW>ZNK z*@^8q2|g)}vXHNHS0p^8ED{r1-dxDMw5nF6D@xlb$e>_dDQm!C1Py4KLG)$<;W4JE zi<@y{jrrgtKM!zTPf1WvR{^K&=zrQ3Ay3c-1fwWaBNM%uij(>03#>&FQ z$zq^xZ)4$QrVl9d7RWYF)Vh><|yw6SRv%u`&M2cnJFPNLD z$ZQ`hsR$dKTg$I$i$5(&9%u_0OIZ%@p8HS_S83T~_TRHyzs3GQF4?omez70nyuvK4Fh81uQvxAt)a zG@AJ}Tm1c&b5x2k!J8*GR!G6Yid?jTo_=8zRZWBk5Z{es$wY2CgFmm6zD#g0mC%S& zBr(Uo{ghE57keTS{14;tfBP1^R~ST!1-1A8iY|<5s-RE2|S~taliwZVzz+#-OJQvI>4odFS%szE5tx=-rKS$zj~| zS*vSpYQ3Y$J>MO+Ne)5-GUroI&6qoogrbLiNPrEXO&DwJHc4E&?C_#@gW|vxcbWs( zDpjcTN=Zw)(FU7YT{#(w@_;d+ZM{}uJgD@c0k)MIkCkRj zrri2GQYMhwHA{#U5{(S`e_b2Lmgp3wJxR#T$X6t= zY?u4K`5`01vAS|xh!Gwh- zUdQ&sv|H`RiW^9;7}f13lup&!xi@5}hZ{1+xEF=mP581;PGdJE*c60ULOtDD7z#9Y z+4n}I+r(J$WHsUOShr+W_HQX(O*tzOIP#HMoF3919Wnbw3GONAD7m}+3zAozf?HB- zj4)w(Mdwnp&^U%3MU~LyA~4K{#8(t-mfZZGKSbD(z?Xm;P(|-JQ#PkCOn8Fxxrzh} z%6z5RrBBi7Dq=3nJjv0Q-R4X9loL(_`M<^>ln zHvT8NCEokkPzSj5&nA`9ZPBwIw0bklg1;W;JB;MLS_kG(NN(nd$CLt8>P@2xhibzr zyg{~|%o%6XxA@(3bW-$4XG+(^co#-q>1{Df=ToAvy3dJZ0W9e!8EA{!fK_A|una<~ z!A)lDYncqp!vH*g%#-t--tG<#_D1~|0wnul41tO1(^+r3LnebGm)dn-$PK?IsGPKH z7nQVc*BG`KqZLi7GVe9`fWr+`@b;(eovUpd;2WPF^2P>L)Fp|G-;s7j!JXU+#tLG$2b__#g*|+hJ0aT>>9i~E znM;G;Yx>#iF`Hutpf%~AvLw$T92#%I6Te&`?n`;b{LX2KETMau{*KflbL$pOI%E>QTJ|Vel$%6!9 zfwj5b;`-1{k#2+KE?EXzrZBb7d{BrAVH$Z9wS)dtV%aLlY(^cJsR=;~kH68lgDTsh zW%4*a><(qH&PLsm!aQnhulk-=V6upiU)@;QRqF!0&Gq;YOwb*$Kv?Bv_OwsAFRse$ zX#3f&=yBbRkMJ=Zb@;bR~8-eK>^ z@nc8zef^W2Ha!>spn8%a4n@N-?Tv_+Y&rJ8B$g{Q;`c*An(8~%7c4Z5;=+`ZY#ijI+4wsU>7tUuCd6c6UH%=_$*8F-MPvmo6x3@hh@V z=%N%fRp|DM9)4q_hyG4c27z!RkO*7JTDBixOXvD18=dr_<`3T8dU==NlNJA8X-`B& zvOq10-fPT|ec4s^TC^(xRGtb7L*eB>ucm|a2RPOdsGT3|I(CgnY5A-b`SIYIAMWJW zt0TU#M%2sqBhhXC%-FTpmeIz5q+{X$QSed>H8|=N)5ub{dj^+(r)fh&0jNHZ2#WPM z@#dOXrk@^zqZ4%T({Z+0y4#-KQipEY*Q?#oOf<1~%q>H2eQQ$ljd&4&NbE}Jo<&>y zEiIh95Hq0p>R;ydpn30K=GUNk|6k@_ev|>}W{?pD!j5TiQZ#q+9T)+yY z?L~DV5lyk6uM}kQy}`d6HS^o*8}u~Mqm|?^`{@%}*1eR^aYunv#blNA5qrZ7Ssx`$ z{2@oa)1$k}qO*#=rpO%y!eS<;$eAW%ZrjhJYiMWj! zempYft2C2B>Vt}AJ|<2HrTHqDXy8{0e=fdm2(cJiP2ZO{gtpRG7r`-VKH3{4FTPxY z^soroTyX1kGgQB{qOgN6IgBpxDPAF52zy_ol~R}1ot#h2|88C(mZzfbflLWZ5P$Fg zrO^0O@hF?xIeGl0NbNLr!EFZ=y*$@jH=1sS8_5fj#iDhpFs|11+#0DFtCZ)ZyZf3e zL}HRLK-mGy2ix1@{l?+8J(yZ!UQ%z9FtK^OH~xofaNos=Mb zh+cV1;N-8 zMkMS*o(%aajImSP=Y-ZZcpLnHMeuzyTp@ule(-Nl#W!n3eXl%n=B{CxT)CYi@Wf1~ znL94NEa^lB%gxjUIBqCnuyTf8c1ntM&ll+77i(WC_Edy2m2e6?rebZWFPc&%T_YoC zrUJGu>QQX$2Yrow_wAV8jHil(`U}93X1pEaV)moTviZ1CZ90dXj;$HdxcjINYdeN| zSI%tKZmU}A*}omPZ_#d`JuGtOl)<7-$ieE~aa>E;AA+IL(pANLp!I<(vFt>RaVlsa z247toGuTb6U*)W~QHL}pD%Wvq_Whizh*Gb@cgNcia7&&YGgy!)fqFOX*mTat#MU1* zMX%|TUlf^)nNcb&!>BF~%!};Eqs-Tk=x4;m?>9Cw&Ows?olqbn*PkUFimO@}lguQx zE#V8m4hbw^VMP0skKXDrg$_@RE)n=cB41^Tigxh{;xL*F#O@!6pcpqNA>&jao$?2p zFEk%_79006XPIhng9)DHd4t5$g3H8*@P1}A=q@VNjR+3*p|~}Qgdw?jTBSuNQ@dDo zoGIPuf?!hHh!G4o54>>y8WA=#bs&dY#3oV%uJo3hiCn)I36%J_mI#6(rA`|dh}l<~ zg6+*Z0*K1fmb>}AwwFAZ{wKx0gtdzS?iXFMM>!q+$l1pHAw1<(n&~d81no#3HpdDJ zpFLV=ZkR)X5E??lB_hlqc6W3)FeF|%15rP&%+GZ$IoZo7G@?0O8M^Kndv3J%6Jcl7 ziR_DG^+7+*G@W8RX-iJr9;5#UwQt`k<6>Rdl8s$Sv{HGmzpwI!4F2Pl3@$|=FqHM7 z&V9$N>KE9}0v_}uX=Ef=M3 zcq|G~IMa^>4Ke*s(@{wj@<<6hMs)#c2r57%W5v?E7Z~&fXZURvl7@7qB4i++73=@*!a(+kw!M?}Kl2>Y7d&^G(EZOl?)c@OuthgOs)Co4 z*2(MK2M@2w<9$9sq?6YZps;K|MLz=3U1;-71*XDLTeWfF;>UiXOP0c>tzcbkQ|%oI zvHj2C()1uA;6%RE)DCqGbsIvvx+8J`V?uOew^>m3Yc@afe^ter>=@HlP>BQk3O@7M z_V*luGo7?%B7rQb%q^Z~O1(u=b<&`NyrI*f-aee1ghlX}aEJTvXdmu2!FYaZ9_>9F zWyoWvdhw16+ZDOBXio^^QVq=W5RdJjf4FZR3CH&Mxd;A{K|)nC6>|{EYC^xxu!(d)2Z^SNBxv&)0T`BX=&$t(Bqn^F!SR* zw=LjPoY(LW5%HId_U8lHo@l_r(uQT) z>K*Yo>Lscq%x)WB*v+e%laE~M6C?6m+B$)0=Xrbvn%KE_-~6n#emxm(+i)O}lq zpO%Bnhglej^LPn~n)NXrfpS>1v>Ym55_C$#;gnig?IrTBR{%gv3xJ*>8PSalKuVOL z|1z>)Rt5%FxsZ}RdA2t3NKy+IE{04e-kp|nXsIWXLYCGA7DS=viWW=Qj!Pn_X56KP zuI>=%q!PKqPPw!yL!u2IM+}RkNiioa{VpYbE?z_CE#oBpqs%k<@GnmO$D+b?(a;kH z88Ul{ndcx|GUrQ0WZ4PcKRA9Z(T_n?umB>X9FrfVaTdkKJ$UF-srdx)^yudSaY(!$ ziD+$$L%90kWy^))L%$?Bxl&I-#(Z!Z7|m902`1SZikHa30G=X}-$YXQ$&9>{$)-{X zvQW;VJp}RTl~KmXXVKeMu6Qh(Pz4dLKrZkEt%$;Q$Gz+Vo`+2Yq!Y>3>Iszt zpB=QcS`y8g<}1!o*9=P7-7|`G%hs}vBN0>%<+G}DwLyfx+5y_S0V@cr?>CzuCW@LM z>V@keuA3m5v0AFSZJ~4IY@zr4%%F?kF8{pb_xdMd;Xo-j{%lMxgQpEB?f{JfrbN=J zYNgNc(4w*5FP2{hTIJW8N!FPzMYH=eVhiBph#b+3UdhPPSeSIge%N4z7>!kt8Fh*7 zXN%Sb15v(|^RZ6V#=u*RV8=^Oyhn?a-UWxZkWK|SLmVO=F_TVhYk!{iAqyE2I*A<)pgv(mYA z5-mi^6A=x-7;%DXP~&bz?iIlet)52wd^1)(#s=_yBgdj{sj3W2qB%jzM0oyZ>o=}iG97=|SLLJBc>J8+1Lf{cM{)u?%$C{f zRMJr1wC{e9q|pdwXaun!GuqjLTq3Kl`MntGu|k$ty|ZjBs13Xgb-Lm~WwS}Ev}?NJ zW}g3t!VnLrYUf8_vu)U1wg*3g+u(MMOc1G!>Sj4n6HjidRX@`-D|hh31_UHy6)crYQe$dDj&IdRlMCP&X?< zq@;Zi11}o@xX<9g9x}MtrAO!@gT~a6aFi?JAcdW(w=mjMP7=nA^d^j4_~QP@uZOO% z?SDjV;vvji$UzT=9{PW{{6tv|6iqEaWh{T`w2?g{W!J|7dNQudgf0Q#ub9{#MJOi8 zzHbGEDr5vY(2nL_b(}?hukHkNKVoOtj%avKy+@%~ z0N@a9zO#0DOrO_g71RQD)p=oE8GR>%6(z}kpo*^e3}8`a^`Ev;Cg~z^=sYvJ>E$GiUC4XF zpY<)s^A~N73&Sp5L4wLXR7g7JP_5fU#B>%OD{yyL!n;%?NuzKINbwy(rkD1SEwitp zD$AC>@d>yofhUxQrjVW(6_so?#6nPzV#wCem{$n_F)TJHlibJdn(b<$K@v4Z#2{jS z$oo)(urxaJkGsqjcUR~GGIQ#9{w*R4+6{@a{r4_2N+|z7-|A`RLc%sEiTb>3n{a$T znAS8bx~Z1>XV#!xMSBNgaq6T|jxXhEzAZOWdm^k!xe3;*Z%6^#2G;nqC&c}pdqQj^ zya0WdW%F`X=FZeQ&$|qBfQXZDYxZg@V%WDRWgNtq3Vg?vMQl4vh3>?b?2P z??zdn97M6}zr|gT;RBfuJh>Q->qJHZz5RZLJzfigmC3D1YqsDpb+Rq3T(K++Dw}Zz z$HNVGE-S!I@zA@8sDMTN`~|kLLI27mDHT#)OskGeRvS7ldnbNtSRHeB<;#`Ed_=D< zxNgI8K>P!uB^UWB+ikQGkgXqZC=oL%LB``uh=zE^7SHno=ZU`yt=F92>4wk)u1pb= zn&XI9B?D-gR2&U}_jd+*gx46WVa5mZnqi?_?Zg?PbBl5KL)W#x{0fvlF}6c8-oMiGab z8l%n|g}dvS!Oz_AA#}T{9X@Sz6ad@c`~mqE6}S&F)kv&C?xtZ3WjW^S)HB!f=fimq zoFUyPmlt&ac*DzHboI^>#m9BF4N@WMehf!);H}&cS^-p9+^ahONy8ui9*t^l!W=*X z#kGtCe$LcIe4n)$ZTsz~gMu^zvXM`rjp>k{FoqD$)d)ah_x9(ko!&s+SADKAlJTcs zY+ybr5SsZY{yzy!sR4>q1->~7*WydyJz2s^#pqw@bdxSyd)h{~ZEUl;JIFT1_7o`< zTOO+GXRaMlf9;)URYp}`Ail==l4fq=9E0SF%9nIy|IZ=mOD|Us^E^mS6rOvV#(ocP z#GfQ=0u3rb(x3StVUziLxG3A@vgs?7GhWx@1wdYhn$iNvCN~=LI@j;vMJyS98+?8( zNWR#EhPJ)7E5C<3zL--jnI!o1Ah}ln?$`xbRD$H|S}St% zp1x4}$YtRX-b)?>wvZrP$$B@&ODuuLqXD>J#idHJQX)_n>xGa zgYkyLt;%-)XY@>%dcK6&`52l0tjX98{OxRUW1>rhK%b@t2+n@pK*RUq&!*Bo`3^6@ zDNl;8WI0j^*V6W=v0pGAu)-Z8jx!BDxBDU2e{7)-gLTR}^c$w_ z{Y07)BqNmBp!@cp@~i*8!B5CgOmRRe44e4>zY6;sQJl7(5~#hckJPsC2TKDHD>}ac z8M^3(h)foXQ8*P5^632@T_lrcg?7u4?&qh*L@J7OHc_8V@NL<sT0xp zA=pgBjrqk*1d{8+ujzRd>{4&Fb+0Lzjc>LGEJanxob#?`-)vU{Bsvn5ZJ zsmnXcRVLfmj*)D$4czNV0qFJNw9=@miADw!=n?$f@q?I_;C4UYqt5k9Sw*}BWM9n@_7<$}8)U|X zXg}SPdi;v>R&XkX&+P1+Ms~Y?H_2D zHi4Q8pe*GndGBbKZjLrV)xVc7k-raE4p#}}7=Av2S;1#Se+Mq{q-ls8P8P*COG(NZ z;o!Z`Rw7Yn(Adg|z9G|VCbtAie-+kRrO+U*j5xgi<>JoLlQ*hmh8~=?R)Ll#2LFtO z1oq)L%p1b5Lx0>jeE`)8EKA!@*c5?EhY`W^t6`s>%e)M=Lvnv}ZClw?#Fzm;|4Z_C zoaQ9!d0tl`^8@lN^!?NH@u=4%&bQdkO??ATpGSu$vGuFhUQZuT*d0`#v?z3sGk+{s z%}lIdaG<*mx&pMWw`y=Vg|qs5S=3;>7{}qu*|ux(^mq0gyhY!#mFSubEN}K|LB8u; zFdzHPAU+`k@d60AInr6XRtgV|u$E;x^=C)p>VD3S@R}R4aylEa-sR=mkQbI3Z{bbk zaNRHx(o!r#QER|SZ8n~T$f{mk4ftgnsqZ~dlp8op`c>}5fOJQZS;$K4!-~2-q*w;v zs~UrjzFXlqnu0XFMbk&dd~niPbvsD(h_B%^RzS=YuN+~WirH_vBPPZ9>MzYI!zb`U zdrIF?nBQ2L-n56LTGXSGWs5ul=HMp4zw95o*9!?e5dYl`1V;}DivTH?_5W!faTti% z*xTFw(+`wsZ@t4sFqjK_MdZukkG(Db#_$#pv=lSLpAz%ca&(iYTW)S%cl(B*WMRD` zmq4TJwD2cm4K{i!3F7f}a%HZAaIA6F*9iy8D+#^{>wp?=Lv z4}ng9*!iEOvAmRkNU}pWv3P|un1XmS9}=H=>ZTc~J$cXMgA;TiQ|{{{y1n|S5-)J( zRMal!#AAybL>U}ogbKSOk!P)4W2){QH`LN^n>Rb3c*wW}Ac}9a#<1mQOjNQNvp^8d zRF|*Da^O;k%mfvFLKY-~sg2Jav;gk!E#2CQq9-TN&fJ7dqsR;tBkM3fs+87BrQVNx z->!r$De=286o}D8)^1d9dcv+3^6gBVQ_Y2O$S@hrG*M-6jt@emCetlW*E-c9uM62o zNT-{`S4rmO6V{I=58lMd^9fWG@?Ge0zKlx=`w~bQgoe79y($X^@{uf%(E8s#5Ozn9&Q-n*PCRsR>blvYOE12Hx;g&xb9A9& z(#eL%Ig=MVw&j$CNcYFi9(y%fFY`+62)`3r0^vloB~MMS5dliyRt*}N&>~m9n}3Z- z7!8GE`uo(7Z!{!nz-Yj&QS`TU%iuIro&;|BnvfBqeDQ&DMY(Y4LTsmHkg@c>w=V?{ z&5}x5E>2gE5-&M44>FdlTmTxD@)`7wgktLTz)u&})jv;Eoj#?;HOtY&k%p1=&wCk< z0i+tx5EkgSBuOv!Wiv@ZM8K{?DWLivuW7+%A0_+&VH&8W@TlgHaMWYe6q4I)ouhWs z90`F;K&n(UfKgcN9jj~{Qd!rSB6+`ep7bkiFl`E%thD^7xB~=8&7jr2jcy$QHt>7* z;_EcU6@SUPlkb)TB!XWqZrifaU_6i$$O356SK*0AqR<~WPrzH|n|I*@2aJVe63Ki3 zf}1~{uFC){2|3D_$?Z=o+m)P(n{0ALg4Ohn#@BxBd~2WE7u700uA}>nF+VWAh~4!t ze+P*PPFI}xb<}0lC8CF1SB=lb@8QY-^U371F-XKVrkTBoe-C>XR^(T!8Qn5u!BbD1D4~Ez1w%?m=WmHU{58y|bh|6gkHOKTTx{{)kt{DG_unyN1 zhY9M&XA64|IAM*R&A{Kb6Rpt{|K>(vVL)Rel~1?bmSjs7G_MVzF7=_^<{Q4)5u7=; zS+us+FR^HadPZq=@lx`4p~up;Qj2~1OHdjnxVBz6A4F-&ZTWmf+p^i?Q@aG^>LPIW zw~tj#5~&}+l1RePUzGN?tF^D-aE#rUuL`yH#n5p{!~0$0nQ+#|h5xS3{F{8j>p{V< z3sC3k|C=-l+U|+782~MfZ0+q#{!v^6>S5`0!iDMo2D`qM#9ZkX)6Iq%jnk(L^QnNs z?o-F1*ufvw>eg`P#p2Oy1q8Yq)WQ9Q(!zb68S?dxLLmmD+!b;aa+!&jQxt?6rkkSQ zi0udY+a0WK(SE7xw6tNCdOHww_!$@x)pQ=PkDe8j6GZnZ4=do+7F=I1Hq zgqm5wz1j%;e~f)~P+U#cH|{bF?ykXI0}SpG2*HB8y95ZX!QI^-=$hx=-IbRekR{r;q#^?pp)07ES-^sgk!WaSr^!vyaW=0BbJ) zB$JZd-t#suDHi?;s*J# zRx09A+*#%)`Pq=>W=h}sCR{?|SFWGkZmKKpRS=*d1aW2LCWy4kmlwr@8&;j6?<~?s z^?7kxZtK%6`Gis*TfW|P!Vt+lU|AdORxhWgw%4jQnaU{Q;xLaTke_xx0hH&SVR#Yi znZ%L2Thf2$#!tJ7`7EY&j}IAaF=u5n!6jB4C*Wr2Pd&_COSBdvDS{8jD#AkemLp3iZz_PAR6@&zEe(7~ zi%GFo7b%3o_n`;_?+aqq*`hRoDH_3A8MeRye)tjrMP;QOc=|pOpqgV!jjb}A0;9wW zb-@PLs3J(O;gkE8JN*+^(~+pGDMH$^!dbGc zFaaNafUS#g_zpz}nZPVgh><+%gE6`!-ziYZnl1?yXI(U=qT*X)jiXZkm%&80DPEef zw4Y7pTmmt6PyINaa*Y(+2dQ**sYFE~yRxGJ%1WxtF6OP!cjSWk7_YPmuixFdMwBxO z)tm4q44se?M{mCBa0qLzMR^snW`a0}CEBJ{JIn2Eykt+M+uM_=T;Y%|QIUxSNvYOj z|65W=W8Xc@^^jlo+}Y&=zqeV+e&19-fLQ`MqVqrRmREZ_Sdq3YYVhY)DxB(%;u$Aa zWRBYI0g*H5OyuDoR-V^t%g^nMds-d}wj1`71(yFqQq95Y5>+rlf>O#h z7^fm_Gbe2@pOB}oX$fqI)QkM!F=JSgwej|wp1d=8FdLmcO`O?P^#~t2)tdiRLzF!9 zFxwr$q2;!$jQAE_$_n$Mm&|HEXILZnW&;Haj|tD;B&A37)v}DXNm=n~Qk>`@z8uRN z@X1`yzdJg`?Zno^p#C&b;D7)0-`LoDLKAMRom?INM_u8M6eY(HPC)n{lpO=(5+6t^ zIV|fxKz6XGRTnf0(N1X4vk}FY{4n0#2?PZAD>HV+x+%ez0FH=wCCSX>Nvvjo>Fw7q zcko58q>1E^(4&cQ(wq?qK5!@hk&s@=mOqgxtHea5Vmv=uOg zqf=t?sP#uEQHjJP$q&^cqw~N;`;m{=hltn4bzJbBs^snXwv}i~T+RE}aH+I2#_GGD zJ~hI+c-OplByB0}oFA3^a^r*WX}_Swgm@YK+(d{#j}_stGY1!WC0wP-ycscAZxruU z1?#l1p%E_VGS?kU$HZSFy{vji=0gBC$ZNf{UvN2?v{m@|!i z`xeKG(&I1cij1##`Uf4$_|a|1{e$HEe*O)MZLvl$SOIEIR*=EKu>Pm0;@{-2wABA_ zxn&;t7DHWbzt!3!n*5^=#8?(;15JD{{J+E{)rYtctj&K8p#So1`=>n{(=;vC@dxd= zOF~8(4<96KZNBmH1C00I8LiZE#XP=dIcmE$+J^wI08BRlEqua8pR>g z?a(QpBO>C{zR1hqd#y9J(y9092pS()Sm*D&-w3LVe1+t^_iYb${cHLXezo0aJGaWG zF79B`Mg#k?D?g1&#l3W`_7NrRItS)izV#Gbi-?xf*IxI2T|eFKopS0Bb7-GY+>dul z$0^hI4R87D?uU~i7Io^~uM&k~aKrj8Vq!t|Q4W zFYoh56)3UUA${k-*;Hse%11y`g_9w<&WOi=yau?vUAal;IOD#?Ca(-ShMkAzAZ(zU zQgeP0FF~Cc1|bML6WvT6nPcu!dxO+#F(YZenD1LkJG*hndI-er)x^_H$dk3R>(QLa zKWB9?2`!{u#Ifsnnu2k_NTs}qlFOcj$nmP<#nh^rYGho$?tpXhZ&>c zIT0vbe!HN27;>AvP)>(yOmKpbkawdEfizUR= z^KPN;-}Qn)9OaM%R3w!`MbdvvbdZ7uz-$~XJZ&tzr2mIB(p_=fJxtr%Z=~*t`O*UvUi|>+JFd9B$K#W*Jlt!8x#iJ7GL*W!->(!MD{B2O& zI*u8J7`LqM#0e)jwg|687=FiD`*RW?jC|43Kca6wIu;_I*FG6v&H)4X?|Qm-=|lKJK&>Lrrl; zeh}06PE}F=Ig|Y~Ob(3kBb4lQ=+(nCbxtn*qI7j;=E{4P9yzX0+TERRlU;R>`)9B{ zx_P6tE%*T0y_B|PI)&BEzve@#PJZ271tDrJ4me530x1JtHr3TsqFVM|v3$!gW<+yT zxrPl58>{OrfLS_ig?S=`wEDdyWPjrm0|x>vB|W^bR=;|Q_KY&v>XqK0J6;rKsWN&g z&AahI${cx(AMhvc7QaCp3K#K>DcKi!zcxMy`*e~7m?4hftL~zl(=fV*j^`q{OgG$j zVgh~G35Y|?qPQBDLlcR@Y=C7ZS&j)6*rJ&5J0`&xGtM+pRl`jUlBTciLGKw|q;?NM z6;aY{9?5$4YrW=-Q6!o_Re@IINnPi3QDqEqv*AH2V^rCELZ`9`NJ`7Fo_zhkM zy2FrhA+C4WsE$+($uv`EzeQzp-mr##|1{`8$3SG!FTLwQ7oJ&y+LV2YWZ>!*Lbo}8 z9lmc*uhA3;QB8VEly79PK_p$ZkNFJD6kn|{=bU8QYn&9#GkvZ1B|j}^11-AIaJi{(l65eF&k;MUiX z`@P$7iB(G;d`I!k0R?k4A<{JpIX$>5~A-rONsy>a6n@gk%W>UtrN9O9bGmQY6THPfd&F<8`9ksi9ChYJi2eGi$UHS zMXi#-%a5Q=XHo<&Dh*N^`WPcni+$kPA#j_2u#ZA6L#a+!W+6<>L=z%i9`<5Yc{7UZ z2e*r+gJz0z^l^HDHs^FDmpw&{v1wdOqNF^=zMbgo7y7^NOLb2gPW_>Q-m%>O;=`Bb zG?MmkbhL4_`nMwpb5fT*i-nYYV#3mKx_gnjMCD??aIAaD z=4e;n&;9<96`Xa8vsvMqNazcj|6}TK^>DSRQIO@p-}z-RJ1UwU^O}UCdFoa}+nSE1+J`@V@e5PD$mBT9QyB{&gLEs~ zPQ+Iub-bo3#;=m4TIgn|B7nM2?(*U4D^90hCNIZoXQoeUeyB(ZYBTPDS!Md0Ozm;a z)Nhk%bK?fpWm#`cH!r0r){;b`Y9FQvKk^;L2MUKeI2e7ILH9@!FslbZ3`aL-Puzh5 zu6dM8r2GocW{9=;G}HJ|&h1uZ)CTb}2v-di_ut?nYobBl0N;mWap*q{F)1f=V$Qq6 zXu!8qW1%uc4u6hHSV}OAl%=-Hc!G~aoKg5JfCRt}biScap;9hdRk3Y;1)pq3?dueY zI|V57XHszrLSgKes6lR^kVZ~e;}16D<>a)(0HIJw6rEClpNn>;0M`_AuD_87FW_S- zfi|X8@sAm%zU2F+{DJ)@C7%Q4itEDOy~0^4&~cx3`k1db-qT!$MI*o)OojV{B@$`o zSHGtHN43OXT?b~;!|bKqkw^gaUJt_w;vuA}y6R7`gYd@+ZG1##p$s(?!2&z4?~xKd z#P4_}v;m_hU=No;n^H6o0@I95(elY=e>lsb#w5U~eHmN@VR1cS9E_hk%d|=3J3L+X z>SyU#3Fn^|KBdOu%VWEfAK8vf1jCkv^AAs)!+6egb7u5ikfd@@?kJx;qsb%zLlQp~ zKRcA6-+@%lp0gu4E(691v-2Kt@FBVsp?i}dkML%6tBS*i! zbOa;Ep>$HC%hD_kj$)4301P9bpN*pU((&+RX%2@|Imb`42jGqp6s&-9Al-J39W^ai|$sNCThY+l#@-sbvm>3p-H^BPD~xi601getER1W>0z*ZUPhdS;=bz zQIu9FmMuMGZMRA}pLpjEQz!44QWjQd7kY3Pm9#Xwho`T!5$C1Sy|Y za})a!;RyGBc~Hki1O-u|shc;RyDew6GTzKCKa{6V=r?KGJvS+Rh?cI5 z)yM2Be>t{06>XNCUwXD{&uY~Sf>HfW!tPr=G`jP*ND0~Ls?8v@Wbs$Pe-q(c|5=1D z^w|z@Vjyil8D9XtTfigqn6G%cR&Nk_l7@(Zh`)aR@NsF$8=)C&ojV@ChmC{S-s#`z z7;(RGwESXq-$j{+O*(+vqa2U@1An!D;Z51`09mIj8vR3s2?P0nixY38S|m=3G7J#t zjA7yFqtrgteyE3;1bdY|TBQA{Mk1A}Ne%08`JolVU&*GY<1! z#+66&ty}_q)h*>+a|@RdgX$DQPQ%{xIddi+U>Xmt0X3zx*nYPDYc?A-V)pK}k^;BNtKR`8El#0PA?x_BHw|h zK$w)4;w~WXOZVruFH;hQyq@OV02MfsiaCh}Tq*BMW22y;7E#`8g7Wav1bX!*CU2jmk3H&f}ngiVMhlS;uC<`jOWS_Lq-`dD|w9E##s5c3msI6Fx5Q7lDPT^LUhd@sYi zfthlBQOFxSSE)YM!=VT^DM$&#F2zY<57UGT&`?x^FU5F9Q7rta&SbH@T=L~NMvCSo zE%g7qDNG4AN}01PNC}~oWKP*cDL3cA`woRQjniuo_KHR7$^G=Q1?;zXR;$cm-%abK8@?s5 z@;3tG+pi%mArBJ9gV1{95kb(X%02pzt{?sv8`Qe#fC3YE+?fU?o_->#lnzuS5BcRx ziTe<#7Ip(zGn4+rf?Sx1O9WI{0VXlIGDpU9wS>2EiZfB+?KCb-6Ck1y#N!!OXC_sI zJiD;xPjcYgq$4kNA7qD*Ow7hJx+rc;AoA4}Y=%Ug!0*3;|O+(!mDnD8K&aOPa`Cgb{H@x+-ydUo8l z9CCK6FeQUsS4QV3C4+OUbkg*;8fPDusBr{#r-*U=9bkGJ8LGi9Fui!-pyChDX9RZW z=;DqmbO@ha4KBTH@Br-W!}5oRBM5q{YmYX+S?J}T1{XVs7U}dSQkY8+Zyxz zr#1eOZRk`i3$<5i55&nT1)|K?A(j$VTD|q8e3f%_q}qBv5Iq=B4Ux-k8+5eDO`fIDJXZ|TEv*=v2VZeICwaIIOfh4H@|u#hRhz?x})vw z4{!7UEnf2!gf}|4x=O5@1MlrWcP@2Ee6v@!7nYSN>rixtz)sCQ`7|lI{5U+&?R#|I ziMQ}0oZu;4Y|oM;X5g0(l9i|gIA6VpqeN>o#lAb)Tf{g3t zY)v8y9!DoPl2ZTb4b1m0JhW*T{dLdB_^Y$hlhLLh^ z8vJZm)!MjOmKKQ+cI+{rntlHhy0uo`(_NWTtMIYfTd{xabl>653y7n{qk3q6CxO2% zYRS?Kzu)g5s`Qh*>Z@E`guYz2g&Pjql)Vx{@S1Wcft$3;Bsk;JxB0D$ERdR9kh^4d z@Va;={+a0{BN9D_c1$d^nIH5THB(y!-;wbWg+X#y+VGu1ct~7Sdmy}jzqAeujdU?c zA1PZ!T1k)LLsQhODm|G4=PV4mLlGu!+!Dha*Of0VQKK+yQ7UP&BfUm8!0@0JUUVU^ zYdme-P`ZFppg+Sd==POGoD7+2BwmmOE)Fz8Jj9R#e${DK#ICL{h=4P^n^UZ*q<*!GBFs>x z5{bs5gj)UOF`AB=t!4Hu!`yRtu(hL|Jo%V!XE&{pVtxsm^*rkYIgO@2eC<`CZ=57$ zvS2)QWO@8p*lqzrz>OTt+#^X(VC%bya)lg5qXiU%rWfB){2aSgtvjI8-fNLHYsO1z z6<)&&63_mjmPK&9XH;&LFahbA)I;BIeDMc-aoRSOMnB@|7i27x0qTK5|82l#nACUY z5$EF>LFtxVKtS>`mFcC~WfS%T_1EnPqGzIKGLnE}&j+8iWhz@ibHOjzWJO<{BT2A` zvB*gxzP}}-ak?fM#0bC$xPuk9Cw%4%p$y5F8o=Jd5_ftc8N`ghh`0-q@*~7@`SU!f zy@c=4Qa@GRhlKXU_f5avmOBfkG=VGa_u>T2aTcmI$CzI0o@gxc7FpBQA~f z`!*%)5O@zvAWvlL17cZ=1klMH`y4ZVz}`5cPck0tKB9eIkZK&!Uh*}FM%AKtr=$N% z-w^w<;lWs?^%8wsjjijVUymfLFpexV3pkdYB;0PVXike>>+yqC@|_ZySUo7hM<2La z&8qw^GPIDdA#*Efq&ZYS$-3$dwm_3{gvaU-0YL>@WfLzls~*s*Y49}B9S!2IyP8zM zoS5V*ZkcJ%x?k8LeQoNj2b@bovE6YbXlYlsnyrxoexajF@QpNo14Q%>vz7vB*vTZ; z6e&PPYsaG1IQHDDij;pfX@P$t2Efu}+qXlWm|u_tPQbbrE?4-KZw0XsY+K~hV)lwZ z!v4E20Or7Xtrn_2-J$C9f5WLmW7INyMpE`Bu6Az!OMxmuElB{t%mvYD`kyg)iI+QiJ%cr4WHT*p(=_E+W<-_GCF1_Z2A zZvu#HJm83!U|^eTR@r%5JsjQaU`GYpr2OGUA7T9 z2^j2AS5YLe8Rb#hq#$IO;fm|33G6v31>`>tC4dR{vP4V>$Defp>L)0x%Zk|RQqqvz zv~(|Ze`FP%6#V)~eppQ-(jPatbRQ_m4Vl zcmAVJbt1;K|ESaTztrj1frHO~c=G;Ir}I14+ke!l(_iZJhqKSCe^aM@|685ja3#Rm zK-atjimCa(fx)0_F3V*k>0#>O`uB4yQbZg>p`pnq`F40hBAfRC637Tj;JN)5ohb5M z70*Ui-4rxpwBOt>oEQ@VJzYKB?hhUqd@6t(qt1DlfIIdIBZ&`2hmS|)uOeSlgYr?v zB5}APUb82?H&z@^DNDf^lsY1dCT);FWqgmYq!f03lo(|NKdO$~@5z~fMLy|6#n79i zuBod(fHfHCjTq)HKXfK-gPfG<7rxJ!(oM~uP#va@fUB-(Ow%F)L8CT2NB8^&+L0gK z!>JI5izP-2u3%~g5L`1MW$~j+T9#)g^m}ZRF2*$H+eWWlm{WJWL4k`iFIZJe54SLQ z!dvQIq-gV+n4LySnhV9!CgS;$*Ao)tevEL_&aSafCaIo6$ZUa8EQ^Wc`th+1=~{pq z^s^#c{rgrFtJcSNl1pFX(;I#-((@Ve8|F!-yGy4pxUaZFBH5e4jo@pHjs@C|g|hLo zaXEKz7JD}Pbb*qWboyuT^+LzrvB$g$7K0O^F@r;@|787eLm_Io|M7|b?Ua!$C$(yM zyl-3C59F$iPQ1(;kZB3mWJH9zl@6|!EEUJ|m=$4`SDNXXb(?BE7%2qSU2O~>jI6mb z<0fuItfpZ7<_feajJ7qcZoJc`cI-SXKRSK9V9nkzKk0rCPuM?xDN3fcoruj$0+gnI z5Y~D6(5+hDDp#yg>k)(jNszaSR4x%#a`uE}1mD(V4&`Kvid(;47Ydbz| zI*UGR(U?pts14rLQ@N2T<8j`3R~{p{Xwlw0cy@yAQJ4P2yo@!4J?==Rtcp#2C~MXM z*8@uqbbp3?z|21#{%#OO{|P`N@9e6-upg9P`4bHdzt{E`!S*&ymy*@iTv5J9ogNL4 zXtvQVViH{>Yh&VOd-JpuDoBPrB z-rA?_cB0ju9n_cU5GCQ99W`Sb$9a^46}r5rhhh>+2O^+}!?3~A4ZwR$q?93#Z0i*& zT9;}Iq}fkS&|6F@%Cos88w?1xrjIlHpNi;AKu=%#K)(D~Oxh+Ddwg4_Y(g z#`#i_7;8v;L6xzKbf6SkZ05Omh~owzfrT!W2iF`U+*?=i9HwSc={-O~vXi*CjW~SUrzR+J=`*`D=_>^`@fnZBj&zA4Pb?n0*Ab-MaT+aHGVI%zKCaAVmIW(4u#jE<8d^%Jtg z<7~?^i0>0A=Nj5xy2)Iii`t>etD52&S-j1rut}y#irhbmaa)5o23EDQnPCU>1{*bt zVyzV0F+M^%_B*)Sb^o$DTonIdbv$yA+Cj~Z=r^aU8o~8xf|d!9`tMrk3%jCe>W7Gv z2%pmCN0e*jj#dFzR;=m44$g(-zx=|Nh==OE5`X2dsna} zu4AYwfmVS#@7hSiZW&MTCR^l#(-1z)fkH>q%$sP=jO&=Af*n3kW1`B`77ZL=r2h^t z;JIPYD}6(5@t7Z`T0VV=%G63e)uy5R(ygP$IeU*S{N^yW!-p3TA;Ea#&9$}l^tW25 zrjUU^C8!dLMEy^O2UMy-L8i2zK?n%yZ;djUEoVwm%u}uS!hG%`R%qDK_k~6 zG;;QRBFg4h>>^r~i6AbaVZ-~U=SdTmPg{ph)MLja_A)sLIFq zIBY0BBxqrCnJmL(wXCnqOyEdiHpW9D;Jm*A;aVBB%fjZmYRA|X*Mp+rQVIZ(1?mCn z#$$+ujip*UTGO0)iluKVeLn|Fqqt|g&ZI^Yb#EGc5}DFw+Vluhh9R_l@I@TY3rpRqq=WDs|&yB`-GS@k}16f5#!EXuBFvM&v9c)VVf$QDab=;5lsi>{v1OHT`dX& zwI_>0Bq5WEFxYEV{gqSrO~4VyW><^A(b(3l-_K9KUzWoVh~p*skyePz%@T5r5>)US{Dk&3g=zYGKgm_fWX;tefg+rKDx!0TH{|Eu9oQ8D zemWR{R3H6rEZsqQLX#wz8$_tUCossWk^WJQjRggP zVo6TqmFKky(;FK>ci4Dc5I(=bCm~81RXMowu13z(1ov=dnDN>%EX)~_ZoQ3WS$_he}B}W@{*B9Rx*sCmM$q$Auy5a0lC_kTm5@N*&jna{5}kdQxBL> z!nU${Md1F|scniL2Mkg4P(sKgsXg)mw ztw`%E)2&}bzeq@-^IDGZ1j0B;V!e}`_rm#@7s^HxujsU~!AdX#c~)Z2E%q?;9(v#fO7?=z2+W{3$r5&|9P$a0P9Qgr+SuI~=ril#4G6ozz~VTk ztU4yWZhx)ffAXdZ&+0&I(5s*Z=&L$v;_ph-A*7|)$inxvP%{f3GZ2_OkVBl zufdX94%AGHrY7tR2XjLzLR6LLFM0(K>Tc%b6n#@m6du*Al3v3IyGy zNU|)Zzt_q|!jJPW)mJfq3%Ofxwly--FmWifYdCJ8DX7?Z->?p2_o?(je%9%UW;iiG zGY8*{Sapp)Wi7m~)+#PFsm2viU(;p%Pb0WF6aAWVN73dj1q;Rxa;d({0QR?e z(qsVPSQ3_l-R(J$akmYjwClm|!B5 z;4Jj-(ToC7%=%Tlr-o`LUu0)+UNZ1&?+x$q~!GS?AC?nLyvdi?M1g${7_NvxFtC6GDJoeM1eCyD2LxLW1m*~6m`pN`b7YMu5SHjC8XSED z3`(FxETCcyB@hP1ubS3c2%{GU!#7mY2zu$={wEOVzdWAZS98P#P&o`o``_Lkf&cvW z{KztNT9t?TJQE+V@3z@k<#J%|38@XnZVL1ADSZuawANOptkR=gV|&UrIdU z-J`k?A-E=biUdu_wa!A?6MZF~JoCB2DG-+{l`}7QNv5u|b(=rEoSlH*_upM^UswoZ zS%qnxgyn#UEeX`)T(F7yh>$1)dQoXFQBF3%EV1H~b3S~NoRh<90K64%8l9vVn~t_j zd@s^b$cKEuxZWfd;q}YwamMVGNKX+fh@S?l9QsB`p+OA;1^MheJg^fvq_3O;Bf>>! z#?{=Gw>;y1^s$EFmv=>YeEwLp6%NLnpHFfe!8nM3vSP7BBT)&%f71%X zxC~kLyA#uibb6HAtc zeUC^ASeKTDE})|_?5I-P29GpG%Lz^*CV14 zF{EpJa~}Wk2LFWK8d$_^MTA9o&BA*S*&=-O=xZiXOSM^~Mjha{2GsY#Cn5#UVTy4+ z>ni(1qo)8L6Ey^lh_m1dWW2if*0?p@Z`)!j>@-dy>tVUD?OA|RDQR*9IzV(TrM75K zoB`#@nF?4JY}Oi_vR5wJ!;N3kW-`DZ2JhMjeju5XyXTT5d`HFM3xZ%BZy!bRQs0O| zbB;)))QNyjAo~CJt-oMA?u01@VxM9MOw}u2-Y>o z_Tq~EFzS0f_iW7Or%eeuy?nt~g*?YJsW%gR;d$*fYA7y2lA&eXfy?k@q89{F%{Y(H zMI`vT?SJkl%uV#Zzck1ECXChAVHWq)YWdFirnH58yXj?CM>_y{UrB}1yFQh{rG|!Z zuPRhmJ4#`y8d#nrLu4qXL{vvFjolK0N~2&1T+3!%ms2RvbitA3i)u=38(|0ten)o} z9op8}V9=@?*~WnGv9y&rP47rQP7&oqw-~fU*N25#X@y!195&IC^H5lrxK`fXb1?e3 z?JU;Dhgu8$YH&73`i(dizVmKTSF)v>Dgx-gETz+}yC~@@Kq&EbkAE|iK;#+1o?B8N z$EcgI^8{3(Zw-EZNPpd*+W9qIrs}tOVVNNzNGR88+^6;CpTWC-iMek&bZ=y!ft_}V z|CA;VH8~~!P0T_49O~K%((LZu?mu!2?biOtId}**@*M;0xX9LHVEGS*1n|_R&u$sM7L$K)LAX4k>540Zin{h331UljK#)2%lN8F-rhf$O*ftI)XjnVT zIjOYCH%lYSNW8CL178wKH>OoIDYi{LeY*;Mt)tifwhbI1={eufBSMu`1; z)^BcIn6yH53>0Fs^C7hFu&1V8|1{<$NrPvWtCGFpGWYL%)=J)SE(x#3wirq#f?|=o zB*z`a{1JEhnH-G;*k0(av>G1}0SP$$Eo}YIcUVGgM zMm+weX^x=)NgDTyg)vaGm~A>#-o3r?f|0wpnTGt-|9rP}_D)LLluhq^!{rxizN%A` zi!if31aWcNLpbvjB>`+s`Q9|R76GB>1YfJ~z>s?0P6F1TH2F;LwEBGZ8bujTgq={T zFY`1~-Z?$0aKNvy=SH95*{m50L`02Ejm#M0ET23`OgA9OEuWMYg|LnG2SkAz>ak5( zaxV;KT96!8)QqZu_9bra zl1CDkKfnqWyZX81X$m!bCVWBPN#>V&7}xnTw{W55f?v7@Lf&AUM9%x5X$W^G!ybnK zAN*&aCs8_qaYLI{+;d8A&Z^IXjHis$+)&G-!&AEuTs{hj1l{|1CXb$Ge#@g-v&S$WrxGm4Gj4;kSzjK0kn4q_|7z+fziee-Fw)al{SYvMRfpMuD3r7i@Y3Y( zxo(Une*0u+xo&bEUONi1)g4)7ZTpI-$1{(0b4c)x4P8Gw%)PbO&T`Xab3M4i0>`dt z=A2+XYvl*0SF3uD=9Dag-zA!$>-l@f$@(rhKv2Az4;`MNqDkZ z7!fSjI8{nabxO*vb?jHRx~9c;mQmqKs7oRGoBj%KxZPCswm+&uDam@0erWI72z><9qn3AQmWg*g z4m#Xp^oCC{-F2zKPye`89`DS2L1~_NLb$j1+5j6iw?Y{)>H`f;kG z=kjxB{V;F-!-r|U1;}7{l-t`&o^JOtsEL_YB#$V@Pv(bk!+B|7!0HCAqoprdBj(CG z8yG6mfYeVGg1zHhZr3{$=S@2OhI1~WJtKr$Uxc`xDJh-sH{#IyN;=Gi7Wha>TI5Dx z;-saUjDC_~>%0s7>5)k_ecW!yQ0Dg(k~q@B%+ufemd#D?9L=S(nqa=SF)xpoH2utd z%-h#W>g!tOjT>`SNey|VZe`SIlR!n^0grsxkBaz3*J1fER6CN^0cSTZp2 z+^p3tE>xC&Th^Vn=TFwqnD_fF#2tVMaUQ;!Um3U=E+J3tXEL;*kDUp7D|@0iqV=_> zR1(D~?JW#dAR^%1k?xQO+jYm-Y3Jt#&)FAWKEYhgvKp|YOo0$bW9#f zEu>HnlOWI38ymQ$YJeSKEiLZ~==Y@>L_A>_bg<6K408u){)kSX3WmMpjm7hva~P>e zEA>pcQ6E=Zo zg8IXllUE-u$q8(}Hqb@BLO_hQqo0O~sQXi@X&~45k=Zf?Y$H<^tSMveffMSTL^RjD zAD&v8gjs|@nhR8CA$rH7K^(eIr?E|QCagfEKGu-LVhL-^ZBvR0vTgXWAMtY?0B4=h zMa{F0I-veRlq&)6mkqSyoh(;qY%+VYmTPYJGYbPsjXkzNb{y`R9aVbe;>$QXMZSmpO{fS);TH?mENoKP$f+!ZQ_~&Cj=oEFtdE6w0sszpcMwoQ0SdsMgcGWui6BKp zXFH-gJ zPe$xNZOq4PRI7N^h8-UAszh%jpAM|q$+hu#Yv$xQQGR{H)JtmVl^b=ieu@3>j;ba; zRu3zvqbdvi|0MRIhaCOO2LHdnCe9*$dBY)u)h_{%P+QQv9qyt3gPItd8|poWmWeWH zFB_?X`n>Qh=~YwXl{u zi>T^=1iM6CknVHMgF3T)j0L)dQv`Ts^hm0TO!JM7LJ-Er8=R8`QA;i{leRwR&em9l8IWM%CsG7XnJj z&lYC#gp|{3^e})iOF$Z5Y1zu0M;hN}sxV7kZ4~+B=6KbxY1Pfj2R$x;$yXMC&X`;h z0U7E$&xq_B5B86mN7ol8&owtqQwQp~;}=U1-6N~qzb9-MeGbmMfNE(B*Z<cth!hK6 z^(UU`+&%3-JPbzbv~D?DM*mejR-U=Cxw=V0a5D}v`pSnwEu<8eJd3(M#y-qWjT)(3 z+1g5z9AEw+BbnlIR=QWw!_(zQ72n@s7m38(aEc{H85S8H+a+ku7Ho8# zIEm^*_O?7HQd-A;a7z~1`uT8YIfpusXZBV`{v7bN>3f47?ox1-O|y3h#DagR$ydtA zxjEFApLB~=is zYEk{A7y>%bb^|%liu?r2K6?^ADRpC-PC^ecuoFM3l$1)`at!2$So9OIh=6WG66L2J zoDUmOu_xUD)z94Y9OKiLqmPFpA=46F(-QvZkWR&Xkr-=9G#~WnJlcjO$@(MtP&;aH zK><$a875xa)4o={5TljFDR#eXQAQWC2FfHGzF53(5|esExhB1Z#Ia=(!C|a1_AOJO@$jZt0gfw(jt1dZ za>C}Q6`1UMPheDj0B8EzP4)Bf`+%R*(>L=^NB7eg!^`kwK&%~gS^KM(!B8dNKDeoPzO{wW3vF-ffl_!n}l@jEgq^<=> zvw*1vD4)UG@fOcq&wcqWFHGlZhA2V+SSUoJD10J34j?vU1O(8PL5TwN=VQGv;exUV zK@TC~6gTC(p$jyjfhbVE*-ii)4b>`jWG7uH|I4--@<-2a`LW^;JX86&H|6}HSbyD5 z6{!ebT7nm*sOQ@h%bFumc+pm=kU5-g^8`Ec_<9|;m}TgSK-=dOD~?-`b3X3ql7(}F zh$u=fYec}<VBK@-MuN)#gMNNblIP^cTXIVku#(s4+fbIL?u%n zr^euD5N2ZaQE`D8l1W6n)*~ncs!yrXb(^%TVZrF9cJWxN?w={UTc6chE3qO*Z z3ii3*=guqKl~QijpzoM4bmMdn`mOP9XaeA9$5>fC#IK01Mi5mvHTifnV{u3NG)i;_ z&sRGuQ)wd0Bh!3-NYWw%#|;PLP)e}`BTz6uz^968nhbt0tE1&R)kKN*o>zmDq?4(c zGyxYu;MtOva7t(*?SFAnkL2J8ItwA72;r$4ml(DeL`g>i>A;qH!6xOF%FPGSj5e5xeqY3%wM|0T8{g8OAGY;DmhZ4w_~O~o66w+k1FH9^F|PQh&8WW6R!WI4i5bv36(f|%veVuyH z3UI3F@Oem>Qst{!-opQ*>@CCUSe9^M+-2bw+zIXkcXtaO2m}eP3GVLh?i$>JLvRnl zB@jpm?hbbr+2`)F&pqdPzK{8_)|#oVe!Hr=r|9Wl7_R8s3sbiaT6V+Q-=J#2}$55X^NS2`e+T0C8pyZjwDzV69CG zbGn&TZF+TAX4L47!{G|cyYd&45dmKw3P~|&iq1NjFTNWmD-+r&aL)(dMp4eF(j@o{#u{~N#m^3Pe*QA~W zJT%aLJ5SzJVg6er=Suyi$6v6?;lumn=fDE5iS zQb#UqT!dxZg9+)|Kub^&<6&M)%9oCo`S+rnFyyRQ7&LIdzo%Zhmmc=w%bG^v_KR7F zRdX$Y(EWhzZA!}|B7@Q@Orw^``DdTVj$A|QwWw#>VNWqBQ2VvWmfC$SkTDxUFA9?V zbj(0v%SomS8;Wa7Wb=(b1tlDx$W@L(bnLN%``49d-PuW-Sld~`f_mqoSw^N>P=?mSEcM;tGyF!uTNk8h6E;$_^0DZ15}D{nK_)JN zVaJ2x-(C7Y88X+y)jwpIZz&wrY-kL%Yni9mi=8m3c&RW#3Nyrk z@w{(4w$OU26d3foCqs`p+D@Q_k2xOhf7nb_0>l3IsYqT<2ZWF|zCz{@sS!9!SnmyZ zZ_eJBUi5qCt-*UhE>;szXg@>&th4^E!V{vEBF^zPz|@cQn!Y=R5z^aq_X}8c&!F;e zxG+GYro9XWnk-KUP>4H4JiSg7+Iyn}N|>^D^4GKA^q}$~oFZ@wLqZ!56|aBBSl2>U zmx!(g+&z#UE&54qexg5a#9ZGG6O%(zkd;HkNs`sUfgmwJg2;RYa|p&{;hlK5=#Rd! zvY1gKkmC&4bcqL@Nl?y}G~I8-|SDCL-WZW)g=fO)0ZU5x^`!B8pKP9y*H= zJ^&k@8xbl^7uFI9{N!|)7R4ioQNeJ)!7ZVL;ENXUe4)t+1%V+h_99edEhVJHrm3;U zZYzcOa|)c@r(LLf`|;KH^otzP4$c^d>>u(3IEN-J=9_Fa*`zS?5d4d}P3ZFR@Ia&0 z*lY)p_}YQ*V#UW{B$rNq=Sx%*<(<{7V3Xw2_ohX>B-F%$VQ3BKx9Jx!b?-owqrBEw>rk{MrollL5H4zRNE+e zq<3ij;nKTIx>X7}@)*O({Mo{tZ|jy6>fayua>(D!uDJ$02rSP&4rY0gH!!4%nOu4A zchzSJdN1S+?p7RfvkpZHM%w*6x!n1W)m6E-h4l%*%Bng@NQjsJZ7q)k*S|kM{&%wJ z%w$!&OZ3lWZgNRdW03aCqlJ{ANKLcQugdSF*0YD z>h!2;rDB$jp4|9bvZV!As`w~u$x;SI-nO8>XnLX$%L0X(97LEv-;zGoU_40 z7cUN7(i?m!DNt%U`(ULPASCZi#bM4~SD}eVYO;F-*y2uRbA?H1aiv$>(~slw&uy^3 zk)c0t@^`3C8Rh-BhA3vuU7etrT~+dNI;eKy;LDeUDibobhBv&Q?Rq}ENP>PTZTrP4 zTq48Pyq-YfEyv1g3PFtrtH$uHtm2tVF~{+DHQGJiX|uVc{z&@*+$LH6u!FIIpUT^h z!re=lEH$0lQ|1qZDasRKp+hQ{nRx0dZwTMsLQBDZTK0i#X;JK?*=_E3cA2jb$3RD# z?tCxh#+BA>1VWRx&*;Ay`JJkBnjSTr613DU!IJz+UD9uWL^4oiQv1Yx&KhN|7?r2F z55jgvN0SuxwAmn1J6B=L=z=ulXqwC`y2Q#b`GJ6x)t z2`LH{1i9#LRwR>19S7L9<29d29Eb^IrCTI|XB>heLw^mKR6(PMDF3R(4LBrH3?~qj z5W8EY+k6n(y)3ZpT0WX5+X;9X#}BCneNj6aiQD`xla(%$u-|JzHkzMH=DJ&)Lsbe< zZHv4)t!Ly6P= zheJN5s|mkX{GpGpuRMdI?6%J3%3nOtIO9BeO?P*#rR7#ShYqk zr^zd~Sa*g&B){h+1*4C99A0359%J5T<8>USm_W!ULQrmbb9D3|sE)pMKXFz?cB3Ae zj*2Z!e&tMai+0M`A16slQnQG!!un0U)n7%?r~y650q)6F4}#>Tc#Z6J)r@6jctshk zTI|!hBP#T)SwxBt!P3v~l`S$kCW8FkX_P)VKacE#d;2iWWxPMR{Va6}5(Nb{Z^H6^ zc;XFo)Ax4@fs>S4>Jp(#vfv7p8qg6LAf+u={z*!a(HU;-E`51bBmDFz+;#7D>urOz zlwalFG+baKrq>{;hiFqTyNn&zKwv7W1-ZB{${oNsHxO<8dIlHPW*XNfLVB4Z zk7+5NX-O-giI2jv0;-M-xo$4NI!OfAR20`VgLv^%p$!sPfIFs1@mX!d0ga8k#Efe! ztPZScJNzOVxCrJD8h@R!EdLa)4Ne0wi48osh@1t#;?lR!!Yn`lX-EmZ4hyW4I@Z9| zv@hNjsF%T_U0{hBfZC8W#Vx3?(iB>}s)B2Vlej7{VoMiMM^}+&UH6g*w~>FPw+gDc zJ!F~K_B*aESIan!t%t-{5tmalFv9|MYn7{5-fFq+H7CZeQ@yoGFY!ANDtNa&U~eK$YW_t zkZFX0E<^CDA1B!Dy5`jRd~71vBv zOMKBxotx7N`5Ey*pN$__GotNTU%yRs=u-Hz>;;|PU$UlPS)ymz@jjb?KPc+MmN79J zi2-Gzi-)RB1&ky4mBDob#nu*I(Ew$zwjm+QkpH)FTohI%{&j#UW()Se0@edGXBaGg zDm6e_>1A4BMsJpXR@-twW2-0e)fNfdep?bV9#pWTs_Q}$YQ&NO80GS6-$6CFWlSqd zSj~bIR_L%`5%ie4kYKQWy7v8%V9A5BZb0N<_xoky1}@keqka7cp`lCiqB@C^i=zem zMR@>T#u1wKI%8Fjmw*fGJv>@Ed>Fuh?b`)ARPRO>S_{ZP5~9ZpYa;7*LU|S@I|iSH zLv3d^-Y;1vFfdrSrdk+&nDB-_ZmluQiCNxyyb;RsF$y_auMm6#y+AiMx!=H#1+ z067F2)LtNrd=u_ZL|A)_*R&{~BEMk@7()r*C}82f)_O0S{Rwgn=^Y}RQ-gQ3B-R)N zH|#77d_;3{4;Ivh3ag^bC)4+70(lV3!0FVtys!6Tp8OSk#d|o7{iyXKP6AQwRbNwG z!!i~$@+#Uxe{g(F#S3Uf%mzW&p+x{C40YvC1ECgp88P8re{RH9PKAIEk?e(%Zvrad z?v^x;J3bt+buS3^V}*FaA>B1DC-51Fqf^UVfC`h;97S~~ZS&JQ7cbm~=pymRSiL9| z?Q}?s$oWj-mN;Y(BpJRGxzxloR^jHpgz{bSsBRTVzqh{sFt^R84kH(!Wlk=}O zBt7}M+TE3yG7;}bKC^hCKtk&E$J5n^I+uYc4`WTHNMBHTEhGrxEK@?dWCofYK|2SA zV>FYIr1y;at5onA6OEhZP&B4z6~bETj4JXa=TMJ+Cy2gh)iLNRPP|1bBrtcjUwxTMdBAM4^jRZYK&_9*KvQ)r_ zmC1AKp@!1nN|4t@Ia*T4Puofdqp6VcP$)$oaG!`UQkJdazeO$!d?5)cjf*VJoat9^ zrAOKaQBt0rqrv!Dh%Qtpq@pYKu$mYV6RKiTjw?jBZ}*0JJlq!c%CwW=TGz|yc=VYL zhOT1~Z%wl~raDVNH57^@&`1T}MndJNQn>OJv~W`z#p7zf>kpM|=XHh;EX6PL{>XUy zYIo0+7gW`aX_ed49uGPUg)LEZE$k^v#=7iH_ZA6_rlKrgLf%y{h2dO+RAU~E(ibc; zqk4@Dx7r&=m!BDfHo9(NpNFqV9d3qm z3KOHQJw1e#@|SH(PIhHOO%ak5P`KJM5;7A>QwvTRvMIvH?}VSszq9;v!ag4P92OY? z0z${?e@xg*{9|RQDo|lq#?`|e&JYp+HUqs{5(hRI!-qs z5g}q2lD;w8lG$0A$3X)8Yp$ezDC4ABIj#)fJuIk`TU4oPbkv2wNMMASuvmQAULxQT z6lA)HQBr|cKWceFXKKv4oH0e-v`T%2lRX(ps>rT(g39tzr^M#{!rP*)ac!TO^s*yG zvS?D8PwO=e4h=3zT+4EnPK%oCpS3sa8|NRm1AU2 z#2=>=b@)ZMKov7)-Nnjpy}ME0vEG|wpWpM{Ef-e?XcOeKoAb3%j5=}#9vh*%P#K~C z+Gle!=%r$mmRDp68{QoDyDTbuSk=z~(B_(DY|-J@eWD6P$hPPX2+b6I@)52u@$0ZQ zWIdaa@lD!Clf8|o7(3JzqfH;qA)Cx#D^OzbSIml&`L8FDx?K@HNzszsjPDWYAl$x* zwXsi|o4o_M;=8adgyALbh`>2*d?f1LkMH~~iK+EQ`bgcTsAyyGlyM;9xfhl*^-O;)+aCrG42 zB5q{wFy8f9t{ya@ia9{|;E<3h{EP@V;P-K;H#nmC9kgtwTWFc^&02lkyBLi#-zh8D z@JCH3=^GRG(1#Rl+=(h#%TH^&rAnXY472cvtG*I;Rg6ELj;-Ll-57mow?(S~fh*1v zy#l)&REunY0Gt2i1FS34MkJIow!dOTy7>AR6|#v6*mgoWs;KWIBC%6Y6NtRy{l-Mo zs4^`g_}sBas^(O9p}oj6P^}FZP)!KkY#<6zKTh%^btAbvL%r-Sv(XAYl`IUym?eUb zaG(vY!fx2#BWb5n8$pJW%r3hrBEIiSyUZwqBkyN|U>z64ZV+YGQp@B@go_y57A3B~ zaO4${ASXui_nev+35DGI1p8V^YovAP=rVV^4e+j{F2=$c%QvDZmDX{7nosX$|KvDs zeQEZcc`)t^FNnsT1Ky9XWhhPR9rA`=S$~F?>hY-Yie{Ic-+31TB(^Dzfdg8t$juA( zDT{d*Mx-28+dI}QnptJwz3Qm2sA122*Do5EN9U$XgM&HfgS*c6P74G$9#78UDM6$m zLBdAgg;u`Muf6XiK{sON~OuL9CLIg5y6lum=X>7GY-iC)Vo8) z$xQ{|TydFl$@NdJ=-SdyMNmZioK{97)ItAAE3<@5)#dqdz#>@~HYI^gK=l^w`b$lb zGt97H5p9@7YCj+cW*o95tt%^9ea>qSL!0#e>;{`zmH>vbph0H--o%|G2_FC0zI&o!Bly*tvJgn#a+{JJ$E3 z?@Z6*TsfHUf7)BL8}cMSE$C0}&DkG#j;X)=mFD_XZ+nnKI%z`J|B1rTXCm9+lYLJ) za;5ZC&}*LlJq(5KCgsd6Bt5t$%b*%*`=E%5wqF+r2IPm|2BHu;?N2oE>Phlg`n?QR zq9F!cVKiN8D=;9C*f{%>5C%TBdY%QhoSff`P8wx}YJv(O{cc#-s)!h3$eFN5z8vxFe5)!EQbVq@rQZFDZQ<(4VI zCg05aGO>Orzct29nl%jadSv&SWn~<9uDmd5xl`aTIh=mci7`_h7ezw zhSH=kW7IiJ&qUF)nHqKwsA9hH`&57u4u_gx7P`!1Q3S%DNkX`2qDMKoi&17q*~JS@ zSYXn(qD6rg4<=xvKX5<^<#0iPDpVwUfA00k7o`I|{02aE;hSYmnp=7u$Qo$JG$GAoYd755p`H&5ZO7 zBZdl5zpNb%`zP`)_;B*>S9K3mY_~(8)iJ1Ga?odu(P+=*B0EZPqOia>O1|89bK6iG z@)FJU7RhE}B4zOS1ei8)gy)%&~TLS1N;J|E5dzjpQc*As&MZque2fT@1s`oC@e2CT!C1UB9< zd;9($bbys#<$?d|!3+RoZmG!F_ZPoH4);lj>PBgl1M%i*%k4Pq%EdDJ(<3o+Yio%ZkQVhSF>vSWY4*#M@`kzLy6umUccNwxzNJ#M|*r3OGb zoC82o05PS&6(9}JdKRS7k6xl?cDMnqqUv`drm!$O@O?k+qh=;*xyNJ{21tFnw@)Lt z>ikBN1hz&wqDL`OvK{ob>~E;_-M={SZGstmQ1z<=M*+qHrIr<-M(7m&?~YrTDOk+t z%npm)+p;YJ0LZ}62zh;O`;S=6;2Jg@->0-#Z#dE(0ADDX9dxGuG>`9Z%*y|c8ED-f z%mQ10t_*uVpzg5IaPt=_V3f3zyvzI1cHE&*#JkhyuJ`n4lJbqjO*oh zN5vMv96Zms0JK=(S_7VOVKPq!f(`dsHME!GZ@_LV8a642U`1P{I6O$Q${K5fD@$l^O zUTS7qeOsWcAK2vpM#K~#CagD3sq{$zkMwR2fc^7-U2ge&O@3*+#9-60zsNOg6bW!S z_!A=qaPCX6%Yjd6eZabv8>ckj&le861cPRT<6_`%;l=6MXkd0#(fq>trG=hZ8}55fST#4xb-# zCJbAK4G#*yypJY3h&B}y;_eku7xDP?M$DLuHS0^{CWl^jw&#YzMLt&m@k?aVPs0e>jQJt58+IzD4N~M|R+oD&;Oa3$&hEI1Nj*sw39lJ() z6Iza#zVM!}V^_hm>FrMmP`?PMn{IJCM!3F@)rrU@ED-8pavKN-tQLJ@W;|wq(Zlhd zBwLu^fL0C}#To;G?29Ay7&W7D>no?$F*EMu94AX=2ZEmM-}aWwKy1(GZ?gN3u701< zPj2ZiYV9|JNy%!}->C!ChqNmI@m}DR(q{m^)(*Z_(O1+ywsZQHah#fw^3w`2&vpP#u+n)|k^z$0JhGq=h7_fwqbmiB_ju@a}05@+z})(`$w-)FW9?#Q9w zp$_01n*pE1a08b`OG$b@`CO{mDW&=UPbs74QZ-H~HUA$=9kQp5{s$=?B;hFN6VP>B za{gD>;r=gO=WCA~KuHI;QSX1Ga-1*n=3RUm)!Nd6FAv5!^QR&IlGTfcENZ5nH}gwy zL(1%=^u|l)_qXQ@9s5F;gR_VB`-jeX?E`lq8GCiGv$HPR>V%Qz1VLFm@qrx)(=BvA z8yDyp!$q#fJ_bX)f$AsY&LwapJdJfKkip@2eF&*(hHvqLGjUKvL6E#iN=LKt9UJFJ zS)Hso6{l}{_l{bnaS%n-P2N4ywzU)PPFJEbU3m*b?&r!6voeNK}%=qD0?`DuaHq;VGyDi1dTeW@lYjckm4gvjnQDvMi%HQ!qa*dolp~1p+hjs z%ZXu=T|#l&)hb_#6i`ENc;IE)VcWHd-x!el`s!)Ce}zP($v*;B6k*5Pe%UO&y8LK= z>;80ayN(tOf&<>+Ebd=3i9Az|q|^8{E$h6?7Jkfg-DmXD=eloQYJnfv-RGspLf;yH z+ig>l@cnmmpX+vt{SLjwK9b8%Asx!j7Y0?&XZzNPjgJBZ_l?m#s`kAKDvrL8J|2g3 zX+37ccogh`rL{-bKF8PF1^e7@kv>^HWQ2Nzc&u!ZTv@F~ki2?#GbsFcQuD1Vs%3up z(jf-8Vt78ow%KX;bPZfFz_|MA)o}qb@`CZY(k0*fcii@M@7Ppo`K)B{x$FG{VDStJ_gW_=R(hDrx(hMlMyz~M$ z@|p+Z%Kc905A4TRmq%V;)WVMsf4!gnue(K=<6AFNcnAo?X2}1}9w5bTBx!7JZT62G zGIO@EZj}`~==-a4GGKF6mOuV!Tgw5=aBaecGWKhHxqEI_t7Ruw;LK-u~{!;p?mY3k|=1-sF$xGq0Y zJ?xc`ky*9ba7MEEekzxpaAMK;BkJ_Gx38%!nOf@m7!=zVpyU+LII&GvQ+~+Pxpw<7 z7>bppdZ~8GY$x~T-V4i}8R1l(TG9t`K&JVJ8f(gA7-<({IfxCsH@MlIQU%cmCp6GGf}T_|-0N#6QhLc+Pb$x$bbQD{Hh|#BzHZ)@c{eDWqg{E@{NF zyVnj}spF0_dZwa4IRTb8NOLl$k{FYx+09H0H zfBWjTdPbYN#?JZIdw&3`qESM4Ck+_u_}*R9uZmw0om=N~@jx@$&l?*$8JPa5OR%cu z;@94@&_#S_G$0h!&^cXTmkZX;BXG9Wx#OTmJ7g|ogYs>*L=2(m8_8@(468LJO02ehN?j=H=rK02s88k%yGlx<&u#3{8k?DV;r}ffwJZ}V$vfS#*80~=rOV&t! zW*&ery1Pg2)d5!j*_Kk)sG8{Z+pJsQxsB`U)YXSot@uuTp7W{_0Q~ZPTi(%bTiK6a z9(VvgtJ^i|{38Rfxk~ol>43uuunkvX%_RUqdEUnK*)`kejj^5IfEEfGG$$2-qbhm! zFYstAP@%NHWASR9AIH3K0jhDlb(aBLu63)lxXXWf{(${#2yZ!w zb!D)!-%9IAr8R(&lV`QXfmU43%yZwCQ~d@9>9Zw*J3G!VqB@hy{;wro0YYwWt5U@P zw+s;wBnW@(eArf{;I#)dLvo#9rg_mte0>~f;nyqqKj^73yt-h(SX*tA%l}cKo71XP zInWuvwm}A5uq+Rh)GGt}G1xtVg*63sFTLze^K0aaJJ*38t*5wd7xwFp2@o^_0?P3M z+{GMktz>{MW_Y_4(MhRoByM!hR8kWJj7$ebHC?~j9sk`HhPOb3B_2AUUu4E($$^9e`+KJYNP~1yVG1xs{9B3EB956_zSLQ5J0Gk10W1* zGR*eCgUI&zMJ(X#(0!DYgornc` z@4H(eBc3E{uO}FwTzaPu=Jb^^IPfRu$4~z@*a6V3gp8WwYHEOy7zlH*TU{2f>8qQz zD$l{h^pKF&BkY! z4ECKm`XW_Rxsl>|6m?1>LItLRV5!=&rk%QYSwynz&jHOa%<>MX$9v%ls85=`QJZz; zU%zgCPls@Q0}7ogRlzyeP;d!roDJp4GH#RI&d?AplR<Ju>ir@J7g8H$%pl~klWqXq+Pp<0t^HK zG^7F+w)p;a4%_q*HdgBjUYs?mj1+r(T%;)uhBZ2Z6stc*hIPw@Y&nA)&Bpqz2Iw2? zV3Pw50%t61mdLCF3Q~UC6!nuhBWQFW-?=W{cT>Xy<&8Nxc4<4vL=7~cGgRbe!pZ<~ z5C98%bL(58`xRtC$GF(xh^WEjN9YHY>?`6F3oWOT2FG1=DnSdoh&5Ud*TX=E%Gm3i zE}klcQjMa8R(qc1Z~DdyWlYPe)s2z5!=anX*$g2KBU2p|lVu?g;JjIeg`x8T0ae7J z;V%gO`SZuK^O57L5PV)&AXO|ITfYs;3O>mHxZ} zPkIS2_II?ML#E72n`+IWI_FkSLsuD`r>fk+y7P1!Zs8D-YtwgxRPcYo@&*xn{^< z={q~q`VB?A{B{R)PS%1r$Bd;=v%%QDcAmmE`7Xu{DLWYXJGTyOhQ6gsnbt;923O$M z-VZPmNRSD$NA?oD0uaXgEohrnGljq45x-IlAE{rU1~rVT-CZXr3*DR_Z!o?b@#JSwBxlytX(uhjPeVi$@*n;&iJ@;O1>X2+ck#Y7 zKPQM)w(h`%ou#>Tgv&d>&L+LgDx#{t@I<;!OA#vR=+|aTdH1xnqcw~R^#%{wTY4p> zuIBxqHf6;dBHXuQpFpN%^;g}K3D%Ihuv0fF5YpO3}$7k91U za>!B@zB9;==7$xL?lO!&8q%V(s_*e9(Z0+0BF!2sQWfs3cRtyBvqO_bTVW;Mwec7x zqg8RU`Yp(ky-U$n14o}Ucqx_1DTxuH{g_Xu2)WA6H74VGQ*wy4yhQINH>TewYi5dm zV&iN+e$dBq+!?q5%(pi7FW4|Cgrn~lVzvMl$L_c5^)D1+ajj^kR5)I}g*Rc|m-9w* zKy^rW72E{t+T z2(Dy1{-HJ#Vc$-tHgz#6ke!Mx;n_y`29g`09qKVTNabt#_mWcI#7m8>ur6=KFZ0J< z1joC@E+DHObbF$o|9&fxEm{|hUwj|3OH7i9HASf~0^@Jmsll8o%6ESl0|9fJEa0z= zo$)a}akqoeZ{t_Zpjywz^fJPl$Cb!C-U2RWpK$fr)Ef21U*B;*5{SdaC z`cWY2!}%))?qNFj=_l%vp5}P#f>#FAtY^orPVReP0~BGquXm40w#G97!-lB>A$K1Y znOQc(RtqJ|PDLHROzT4~2knRr;LGkJVoNBY7>&t?8s2E<8o|4-S21cRI$&Fl_O!6% z85&`-(qnuV58KZN?dM4eB*GX|5-6CGh3S7Xc`3y^WB67u0&~#-nA@+;gc>S!Ih8QE_M-3zb9!#GyXg~FO^n4QT^ zu4IozFwd#g>NZ+UCs{;LoKEbGC<=cp#n;_Vh;8rSa1ZY=Ow0-EC5@9_7*oW{M4Net z`p>=dMou`9NE#g%yQA-(-e>pSHGO9oNXsfe&j4>%JEW-!kqSyB!1-pJJV+DUO6fwi zWo8{&d!xIlh;}L^jrZH=pQFF19-0jl zeB}RR+!F!iH#|nQxNp-1wI(suE)wTo()8$4Qf+B$|K4CpPc4^a@nb6Im{5a{`^OjM zKj-e;+x2Xk<~po3+%EH4JJLvcCaoN;6z#pwqXSMl-25IacyAvJHDVuv5kALAL5ZW1 z`5715vKkP!e=RB`vu02-*rRw&8Pt0YrMQQWEumN>{}}w5ESV)@W>^kNPW^z*H!Dab z_b~^Q;7>O$#{5JBR{#|Y2?Zme5^IO{p?W|(pfv(P-nPaNYJghhrAjv;$O6q#grNMa zdq*SZS0S0l=7(=&uVJ_SBvXZUK*e|g1wFq&@7G_-z$! zeyDDX00J3n0m6c>QV`A_579V>S(GCKvmt-nIj+W>T?H$*5DCH`E+`zdr(0(H3x|Sx z4omi@e0DYcjXf&i6`h>F2>*~kgQ$9S*e>TW%c`VQiD>uNeBe25@mFE>h!#BrxCAO& z6&utZ*J(CuCJX4{4N0|BqQb=>%<GM|{kf4Xhr&Y=U_VH|C>{$A?Z)aG{)fr0?_sx-{nE(kBV zfCBTn`e%K^k<>A8R8@&_g2H(;J)s#0aa7q9B;7PP8P+tWp&4))@=a31=TvJ|9BRY= zW3sq2DTpT<4tPE5zf!ROr%V5xb|XR6Zi)5JN_`(o7BbP_R0Kf+sAAfw2qSV9w2B_b z{*WI(TDcHVyLIdPO-;Y$z?7HIf__&y;M!vTXLd_g@)(aN5zPcQR!E#f#>$mWFzB_KuDx#CqG&5uB2~K+V^oj)4isuC^bpJ^WBzFe< zmcW+R!NF;6V@p+bSzRV&asJY5WhJ&cIZ0Y+%bQ|td5ah>L5@`SozknX&2p(KSW+O* zfIS78mmf4t;|4AEM3``Y8fY}v+?py z5u5|W`Mf<^$8{EtyTpRWsfNUr%_rFJTi;ql|JEsanm7+n%wkcPZo9jjGB|BKtl7|1 zHIJFv(Yha#m&Y7kHJlU>9bFe)-J78ge{8+6OlIMKX{R#` zJ!xS}^AH5=s55@HuNEX@;hGQs&N-&g%Ky9+f7LJWLowg_oaY(i(6|`UgWY^(lm4I| z-R(4{1%?>jf`9tZBV~fMkS7SpUn<0=uGiHc6WkpDFcy%_kylN;G7D^Q)3u{7Ee#JpP37=XTK{0#=38^IE z%BvO}XRuZRIbcE#icJ{c!?3~cIUH$BsV0qGB~H>uf^rOB$YC_Z(rr*O1nW8yXfqlo(jB$Cu8x#4{6S5ca2aIF0aWA5@VZURVoUY|UPRCOw(G+jg zt55XoaoISs5Xg0O?4umU6eENN5W}ZC7hf&}zqBTrB^bnuE<_?OT--P44@t9-lFU#_Q*F8!(ucnt~5l6;ae9rmsK{3(@LZzEE;fZG$!dd zZ*>&HUQdLVG2({3o(vz*$kh4~vhHox<%-9$-Z8&AJc0>5WyE^<%^qoknH#xDtzLNR zDquNH`0csdmw7>SexVQOFJ6d*t0Yl4%4AcB*({VWYOH%6>0N##ti8L3Dw|jASIqdq zLiUL0?*U^I{efd-v(<`CdLO11$tL(3h1_^66cdI`JhFtzpS&c6OYx;W)<7Oj4NO zVo}VPW9T=Nn+{ElLPNc92rQlMl(U`QLz$*Gaii=-VWY=1-#cROR|=Pdh$Uy1wvR|v zO>PYc_6$aWN7W&nXhm6Mv4{APi_t0(Mli!%6GvKwVJ~P{z}hV363&~dQ-Ct#Mw8V?u9#C5p`S?d{P#(uF_RpNqR4&5YOEtgv5tdww7BzN?My z;=J>F@V;?(3(+(;cWY~RBZ%M=nZkueyqtk&Q^(#{8$j8V3B6wK!h5>^k7*}=g5NU> zK;E*4^FRI<=HdPCdCTm;x38?&5F1>VXgwE>)sjm%nk%cW_t6ysf&{Y0j`&qyIzOa) z#MCtJ^n9CGOR3Sz=}L8C>&YxU+pg_PV9Yc$Lz>&D+RM~LuXgxWu_uDeBlmI)Sm=4w zbZFydYn6p}Z>INb-5FaF3gqrnL@T-^hmCL$$sQgxGGJ}68=&sXPCW{b? zAbvs3(3E~=Mg{AsA4Y~yd`5ZX5tS@01>H{a#GQF3G$SZ=XCqhxg8F;dINQ&K;#vkV zToK5)=^Qq3X7ckg#u5=WJAY5^iZSCGwLrz>`~?_IjE`tTbWX9li70d8@-X#~x6&n& zIT1MTpd%BF3GHQQ8G?Fe*w8|Elu*ba;YUn@q1YjDJ8`$EROa5^eqU{sZl25-8jtu)$Q1Qj^@O6kG{HMG z)Seb5v~wnR?K5`GH+?o|ogcp&*FQ43W_85H-m$3l`@X`v*=ACWp7F*rHCPZ#Sjlny zy#NP+ALzHC6g}`*P*frw+B@UM({thB;#1SY^TY6PZpYAp*^}qqZK$~cgO|& z+%{Za*IOCwAiw&yv$kn?cyRsCNlCdxRF?uE1qzb+ACp_6d`7aa{|~jbe*9eg7Ar_H zC*(0NC1k%rR_VUM_#N$Nu4AGEe{?20idP4{#>TDAD|Hu={}tOB>(WYZSsb?NF{L2!tJ(0oF2{EQ?EVbToVrm< z`!?mf6Icczqsml`dZ%|kX6$!wGN5PQC*usTI=T?n9VAE0iB`P~%2vaFV;rdc(*`5Z z`$u3Iu{!Qfzf;^wNs`35$FHldwLWLvNd~Tp#=7FT ziSO>m>>RiK#>rn$Q~rD|Hx%1v3l1rjUNtmnaAjEHJk)B`!DR_;g()(xwEam-4xeuA z(6=qJ0!ztoF^XEU&h)FX;d_B+f9q0;F3l8c2>K0tKR=@>OnhAP9xyYLZ)06Z2*Iq* z*BH3bRTSVg*eY+sirR|WBb?_=39^VGKoy(w75b4&{_}&y2>OyczA1U_Acd)IY|syq zK3owB@(^PfiZQAc$IxstDoI?iW)LQm6)C1F!m6x{IXMnmAWSx@NTg+zC#l=%3k)N&&=^M!#e7 zdFj2DS{9=8D!(kMvJ9A0MVKcsKC&#jEl#G`u6H#1T-+?O; z25b3}I;PG@JIgYeCK*@M_#)akMx0?>;HVa>+eC@?(pjGgH(54W=33Aa2(yv=SFxAM zW_s=f>oX%1ixi7oGFn1mre<;0z_HIjRWU)fm~z2X#n8mmWDsC8m$0CPvy2NI)xAx( z8cjGXTY9<%RC-kHaKpc8<0_fsnSjF}$aGwX`VOGN~IckppB zS7mwh<8* znm@DJVyIUUKX1De|@b_+d ztCv~1K-$+8a)&GQ=32X#2bxr6-o;x3vOiRX4KsWhzm`@r7Ai%{vYp9<4+_eSGsD7^w zQ)EPsM?TZ*Yi)(bzDXvkG5dxtSO$ED4f=U*dqDZ9^ zt-gN)q=WAZPKp#dHc{@;pQWP{81`8?lsqoc>G)-DHeXPO!et#ek7I~X4IMhvY87gx zBT9(+H>iio#twvpd^w3)F^{U>Qe=zmgD}`RQt**EBrJ93aKB7=9 zMA)Gw1$V!;YR8#~BK>q`!hQcA6q}FIL_$wM7WAIwztOq_|LXtyeNJ2bpVK$n;I-Dz z(>IYKJw_?jho&h%3VT*rSr1_)V6@ARgr(mS7qSKO4e!vF#r#HIJv-{+2|1j6=-V3I zdpMK7+Pltc-`x9tYVr^?X&&mFo9TICn&x?#IF47hw%&Dtx`|$RTubZg2c=Ry+hS40 zIcHX`UWFQ;H;Sf6nd%!ZYgL2~3weeBfjUEuX~EAq6dY|1P_7+k=T6J+3B_~7S_ZTn zl4UI><@#wkiLK>gBOB+^h-i=d!+p%nEYPAj$Iwk&rcUW?mp7bPEO~svNusLNovSyL zhnlXG)uMy&n9ma@DXSCU+dSntk%>l|C`{D9Q+_}Jr)1Ht9=1hNCNV6uNxIWd6-0zR zXz;1?N5loG=!kox3Io(`0;fz&>GkFuR$4W+scftoR2kimvH6fgSY0v)2uA*nCsA||A?ZVpRc&Ofu&aY3jb|&ArM9497Zz6 zPHtw_)_+Hksd|rX0V}9O`?qjpLyCl4DKw`k9~1d1jaunKa6^(7Fj-C0pLs~`1xPY3h_XW~OE+-tciHE)=e5hQ`NQN#MG>a0FciH$oDm1U;5jx( zO&~Nf8b_SGiU2ke6+g}j#?oE_6`bdhn084&vWsiX@o7h5w zf>PMCfDXk8#Ug?bzs-;G8A3OejC0>L41Yk=E`_>UDX{j0V(&Wf`>p2C%<0~p1$(O` zackM|iOkJJeC|08i_!JClZa1118h3`J$*j8X_nM~X z=O+IC!U-}x?NOE;x+4A`&%)2z;v|CYl|P8{v6(j`;e3ZoDZJwoM(@pj3!|Hf7tuVusF7*T>=9PK4`E2gKKby;2I>jgy1g0 zLa;z^m%%l-1$PO-Jy?LC!7TxTJ0#@xkh9OX&%WPxf8BrgKHX1J)6~0GRrRWwuD4gO zP5@I#ON_CdwORdET$GgkL=&f*{ZR}7KZuIHJWsjMJ(m5Io&MwkvzXfwEt`6?t~USa z+PvaA`$vZes$FTcmrz0mY6pIn1(zcH0)Z+1HYM4olS!9P89p&}x%Z4yjF;MOGd_!3 z^ca=)rRqDftH1~xH5~NvP}>t~$FXqJOSk4HyVmJ62rCUKFyR&DQZz4A+<<&M+y@(A zh+tWwUy*_wey3IT#cZdhncRfj#1e8RQ)WQaGbxW^5CX`!15wPq6`US01~H6S=bkV9 z%soYCyRrWELw}JkkK?D#c5U#8%UIgsXM!_cNIDxG@aWKk#qzJLK|u#XY}c35b7c)< zx}^qEdiLA>m@}tYX%kUrx_;A&R`yoWuP6Ct1RR9l2P&^1J997pKCB~cUg^L?cp&2U zic`BLMs231OoIkv;^`VIV;REjv!I2u9~>p^6UMgY&?GNXSc@#h0Ln-<4IVkbcJQU`N^i+yw1Z&))IMeh6 zdzQ=FPeQ>Ol3J85%*sZi!K@{$nqucc^WmLpUVH_py@#YAfrqv#X&Sc#F2d3_tI<1< z><2qHBSY zj3U1*8JJOiD^Vj|--b#{jS7tilG?8Fa^+*p!Jatff#w2#<)mS2Pg-P#oZUBP*Ub;L zuy>eHKV(rdmtj#T&VH2`^5*6np`leQ`ryX0QAM6I9LibtCPgh;-%=y++SW>$W1g4C z)ydk+hL&5qUy{0PZ*LnFx_^IM?rZ88tW=5AxN$zYUAlQqz+e^|UDne)P`&qPU-FGg z<(1J^M68Ps)VHm5<;@G9o8N4aeYJhHDaLvteYLu*&w}!6|>1w|-)zkV5H7%!?oV9_g{ji0o#W29&oXKSx z-hdU`EVYhnra|^O?uELKtYX;Mot^S03VJzS7!I1i#&+Ju;K8n*7)ouCYBL_&h)RdvDL=qY)XEE8IC5prXhJ`zgVJWLgDK#jG(&Rhjhv15Gs3zty$-0G=4>^>WM+#+> z%e+KV+Ib*u6xLZr+iM}8L=*aG8XxRZKti)zc2TX^I;VzAeoXHJ3W3O#CzsSQd$r`- zPkJHlSe*riP4Dr)VDUAVo0A@dC2bBy$B`C=7!wD~leprEAV^s|Q`e-;P1DCfkU6+< z_o2aG6$2a`sc*#y(DxoX_3R(kxv!m2A{XtapgQBq4GT7pJxa zw+3jXmko?@^wuVPu*2o*#TwLb+zEu<9hE*n2m!_9B+OW76+LDxCFU~FtqgY_=iIdM zr^x}8C4MQ1gYKV@y3LdN*I$$Nz2_|*koODcH4Q^n0tZM(-{6Lm5=(O5P6RB3>~o;j z#&Iic-1%*&H?baB^&-#uuxx}0GE zlKDODkZkKAYVj3;^237eIWF_bB!B4nqBIXHwgipb8<2P``Qh?AzC3vNlxgu zMEW)=c>|*tRs574ix&fJkd;ECkLye0ZeDFu=NAn!mw6xB+Kj|Rz!Tg=Sm(rEN0c3^ zN$SQrrD72XIysXp&Ggt*D&*ib=Ag90rIE|(+q-|&v`8UB($-Vlo=st_ySa~62kViinTa+x9A|tglK^+p&R3hbK zA?=m5yPsPq)-_dX_pulFJ@lRIE5ZDPWbU<@W#8j5-fWe+jh6{mQkIPIdOX2hPq6xU z`9`E0dSlGeApI#~Uy-5QV^#7?$C*QCgYg#a@V7m`$c^L;kokn~(8EYgm04@K2gS9F zr_4;}KYa}KSC2W$ZPajnk*;6aVg2$Q2hYl@4khhgV_Cf?oZCH5BKF~xd>6Z(Y~#Bi zGh)tbqM)}WA{S)#xJ=Wfr;Axy!JxLKkR_lCcoLC=z^3Aet>}ovu%~z<;hWYSTZigs zcKx;VrrO-GrR@mOf?$GK38QiJxZkCeCqo_TdjZ3#rbnBCLe>fe=t3lzpQRbv`=1qA zm;@SZsSk5p@ms|bA6*B0Q^G0b3{r zb3zApe0*v>P25U7mw_Vkf)1MD3eME6%xDQ*S)~HAM~;HIzxOk@UT+8xhd9doCgS~u z1T6JF$;B-J?NM^Nv}?%!qW;7Ab+hQMxZC=-U((K5M;qB%_HL85Q)Ct8JQWk#X@;er zf`*xo2RxqNeX?C0idRGcIU!7X8Qu1K&tJ8pMYBq?m|#_#bV4_CCy>Zcd3p3Pqgi`d zI3+DfJ>@GvjR@#ybU{Q;Kf-?jbP08V07kA6*g4V?e9RbhM{8aSi^0ehx5Qfg{0#m> zYdW|vsBW+6+EX_lpWv9@N9V3ur#d|qvbbcGk_@S&~MJ8wz2x!ExM zsE4-QdYQ0$2-Q1Q+UMI?bl_8OclITt4wk6++t`E3zLY?mm<>61qA}4InE~wMM*5U7 z>jk5g&dV{vt=23EWYipZV%ep%Gj6dbVZ(vcoT_4s&449X0ZXA z=vG$YJCVq$brV*?HlnsHftyFMu-waIQoEQ2)#p zz!m+4n?AV5&1C(-EdV&Uk${;#Srt_jf)^@xxOPxux?M*xyU;?yu9~my?`~lBnD@W8 zY|jUnc}gV{w48jwBIu`YJWRm0nlj4Tx!2I|YP#d04?~P)wMNVdvnT@|1@B9Gn1b`| zKIw?PVQ)7wYJT9-)80m{FfD z9zxQ_{^r+wiVwpRr5IX#sEmF*lv|cGl{7#FqNEcgjD}4m0sQ8+ziZaE6O$x1wxs?f z0d{Wy@h<2n!V=WJ}Y`0vh1`SN--shF4UukGS8rHmY_eK^30}ko}xy?<&DQeZuma0MwKLm4>G{$|TX)-8Ogp_|QSSSVAB$w5@wub&%#0}W5jZq3% z{gRf98Iw{xI8Pu<=fB4%LH|OJPM(_|7dcYu*|l`kkLS^7TsuLJC5pBc6RD<8bayRi z=bib(>!-B3`9&%mL)p*fTYal9nr530Dyk?&@F>BSJm~^Y-dI;H3p7)=3tdj%9Q2We z_Bb>2W~{}OT&?ZVzhVEZvkp)+Gfgr+9vI#6fR9OI}i zV93MLA(Jmv$PgXkFyXLruLY7cEnlM3U0hc|gRnl^$RdH%ry`6x4dqcvqC;c))N z0=8OhpJIE-OVsC2e^Zb=(ecw2b?vGyDG5uol-1z!7m6OJ%T6%|%`$+F_fb(QWAW*O zFf-aDyKE-r?J5bE+PIg-;YkcXEId{Hq%7cEY>4zy@wJFci(?mEOEaIl!BE~8 zEp2^#zVhgXkzlpNqEUV4= zHk6bJYOeS**qvh*gL78%z*t@!gVL`{yIt}8adc~i!;2U)y|H=mo)%>d1F8sodph>W z5HseN9S^4x0$Ux(*H!lCT7uvCovEs*%Io=>r!RQB%dOpF;^HG$p|^SlJ$4v%HEfig zJQ<^DkU#3H%@^!38xC*ZR;q;X5x82@?!Mb;)O$LwXo6wy9>Ok^l=!VY&b<&Hb4KwX zv|(`|-)-v?6ofo%T=OGoKjinG0VW@6;joEMtsc!Q5ggBnq`sLRMKP9lRNW|tl8&H$Nhgg@23z2-p#zX!|pLETzAG*l$))$JGn7w!Ug&DM>*0SzY4=74j zg@+w2qcU}z#_k#%4ZlWz6({y3TrBLiLI?Zp*vlWb4Kx&3?aepg$g{IzONZ#&O?d_) zMXrc(6L(HlN%AZZHr53@FYq-w^}k+7Y#0o8(*z~+n|?%M+Ap8S{WR#83p9;@m{xIJedh=x<4gq+Ke!!%iEhf5efPWRG|R%0l-w z9s~PIfkEAyBZg1sJ2I@JKVABR#@q?fczFfrBBEQoYT5e`r|ORNr}D0g;NGHw(wqH~nLH>2fnZfQ{-+30N~aU@47rf;#e%}4Q0i;P_2 zQ;hgg0Di!lsu%ZsEU1OCO`Zdm!R}aH*lcWwwTQ#No|x5d}V0FDnh z;M*`{guNXI4XgjqGyUj}auK?}fofUXe&6v}ke%|ZQDsZ0AOWPku{H>4M zl3ONMjUYWL;FRu2exz>w8jnxZ>$V5y3u^JVl%~VXWxVK!hm%vEou1W@sLWbEGrAC4 zji&opvN#)1<^3c#cW=EML`-846}L${LVTRh_+s5Wv4{*NDb-bh9cc5CZnC99ddAg} z2fVsR!iCjnTe>8VDp7P!5|Cca$u-A=_93^kHI5KfShAYObHRijMiAWWIcS1h{m${N zI@Ol;@n=it0OU@vz0JX)_&g zZ$y#dC>VJiFTNHlP`oi)mJu6~iLP7ad5TQhja8u{)wv(R0x#5Fz~8{p3E_)zT7yI& zqD{(W$?yfZe)N)2X(2%HiV*NsbwFZ zoqJ&}64UZB?jaUhL6&%C)T9y>9lCiPjX95$!)cGbv&W%{ytmU67Y8ycOhkz^M!&~G zv!AS11Z!Vn9Z2TMK7a0i)Z4;aC_Vy`l%)c$%1mwwmA&yJ3!_Y_XIu2OMdk8P>&O&7 z!^DY(73k8d5wi9uYRTnbd91k`v*d9z<8 zUsu`r8)M*y**~H$=#V%+(|)VEzBWEkyf(Ar=)O@=g7YO3eQ2S(^$ffAnsb@Hc=?IP z?b%o#JHzn@o!z0kM`<@l?>=-i9Ph6cwLLEt5^Nz9+j+*!MT8Ln)Zh|GD!LL4Tolb6pEAT-H&v8(DcAlHgE_dpUN z=F>HZo%4V!x8^+&SH!SkLok6r2c*A97)hSE@G|ugF3M(zP@XQ{XHQp_0jL*=-U@HTN>yvk+ZBY#(`8*UWw3D5OIfjU$Pkh{d zJUmf2_qOGe9F*yr6fPwTQDho%eMaT?*at+se-$2yp>y*3(>do@UY`N4W@<4{Fp0D? zqOeNYq_Ji%3AX8??$O6cDGwsSmPYGPs$W{GDC+8&;l2CQw^PP6l+@jd`Y8_Q-`N*K zi0VH)x(wkqYf#E*@*?!{*rS^G4Xs4V^)Hcp9DCTQDS%c1n^v?w$OTyOiBdYj1*DQoB;elH_j^Y8T=9X7YB|P-CdH zo`gYNL>38Mt>(j6g6qmOzbPT#DPZQIa}J56mu-9Q-NU{pi*H`oXk#i@;s{+zsu`~* z^JxW8c|vtYte4kEbD(va-9H*HLw!ySTnq+skIIf#WK|x3HZ19uGhOFCcO{rL@wfeo zKS^TytUffgJYRxF`r-Hy1jKt1Hyl4UH%7W&;85<4K#tiL{L6U3(JoqT&2)E6cz8LzrrxvzG<3Vv52-?5PCsb z{cH?9zio9|;c{l9j)6IYOe$iImCQ>|dJ(+qcVXf!*C$?)H%}tY%G%}(!?xFV*R~&C z(=ig>Ss&|UVb6*SH%~-Uu*cBV~=Q6Lu2V$Ie z_re2-B?B|RgVoD3FE7puQGw+qDQsH!(7oacE3*E!t+!h2i&;U)dpuStr`je=wMdL` zW&iK5IQGF%;G)5LMQ2_c?+l8>9710D$~jgyq=4BhN}@Q~&CxG+PZ`KQN_O?RH-lz@RV1L*{Rgq+-}&`22}r6i>zJqAjF&Qp zd=WLJ<>jOh2>HP;fT&n4t)4F%Qa|kdh0q%`ne0tad{II{^ML*$49X{Lft89#+OU`* z8d8#WI)S+L)BIAIPC>dCBFfSz)5?PO$m#ev#-obxo`h$;C*dPggd$wQ+EZKAg)!A z!R~NpMwNZ_kJqoK>6h&de+h~f-?$&!`S*KJIyEQRpVYao2YOT5H{uu>6gNLyAGn@T zdUIj&j?(LA&fCmGSI!XU7W`_$xI>mxxH{k6t=HTJr%Sy7Ym zhtFZ_u&-0aB_r2Czokj^@uJJD@!ugaLiV7!Q#^{28J<%CfYPI zD+=cG;6mf~x+ttP$!Nn-7G1Tb^VL6eu~`|CF@~eJIMc!~*%NHV9NmVk#HOLso77d7 zS9`@*<~*K!g1P1{c_WTuydStDhbqjQnzM6F=4;4xRahS;-^RZi4CGq*&q<;IelG=X zfJF*(i5?&TkIEp(S-ftPqs15HmpxPv^>l+JwEN`881j8kTLwnLTCAN%5e{-3q3hN`)XfMj$kZ1}_Bo0D1{5X~ zUHO~O$I?`uXBo{Gd&-@Oe6VLk%Yo6DLqfHUY#c#LJ5mHa>|>%F-@!>bq|QrfyBgA* z-AoHQoi{n^6azj5B1M@rUe)yI27|fIizL6$Lc3`6ihkjlp0zTZwaS0%bTuE-CZDv3 z;FJumf$k%N@(hBJV2{&z1qrej7(#y-N&89Qs0md`Q$(NAuHGD-E{Yv5jlCm~hzC8u zET|=@J@9&cipooFI+i4e_IBv(G@U(t>SNAzx^=s?%4tXO_1lijQ>`v{<0xOD{ z8|2@-{arIR-efzqrw9xPj>RH=6BxMWT>HuB9OIgqjXdTYbL!fCt+!78O`roEu0I=e zit$YVCz#D$!Zm&BXO^{ZC{MBAXm-FhPw_SP#7{IE71#6*^OtJik9@ zZX=J1;g5>(6nn~_vX9yre*P&u@e}x?JCBhi8xOm6JAGZU#f;=>{C4E_{YSXrA_dp7 zuIUeXR_N0m;YimqqI3qH6^8WZ4WB<2v}jw_uv$;|C1 zY-po4cWM9e3H~=c;BOhKPXUh|6I6${?{&*^1V?S!>C>xVaL=^?AMXu?0-gii1_7TK zfW8uWih*t=UEzlM=qsjAEf&+|3c?M2!bUd=7#a@%|L+>wdT;0!oe@hjy2ZAlWw<~FN*_%=x>_)96FB*EOrzBi=an1=1`V(bj|<2z@Kg-_8> z*NfubIAfg0zj8TUpBlIolPSaVm;hdC>QCVISjJY_mCf~?-6H~iLhKsulJ^m5&p8{5 zgSXyb1;!V7jlLvKXXTeaf6O{GJm#{7#048RltS z3CB5`rL_;MUMg5rDA;0hOW{4-j-1P>fA16$q!gZO9hV>;@DxKllh+ROQ!LENw(0gTI@}D zNwy*U|H2rrFZsUVB}QKFDVDUXLyyWdYaOEDzpLbUQ z2WEdjLIwW)-kG+3FZ_q8?eIfJ)Vq;5JjpLIMa7Y8%Il=F5$6;#*E8lQ%<~NgubWNk0j2ND6 zN8L}0O`XN52{oAYz4X3qq%X$bLN#0Qn6d6F)8~^}nr^3Sm}#nWT0j%VEP@rWYs|fT zsPCbFqnK`&E9Bgs#OdobA=!1yqwQ2P{a(jap3~9LS&ct_5KIAfWMug8rso+Rg|ouV zfX$Q#_rxg4w;hmDAkQ(&RZJ{Ja(2JB)bjhRoC{g-HRH$2n9^?I1KMrxXS4`rPY|Qr ze?~{*RHoYr@o$182ClzK$voc{G?0k5tlp@v!;N7srZ?YFwDb`s;8KbW7k_A1X$Vetn|KzzHl+{ z;4_K;9V7vkSWM8gfQ92wk49qJ4Cob8-PT>(<_y^=cwOd}mEAC1ndB|~LKr2d%u34M zqXH2!ohhXGj1Xcc2l2VUH3p+dBsPvIyDMa@4k62O0bX45W{)0JL~!NVjV+9l zuFG2-SHwj2a%Rx}u~7D4j`uB2v0Ku)EEpNVgN2pq%mB&qBpG*?-OXL+x~!G`)hF6- z^qGSqCX^H|fv5TIc;$y}80&H@72_5aEgjcWo+US(=c7#s;LiwikPYJ2#|w{RUi>iC z3`?f>Fdp|qllg8C)u_Zw=QV;B?2*MbXDdlFlz~GfZw)Q>8|E^dr3(+$Qt}3- z)>d~D^A;_odY_>UqZBpw`*xStu#nLiYax2BCdW68s(wqa-M+vj6tA zma@)<=X3eeR2~XdJ-bCo;zr2(hMDS>X^hu z_2s@?Eu);MrFMQ=rA-oWH9}?a>i@_?{^qH8g~fWvBP_m4=%YYFDyOl+sR@ag137gu zC7N#&J&L4gA5RmXIu*1Df6pO25yst?N?=C6m6MGAWY#O5U$OUd+!I;(CZu>JJN<6w zl%G9CaM=8@JBAtQ?cNS$osjVD&!78KhmLRC4T#w<=Ccn4OK#3wCVwNYxH8y$T3ab= zVmB)16?|K=?cne^txN&`$3z1oC^lO1=q*7lN7J(J?cK(X(Z#_d-T*3;?jx-?pi4Un zlX2OMYpRUvJLCQYp4T|wUh1GbB+cBTe7v^h@i>s&syrx$7E2C~+@B^(5E1xDp< zMJ*U0`3#IcL>g>9jxGUZ1O?~7s5QcN7}cqrKrx+hd290iG)}$Ta;sqS_tY`wk!l69 zfW8D&D<8J2cdrj2nA}9?B$Lqx^l=3ydB|<<+Xn+3MTXJznG)y$fbblcOg;=bI0r%y zASuFPp2XDqia>7-Odj4Dr_~cj2!|rdiMX2MI~V9jQIi2Z;1bl@5Y*|K{r8i!8-a(hcjs?1RijiQep(Iv#2qD6krG%6IaG6P z*vzFta_sp};9NPoAUZYBG3h*L%=GQ&@T*A!o02XYYnBD8$}kq#{iy5t0H z8=v$(6n#s{67Iv6(kESIy+;Mz;EK;EY1SgFdnYN3_L4tfkLfBr!bq#;D^rkyQwhki z$gf&QLRZU%PeVKtWX9$}7yQe!#p^ct!}-sxy{eV0x45Apk9rcm1(8xRd*>gV7*{_D zo{BiYc)}%?Lud6Ff>0D@Lk}h!pjXE2(8;yj3{w0gWjZANB1%q~F>Y~;C_?CF484~f z_K1{Uf@6*(e%?yTHj<}J_4X>1}q96#aBYiS7);|}-p+Xslt zm-6UI@oUta2MdMk^7$d|um}|@x*sbpzvu3rdMGJfz|bF0C{HwK3{of38;b+m1@j-CdYsRixg}S{GZ&$vYCLEWUG)KXJ=h)GZ zs-;x2S{l#Ne>DP~Povi(JZDSWPkdJ<UZLR0bXw%N~tAy*w@hU_%9jOKRk(r`rZY98-H?lbmn<|^7Hia8)ep=c5xCk&yVBH z8XbjGX(fe$&)xp?fK}THi(BeS{PezE+`ydSFJX`K$lWZ_+moMrI)z>+UC(0uk$>-k zS)4oHGF@~(@XF%*xD6)54yXugT)+Cq9Y?*1`biB40>VHP;(x#R-`}olp8eM|Kbgrk zj%5M_Asup`-U`&I7Q&80pd+8Wnw*jj-uX1Y|H_pjj{K^%!`D8{MsfI+GwtaoU&`C7 zxf*+(Eq4KkMG}!G^4mtXjR}u>#>goyy`3jcoj&-@nO%i~GS-Srd8^?AM)T|PXp3K^fOzGDuOUW>k_&cmU2(7nK}8Z* z_9!W@5QC^e$9t+rY`IiRV21{&7QJ*$GO0F|QkFOi*=Fn8hkEMS1Y3%i<3=qY6MF-7 z@J#ZOer9&@_4~$N4-u~f9XHRKaxLoDGE4PFU*F_02i5^|#wS3p-Fu3tm6a_j#BxUl zZ&-wv0`rUFxgwS6bv+hNzCt`oZyOv3hwEVRIwe!d>mnPGhI^Q4DPIz># zwbY~#VC1L79_hbu{N9F{pW-Ljgb;EOp4%4r=(XkQu^+wRkPoKS|} zv}2NdvZ#>zs(txu;9+O%!|Lo}x9Nit`>qQQ0)|-)j}FS#qjmwqDx|<;jjzetut9R8 zi19B&bGPnE20dB2?;^R>^yWpV`B06_wY=2cqx}+Y^!%W>_wv!ZDpA`m#GAtCfHWro z3S{AzBE~L$C+~T7{D1oUvtqy8iz^G3ai&vz6n_CD36M&|3n>Ci&?Q&Aor<(Djr{p) zk53>;a^JC$o+X*G?|8;1xwEO&N=DDI;kY`ap@=U;%Pl2JD}?)z4ZY$yl9(u7scnPa3@vcmi4-QNiS?gr)jOVs&9>iAJ+VfkwSXxrSx2 zM{&8ze8s{?v+X{c4@z9m1g{YtmU$GC*~Zz)b!mrVhu$L;sMx4AnjV%D3~^GSV#l+J zYTsR`2F~c(4*(k91Jw(cS)@+-fVwePS?DVWXogrNcOm)MdMzY)QN)_QjKd73X z;V;y_$X|O6p)jQBLODK`f;i{2y`3MS;!c2M+@i!b+bn=~k|Dl_Vu?4n8mLNB(oxLJ zIrQ9xIo#J9iNqi^TW4zb;@_RSu|4EeP&(-)=!hjz(xw+~a%;`-Qct;<-*x7@8OU2m zcP&zl#Guz3`o+*Q2Weci-~1nstz#sTsovusC2XZRi4!TVzT2TvzeBWe8e0}+M3V>V@_JI(avV*fPA)ASs<@3~fB-ve$?RW=k~ zKz{g!`a1TVw_q-9_yel%lVx{WO{#mpJyl&FflMKiYceqLyURn-T6&KlIS+FSky`lw zL2~-un_y3KE%P`tL@5rCR1Bt6%nW811ilMyU@{F;e*?uHfnzgCVlyj5yJ~PoDnso2 zVhe_gEy#rp2*AtWVcXb(8`w-3G>v8AT!^$*D71ipNGm=`PFr)hTM4FVFC*vbhU)Y~ z0ihd8KDh{WUxZqi^m-7=%ld7O`N0K0kbHU|?Q26HmhP}q=Fljo!31Zx02ssLJ{Tih zz#64ng*XI;{lJtj*YO9*`xOYvn;uSAQALqc(2#R=LFKkNT|A-yeJ6R>&^OMZn!#~B zW+0#ka|`ixPQV^S+BON7-tDqI9W_}cS#fiabPT36Ab_OB3k0RL$*J9JdM$$FWy3Z{ z!r($!kbHXNW>~nnRsn7XE`;Pk919X$0A49?gB`~Wj+^9J=a!_Uk#@0?h6~b?w4*XE zebO$P1-SY5`V2^L;g7!Xy*>|Izm}WYnG}jg4UONX_B5pyWSJbqpr+z_K<$V^%^v0l z4)c?D4EsSPtvEF(M=Q-GL2D#SOBn}2i-RaQ#(m_BGeEZ4d}V?hhXxVkemFA~OehWb zkS?`}Az8o`oyk`&%_T|8LW4)9O$~Ii!xqooY|_Ru8HU9Y7Uee>=MNWvPIy8G(IpFb zqUWmdhQM)|ByoTM@4__>#9yu|Ls|p$fD38if&c>GMBFw+Fc89|O!KFGcUf9M0GysQ zpzXritCRa6uqQDqYyTk6fKp)&Lk6 zAo&AKc|iCxm|`IEV-Xytz(}PbKQSkV3&3a{edN*)*OwK6>%B&y9i^m!4{k(S9Wbqq z46!Ez(5S%XsKDm_KHvb{2jK%)Eysy60+2F8DG!Eb$>7?+UUR+s0wQ~WcB%ze;x=l_ z7}pWJH|q5wRLf+Og45_vy76RJ!Sf9b1`Jjp-AFi%fHVWr&E^SQ0Q$IIho>9OHayLM zbZh%|pKpk??)L2;Sh@$pu7SK6Omdb#g$qEO1|#746O{^Yc98`3_x2tCYTxs3?f*&V zKkW-6#c!W#QQb#%?#($1m}Wd^0N!STXOsvK40uL&!xI|tfaI7M&;!0Oc-}_A-M{w$ zo^J4byHB@t)%$z{Nxz1toB4g30qIt7{U_hTHlyL`7I&X!K)S_k|H-!paqQS}A9%R# z(+o(r$=g5qCVlb~$RFm(L0~w9`3)xc%b&spxEvu>@Hje3AR0)UA5rq@*|I=71A9y= zaF%&aRPJ>${0G01QNu?oBDEFVpv?>_cv`a4#8)-JwSm1dRlYKSra_|5UGv+gb2u=u+6csf=jpnm}HL1U*1X` z9W_@S01gu&2?P2C1i+ti0qI>J5?Cy8kRd>S>0kPrZw0sgp40RVD&syoQA5D;5oa60eWJ5b=G_OVhX%U-IsO>DjtYpL7|`o zLH)PE-5_p%oF1uw$ij~9?I6e%rwHvJxlcoK4;o!HAluh?*tKLjfv`hDL1|`ZXtDTN zo&HC#)u*iUdiEv(8J)acsjEQyeF9L>6Z|MNrsS{p-ST&(Qn`*y>j&V+bn)e$uDnNp9=@B1FgU1~sDfg8++@N70~8N*weBy0s1DDvbVi0h|)s&AeUTrwh>J zR@04@n(y0RLwf^&UBb5-i3Wmr{3!vOM~=&9@G>EYWIa-n5q-~}x=5mtW8$E34SY4q z1^l%KWF6LJeLe;ef21{NZZf!@Y(G<T)AkxI>IY{Kk&A4nUo-8(AglmE?Ku8Q0H2vbMOL8& z@61oZj&TAXmOxwO+5|!Uv=KUm{;m8g9#p@lI1a?QX$a|nerhp9v3rU<@?>9;g!|H2 zg3-xUJ>V)F7Vbrjrj~VhE-w)#!W#Yq-Vq{u{Yxe0#b`7 z#wgHMySkEYqg|vjlgWNv_PVh#sBz<8l>B24qbG<;~mY~wdt?9CrMp2yyoAS%hFyr;UgI(L7OF%kE z{3L-TUuZWwKWHV+v{iXYtV*)guj(nm`C;mp_SOp>a9wijy zOESHlXjKFTE1}PYIS;CfiTo`H5bn?)R zsX&^akSY@{Ltjuk;|Ok%kTWpUy?lzqNA*rt-#9;->R6!el{)40Yztw@(v+8~q4c;fJeAd9zEv)dF13l>b*$ZG_ABeXq*P$~sJN;+jChWf&kpEp z5^JTR&DoHbwBv+*(&V4{bQPe|KK-oZWPhkdrjcWKc?iE&#PElVDTZHigTd>^&mbJ`&ykXhcXHnL0}KZ6_{a&XR`#&K8}s<_}CaQbKkvg>qx{ zOV#+2H-jg^JCyG{2+(S>NHF=6ZJ1Jq1$=mjC~eLxbnTJb#mhd0F&kwV(0W)j0c z*Gkt`^~3Bp7Ig=%kNWxx>Q+duj?nwU`?X61G@1$PL6{_M! zju_b=SnkbYW&3NSsl+T>6&w!TT{<(QzJ4XA5ArN4yp0d*)Z|?&L|rvVr@vBG*2G`% zs++21zd=!ZxO2UgDDk`-$Yv^)6FSq`U0FKA=`$H`aWQbE68!om(z$4t_is3+Qk^J4fm zlG}Wy@`2eQ?j9V}IiEO~X^!&e4L;mc5ZH=O2yB$Q0BQF4_m4$kbYcZe zgb5Z0)$vP#49EJpOZUw$;2>PdL!wyp-QSdAzkeMbdYk{L-#>YnH(UUPJiM02JsB(= zq(%)f9t4GulZ22H2S9tsSL^fuRVDbiNsST^D!@AV5Bshk_TLi&4QVhHY6Eh?ZAeD@%HpBY|$@SrOEXuZ)4!d=nA zCRu}VZ$JP6D4=W(U@Y6PNeJs> zT(E%WUlfE02@K#O{>6waml??r9~;6M5l?PxK!CUYSBVBxXaFN(ghG2?s)5>U&gRZ(pJMU1cfInRgCN48{fOvp-&6|I6zk62u`jT-gyFLGvJ~u_!4(01C~57OBc+sZZTNeF%#} z7)p8&{%`$9h(iET1DF9+z3%E z{!8C0(0pLKOh-m zx5(T|+_e3#^OjNd1UPSR?$6tZ09^QU-tJ4^KLIrWn5=)Fx9u{Z^!*di7H({~univ> zo_{N?Re@^%uhJSYM+a9H9?>AFjl)s{}*TH0Z;Y+J^o9`-WgF=Mo9Kn_TF1o7uO2c9uX3e zy|T$FJ3AyJqli@YCL$5qNb-N(`rO~A%gyKe_}_cqk8an!&-Zzsb6)3lUh{on;l79g zC6nOmnTtWO3Fj@C$G%VB7m3?_y7={@_q92TpBsta9;vyU^JClzBdWqPwiMEe>Rc%4 z_LPMX6H()xO3Aro#!lES*Y4F33cHu`5|7{mxodV6bfV<$TIjKD+(vcY@`C5X{5B!9 z^Q`mYkD5KKD2jMWqk4iAmOdMbXi z(`tWP;^D8q5UXjOyGMcf;iYTBOK5sYw^s+`k)YWbbz^TwyzD9n1NgD=(^*}$F}&kd zDvin!IBFNdm?%2_`9p#hbTt&>bdrZ$oIB@IiY864T&F@u=-r}}3JR+Eyw}XoPJX?< zS9r%i3|1-6!*+hoL|t?4bLoIU_D;;|dZl8~$caCRpZ%OXtGT%}T1lcFV9QN+UTZZ< z6KaanySG-^WprGL-Dm4~!~2glgoJRt&PAyYjIFy1KT>xk!y2%Ewg-rOJFAH08DX8D zp`v={*gL-JX6~99@f6lBqUvCov&z}5j4xEO`pvJ}-yqt7=`r8=s&7SbiM1t8pVTWN zdK`~Q`N;!G6LaC0xq`dOL={5r@;&byi)gBkG2Pgc#$=wFYdb^hR-3MpLE3g<$0a+I zuiB7Ry3cm+d{1LS^p`S$&yB1Pv8IyeX%ZyWhA_UXP_?wOyts8g{!xB|{3nJ$a{rIS zbiD+5Iajv@7u-e@zq7?4DE!5$lY^%(Qn?}OQwHAs>T_jeC|cQYKriQn%?~OFK7Aq>5rL) zNDDH($1EciGL9r-v3+1KuM%B%Y+}6vOY!}Wu7T@hPx0z6PpYI$Hl3GZnUS7M9vtAS zS@)F16jZ&=rV;&RO)Bz{QhJ(0oNk5EOqyuO`nXK-Y*K>KUsK4MTysw9XU07D zCc@y*zAS&<#c8==E+R7F`$$>>P>Rqm{ih8`slNSGh}7oVT%tgAFG6Wu26S z?IU7X0{JTYa6&eluN7W@$=Ml^QTamrf`EC1dhin_MjccKC9I9%2^W^$RE>^vX%gP3dAIb8! zzuchSf6@NWbV%ea)U-uaRKmgTn?ls+)@=&@y7k>Zv%?J3_5U44T~AhX?BpfAxfKSM z574BgDn9V3c9QX#`SR1KWLnX$*b9q|l=st(qJ31`oprV9 z@<7?S+#3~FI(Mf|$zP1m7sHg7eNXoI=?-Pl*$&FovzmNV;ND~+loV!p5lK;GV6%JN zx|^7ZeC(mmwPnS;s*QU%Yd&9ozN}Owwq7kJlqr(Q(6c=4H0uiW!d-C%&vfHobnU_O2YR<6ID8JPU zx}Zct@c}cGv1vCrfm)h?M|SbPy1uU2*0ZjKmXyX&cHNXAgVBUR@;+)FPPI$3iub9v z&0V>A-^ow>)O~!4c(gnvzxVFwWwpYO4N;f#p9_9qk3aK*V%!BDold)U_DTaC>k~ht z$15KvXt3MZ6GB8xhpx7SVAU>TzpWvY4|P>DmZRmvH@;cp8pkzwY9LgR#Jb=GhuRbB z7{ZTqzK)s=J`BRU*B|K$s3gUZe$pXrJnq$rn}S)3Nr~5flLS(5N`n9AljK&z2N&!f z3})2^M|z~fT(R8}J7RTAeCU^S7TCaqzra*^*B1otE_qMy?3K6@(3WV*U-tU?Q{rVo zSX#1>v!l7x&+vx46Sq?)7SoT{tG-S;A?r${l|mk*nQkdJtTUX)v;>zQw@9h6zUv*o zK;OFR$A2k-r{&IShkfTnV1QWYGZRr<84dTB)jyOYKkoYp&^VKr^;8d-HpbfV+r@6m z8EjEdR9LYDdKkM~s3~XY4(h4gD!v`-hC4gvjVVAxh3|W^|HKC&+{vHkXFfwC>8sObo{SQ>Aq3J)k_(Ac8FMWXo)&ouK@(!TR1MCev27>z zn`8_EwXS{`#|b2l{`$lo3Q@XVo?3DIE-clvU^CEAcg7?#rnX&_QJgX2&F4Lp8mA!c z`Dw1Q=a=h@Vd4c9X)-F#9X?)O5>g-MY=u6&dt?B?orffUZT;xHX0R4M+AwR!baHGM zLU$AFO6s_2KtDXb!Yf!q8lJ;kGu|UhPAnA6m>2RAGghkFlH?UO(`)X~K-R8P8GQ0d zq~D9;P4Juex=w93#oI8QipvRpcCtMjhiR!(fX~L+=B)7QU9kzL>>lCuRq-Y@s)p7x z!_iEA(C?2Z`P)s3uf4~sJ$60mi) zVmZ$jgFoJ&?_F-Z5l!+G{99(})Fc14y^Y+<_g3G2Q!o(w`eIpaR(0udVbwe40`bVVe6%OYVcfB8@>-tqVVgv%w7N4!)f$6;x{ccGiFwv9wUn9 ze?1%C((O$MuYGeIu^6@(b~&%p+#>u7KwU4wKzwO#37%5iq4;R$YmtjtI;Z`f{zs4f zN2fbQ@fO{EUt=&C=Bb>>s0itkn^#Fo?c|b+S2>YhA=@YSGO5afxRUU(dTH7O=Oalh z3B0M>ANonz?4CW(92;3%zq8f6_l-%+yo1DbyR-8|oKm0UHT{OytTc7Y}VD!xES498Sr_iEUz+9Jy3;BR`yatp3T=wX>^Fqy5eXauq&0{9l5pbvRpnI z7{c4$A>So~yA^|(Ue3kZGsIC5B(EM4UGQag%<%_}>{!*0K8(TZ=hC&LI! zW9mK854}%(Je$!rve7zSqWsx(n1V(~7eQ3Bs6&s$ zRkO<^#qGRYGAee%m6fmJE66yKDiiLQ7I;Sv^VTZjSwW74i)6?w4UHyHDD4(V5|)r|LcxQ|&T7azb}IPRz!ZzA>uk6*+{ zRibq4>0mia?_je@p=pI~C*|uLY3NNGi`(g(B}RF1%D#7IzcD?McK-ZvX7r-d{&&e% z!OgyHj^2n-hiJN#jm~Yw%GKqi=id82hi0~$%Sz!L1@N!Sslt!K*Ox!stPU@2YW5%B z@HP z#(`}`dNY5;@L}ka;`%%F8GGj)28sLY?ldtnKYNYMRQ%lUe9r#H(uLOL@om+|{Lm7f zyVIs#CajDC1Kh@j+#=j`DH18iQ%?0!^nFYuj~}`_0mmwA(mzgKVdxqZc{#mGpIaaW zyDxI-Calx_>8I^J%A~!-TRjv;5mIMoA2h_ZoiC}>c)O<*0r|kP8NN%yj|B~E_@cp}88MxK8wt@<`8rR4QDbQMShTy*k#7nXZI%B%c59KjG=7_rNXUbUAx{DCl6ITy zXkJ~tO)ii0+>NSSxxoC0&*oys;x;Jnygg%9xEvr+1hZ{iBfQ$0r`?{*^5!M+QW?2V z%)Hjsi0Dhk7eb<&jd(&^hpfLm)ULxEtvjh`f9IV=wsbUYmw>Wu`~c(bXjaOV&IfhT zTwm>{ajDqOP8U3YUi|i;;>;CtlSkSSMtT?%T};#0+ppXg#5|-Go0WZp09&D|;T^CFv65&jrsprcdma}cWTgGm_pS(QW zL>@u@iV@#1?5u&|t#Zy<&a%?e@_6>?ZjKnQR}F3_eYi16ay4G{^4X;lQg%iU5%ok& z)@EDIR5~1v*Q*oODUBC!liGPs-duuYsTpD#;Fgt==rP3pFr!sCFU^{~N=4=$|Bdv? zh139E+Do~O4W;tS?@XZQZkq=x3?# zoKCu|rZZQ-*smC z`*@RJ)#Zyh=crO-%{lEmXVwSf;5|Ke?#^h#sa@6e9=pNV0J_OM9f<<(S&H?SefHss z>(P@tjdgM_3Qt|7n|%GxUp|1pT;u_NqOC8;QIS}6wpWS+??30*E44*?e>q;6jriiA zNl{jdw&(-m`Q*eL@vNyZjG`>q9)xH2X(xZM11onp6#udX-Vkp&rg3FRc-=drH`@~e zuJ=sfTN{GS1bqvqFB`pCyunJ!MM)t~RTHh-c-7Hxu3Bmz!}l7~#m_q%6`X2xCY^g0srQ+gxul-hYexB+Gese9A|c z-k)*D`UDFJx2-ahPHJ0%>Nz_c{@~)i^FB<>(t|IvabIwq{RtMviutR2)yVgL|6PP! z+0Vx|@u5qgX_7aq*nV5Z_*eLu_*OGZ*cmZ;IgEU1vtkAc1GuD4$%uMJ`j@4fE${Eaw%uEle$#A!1@{@^_5fY_^e(^>p zl&W9gy$SGOhmtoXxSE!M4RZZ&xpx1&ri+oN`6*|eCOF`y?^%IkXO(T(-x)5wV_Jo{ zUyy%p-FoVnAHxS5rdZ}T-30Ni7Yf`YSnl~=EZFf>oVraJD9XZ^0P|vC>4e?vO1~wN zv@HgmhZJU5&h{6kt61LG-ez1l8#TmY@Jy16be#RHR8r`|N28&{j7#4&9}d!!dW3gp zst6}pv1O(Ua=H06Ro{o4b=Fo9TC_-Wx85;K!7t2^%3S;6#Ae0j$eQqi?XGQUx1TQ0 z>7MUP3g#3IY(LM4dEyV=E);*yT3*&Aq(TBz(cB99WtyU ztNOVv-uoQ6Ou4iOSbs=O{DD{4J*(sUnw^B#35U;}JDywDe3~{F@+2)UsgQgWiGV57{UU#Yn2ZXrH#29l3`(~p{>8WJJByEpd7-hyy)wzLSg!> z;Vjjaw8)D052~w2?of0*?VZ0OClaP_-+oezvPVY+?_V!{rO!-S5f|GX-Qpn;H}B- z^NXIBpYv+qXs65_uQIzJN+Cu^w^n(arE}Lgai?>zK4Vr+MWOcYZ5PT?!qYl}>baRC zEYV?NQdYZsJR|-a{;XM7NHs~f2^F0_ZGTzreX;#)`WbyXX<~d`#FlODbR@IzWogKT zmg6fG-7-D3ysB5TAEt@crIBK&vsH}E>=4x`vb!b18P6pnTs=9SfL_Ne*iMThY_ilEJ zPTLvv!g8TxqOtc~w55~rQH1$l_=9^Ss(lhi-(4t3pRSH{-y#TLo_Q)SR;j6hLvZQT z3h|8Uv|P=AV`aQcu+0Zqu_@z#-M09xB)`q`&CB(yBKV=Njb6L3c$7wB<~>(+^8A*) z80tOnaeLj!zMNL|T)DTV)b$$=TiZCUznm)>4fD#bHM1WRHLY3`Oy#*?SW58j>s5!u zV{w%tM2P)BYaOoHts?dV%_D{~=if>0%;16ye-sV9`Neox$Bvo5Q<>a^(k*M%m@NyT1{w?EfTq}Ess@_zYb)gM7;Q}DRZisGJCM&!EheZs4Q7zHu3Y-DWAB9XZ? zCMP9eE+LV<<>Wg{cR#>uD3>xLO2KWuk7FiLnDA2QToWXBoOmoR#dFoL|B^Q@FIk_$ z)?(~Q|G*u3CCXZg8^IZpn(~WO%%VR=?k~Ep#9y3l$soeGoidDlB8dEA!U>Y*QbxN1 zO;hGgaq7CTPOOaPw6RNGGT-CH#h!PzI0RSY#Js`^Fiyi*EEXunh>Vn?UhTMi`6;om zhPB8e<ec>=e2`DW^qrg~5YGEobMi?L)J+ytjJqJ9=-y%L60ByH@AEE8Wcs zY~7VLh+~+WYirtlvs^n8_pEx>|KpiUb1frzSAF?wl8T8=mG0$d5bcb2=_kbLt1p13A;FiOB&wD~T_{|GXcANz^5*zkFJCYIbs9)cXR()a!=o-|t&_ zrugV4Vs~gBEIxQpTc7=+%X@liJa!84y;k3;k`2O?&%WQuN+MHqvwt?fV^>t@GikWf zMB=CT`#!H0>bKJDx|69h<=-!NiA~Ylz3FPIU46g${rOWZ!?>=xuJ*o}AD=n~AsC)` z?I*de42Nw)Z7+VR#OJ|lJ-ss?djA+v3#US{D%oi`&snSQF`uLGN9OjuD!!kK*)I6; zMDT`-#&jJ^qA+*7i@cdrF+3h)IBeuQtyh@3QZbQxz&*_mj^y|=RHJZN@%3En>)Uv; z8P94cdil?+MA8Z~nd~O2FlI~lY>%sv$zP{D^%YlEIU!L=UJ#S^%16&oQOB{eK!06E zn63#GVpUb3~XP?}o#8v4symHJSYa-v+U_v=5rY?%& zQYXC?c1Y6?p(WwHu@NwS8;$D{f~Oo|@)JM^fG@Ac~P5g{xpez-FBxQo8Cj z{m$~MSo|*XpUg#U4M#_VtvbhwGt0^BMa+NS5jGh#?J?bg)g&IvY*=|; zt|1#xocnx)^wq9`TO&zyTO{8bjaH|&Pa0%Pm^_8I=V-r$&zei=jy!%`FtYem zwVVEO@zdbPb1Uf>4CG&{^QX`DZO6PxdmFG1v33YIs{aT%NBZTs)@h=8_3qQ&?V4R? zXRNCH-00KUt&$>pA6>Oci#XM)II&^ymXPNJd*$13!LJ*Ow8f_>p!z84j$2#q;Y$odZKwdDm1P@G^FaXHP| zd0g!=KiEM_5%d<&_JzQ@YyNK+EV@3qyMgLFyWVA{ty{I?HoShL0=kxZ`x+m6eKRv3 zY4ewa3x0Oah~BW}Yq~v6wOJ(0Es=7p@77X>yQNr!&F&61YI5SjC*XVr?0+-G^_S#C zUer<->S70Tg8BW?K`_)kNGU;sGyherT?%VVdy_q3l&K%4`>k}$+-};v(q=Eb?13g@@37zo$urOpSij3i-(`2%i3%ix_oWTTzk&6;)h@b z|E|%U*4^))W`@=_TP3e~7!S+Tic_{mQ86-N8s3d+5xn7ivz0aj%0W8zM2{s2iyZT2 z9xPKr2nYX6y^M*?xxq-M(LJ%x7b@IDHKzQ*9K4b_*reex1TMcDT1$UohI#$Sp~OItl0O_ z_n8wVQd{!@69y$Q3?ZDXMcG68k7|iI3GcsufBda3cGCIHxg3Ab-A5|Zbughzbhj4H z;F{hX*kvMJvKYsN=Ih*;csrlpWVKzhuv%{kJLi(wl8~^^uFEK!nqSq*%BeHEi8*?E zMqpykr6|@Ja#Mx_e?uNOubz9eP4}t~u1>%^FOkPHTa!Opp0rGJxmS8^)OWOi8}7dN z(Zb_?e#^bmXTxh_X||)~LJ&Lxd_GN=?SI3+sljzqA_yLd_#iXeKMC;xynn8_G1XsT z!#vyH=(Pp-5&Y-ua|CpAW4f7O3(%H-w1oRN8NHbuYT9x=zcsskpoih)l-#Bq*g4<2 z7F`d65Ez={|Fo7h9J8-pok*m`anjQ= zHMJM<8NTmkTM_Yw#C6*?2^Tj=Nors`J$I5_m-!`|z$NUCGm6Kb*~r%S&tD>Fz3=@X z?%Ddl(0b>G z$(Ma6hjaJF!m6?)e&|Zj(?;VMH3uh}l6R+)`fK>!QDPU6m%POL`R?BH=1bZ4ql%_F zo<&V`PjFv(&ZWG3qAREVp=kLUYq2F4)a&7UQ?BoBlAIcjqZ$5+_h^M98)=({vWb$S zmbixu4CGykHAT8~qS($l(Yr^56f*k?9hI^(Zl%M)1@a|@R9Pyv`nZ;lIhC;;!amUWPOK{_s{Xhj@xDFEy;)#TtAT`gE7fk0aNjv~rl!_A z&m^P*IGv*+zNa zkX+P*>Dlzfad#WnPnVxOx~xf%N=M)Nc3;4)xLsbotBa|l3xk4>?AMDg^OiLQMfhnl zxAI&$@xo5N{LTd8ck#boyr$uLnZ(VCT_u=^?-t=w6oD2i^FOZv4Rv~d`L3oA#CP9D z5WjUgHOTbOi^o~~{YkP^eDyAQbu(slvzqjXTWP;vjlz6jBU&;ea4vjtGZt~PS})~r z&)=`c`n4)k`DtD<3NBu^C|gxga&$@2D2sgBN5Bp*qCy?C?3<>*M7ZM(SG-L0_MEm$-k zxiho>e%+IBb8=spWMMh&8xelO*H_-xcb@6=!mro8&#sP((6MOWMS0Eg`7YD0TOyio z!!F zWu-&G$Xs6{t@gx;pW{Y^(a`i$hV#oE&$O{o@yKB@{z$%4v<&<~(t6R1?HI`sCsl3s3u6eY!=l9832ChrYeqR)6YDtQ-K$=RQC4Zc z;`SzFR?ZCibT&^e1XtNpc+m6{VKtWx{UcjjjX`5o=S2UTCDJcn;rE6y9jB%z^HDxM zd$p}EiO@~bgy`emhrGCGR;%@I@cQ9Yc3OU~BtKE+XcaL6U(4>rNGjom znlW3?!8UMDiC1%--h04%W`oRvCh?(iuuDqt%rV@WwM65gL6v7L#Mt@4u>a_sGmavR8!Zi}#YV($xA5Ihapwwac?9%j)k>=2_k*ITV5tMjJ&jdpr##NA*gxpGK;tg?4vRyY zixn4-mjCMu4xRzrP>UR$(rg_Lvg5Y}tRisC7$9tydjc%)J14g7GHPbhIl=rjv>C$h zh7Icqgl1T^&@@n!%J3ELR+Te-NvMufUlIt)m5G!g)@R1uEoh+O55G}Wd`>Rjxv-FO zRH2t)WUY`qH%5%kAvuarXXa--KXVd9Y-vO^73MqT<3?DWfpt|j=b^%-6C)EnD@v`- z>k)UYdwf?&Lb3>MHu=7YAAcA@KKhe|^X6q|QR`d9KYt{bF|U=F<=8~Pz3$6i3CnE? zd46KTtmHY)EhZio9AXj5!PT3IcFGk7Rz}^13Due1GCue6#O?$WeGEd)_`q$|pV@;! zArsKwe|UWcsEK8GEj8e9cbKgM%*p28ia0x|o_v~@Qeo}o#bSci{%czH1}4^NLs$=a zglkO;1eVW=i+m7u!@@Xl4WUKE7Vd zG_`DN+xfBDF%cs!8f){~kP-J724lh0%Xbfp9&WC-ZtTh?7SoSi#pcD3o)eKZjwK8$ zERZ#^skF&oz=04@j6+`T=?Wh+Zt-7Zmmt-6x|07!s2MW=t_(v;K zHgcJa^Rmm_;mO7F&`p}!E>rfKkI!5uIIEz{dnXwh`vF(az2*7DIf>GOlX5Pc7$yn4 z_j0(Ssg&#W?Z>_+@2JI{FRM2nh2{^YY06;=hzSO&6{SPk_#gXz?SN>DP+A_pnHkh~ z={?yLv)V>mA_iu^VecmV7QtD#7ZIOC^VWg=DG8h=oGyS)!zJ=|22~bG45AS9o}F}E}A~=vFYLdk^bQ>v$3x6uCC#p9_g{3cEU5Zy?tT%y`-hR z!yW3>w#59Mn8jT$wXdfV92h@LOpkbW9k|LT&_F<(T-U(^hCF_qoLA7&SzGwulY8kn zU+Lf_{b{ihBudkcQ>!**;0z7+j_u`6p6tC$h&xd-@qHoD(6cS@$;ori?o-B2C;3|p zPK-(PYb#q&kzdH57~+jFP9~7?kh%d;tkvPqxL5U!JJp!jZ4(-CLMVob%4tV5-QEcj zyJVs{*AOvTXwtEL;z{=-r`qCL&t_Rs0|;I!uHSSE_7pp*)V^$%=>4hONxhr=>_`* zoro`7MRdx1mU+3WOg`3_Oty(*gMvT*u^)1BBfj)aW?f)E_rKYXpAXf3Fzt0!Fo>~d zxgudkD*gC&Vf~CDsVl=mZrI=`Q-pM}k7=C-7|?lMb6ktg!C& z3UGIoZV;?A|EN;f&L-8pPg;7W5j&MM;!Z1*$_(SmI0>s=>5Eumt2r5!-VB3tWdzA1 z-R#1=broUSF-}p6;XPIF=J!@O$ex}r8jGUsQm^AO6s(Zj!HbVK+X-?%CMGkGPN!uVn@g+0EFqA+oIA>yt|RgGkC_M2f}n#%SRD699(DA! zt^H4L$@c2SdH27hCM>^fZ4p&t>J~C0QXTQ}QIFI;4$E&>x@CDTasjd>{cgN~#Yo^& zT;w{_Q^%;pcj9rp*UzRzHavT9a6rB)IV@QT7{mw|gauuJ66Hl0L`CJ_A_dbih@F-u z-D`Lwp`UiHlYf9;fTTej_T=Wvch;dCu+Z>z_)_#d8SPeLT4&+a0?tzR=j7oD#XC4x zTtE1_g2}KX7pa8Q#-a_(jc%Jqmox_j&bE)X4^s(xObmXJE#w<-4h&8j*Zhvt-Ml+@ zR#xPS>zZ5W%GGyVX%C61p9al;A2qvF`f`kk%)29>>RRec2sU@wGnIbqBz;PiO>O-< zK^1Srsi|ME?%FW$D04f@hS~HuRxaB!Hf(ottr_B9<%{BaSjJi57wdTJ{rW=)Lnh6g z@3&u2JS{lGUDoz$w_Al~Q2+j87QB|t(m~_3ujN8MPa5ua!>%}Zz520#k4fky&uW8W zQBbY!<>p-fm=*K)j{|?|d0}ee0Jxk>AJFp2M{x2lN`>!ET18YzF z@Ob~=Fip~9WGHRd|2LFk90;TpZUuFSASwZdfe`2WXPa_;4PQ~=U*{79tlM%#HJ<*wWsYJ(C&)A09MhkP@;A^*W%sl5NF7Ylf;Jb=j9k_!u zzVLalvDt=2$n&i=f@Uv`=IP;cyOZmL$2%WCwe^_OU-Nz9F5HrBp#@)luM#U59je%e z-%xS$M#o50c<+e8n`J^J_t0n2jH2C~i*a|xVb>bo8R7YVz8DuPRhjiXv(#m5HX|m} zyxGm^f*#fUISNR-?dCr5@l>y7XYVNImG@7aC1&7db2St1KhJ)1@31v!X)dFhGGEMS zt+*JIti3N+@BQ?)C43A{JhJt&sM^)J*@3u4ey`sD(#-^ttGH?^S3m4jl&;U*GZA?4 zi7V$K@3-%Idj+#UO6R_GHcd{Sryg;fd&#w;q+eke_0)X8rEKJr>G%p~Cv=I7Ohi?y zKJjJ}+m-SxS5~j_zF7H%CcV?wzPGDp>iC`M$YPxynpc*WBC|4#uS$RG=*Hw+P3<7@ zO2=kVoy=jQnHuNz8`ZP%h1ep{d$;oRJp$n1IhBd#cG<;DalzMZdfK-SQdUy=&K>5PGy8(g&e;u z(_@`*VMl@~nDU!GYuQ$UlFfk9=@OMUn91SeCvr>HgK4zlYEl<+VCAV{@rRah$lq77n>-(z`}ERE^p&OS{50NRMPNko!uCZ zq+Z?H*W(mFwIi0$Ym#xB-!1Ummh`0Ct02XGm-`d-&6W>L$IiT1btN@Bhr43tXGg9h zOO}v0O&)pep8Zb-*5vn(`V~&gp4-4;Id!g}a=~Em+ro0IzZ+b8 zDBz3v$tM%D8H#-)j;CnX_L>FG-RTUEfI!4|Kfy|}Hb$YNhMKjK8k%vfk?Tzn?$lc` zy?ym>F9k*n3ztp9amFy8Z91jIymr}Z$mEdfwEkRnx>L31E~OciE!{BVeAWEmb3Z9E2j*^< zmB=`*8)-P789#*NvgZe$tDGpx&WRYw7rPhWV(vgP)QOKp6OqP8G^AQsmQ|YbMEGic z@w_oEMwUv*?LLP*W3A!75{A?1wZVd7@5GCq$v9K1^B>$#*Cbb=+uQPdjGMI2s)$N;*s3`=D6I zG;KvjYqi8)Qqnw<n!+1Q;*0?5F zdb7j&g4GXKKMvbyoqIHwg}totjd3VxppV!WE^uyAp5?<9OO?NBj6X#dIZ5kZ)B9Dv z<7R`+WuIFZX@$`r6IO}Lr^ymN=@c0<4qG3$S+Du5c(J)jactQ;dx>p5Kyn(hQSp(3 z!wDbax*Po#VbaIb_m3}hj7jGzo_Xq3c_ZG)gz1#L2rh%`8=;Mv;*C|0&j`Y&P&)sTJpykD zkB9!_j4i_jrMdLI78SXzJMBEjGBV8{@YD}@6vR4E_c7!%`5k$FAPVyQ8voztujd{5piq z{vjHO$4BXH)!c_10(5rnkZd|2!XKi6@c^|yT9!yFAe%OEn70^l08QW!Esg*UO$68! z4Grlb{1n>P@BmE#&=6(h-^UOU8XCyb5j1iF$NIBmKjz=;AW&~iK{Z~lvZsQah zrU1~Uh^3yZgQu;7`yXwKgGSQ2Nj-`1)C7R#M!^~|qQMFRjfz<6+k3g#z}&4I-2dn$ zJV^dbU(X>4$k-tMpbFf@jE0OT^*{+wC%ChN3mQEjT|l^b*5p1AR0*KjQ3O^3PIj

k;2Z~`ih?qhYND2MPEa3vsIxP=fQXcKdQ{5j6#$PBA5^f~c{E@l zpaoG&Jtvrr9qeytq(kV~TjVtZ^hZ$TquS1nA07Ia%txbW}EGji6 z12y((l7r%QiX5c!^D4^zQnCj0zr`g^?$&ApDt--Aj4JLa2{d3iP?SXxMH#)gNbSy^ zy9;hM2!UV%XG1N?%%I;J)!Bf!zm;GJa{=wXzlTZPgcT-)4!D61P(>A$IS3WxRTL2T z$7D7ha5VKfQdDZM&paEzUcJB(P^oe92dP3p)L&FBcPALs1x;;+q=J3mW(k3;Oh8uD z2-&G{kSdI{m#n*khZWT22o=0ItIM$Yk8`ntfB$_@sT{tSu z<)jHDg#dG-76fJ014uqzUPaKktj5QSh&I+RC%DTI;2;GCmt+8DVLIpoa~kNtz_S2Y z#tw!Kiqxx^?W0;LP@R{83=XyWZPY;r1=a#kH7|4;Kr-JdJRy<>A-ok#xPN zh%*1128hg~)sz6(@8ZGwp~DCbSn#(7KuYIgXAgBaY%-+4hAX=`vOoz`AmXCdJ33~6 z=gL8yoE$uk%0oU~_lGL2T&^Dv#1fq#o_NzJt)X)&_oy{l`gop%^f(GKQK9}6F4}d zp(64cAgT)3Cc(wZ>yO1=2XniAgR;P7pj#8*`>4{gxTE9#jtA->avha@yocM!B2p## zl7qRZmM0o2qHzPH)qvW$_{qV&+>g)$$940XSfGbc!GrR?@J2&MBujt{(p(T}4?6;~ zh}lAx4Zb3xE6&0AUEqI!$`9NYk&=T}ypp>E=(|LNMH+4Khi`l>5Y`tIFVuQ*F5m!G z0APWjYM@o3?gT}bHX~)tY-|oV3oI50!U3wq#;zZL3IQlDLbrmJvT!SFD4OOdl6vRe z?Gzb6RR>hm8cgv98tN}mk<>pnfJC|%5_>MXVOs$$b|Cb>umXR#7vFZzf+fJJ9@4?3 zn`p572*o0$JxoQK>uv?CyaANl;~*fSYIZ*y4HZQPf2W4O+GE%TvYG=AK&@|nL>-`l zairh&60(%_a&oePUp*@I#8C1+gBTgs0wSY=rDD;55$#<*A!P*`~h9erNp*I$0 zN&&YGv=LDK_ign-uE76EtOf`2bf0SuTVv)u2`mE=NfFVcFNR1o$q$@DrO(o1l1%vsL_F!{qacZJ4i(uOxRKu2C#oG zWHGopzWG2@FAx?`p=<*Xh#cr9hkCgyL%p0levex7A=LJ5CdJ_J&P7R&#?$f`_?&GQvN1F#QG>&+;02R@5jY|EAmJ0HX|AD%54BsUPPzQkq zP)ow|88otrAgHqcXyAyFVAs|z`T`)CLAnTH%pZ@WS#(&?StlfCsc;ot4Te=`8_K0-aI-c@Y4TezFzH^3kS@%fQhP9+t+BAqGEul`Ag1of9$-6Obn2c2JN!> zA-e9vfvHea8G!{fRM1|K6Eaq})P&i?oE@NOA}kVoVf*4h0st!<0-sn!2S!-ye*%v* z^=bqIFhaMe5^tgf3;wTQf&PR9qy>$#y99B2BVxuON=ZI9%h%=}j(ef4zR|eq`s+I~KV8qt_?}6rHsnf6opt>HS zURgy$1w&5%3srx1(CR0+@+6=GR9WA@M?(c2YI2$~pcM^8>tsmHE(Fp#k^#;BJVfQ) zKt}~(;0P+xbyrswIU%49cf>m=YdGi=JXntlD*}6I%KlYWB(<;*H=7U0dI|p^_4y}s zR1gz1<^D=VY9NbPK>Gx^dOgO2RQWIHsGyCYsq>#y^~@&fF(4}*Afv{wJKKQj=kDOE z;sUzop*FuW8PJ0OvvGhb89N{LE2N|y;_PZLz_bRw#q>uRfIuF8KgwzdEVJA||Nfey!aG)^h7<#aKSY6>7xGmK-vZGVl^GFtgDYU=%-^&!and+gRy z$ryMla_6UmGP)AgXjB0xVn7%b`T-pjjM)4-5rCqpuaJK9<-sgXC4f#Jf-dc&kyPlP zQD*c|q;VwWRyf1})Dav^;Q0430l`2{xI{Dwoe%~W1f5)hVB*Q43rFHo-@J1MoxBhi za4`PM0`GJ%4&#LQz@X(3b4E5W7F;aA)gnyIj6&;2N8<-=K_S5-8pD@_ge1(+@*Iz$ zk&a*ZKX|>Ly{{rX8-7SW9Bgzvx&PoTc7zrd0v9 z@8qq~HUD-XDL;rij3|~KK|>Zs_{|Ys2%D{U%m%bkaNVf1A;QCQ3iF8_Ny~df7i<7z zDgXznRqhj`q5ZOomi*tZ^_stkuKqtf)EZHa1RW1p1@t2U4MNe)K|$IYs%hIX1g;q| zAcUH0%%G!!kOQc4aBl|}yCX-n^EqBw&jYS2una198&tsm%*g(~03rOFD-ZLqM$8X8 zq6^9W#rhCJt9QYH%4MWP$Ni-R1lQin6CD>BB~9lSJbnOq$qvcef{qKCOF$1AFc%xR z^^sF2j1Amt5zXNR7Vg2V=spS4cK4+RgQZJ}8x2%J5CJs-qwZ)LxJahHb}B&>VA|pzWM1G!$NVMeUzkXpj;^G3UI13o z2c_T)u-Ly3B0)4va4#@9xQqLr>s}5P)=venzFZ*XD!6h~VvGs=i+?WHqi6j9iVdcAviy71;9Vq`g>cB~;4WVpFn9P7 zt&LaL9u2X9Vvoaj(C1TS&;doj6f8LCj`xK795Jjos%yS81;qRcuKgT}n8y^+Q`JDP zugCAT!1D6CXwrJ5JKb%N*jNQUv#S3K8pM}_%@8EoBKe9t44_$oxlrpC3r%!r zF_5a+AyjdMCjJ}(L-niUU}WsD!9dUEfA|%@deF#aQ1CNBzXNJa&D1+gROAD}S`hTe zB63QYr{@vDT9ImL8qw&?0$|h>L*5V#7)-a4; zrQ(lA8faY|G?^klNUs0TgB;ky$o(jfXwY^sv-?NQs8XvzkHjCXWxDFmIEc>4IG_wv z>+OJK?}XTa>FL(=}n%DF>bY~e>uS`K;Q#D5-y8ymud7Grfmhy7KMRos0XTx`H}$G=;Q z^Z5ebIlzShE~>a$Zhz(eT?@!!p%;W-&ke9#0E-%TNWK1sRZuuWy-0A~Rb|#w0DSro zILsFv_?L(2IXigTAJ{wMV4dE}O7P4C*o|K3pd!}%(Sbqc0oYJqZxAex&@a^pU%3g8 z_bTN~ih z@6z56l=!g&N-%`+U==J0?w@q1s0o7xgCIzjoji^hZtj=!>qSJc=~D-pev#;yzue$I znE34*yRU$lsX$g%@bABmwWxzkK5%;{Fu@D%1a(C>i4s{13^kq-#sPKOfIJx$xgU)N ziMYwouS`Mx@7g49roD(*xR-)2#xPW2NgOBiYy9{CD*A6AgL#i6g6*K8$b^QtD)Sl z{L^Ya)T%|w`k5~t6J)=Thag=!V62yDuwX=4#>>jf{Vz!-lIoK?^8ZRZ*N~`!D2}g& zJ+LQ5U`B-%R2V%>ETN|^R)!Q?X;E3Z>m$WzVS7M9Y;6RkVOfxxn%Re<_inXY5o*zc z=(Ql)!#*TdRA!Qx_@Vk=_3n7j%$*yBAM}eq&Yd}P&Y3ea=Qx#jd>_Wq5y;2A6RnMz z2?vNBy&|kUa&_;!w>J@@9vnbNz=~5=4hk2z5_)CJiL={mlGBpi8=Ft91-23LYWMZ+ z^#W{+l8Ck%Xu$aOt41iJx*5+)wUbr&TEK*jwcuvtF1)D0Gc$dUy|T8W=_j!9(d#VS-{B%8F1i~bgGN0WdId;F8AUD}DMBh2WDTS|XHVN>?T4$! zH-pIR&k7SDk>ECO%E+-vzdWxg*{xh<9gcul>j>WBvA1@TqPkkrcBgukV1S<@)wD!L zj2VJ-g~^AINb6qWZCqvKH9WT#Oll8~GeI9=6ZEb(3|6rsXh&TJqP; zo&gW=0-vw70b^GiKm`j+71g;ncXlVt^y!g7L|ad!3aI8NrT{Xpvd4SXe;#(VPd**k zI-FB*BLM3k(5rvLK1%-&?C*vJ=a0b$9^OS)fiFvdg~{&GEVE=}*Sz%jEy%MxJRD4{ zYk^%373}2I>9W2`%FINvwHV$&s|1sAoWhN3FG-aGvw7|S>M zqDqiqIP)z54%b#m zeOL;lrA-;|De9xBMNXC9-Ji=BI;BKfyp$2=-U-Y{pe$pwpp+>k($bEMxD5qHdQ?0> y6c>7=Oj_oSF?}_`e_iyBQfcuzMxAp{K-DQ_w>&WfK^THN{1hZ1BFF!lOn(3xbxJ<~ literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/cpuid/testdata/getall.go b/vendor/github.com/klauspost/cpuid/testdata/getall.go new file mode 100644 index 0000000..9b51c7a --- /dev/null +++ b/vendor/github.com/klauspost/cpuid/testdata/getall.go @@ -0,0 +1,77 @@ +package main + +import ( + "archive/zip" + _ "bytes" + "fmt" + "golang.org/x/net/html" + "io" + "net/http" + "os" + "strings" +) + +// Download all CPUID dumps from http://users.atw.hu/instlatx64/ +func main() { + resp, err := http.Get("http://users.atw.hu/instlatx64/?") + if err != nil { + panic(err) + } + + node, err := html.Parse(resp.Body) + if err != nil { + panic(err) + } + + file, err := os.Create("cpuid_data.zip") + if err != nil { + panic(err) + } + defer file.Close() + gw := zip.NewWriter(file) + + var f func(*html.Node) + f = func(n *html.Node) { + if n.Type == html.ElementNode && n.Data == "a" { + for _, a := range n.Attr { + if a.Key == "href" { + err := ParseURL(a.Val, gw) + if err != nil { + panic(err) + } + break + } + } + } + for c := n.FirstChild; c != nil; c = c.NextSibling { + f(c) + } + } + + f(node) + err = gw.Close() + if err != nil { + panic(err) + } +} + +func ParseURL(s string, gw *zip.Writer) error { + if strings.Contains(s, "CPUID.txt") { + fmt.Println("Adding", "http://users.atw.hu/instlatx64/"+s) + resp, err := http.Get("http://users.atw.hu/instlatx64/" + s) + if err != nil { + fmt.Println("Error getting ", s, ":", err) + } + defer resp.Body.Close() + w, err := gw.Create(s) + if err != nil { + return err + } + + _, err = io.Copy(w, resp.Body) + if err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/klauspost/crc32/LICENSE b/vendor/github.com/klauspost/crc32/LICENSE new file mode 100644 index 0000000..4fd5963 --- /dev/null +++ b/vendor/github.com/klauspost/crc32/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2012 The Go Authors. All rights reserved. +Copyright (c) 2015 Klaus Post + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/klauspost/crc32/README.md b/vendor/github.com/klauspost/crc32/README.md new file mode 100644 index 0000000..440541c --- /dev/null +++ b/vendor/github.com/klauspost/crc32/README.md @@ -0,0 +1,84 @@ +# crc32 +CRC32 hash with x64 optimizations + +This package is a drop-in replacement for the standard library `hash/crc32` package, that features SSE 4.2 optimizations on x64 platforms, for a 10x speedup. + +[![Build Status](https://travis-ci.org/klauspost/crc32.svg?branch=master)](https://travis-ci.org/klauspost/crc32) + +# usage + +Install using `go get github.com/klauspost/crc32`. This library is based on Go 1.5 code and requires Go 1.3 or newer. + +Replace `import "hash/crc32"` with `import "github.com/klauspost/crc32"` and you are good to go. + +# changes + +* Dec 4, 2015: Uses the "slice-by-8" trick more extensively, which gives a 1.5 to 2.5x speedup if assembler is unavailable. + + +# performance + +For IEEE tables (the most common), there is approximately a factor 10 speedup with "CLMUL" (Carryless multiplication) instruction: +``` +benchmark old ns/op new ns/op delta +BenchmarkCrc32KB 99955 10258 -89.74% + +benchmark old MB/s new MB/s speedup +BenchmarkCrc32KB 327.83 3194.20 9.74x +``` + +For other tables and "CLMUL" capable machines the performance is the same as the standard library. + +Here are some detailed benchmarks, comparing to go 1.5 standard library with and without assembler enabled. + +``` +Std: Standard Go 1.5 library +Crc: Indicates IEEE type CRC. +40B: Size of each slice encoded. +NoAsm: Assembler was disabled (ie. not an AMD64 or SSE 4.2+ capable machine). +Castagnoli: Castagnoli CRC type. + +BenchmarkStdCrc40B-4 10000000 158 ns/op 252.88 MB/s +BenchmarkCrc40BNoAsm-4 20000000 105 ns/op 377.38 MB/s (slice8) +BenchmarkCrc40B-4 20000000 105 ns/op 378.77 MB/s (slice8) + +BenchmarkStdCrc1KB-4 500000 3604 ns/op 284.10 MB/s +BenchmarkCrc1KBNoAsm-4 1000000 1463 ns/op 699.79 MB/s (slice8) +BenchmarkCrc1KB-4 3000000 396 ns/op 2583.69 MB/s (asm) + +BenchmarkStdCrc8KB-4 200000 11417 ns/op 717.48 MB/s (slice8) +BenchmarkCrc8KBNoAsm-4 200000 11317 ns/op 723.85 MB/s (slice8) +BenchmarkCrc8KB-4 500000 2919 ns/op 2805.73 MB/s (asm) + +BenchmarkStdCrc32KB-4 30000 45749 ns/op 716.24 MB/s (slice8) +BenchmarkCrc32KBNoAsm-4 30000 45109 ns/op 726.42 MB/s (slice8) +BenchmarkCrc32KB-4 100000 11497 ns/op 2850.09 MB/s (asm) + +BenchmarkStdNoAsmCastagnol40B-4 10000000 161 ns/op 246.94 MB/s +BenchmarkStdCastagnoli40B-4 50000000 28.4 ns/op 1410.69 MB/s (asm) +BenchmarkCastagnoli40BNoAsm-4 20000000 100 ns/op 398.01 MB/s (slice8) +BenchmarkCastagnoli40B-4 50000000 28.2 ns/op 1419.54 MB/s (asm) + +BenchmarkStdNoAsmCastagnoli1KB-4 500000 3622 ns/op 282.67 MB/s +BenchmarkStdCastagnoli1KB-4 10000000 144 ns/op 7099.78 MB/s (asm) +BenchmarkCastagnoli1KBNoAsm-4 1000000 1475 ns/op 694.14 MB/s (slice8) +BenchmarkCastagnoli1KB-4 10000000 146 ns/op 6993.35 MB/s (asm) + +BenchmarkStdNoAsmCastagnoli8KB-4 50000 28781 ns/op 284.63 MB/s +BenchmarkStdCastagnoli8KB-4 1000000 1029 ns/op 7957.89 MB/s (asm) +BenchmarkCastagnoli8KBNoAsm-4 200000 11410 ns/op 717.94 MB/s (slice8) +BenchmarkCastagnoli8KB-4 1000000 1000 ns/op 8188.71 MB/s (asm) + +BenchmarkStdNoAsmCastagnoli32KB-4 10000 115426 ns/op 283.89 MB/s +BenchmarkStdCastagnoli32KB-4 300000 4065 ns/op 8059.13 MB/s (asm) +BenchmarkCastagnoli32KBNoAsm-4 30000 45171 ns/op 725.41 MB/s (slice8) +BenchmarkCastagnoli32KB-4 500000 4077 ns/op 8035.89 MB/s (asm) +``` + +The IEEE assembler optimizations has been submitted and will be part of the Go 1.6 standard library. + +However, the improved use of slice-by-8 has not, but will probably be submitted for Go 1.7. + +# license + +Standard Go license. Changes are Copyright (c) 2015 Klaus Post under same conditions. diff --git a/vendor/github.com/klauspost/crc32/crc32.go b/vendor/github.com/klauspost/crc32/crc32.go new file mode 100644 index 0000000..8d6ba5d --- /dev/null +++ b/vendor/github.com/klauspost/crc32/crc32.go @@ -0,0 +1,186 @@ +// Copyright 2009 The Go 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 crc32 implements the 32-bit cyclic redundancy check, or CRC-32, +// checksum. See http://en.wikipedia.org/wiki/Cyclic_redundancy_check for +// information. +// +// Polynomials are represented in LSB-first form also known as reversed representation. +// +// See http://en.wikipedia.org/wiki/Mathematics_of_cyclic_redundancy_checks#Reversed_representations_and_reciprocal_polynomials +// for information. +package crc32 + +import ( + "hash" + "sync" +) + +// The size of a CRC-32 checksum in bytes. +const Size = 4 + +// Predefined polynomials. +const ( + // IEEE is by far and away the most common CRC-32 polynomial. + // Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, ... + IEEE = 0xedb88320 + + // Castagnoli's polynomial, used in iSCSI. + // Has better error detection characteristics than IEEE. + // http://dx.doi.org/10.1109/26.231911 + Castagnoli = 0x82f63b78 + + // Koopman's polynomial. + // Also has better error detection characteristics than IEEE. + // http://dx.doi.org/10.1109/DSN.2002.1028931 + Koopman = 0xeb31d82e +) + +// Table is a 256-word table representing the polynomial for efficient processing. +type Table [256]uint32 + +// castagnoliTable points to a lazily initialized Table for the Castagnoli +// polynomial. MakeTable will always return this value when asked to make a +// Castagnoli table so we can compare against it to find when the caller is +// using this polynomial. +var castagnoliTable *Table +var castagnoliTable8 *slicing8Table +var castagnoliOnce sync.Once + +func castagnoliInit() { + castagnoliTable = makeTable(Castagnoli) + castagnoliTable8 = makeTable8(Castagnoli) +} + +// IEEETable is the table for the IEEE polynomial. +var IEEETable = makeTable(IEEE) + +// slicing8Table is array of 8 Tables +type slicing8Table [8]Table + +// ieeeTable8 is the slicing8Table for IEEE +var ieeeTable8 *slicing8Table +var ieeeTable8Once sync.Once + +// MakeTable returns a Table constructed from the specified polynomial. +// The contents of this Table must not be modified. +func MakeTable(poly uint32) *Table { + switch poly { + case IEEE: + return IEEETable + case Castagnoli: + castagnoliOnce.Do(castagnoliInit) + return castagnoliTable + } + return makeTable(poly) +} + +// makeTable returns the Table constructed from the specified polynomial. +func makeTable(poly uint32) *Table { + t := new(Table) + for i := 0; i < 256; i++ { + crc := uint32(i) + for j := 0; j < 8; j++ { + if crc&1 == 1 { + crc = (crc >> 1) ^ poly + } else { + crc >>= 1 + } + } + t[i] = crc + } + return t +} + +// makeTable8 returns slicing8Table constructed from the specified polynomial. +func makeTable8(poly uint32) *slicing8Table { + t := new(slicing8Table) + t[0] = *makeTable(poly) + for i := 0; i < 256; i++ { + crc := t[0][i] + for j := 1; j < 8; j++ { + crc = t[0][crc&0xFF] ^ (crc >> 8) + t[j][i] = crc + } + } + return t +} + +// digest represents the partial evaluation of a checksum. +type digest struct { + crc uint32 + tab *Table +} + +// New creates a new hash.Hash32 computing the CRC-32 checksum +// using the polynomial represented by the Table. +// Its Sum method will lay the value out in big-endian byte order. +func New(tab *Table) hash.Hash32 { return &digest{0, tab} } + +// NewIEEE creates a new hash.Hash32 computing the CRC-32 checksum +// using the IEEE polynomial. +// Its Sum method will lay the value out in big-endian byte order. +func NewIEEE() hash.Hash32 { return New(IEEETable) } + +func (d *digest) Size() int { return Size } + +func (d *digest) BlockSize() int { return 1 } + +func (d *digest) Reset() { d.crc = 0 } + +func update(crc uint32, tab *Table, p []byte) uint32 { + crc = ^crc + for _, v := range p { + crc = tab[byte(crc)^v] ^ (crc >> 8) + } + return ^crc +} + +// updateSlicingBy8 updates CRC using Slicing-by-8 +func updateSlicingBy8(crc uint32, tab *slicing8Table, p []byte) uint32 { + crc = ^crc + for len(p) > 8 { + crc ^= uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24 + crc = tab[0][p[7]] ^ tab[1][p[6]] ^ tab[2][p[5]] ^ tab[3][p[4]] ^ + tab[4][crc>>24] ^ tab[5][(crc>>16)&0xFF] ^ + tab[6][(crc>>8)&0xFF] ^ tab[7][crc&0xFF] + p = p[8:] + } + crc = ^crc + if len(p) == 0 { + return crc + } + return update(crc, &tab[0], p) +} + +// Update returns the result of adding the bytes in p to the crc. +func Update(crc uint32, tab *Table, p []byte) uint32 { + if tab == castagnoliTable { + return updateCastagnoli(crc, p) + } + if tab == IEEETable { + return updateIEEE(crc, p) + } + return update(crc, tab, p) +} + +func (d *digest) Write(p []byte) (n int, err error) { + d.crc = Update(d.crc, d.tab, p) + return len(p), nil +} + +func (d *digest) Sum32() uint32 { return d.crc } + +func (d *digest) Sum(in []byte) []byte { + s := d.Sum32() + return append(in, byte(s>>24), byte(s>>16), byte(s>>8), byte(s)) +} + +// Checksum returns the CRC-32 checksum of data +// using the polynomial represented by the Table. +func Checksum(data []byte, tab *Table) uint32 { return Update(0, tab, data) } + +// ChecksumIEEE returns the CRC-32 checksum of data +// using the IEEE polynomial. +func ChecksumIEEE(data []byte) uint32 { return updateIEEE(0, data) } diff --git a/vendor/github.com/klauspost/crc32/crc32_amd64.go b/vendor/github.com/klauspost/crc32/crc32_amd64.go new file mode 100644 index 0000000..4827128 --- /dev/null +++ b/vendor/github.com/klauspost/crc32/crc32_amd64.go @@ -0,0 +1,62 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !appengine,!gccgo + +package crc32 + +// This file contains the code to call the SSE 4.2 version of the Castagnoli +// and IEEE CRC. + +// haveSSE41/haveSSE42/haveCLMUL are defined in crc_amd64.s and use +// CPUID to test for SSE 4.1, 4.2 and CLMUL support. +func haveSSE41() bool +func haveSSE42() bool +func haveCLMUL() bool + +// castagnoliSSE42 is defined in crc_amd64.s and uses the SSE4.2 CRC32 +// instruction. +//go:noescape +func castagnoliSSE42(crc uint32, p []byte) uint32 + +// ieeeCLMUL is defined in crc_amd64.s and uses the PCLMULQDQ +// instruction as well as SSE 4.1. +//go:noescape +func ieeeCLMUL(crc uint32, p []byte) uint32 + +var sse42 = haveSSE42() +var useFastIEEE = haveCLMUL() && haveSSE41() + +func updateCastagnoli(crc uint32, p []byte) uint32 { + if sse42 { + return castagnoliSSE42(crc, p) + } + // only use slicing-by-8 when input is >= 16 Bytes + if len(p) >= 16 { + return updateSlicingBy8(crc, castagnoliTable8, p) + } + return update(crc, castagnoliTable, p) +} + +func updateIEEE(crc uint32, p []byte) uint32 { + if useFastIEEE && len(p) >= 64 { + left := len(p) & 15 + do := len(p) - left + crc = ^ieeeCLMUL(^crc, p[:do]) + if left > 0 { + crc = update(crc, IEEETable, p[do:]) + } + return crc + } + + // only use slicing-by-8 when input is >= 16 Bytes + if len(p) >= 16 { + ieeeTable8Once.Do(func() { + ieeeTable8 = makeTable8(IEEE) + }) + return updateSlicingBy8(crc, ieeeTable8, p) + } + + return update(crc, IEEETable, p) +} diff --git a/vendor/github.com/klauspost/crc32/crc32_amd64.s b/vendor/github.com/klauspost/crc32/crc32_amd64.s new file mode 100644 index 0000000..9bf05d8 --- /dev/null +++ b/vendor/github.com/klauspost/crc32/crc32_amd64.s @@ -0,0 +1,237 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build gc + +#define NOSPLIT 4 +#define RODATA 8 + +// func castagnoliSSE42(crc uint32, p []byte) uint32 +TEXT ·castagnoliSSE42(SB), NOSPLIT, $0 + MOVL crc+0(FP), AX // CRC value + MOVQ p+8(FP), SI // data pointer + MOVQ p_len+16(FP), CX // len(p) + + NOTL AX + + // If there's less than 8 bytes to process, we do it byte-by-byte. + CMPQ CX, $8 + JL cleanup + + // Process individual bytes until the input is 8-byte aligned. +startup: + MOVQ SI, BX + ANDQ $7, BX + JZ aligned + + CRC32B (SI), AX + DECQ CX + INCQ SI + JMP startup + +aligned: + // The input is now 8-byte aligned and we can process 8-byte chunks. + CMPQ CX, $8 + JL cleanup + + CRC32Q (SI), AX + ADDQ $8, SI + SUBQ $8, CX + JMP aligned + +cleanup: + // We may have some bytes left over that we process one at a time. + CMPQ CX, $0 + JE done + + CRC32B (SI), AX + INCQ SI + DECQ CX + JMP cleanup + +done: + NOTL AX + MOVL AX, ret+32(FP) + RET + +// func haveSSE42() bool +TEXT ·haveSSE42(SB), NOSPLIT, $0 + XORQ AX, AX + INCL AX + CPUID + SHRQ $20, CX + ANDQ $1, CX + MOVB CX, ret+0(FP) + RET + +// func haveCLMUL() bool +TEXT ·haveCLMUL(SB), NOSPLIT, $0 + XORQ AX, AX + INCL AX + CPUID + SHRQ $1, CX + ANDQ $1, CX + MOVB CX, ret+0(FP) + RET + +// func haveSSE41() bool +TEXT ·haveSSE41(SB), NOSPLIT, $0 + XORQ AX, AX + INCL AX + CPUID + SHRQ $19, CX + ANDQ $1, CX + MOVB CX, ret+0(FP) + RET + +// CRC32 polynomial data +// +// These constants are lifted from the +// Linux kernel, since they avoid the costly +// PSHUFB 16 byte reversal proposed in the +// original Intel paper. +DATA r2r1kp<>+0(SB)/8, $0x154442bd4 +DATA r2r1kp<>+8(SB)/8, $0x1c6e41596 +DATA r4r3kp<>+0(SB)/8, $0x1751997d0 +DATA r4r3kp<>+8(SB)/8, $0x0ccaa009e +DATA rupolykp<>+0(SB)/8, $0x1db710641 +DATA rupolykp<>+8(SB)/8, $0x1f7011641 +DATA r5kp<>+0(SB)/8, $0x163cd6124 + +GLOBL r2r1kp<>(SB), RODATA, $16 +GLOBL r4r3kp<>(SB), RODATA, $16 +GLOBL rupolykp<>(SB), RODATA, $16 +GLOBL r5kp<>(SB), RODATA, $8 + +// Based on http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf +// len(p) must be at least 64, and must be a multiple of 16. + +// func ieeeCLMUL(crc uint32, p []byte) uint32 +TEXT ·ieeeCLMUL(SB), NOSPLIT, $0 + MOVL crc+0(FP), X0 // Initial CRC value + MOVQ p+8(FP), SI // data pointer + MOVQ p_len+16(FP), CX // len(p) + + MOVOU (SI), X1 + MOVOU 16(SI), X2 + MOVOU 32(SI), X3 + MOVOU 48(SI), X4 + PXOR X0, X1 + ADDQ $64, SI // buf+=64 + SUBQ $64, CX // len-=64 + CMPQ CX, $64 // Less than 64 bytes left + JB remain64 + + MOVOA r2r1kp<>+0(SB), X0 + +loopback64: + MOVOA X1, X5 + MOVOA X2, X6 + MOVOA X3, X7 + MOVOA X4, X8 + + PCLMULQDQ $0, X0, X1 + PCLMULQDQ $0, X0, X2 + PCLMULQDQ $0, X0, X3 + PCLMULQDQ $0, X0, X4 + + // Load next early + MOVOU (SI), X11 + MOVOU 16(SI), X12 + MOVOU 32(SI), X13 + MOVOU 48(SI), X14 + + PCLMULQDQ $0x11, X0, X5 + PCLMULQDQ $0x11, X0, X6 + PCLMULQDQ $0x11, X0, X7 + PCLMULQDQ $0x11, X0, X8 + + PXOR X5, X1 + PXOR X6, X2 + PXOR X7, X3 + PXOR X8, X4 + + PXOR X11, X1 + PXOR X12, X2 + PXOR X13, X3 + PXOR X14, X4 + + ADDQ $0x40, DI + ADDQ $64, SI // buf+=64 + SUBQ $64, CX // len-=64 + CMPQ CX, $64 // Less than 64 bytes left? + JGE loopback64 + + // Fold result into a single register (X1) +remain64: + MOVOA r4r3kp<>+0(SB), X0 + + MOVOA X1, X5 + PCLMULQDQ $0, X0, X1 + PCLMULQDQ $0x11, X0, X5 + PXOR X5, X1 + PXOR X2, X1 + + MOVOA X1, X5 + PCLMULQDQ $0, X0, X1 + PCLMULQDQ $0x11, X0, X5 + PXOR X5, X1 + PXOR X3, X1 + + MOVOA X1, X5 + PCLMULQDQ $0, X0, X1 + PCLMULQDQ $0x11, X0, X5 + PXOR X5, X1 + PXOR X4, X1 + + // More than 16 bytes left? + CMPQ CX, $16 + JB finish + + // Encode 16 bytes +remain16: + MOVOU (SI), X10 + MOVOA X1, X5 + PCLMULQDQ $0, X0, X1 + PCLMULQDQ $0x11, X0, X5 + PXOR X5, X1 + PXOR X10, X1 + SUBQ $16, CX + ADDQ $16, SI + CMPQ CX, $16 + JGE remain16 + +finish: + // Fold final result into 32 bits and return it + PCMPEQB X3, X3 + PCLMULQDQ $1, X1, X0 + PSRLDQ $8, X1 + PXOR X0, X1 + + MOVOA X1, X2 + MOVQ r5kp<>+0(SB), X0 + + // Creates 32 bit mask. Note that we don't care about upper half. + PSRLQ $32, X3 + + PSRLDQ $4, X2 + PAND X3, X1 + PCLMULQDQ $0, X0, X1 + PXOR X2, X1 + + MOVOA rupolykp<>+0(SB), X0 + + MOVOA X1, X2 + PAND X3, X1 + PCLMULQDQ $0x10, X0, X1 + PAND X3, X1 + PCLMULQDQ $0, X0, X1 + PXOR X2, X1 + + // PEXTRD $1, X1, AX (SSE 4.1) + BYTE $0x66; BYTE $0x0f; BYTE $0x3a + BYTE $0x16; BYTE $0xc8; BYTE $0x01 + MOVL AX, ret+32(FP) + + RET diff --git a/vendor/github.com/klauspost/crc32/crc32_amd64p32.go b/vendor/github.com/klauspost/crc32/crc32_amd64p32.go new file mode 100644 index 0000000..926473e --- /dev/null +++ b/vendor/github.com/klauspost/crc32/crc32_amd64p32.go @@ -0,0 +1,40 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !appengine,!gccgo + +package crc32 + +// This file contains the code to call the SSE 4.2 version of the Castagnoli +// CRC. + +// haveSSE42 is defined in crc_amd64p32.s and uses CPUID to test for SSE 4.2 +// support. +func haveSSE42() bool + +// castagnoliSSE42 is defined in crc_amd64.s and uses the SSE4.2 CRC32 +// instruction. +//go:noescape +func castagnoliSSE42(crc uint32, p []byte) uint32 + +var sse42 = haveSSE42() + +func updateCastagnoli(crc uint32, p []byte) uint32 { + if sse42 { + return castagnoliSSE42(crc, p) + } + return update(crc, castagnoliTable, p) +} + +func updateIEEE(crc uint32, p []byte) uint32 { + // only use slicing-by-8 when input is >= 4KB + if len(p) >= 4096 { + ieeeTable8Once.Do(func() { + ieeeTable8 = makeTable8(IEEE) + }) + return updateSlicingBy8(crc, ieeeTable8, p) + } + + return update(crc, IEEETable, p) +} diff --git a/vendor/github.com/klauspost/crc32/crc32_amd64p32.s b/vendor/github.com/klauspost/crc32/crc32_amd64p32.s new file mode 100644 index 0000000..a578d68 --- /dev/null +++ b/vendor/github.com/klauspost/crc32/crc32_amd64p32.s @@ -0,0 +1,67 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build gc + +#define NOSPLIT 4 +#define RODATA 8 + +// func castagnoliSSE42(crc uint32, p []byte) uint32 +TEXT ·castagnoliSSE42(SB), NOSPLIT, $0 + MOVL crc+0(FP), AX // CRC value + MOVL p+4(FP), SI // data pointer + MOVL p_len+8(FP), CX // len(p) + + NOTL AX + + // If there's less than 8 bytes to process, we do it byte-by-byte. + CMPQ CX, $8 + JL cleanup + + // Process individual bytes until the input is 8-byte aligned. +startup: + MOVQ SI, BX + ANDQ $7, BX + JZ aligned + + CRC32B (SI), AX + DECQ CX + INCQ SI + JMP startup + +aligned: + // The input is now 8-byte aligned and we can process 8-byte chunks. + CMPQ CX, $8 + JL cleanup + + CRC32Q (SI), AX + ADDQ $8, SI + SUBQ $8, CX + JMP aligned + +cleanup: + // We may have some bytes left over that we process one at a time. + CMPQ CX, $0 + JE done + + CRC32B (SI), AX + INCQ SI + DECQ CX + JMP cleanup + +done: + NOTL AX + MOVL AX, ret+16(FP) + RET + +// func haveSSE42() bool +TEXT ·haveSSE42(SB), NOSPLIT, $0 + XORQ AX, AX + INCL AX + CPUID + SHRQ $20, CX + ANDQ $1, CX + MOVB CX, ret+0(FP) + RET + diff --git a/vendor/github.com/klauspost/crc32/crc32_generic.go b/vendor/github.com/klauspost/crc32/crc32_generic.go new file mode 100644 index 0000000..a53cf96 --- /dev/null +++ b/vendor/github.com/klauspost/crc32/crc32_generic.go @@ -0,0 +1,29 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !amd64,!amd64p32 appengine gccgo + +package crc32 + +// This file contains the generic version of updateCastagnoli which does +// slicing-by-8, or uses the fallback for very small sizes. + +func updateCastagnoli(crc uint32, p []byte) uint32 { + // only use slicing-by-8 when input is >= 16 Bytes + if len(p) >= 16 { + return updateSlicingBy8(crc, castagnoliTable8, p) + } + return update(crc, castagnoliTable, p) +} + +func updateIEEE(crc uint32, p []byte) uint32 { + // only use slicing-by-8 when input is >= 16 Bytes + if len(p) >= 16 { + ieeeTable8Once.Do(func() { + ieeeTable8 = makeTable8(IEEE) + }) + return updateSlicingBy8(crc, ieeeTable8, p) + } + return update(crc, IEEETable, p) +} diff --git a/vendor/github.com/klauspost/crc32/crc32_test.go b/vendor/github.com/klauspost/crc32/crc32_test.go new file mode 100644 index 0000000..d9dd309 --- /dev/null +++ b/vendor/github.com/klauspost/crc32/crc32_test.go @@ -0,0 +1,170 @@ +// Copyright 2009 The Go 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 crc32 + +import ( + "hash" + "hash/crc32" + "io" + "testing" +) + +type test struct { + ieee, castagnoli uint32 + in string +} + +var golden = []test{ + {0x0, 0x0, ""}, + {0xe8b7be43, 0xc1d04330, "a"}, + {0x9e83486d, 0xe2a22936, "ab"}, + {0x352441c2, 0x364b3fb7, "abc"}, + {0xed82cd11, 0x92c80a31, "abcd"}, + {0x8587d865, 0xc450d697, "abcde"}, + {0x4b8e39ef, 0x53bceff1, "abcdef"}, + {0x312a6aa6, 0xe627f441, "abcdefg"}, + {0xaeef2a50, 0xa9421b7, "abcdefgh"}, + {0x8da988af, 0x2ddc99fc, "abcdefghi"}, + {0x3981703a, 0xe6599437, "abcdefghij"}, + {0x6b9cdfe7, 0xb2cc01fe, "Discard medicine more than two years old."}, + {0xc90ef73f, 0xe28207f, "He who has a shady past knows that nice guys finish last."}, + {0xb902341f, 0xbe93f964, "I wouldn't marry him with a ten foot pole."}, + {0x42080e8, 0x9e3be0c3, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, + {0x154c6d11, 0xf505ef04, "The days of the digital watch are numbered. -Tom Stoppard"}, + {0x4c418325, 0x85d3dc82, "Nepal premier won't resign."}, + {0x33955150, 0xc5142380, "For every action there is an equal and opposite government program."}, + {0x26216a4b, 0x75eb77dd, "His money is twice tainted: 'taint yours and 'taint mine."}, + {0x1abbe45e, 0x91ebe9f7, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, + {0xc89a94f7, 0xf0b1168e, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, + {0xab3abe14, 0x572b74e2, "size: a.out: bad magic"}, + {0xbab102b6, 0x8a58a6d5, "The major problem is with sendmail. -Mark Horton"}, + {0x999149d7, 0x9c426c50, "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, + {0x6d52a33c, 0x735400a4, "If the enemy is within range, then so are you."}, + {0x90631e8d, 0xbec49c95, "It's well we cannot hear the screams/That we create in others' dreams."}, + {0x78309130, 0xa95a2079, "You remind me of a TV show, but that's all right: I watch it anyway."}, + {0x7d0a377f, 0xde2e65c5, "C is as portable as Stonehedge!!"}, + {0x8c79fd79, 0x297a88ed, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, + {0xa20b7167, 0x66ed1d8b, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, + {0x8e0bb443, 0xdcded527, "How can you write a big system without C++? -Paul Glick"}, +} + +func TestGolden(t *testing.T) { + castagnoliTab := MakeTable(Castagnoli) + + for _, g := range golden { + ieee := NewIEEE() + io.WriteString(ieee, g.in) + s := ieee.Sum32() + if s != g.ieee { + t.Errorf("IEEE(%s) = 0x%x want 0x%x", g.in, s, g.ieee) + } + + castagnoli := New(castagnoliTab) + io.WriteString(castagnoli, g.in) + s = castagnoli.Sum32() + if s != g.castagnoli { + t.Errorf("Castagnoli(%s) = 0x%x want 0x%x", g.in, s, g.castagnoli) + } + + if len(g.in) > 0 { + // The SSE4.2 implementation of this has code to deal + // with misaligned data so we ensure that we test that + // too. + castagnoli = New(castagnoliTab) + io.WriteString(castagnoli, g.in[:1]) + io.WriteString(castagnoli, g.in[1:]) + s = castagnoli.Sum32() + if s != g.castagnoli { + t.Errorf("Castagnoli[misaligned](%s) = 0x%x want 0x%x", g.in, s, g.castagnoli) + } + } + } +} + +func BenchmarkCrc40B(b *testing.B) { + benchmark(b, NewIEEE(), 40) +} + +func BenchmarkStdCrc40B(b *testing.B) { + benchmark(b, crc32.NewIEEE(), 40) +} + +func BenchmarkCrc1KB(b *testing.B) { + benchmark(b, NewIEEE(), 1024) +} + +func BenchmarkStdCrc1KB(b *testing.B) { + benchmark(b, crc32.NewIEEE(), 1024) +} + +func BenchmarkCrc8KB(b *testing.B) { + benchmark(b, NewIEEE(), 8*1024) +} + +func BenchmarkStdCrc8KB(b *testing.B) { + benchmark(b, crc32.NewIEEE(), 8*1024) +} + +func BenchmarkCrc32KB(b *testing.B) { + benchmark(b, NewIEEE(), 32*1024) +} + +func BenchmarkStdCrc32KB(b *testing.B) { + benchmark(b, crc32.NewIEEE(), 32*1024) +} + +func BenchmarkCastagnoli40B(b *testing.B) { + benchmark(b, New(MakeTable(Castagnoli)), 40) +} + +func BenchmarkStdCastagnoli40B(b *testing.B) { + benchmark(b, crc32.New(crc32.MakeTable(Castagnoli)), 40) +} + +func BenchmarkCastagnoli1KB(b *testing.B) { + benchmark(b, New(MakeTable(Castagnoli)), 1024) +} + +func BenchmarkStdCastagnoli1KB(b *testing.B) { + benchmark(b, crc32.New(crc32.MakeTable(Castagnoli)), 1024) +} + +func BenchmarkCastagnoli8KB(b *testing.B) { + benchmark(b, New(MakeTable(Castagnoli)), 8*1024) +} + +func BenchmarkStdCastagnoli8KB(b *testing.B) { + benchmark(b, crc32.New(crc32.MakeTable(Castagnoli)), 8*1024) +} + +func BenchmarkCastagnoli32KB(b *testing.B) { + benchmark(b, New(MakeTable(Castagnoli)), 32*1024) +} + +func BenchmarkStdCastagnoli32KB(b *testing.B) { + benchmark(b, crc32.New(crc32.MakeTable(Castagnoli)), 32*1024) +} + +func benchmark(b *testing.B, h hash.Hash32, n int64) { + b.SetBytes(n) + data := make([]byte, n) + for i := range data { + data[i] = byte(i) + } + in := make([]byte, 0, h.Size()) + + // Warm up + h.Reset() + h.Write(data) + h.Sum(in) + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + h.Reset() + h.Write(data) + h.Sum(in) + } +} diff --git a/vendor/github.com/klauspost/crc32/example_test.go b/vendor/github.com/klauspost/crc32/example_test.go new file mode 100644 index 0000000..621bf83 --- /dev/null +++ b/vendor/github.com/klauspost/crc32/example_test.go @@ -0,0 +1,28 @@ +// Copyright 2015 The Go 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 crc32_test + +import ( + "fmt" + "hash/crc32" +) + +func ExampleMakeTable() { + // In this package, the CRC polynomial is represented in reversed notation, + // or LSB-first representation. + // + // LSB-first representation is a hexadecimal number with n bits, in which the + // most significant bit represents the coefficient of x⁰ and the least significant + // bit represents the coefficient of xⁿ⁻¹ (the coefficient for xⁿ is implicit). + // + // For example, CRC32-Q, as defined by the following polynomial, + // x³²+ x³¹+ x²⁴+ x²²+ x¹⁶+ x¹⁴+ x⁸+ x⁷+ x⁵+ x³+ x¹+ x⁰ + // has the reversed notation 0b11010101100000101000001010000001, so the value + // that should be passed to MakeTable is 0xD5828281. + crc32q := crc32.MakeTable(0xD5828281) + fmt.Printf("%08x\n", crc32.Checksum([]byte("Hello world"), crc32q)) + // Output: + // 2964d064 +} diff --git a/vendor/github.com/magical/argon2/README.md b/vendor/github.com/magical/argon2/README.md new file mode 100644 index 0000000..4620edd --- /dev/null +++ b/vendor/github.com/magical/argon2/README.md @@ -0,0 +1,21 @@ +Go implementation of the Argon2 password hashing scheme +designed by Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich. + +Documentation +------------- + +See . + +License +------- + +Copyright © 2015 Andrew Ekstedt +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/magical/argon2/api.go b/vendor/github.com/magical/argon2/api.go new file mode 100644 index 0000000..bd9f7dd --- /dev/null +++ b/vendor/github.com/magical/argon2/api.go @@ -0,0 +1,67 @@ +// Package argon2 implements version 1.3 of the Argon2 password hashing scheme +// designed by Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich, +// as specified in the document +// +// https://github.com/P-H-C/phc-winner-argon2/raw/54617af02de0055b90e39c4204058bb9a84c2b78/argon2-specs.pdf +// +// Warning: This package is currently unstable; Argon2 has not yet been +// finalized and is still undergoing design tweaks. +package argon2 + +import "errors" + +const ( + maxPar = 255 + + maxIter = 1<<32 - 1 + + minMemory = 8 + maxMemory = 1<<32 - 1 + + minSalt = 8 + maxSalt = 1<<32 - 1 + maxPassword = 1<<32 - 1 +) + +// Key derives a key from the password, salt, and cost parameters. +// +// The salt must be at least 8 bytes long. +// +// Mem is the amount of memory to use in kibibytes. +// Mem must be at least 8*p, and will be rounded to a multiple of 4*p. +func Key(password, salt []byte, n, par int, mem int64, keyLen int) ([]byte, error) { + if int64(len(password)) > maxPassword { + return nil, errors.New("argon: password too long") + } + + if len(salt) < minSalt { + return nil, errors.New("argon: salt too short") + } else if int64(len(salt)) > maxSalt { + return nil, errors.New("argon: salt too long") + } + + if n < 1 || int64(n) > maxIter { + return nil, errors.New("argon: invalid n") + } + + if par < 1 || par > maxPar { + return nil, errors.New("argon: invalid par") + } + + if mem < minMemory || mem > maxMemory { + return nil, errors.New("argon: invalid mem") + } + + // Round down to a multiple of 4 * par + mem = mem / (4 * int64(par)) * (4 * int64(par)) + + if mem < 8*int64(par) { + mem = 8 * int64(par) + } + + // TODO: test keyLen + + output := make([]byte, keyLen) + argon2(output, password, salt, nil, nil, uint32(par), uint32(mem), uint32(n), nil) + return output, nil +} diff --git a/vendor/github.com/magical/argon2/api_test.go b/vendor/github.com/magical/argon2/api_test.go new file mode 100644 index 0000000..277c41e --- /dev/null +++ b/vendor/github.com/magical/argon2/api_test.go @@ -0,0 +1,50 @@ +package argon2 + +import ( + "fmt" + "strings" + "testing" +) + +var zeros [16]byte +var ones = [8]byte{1, 1, 1, 1, 1, 1, 1, 1} + +// Fake salt function for the example +func randomSalt() []byte { + return ones[:8] +} + +func ExampleKey() { + pw := []byte("hunter2") + salt := randomSalt() + + key, err := Key(pw, salt, 3, 1, 8, 32) + if err != nil { + fmt.Println(err) + return + } + + fmt.Printf("%x", key) + // Output: c5dd631f4e715853e0354326c56f7c3aac983e5d86f7fb02f935899c38690f9e +} + +func TestKeyErr(t *testing.T) { + pw := zeros[:] + salt := ones[:] + + want := "salt too short" + _, err := Key(pw, salt[:1], 3, 1, 8, 8) + if err == nil { + t.Errorf("got nil error, expected %q", want) + } else if !strings.Contains(err.Error(), want) { + t.Errorf("got %q, expected %q", err, want) + } + + want = "invalid par" + _, err = Key(pw, salt, 3, 256, 8, 8) + if err == nil { + t.Errorf("got nil error, expected %q", want) + } else if !strings.Contains(err.Error(), want) { + t.Errorf("got %q, expected %q", err, want) + } +} diff --git a/vendor/github.com/magical/argon2/argon2.go b/vendor/github.com/magical/argon2/argon2.go new file mode 100644 index 0000000..12d6a66 --- /dev/null +++ b/vendor/github.com/magical/argon2/argon2.go @@ -0,0 +1,302 @@ +package argon2 + +import ( + "hash" + "testing" + + "github.com/dchest/blake2b" +) + +const version uint32 = 0x13 +const mode = 0 // Argon2d + +/* + +inputs: + + P message + S nonce + K secret key (optional) + X associated data (optional) + + p parallelism + m memory size + n iterations + +*/ + +func argon2(output, P, S, K, X []byte, p, m, n uint32, t *testing.T) { + if p == 0 || m == 0 || n == 0 { + panic("argon: internal error: invalid params") + } + if m%(p*4) != 0 { + panic("argon: internal error: invalid m") + } + + m0 := m + if m < 8*p { + m = 8 * p + } + + // Argon2 operates over a matrix of 1024-byte blocks + b := make([][128]uint64, m) + q := m / p // length of each lane + g := q / 4 // length of each segment + + var scratch [72]byte + var btmp [1024]byte + var btmp2 [128]uint64 + + // Compute a hash of all the input parameters + h := blake2b.New512() + lh := newLongHash(h) + + put32(scratch[0:4], p) + put32(scratch[4:8], uint32(len(output))) + put32(scratch[8:12], m0) + put32(scratch[12:16], n) + put32(scratch[16:20], version) + put32(scratch[20:24], mode) + h.Write(scratch[:24]) + + put32(scratch[0:4], uint32(len(P))) + h.Write(scratch[0:4]) + h.Write(P) + + put32(scratch[0:4], uint32(len(S))) + h.Write(scratch[0:4]) + h.Write(S) + + put32(scratch[0:4], uint32(len(K))) + h.Write(scratch[0:4]) + h.Write(K) + + put32(scratch[0:4], uint32(len(X))) + h.Write(scratch[0:4]) + h.Write(X) + + h.Sum(scratch[:0]) + h.Reset() + + // Use the hash to initialize the first two columns of the matrix + for lane := uint32(0); lane < p; lane++ { + // scratch[0:64] is the parameter hash + put32(scratch[64:], 0) + put32(scratch[68:], lane) + + lh.Init(len(btmp)) + lh.Write(scratch[:72]) + lh.Hash(btmp[:]) + for i := range b[0] { + b[lane*q+0][i] = read64(btmp[i*8:]) + } + + scratch[64] = 1 + lh.Init(len(btmp)) + lh.Write(scratch[:72]) + lh.Hash(btmp[:]) + for i := range b[0] { + b[lane*q+1][i] = read64(btmp[i*8:]) + } + } + + if t != nil { + t.Logf("Iterations: %d, Memory: %d KiB, Parallelism: %d lanes, Tag length: %d bytes", n, m, p, len(output)) + t.Logf("Password[%d]: % x", len(P), P) + t.Logf("Nonce[%d]: % x", len(S), S) + t.Logf("Secret[%d]: % x", len(K), K) + t.Logf("Associated data[%d]: % x", len(X), X) + t.Logf("Input hash: % x", scratch[:64]) + } + + for i := range scratch { + scratch[i] = 0 + } + for i := range btmp { + btmp[i] = 0 + } + + // Get down to business + for k := uint32(0); k < n; k++ { + if t != nil { + t.Log() + t.Logf(" After pass %d:", k) + } + for slice := uint32(0); slice < 4; slice++ { + for lane := uint32(0); lane < p; lane++ { + i := uint32(0) + if k == 0 && slice == 0 { + i = 2 + } + j := lane*q + slice*g + i + for ; i < g; i, j = i+1, j+1 { + prev := j - 1 + if i == 0 && slice == 0 { + prev = lane*q + q - 1 + } + + rand := b[prev][0] + rslice, rlane, ri := index(rand, q, g, p, k, slice, lane, i, t) + j0 := rlane*q + rslice*g + ri + + block(&b[j], &btmp2, &b[prev], &b[j0]) + } + } + } + if t != nil { + for i := range b { + t.Logf(" Block %.4d [0]: %x", i, b[i][0]) + } + } + } + + // XOR the blocks in the last column together + for lane := uint32(0); lane < p-1; lane++ { + for i, v := range b[lane*q+q-1] { + b[m-1][i] ^= v + } + } + + // Output + for i, v := range b[m-1] { + btmp[i*8] = uint8(v) + btmp[i*8+1] = uint8(v >> 8) + btmp[i*8+2] = uint8(v >> 16) + btmp[i*8+3] = uint8(v >> 24) + btmp[i*8+4] = uint8(v >> 32) + btmp[i*8+5] = uint8(v >> 40) + btmp[i*8+6] = uint8(v >> 48) + btmp[i*8+7] = uint8(v >> 56) + } + if t != nil { + t.Logf("Final block: %x", btmp[:]) + } + lh.Init(len(output)) + lh.Write(btmp[:]) + lh.Hash(output) + if t != nil { + t.Logf("Output: % X", output) + } +} + +func index(rand uint64, q, g, p, k, slice, lane, i uint32, t *testing.T) (rslice, rlane, ri uint32) { + rlane = uint32(rand>>32) % p + + var start, max uint32 + if k == 0 { + start = 0 + if slice == 0 || lane == rlane { + // All blocks in this lane so far + max = slice*g + i + } else { + // All blocks in another lane + // in slices prior to the current slice + max = slice * g + } + } else { + start = (slice + 1) % 4 * g + if lane == rlane { + // All blocks in this lane + max = 3*g + i + } else { + // All blocks in another lane + // except the current slice + max = 3 * g + } + } + if i == 0 || lane == rlane { + max -= 1 + } + + phi := rand & 0xFFFFFFFF + phi = phi * phi >> 32 + phi = phi * uint64(max) >> 32 + ri = uint32((uint64(start) + uint64(max) - 1 - phi) % uint64(q)) + + if t != nil { + i0 := lane*q + slice*g + i + j0 := rlane*q + ri + t.Logf(" i = %d(%d,%d,%d), rand = %d, max = %d, start = %d, phi = %d, j = %d(%d,%d,%d)", i0, lane, slice, i, rand, max, start, phi, j0, rlane, rslice, ri) + } + + return rslice, rlane, ri +} + +type longHash struct { + buf [64]uint8 + h hash.Hash + h0 hash.Hash // large hash + h1 hash.Hash // small hash + n int +} + +func newLongHash(h hash.Hash) *longHash { + return &longHash{h: h} +} + +// Init readies longHash for an output of length n. +func (lh *longHash) Init(n int) { + lh.n = n + lh.h.Reset() + lh.h0 = lh.h + lh.h1 = lh.h + var err error + if n < 64 { + lh.h0, err = blake2b.New(&blake2b.Config{Size: uint8(n)}) + } else if n%64 != 0 { + n := 33 + (n+31)%32 + lh.h1, err = blake2b.New(&blake2b.Config{Size: uint8(n)}) + } + if err != nil { + panic(err) + } + put32(lh.buf[:4], uint32(n)) + lh.Write(lh.buf[:4]) +} + +func (lh *longHash) Write(b []byte) { + lh.h0.Write(b) +} + +func (lh *longHash) Hash(out []byte) { + if len(out) != lh.n { + panic("argon2: wrong output length in longHash") + } + + if len(out) <= 64 { + lh.h0.Sum(out[:0]) + return + } + + lh.h0.Sum(lh.buf[:0]) + copy(out, lh.buf[:32]) + for out = out[32:]; len(out) > 64; out = out[32:] { + lh.h0.Reset() + lh.h0.Write(lh.buf[:]) + lh.h0.Sum(lh.buf[:0]) + copy(out, lh.buf[:32]) + } + if lh.h0 == lh.h1 { + lh.h1.Reset() + } + lh.h1.Write(lh.buf[:]) + lh.h1.Sum(out[:0]) +} + +func put32(b []uint8, v uint32) { + b[0] = uint8(v) + b[1] = uint8(v >> 8) + b[2] = uint8(v >> 16) + b[3] = uint8(v >> 24) +} + +func read64(b []uint8) uint64 { + return uint64(b[0]) | + uint64(b[1])<<8 | + uint64(b[2])<<16 | + uint64(b[3])<<24 | + uint64(b[4])<<32 | + uint64(b[5])<<40 | + uint64(b[6])<<48 | + uint64(b[7])<<56 +} diff --git a/vendor/github.com/magical/argon2/argon2_test.go b/vendor/github.com/magical/argon2/argon2_test.go new file mode 100644 index 0000000..e84f283 --- /dev/null +++ b/vendor/github.com/magical/argon2/argon2_test.go @@ -0,0 +1,137 @@ +package argon2 + +import ( + "bytes" + "testing" +) + +// Repeat returns a slice containing n copies of v. +func repeat(v uint8, n int) []byte { + b := make([]byte, n) + for i := range b { + b[i] = v + } + return b +} + +// Runs argon2 with logging enabled, for debugging purposes +func TestDebug(t *testing.T) { + var out [8]uint8 + argon2(out[:], repeat(0, 16), repeat(1, 8), nil, nil, 1, 8, 3, t) +} + +// Runs the test vector from the official repository +func TestArgon_Vector(t *testing.T) { + msg := repeat(0x1, 32) + salt := repeat(0x2, 16) + key := repeat(0x3, 8) + data := repeat(0x4, 12) + want := []byte{0x51, 0x2b, 0x39, 0x1b, 0x6f, 0x11, 0x62, 0x97, 0x53, 0x71, 0xd3, 0x09, 0x19, 0x73, 0x42, 0x94, 0xf8, 0x68, 0xe3, 0xbe, 0x39, 0x84, 0xf3, 0xc1, 0xa1, 0x3a, 0x4d, 0xb9, 0xfa, 0xbe, 0x4a, 0xcb} + out := make([]byte, len(want)) + argon2(out, msg, salt, key, data, 4, 32, 3, t) + if !bytes.Equal(want, out) { + t.Errorf("got % x, want % x\n", out, want) + } +} + +func TestArgon(t *testing.T) { + var tests = []struct { + n uint32 + mem uint32 + par uint32 + want []byte + }{ + {n: 3, mem: 8, par: 1, want: []byte{0x87, 0x22, 0x4f, 0xd2, 0x26, 0xbb, 0xf0, 0x76}}, + {n: 4, mem: 8, par: 1, want: []byte{0x65, 0x5f, 0x33, 0x24, 0xe7, 0x29, 0xa9, 0x3a}}, + {n: 5, mem: 8, par: 1, want: []byte{0x56, 0x61, 0x52, 0xd4, 0x5a, 0xd2, 0x5a, 0x47}}, + {n: 6, mem: 8, par: 1, want: []byte{0x80, 0x99, 0x38, 0x39, 0xd9, 0x19, 0x20, 0x5a}}, + {n: 7, mem: 8, par: 1, want: []byte{0x57, 0x33, 0x09, 0x7e, 0xf4, 0x9b, 0x19, 0xa0}}, + {n: 8, mem: 8, par: 1, want: []byte{0xff, 0x7d, 0x02, 0x0a, 0x8d, 0x25, 0xfa, 0x87}}, + {n: 9, mem: 8, par: 1, want: []byte{0x95, 0xae, 0xef, 0x81, 0xd9, 0x15, 0x61, 0x06}}, + {n: 10, mem: 8, par: 1, want: []byte{0x40, 0xfb, 0xe9, 0xd3, 0xa6, 0x50, 0xb7, 0xcb}}, + + {n: 3, mem: 16, par: 1, want: []byte{0x44, 0x82, 0x67, 0x1c, 0x29, 0x5e, 0x5b, 0x84}}, + {n: 3, mem: 32, par: 1, want: []byte{0xc3, 0xb2, 0x0a, 0xdb, 0x9f, 0x6b, 0xc0, 0xed}}, + {n: 3, mem: 64, par: 1, want: []byte{0x6b, 0x49, 0x39, 0xf5, 0x15, 0x42, 0x5d, 0xe3}}, + {n: 3, mem: 128, par: 1, want: []byte{0x1e, 0x50, 0xad, 0x31, 0x02, 0x7d, 0xa5, 0xbc}}, + {n: 3, mem: 256, par: 1, want: []byte{0x49, 0x83, 0x61, 0xdb, 0x18, 0xab, 0xaf, 0xb8}}, + {n: 3, mem: 512, par: 1, want: []byte{0xd0, 0x48, 0x7d, 0x84, 0xcb, 0xd3, 0x9f, 0x10}}, + {n: 3, mem: 1024, par: 1, want: []byte{0x51, 0xf7, 0xb0, 0xdb, 0x3b, 0xdb, 0xef, 0xb8}}, + + {n: 3, mem: 16, par: 2, want: []byte{0x73, 0x16, 0xaf, 0x5d, 0x31, 0xe9, 0xed, 0xea}}, + {n: 3, mem: 32, par: 4, want: []byte{0x16, 0xb7, 0x3b, 0xb9, 0x69, 0xcd, 0x6c, 0x63}}, + {n: 3, mem: 64, par: 8, want: []byte{0x25, 0xf3, 0x85, 0x08, 0x60, 0x5d, 0x35, 0x45}}, + {n: 3, mem: 128, par: 16, want: []byte{0xe3, 0xd3, 0xe3, 0x72, 0xdf, 0x0a, 0x22, 0x7b}}, + {n: 3, mem: 256, par: 32, want: []byte{0x5c, 0xf9, 0x79, 0x0a, 0x9c, 0xc1, 0x05, 0x6b}}, + {n: 3, mem: 512, par: 64, want: []byte{0xa6, 0xc9, 0x71, 0xcc, 0x99, 0x4d, 0xcf, 0x8f}}, + + {n: 3, mem: 8, par: 1, want: []byte{0x3c, 0x9a, 0x65, 0x86}}, + {n: 3, mem: 8, par: 1, want: []byte{0x20, 0x4d, 0x2e, 0x37, 0x4a}}, + {n: 3, mem: 8, par: 1, want: []byte{0xc9, 0xd5, 0xd9, 0x75, 0x36, 0x89}}, + {n: 3, mem: 8, par: 1, want: []byte{0x8b, 0x32, 0x11, 0x8e, 0xf6, 0xf6, 0x3d}}, + {n: 3, mem: 8, par: 1, want: []byte{0x87, 0x22, 0x4f, 0xd2, 0x26, 0xbb, 0xf0, 0x76}}, + {n: 3, mem: 8, par: 1, want: []byte{0x05, 0xe6, 0xbe, 0x6c, 0x27, 0x1e, 0x93, 0xac, 0x74}}, + {n: 3, mem: 8, par: 1, want: []byte{0xee, 0xb4, 0x11, 0xb4, 0xfa, 0x1a, 0x6c, 0xe8, 0x14, 0x2b}}, + {n: 3, mem: 8, par: 1, want: []byte{0x1e, 0x23, 0xa3, 0x87, 0x53, 0x8e, 0x21, 0xbf, 0x07, 0x0c, 0x59}}, + {n: 3, mem: 8, par: 1, want: []byte{0x7a, 0x0c, 0x41, 0x54, 0x5e, 0x20, 0x38, 0x23, 0x57, 0x16, 0x61, 0xcf}}, + {n: 3, mem: 8, par: 1, want: []byte{0x1c, 0xe5, 0xcf, 0xee, 0x7f, 0x6f, 0x43, 0x55, 0x67, 0x14, 0xaa, 0x5b, 0x8e}}, + {n: 3, mem: 8, par: 1, want: []byte{0xef, 0x92, 0x6c, 0xa6, 0x6c, 0x25, 0x74, 0x3c, 0xa3, 0x32, 0xfa, 0x0a, 0xdd, 0x2b}}, + {n: 3, mem: 8, par: 1, want: []byte{0x47, 0xcd, 0xb0, 0xd0, 0x10, 0x88, 0x54, 0x76, 0xb0, 0x0c, 0x30, 0x1d, 0x05, 0x59, 0xc3}}, + {n: 3, mem: 8, par: 1, want: []byte{0x91, 0x69, 0xdb, 0x87, 0xc4, 0xd1, 0xc7, 0x80, 0xa1, 0xdb, 0x8a, 0x47, 0x5d, 0xc0, 0xac, 0xcd}}, + + {n: 3, mem: 8, par: 1, want: []byte{0x06, 0x4f, 0xc0, 0x84, 0x30, 0x11, 0xab, 0x42, 0xe8, 0x74, 0xd2, 0xba, 0x3c, 0xeb, 0x26, 0x41, 0xb0, 0x50, 0x88, 0xc1, 0x3a, 0x13, 0xdf, 0x5c, 0x6f, 0xf1, 0xf3, 0xf3, 0xc2, 0x61, 0xf6, 0xd1}}, + {n: 3, mem: 8, par: 1, want: []byte{0x4b, 0x63, 0xb4, 0x2a, 0x51, 0x2b, 0x81, 0x5e, 0x75, 0x0d, 0xed, 0x7a, 0x87, 0x14, 0x42, 0x1c, 0xcd, 0x59, 0x85, 0x66, 0xe4, 0xbb, 0x5a, 0xf5, 0xaf, 0xc8, 0xb3, 0x7c, 0x58, 0x42, 0xfc, 0x14, 0x0e}}, + {n: 3, mem: 8, par: 1, want: []byte{0xaf, 0xed, 0xcf, 0x2d, 0xbf, 0x00, 0xf0, 0xad, 0x5c, 0x18, 0x4e, 0x82, 0xbc, 0xc3, 0x10, 0x85, 0xed, 0x9c, 0x63, 0x54, 0x43, 0xe9, 0xc9, 0x88, 0x71, 0xe4, 0xfa, 0x9a, 0x6a, 0x54, 0x15, 0xb5, 0xc0, 0x07, 0xdd, 0xaf, 0xac, 0x48, 0x71, 0xf0, 0xab, 0xe0, 0xa6, 0xdb, 0x35, 0x52, 0xbf, 0x3a, 0x07, 0x80, 0x78, 0xd2, 0x7d, 0xa2, 0x41, 0x52, 0x00, 0x6f, 0xfe, 0xd0, 0x8b, 0x17, 0xe8, 0xe9}}, + {n: 3, mem: 8, par: 1, want: []byte{0x7a, 0xf9, 0x5b, 0x8e, 0x44, 0x63, 0x48, 0x67, 0x15, 0x87, 0x4c, 0x35, 0xf6, 0x7f, 0x52, 0xd1, 0xe7, 0x97, 0x95, 0x12, 0xce, 0x49, 0x5c, 0x06, 0xf9, 0xd4, 0xf8, 0xda, 0xc2, 0xc4, 0x61, 0xa1, 0xfe, 0x0a, 0x1f, 0xd5, 0x26, 0x89, 0x21, 0xd9, 0xdb, 0x03, 0x15, 0x6f, 0xa2, 0xf6, 0x83, 0x7d, 0x7a, 0xf6, 0xde, 0x3d, 0xd7, 0x8b, 0x9d, 0x03, 0x7f, 0x6c, 0xd9, 0xe0, 0x99, 0x1e, 0x52, 0x82, 0xbb}}, + + {n: 3, mem: 8, par: 1, want: []byte{0x7a, 0x3a, 0x97, 0xa3, 0x65, 0xcd, 0x6e, 0xb3, 0x64, 0x32, 0xbc, 0xee, 0x38, 0xa5, 0x32, 0xef, 0x85, 0x2d, 0x30, 0x7f, 0x65, 0x56, 0x0b, 0xb3, 0xfb, 0x8c, 0x94, 0x60, 0x7b, 0xbc, 0xc4, 0x52, 0xb0, 0x4a, 0x26, 0x99, 0xaf, 0x40, 0x7f, 0x25, 0x62, 0x09, 0xc3, 0xe6, 0xd9, 0x8a, 0xcd, 0xac, 0xdc, 0x9c, 0xc2, 0x25, 0xd2, 0x2a, 0x96, 0x9f, 0x80, 0xb6, 0x5a, 0x3d, 0xc5, 0x10, 0xa0, 0x03, 0xe5, 0x32, 0xae, 0x17, 0x3b, 0x76, 0x8b, 0x91, 0x4d, 0x48, 0xc8, 0x42, 0x43, 0xee, 0x23, 0x65, 0xb7, 0xd9, 0xae, 0x4e, 0x29, 0xf4, 0x6a, 0xcd, 0x19, 0x4e, 0x5b, 0x13, 0xa4, 0x38, 0xf3, 0x57}}, + {n: 3, mem: 8, par: 1, want: []byte{0x0a, 0x25, 0xa1, 0x50, 0x63, 0xfe, 0x10, 0x36, 0x7c, 0x46, 0x4d, 0xab, 0x8d, 0xb7, 0x30, 0xfd, 0x46, 0x31, 0xee, 0x3b, 0x6d, 0xf3, 0xdb, 0xef, 0x8a, 0xcd, 0xbf, 0x9d, 0x9a, 0x4f, 0x61, 0x74, 0x26, 0x35, 0xae, 0x39, 0x70, 0xdb, 0xe9, 0x73, 0xf7, 0xb6, 0x62, 0x04, 0x83, 0x6e, 0x90, 0x9d, 0x5d, 0x91, 0x07, 0x15, 0x7b, 0xa4, 0x60, 0x23, 0x16, 0x06, 0x15, 0x7c, 0xd2, 0x5d, 0x45, 0x0b, 0x89, 0xf7, 0xd1, 0x8c, 0xdc, 0x48, 0xe2, 0x9e, 0x54, 0xe0, 0x65, 0x99, 0xc4, 0xf7, 0x5b, 0xed, 0x9b, 0x9f, 0x2e, 0xd9, 0x78, 0x23, 0x5e, 0xc0, 0x8d, 0x4f, 0x91, 0x29, 0x0c, 0xcb, 0x1d, 0x8f, 0x85, 0x43, 0xd3, 0x3b, 0xbe, 0x5b, 0x85, 0x33, 0x3e, 0xaa, 0xca, 0xc3, 0x83, 0x23, 0x6e, 0x4f, 0x26, 0x28, 0x77, 0xf3, 0xf4, 0xb4, 0x87, 0x66, 0xc4, 0x84, 0xd8, 0xbe, 0xba, 0x5a, 0x5f, 0xba}}, + } + + msg := repeat(0x0, 16) + salt := repeat(0x1, 8) + + for _, tt := range tests { + out := make([]byte, len(tt.want)) + argon2(out, msg, salt, nil, nil, tt.par, tt.mem, tt.n, nil) + if !bytes.Equal(out, tt.want) { + t.Errorf("n=%d, mem=%d, par=%d, len=%d: got % x, want % x\n", tt.n, tt.mem, tt.par, len(tt.want), out, tt.want) + } + } +} + +func TestAllocs(t *testing.T) { + pw := repeat(0x0, 16) + salt := repeat(0x1, 8) + out := make([]byte, 32) + allocs := testing.AllocsPerRun(100, func() { + argon2(out, pw, salt, nil, nil, 4, 32, 3, nil) + }) + if allocs > 6 { + t.Errorf("%v allocs, want <=6", allocs) + } +} + +func benchArgon(b *testing.B, par uint8, mem, n uint32) { + msg := repeat(0x0, 16) + salt := repeat(0x1, 8) + out := make([]byte, 8) + b.SetBytes(int64(mem) << 10) + for i := 0; i < b.N; i++ { + argon2(out, msg, salt, nil, nil, uint32(par), mem, n, nil) + } +} + +func BenchmarkArgon8KiB(b *testing.B) { benchArgon(b, 1, 8, 3) } +func BenchmarkArgon80KiB(b *testing.B) { benchArgon(b, 1, 80, 3) } +func BenchmarkArgon800KiB(b *testing.B) { benchArgon(b, 1, 800, 3) } + +func BenchmarkArgon3N(b *testing.B) { benchArgon(b, 1, 8, 3) } +func BenchmarkArgon10N(b *testing.B) { benchArgon(b, 1, 8, 10) } +func BenchmarkArgon100N(b *testing.B) { benchArgon(b, 1, 8, 100) } + +func BenchmarkArgon1P(b *testing.B) { benchArgon(b, 1, 64, 3) } +func BenchmarkArgon2P(b *testing.B) { benchArgon(b, 2, 64, 3) } +func BenchmarkArgon4P(b *testing.B) { benchArgon(b, 4, 64, 3) } + +//func BenchmarkArgon_4MiB(b *testing.B) { benchArgon(b, 1, 4096, 3) } diff --git a/vendor/github.com/magical/argon2/round.go b/vendor/github.com/magical/argon2/round.go new file mode 100644 index 0000000..fac2075 --- /dev/null +++ b/vendor/github.com/magical/argon2/round.go @@ -0,0 +1,443 @@ +package argon2 + +func block(z, t, a, b *[128]uint64) { + // t = a ^ b + // t = P(t) + // z = z ^ t + t[0] = a[0] ^ b[0] + t[1] = a[1] ^ b[1] + t[2] = a[2] ^ b[2] + t[3] = a[3] ^ b[3] + t[4] = a[4] ^ b[4] + t[5] = a[5] ^ b[5] + t[6] = a[6] ^ b[6] + t[7] = a[7] ^ b[7] + t[8] = a[8] ^ b[8] + t[9] = a[9] ^ b[9] + t[10] = a[10] ^ b[10] + t[11] = a[11] ^ b[11] + t[12] = a[12] ^ b[12] + t[13] = a[13] ^ b[13] + t[14] = a[14] ^ b[14] + t[15] = a[15] ^ b[15] + t[16] = a[16] ^ b[16] + t[17] = a[17] ^ b[17] + t[18] = a[18] ^ b[18] + t[19] = a[19] ^ b[19] + t[20] = a[20] ^ b[20] + t[21] = a[21] ^ b[21] + t[22] = a[22] ^ b[22] + t[23] = a[23] ^ b[23] + t[24] = a[24] ^ b[24] + t[25] = a[25] ^ b[25] + t[26] = a[26] ^ b[26] + t[27] = a[27] ^ b[27] + t[28] = a[28] ^ b[28] + t[29] = a[29] ^ b[29] + t[30] = a[30] ^ b[30] + t[31] = a[31] ^ b[31] + t[32] = a[32] ^ b[32] + t[33] = a[33] ^ b[33] + t[34] = a[34] ^ b[34] + t[35] = a[35] ^ b[35] + t[36] = a[36] ^ b[36] + t[37] = a[37] ^ b[37] + t[38] = a[38] ^ b[38] + t[39] = a[39] ^ b[39] + t[40] = a[40] ^ b[40] + t[41] = a[41] ^ b[41] + t[42] = a[42] ^ b[42] + t[43] = a[43] ^ b[43] + t[44] = a[44] ^ b[44] + t[45] = a[45] ^ b[45] + t[46] = a[46] ^ b[46] + t[47] = a[47] ^ b[47] + t[48] = a[48] ^ b[48] + t[49] = a[49] ^ b[49] + t[50] = a[50] ^ b[50] + t[51] = a[51] ^ b[51] + t[52] = a[52] ^ b[52] + t[53] = a[53] ^ b[53] + t[54] = a[54] ^ b[54] + t[55] = a[55] ^ b[55] + t[56] = a[56] ^ b[56] + t[57] = a[57] ^ b[57] + t[58] = a[58] ^ b[58] + t[59] = a[59] ^ b[59] + t[60] = a[60] ^ b[60] + t[61] = a[61] ^ b[61] + t[62] = a[62] ^ b[62] + t[63] = a[63] ^ b[63] + t[64] = a[64] ^ b[64] + t[65] = a[65] ^ b[65] + t[66] = a[66] ^ b[66] + t[67] = a[67] ^ b[67] + t[68] = a[68] ^ b[68] + t[69] = a[69] ^ b[69] + t[70] = a[70] ^ b[70] + t[71] = a[71] ^ b[71] + t[72] = a[72] ^ b[72] + t[73] = a[73] ^ b[73] + t[74] = a[74] ^ b[74] + t[75] = a[75] ^ b[75] + t[76] = a[76] ^ b[76] + t[77] = a[77] ^ b[77] + t[78] = a[78] ^ b[78] + t[79] = a[79] ^ b[79] + t[80] = a[80] ^ b[80] + t[81] = a[81] ^ b[81] + t[82] = a[82] ^ b[82] + t[83] = a[83] ^ b[83] + t[84] = a[84] ^ b[84] + t[85] = a[85] ^ b[85] + t[86] = a[86] ^ b[86] + t[87] = a[87] ^ b[87] + t[88] = a[88] ^ b[88] + t[89] = a[89] ^ b[89] + t[90] = a[90] ^ b[90] + t[91] = a[91] ^ b[91] + t[92] = a[92] ^ b[92] + t[93] = a[93] ^ b[93] + t[94] = a[94] ^ b[94] + t[95] = a[95] ^ b[95] + t[96] = a[96] ^ b[96] + t[97] = a[97] ^ b[97] + t[98] = a[98] ^ b[98] + t[99] = a[99] ^ b[99] + t[100] = a[100] ^ b[100] + t[101] = a[101] ^ b[101] + t[102] = a[102] ^ b[102] + t[103] = a[103] ^ b[103] + t[104] = a[104] ^ b[104] + t[105] = a[105] ^ b[105] + t[106] = a[106] ^ b[106] + t[107] = a[107] ^ b[107] + t[108] = a[108] ^ b[108] + t[109] = a[109] ^ b[109] + t[110] = a[110] ^ b[110] + t[111] = a[111] ^ b[111] + t[112] = a[112] ^ b[112] + t[113] = a[113] ^ b[113] + t[114] = a[114] ^ b[114] + t[115] = a[115] ^ b[115] + t[116] = a[116] ^ b[116] + t[117] = a[117] ^ b[117] + t[118] = a[118] ^ b[118] + t[119] = a[119] ^ b[119] + t[120] = a[120] ^ b[120] + t[121] = a[121] ^ b[121] + t[122] = a[122] ^ b[122] + t[123] = a[123] ^ b[123] + t[124] = a[124] ^ b[124] + t[125] = a[125] ^ b[125] + t[126] = a[126] ^ b[126] + t[127] = a[127] ^ b[127] + _P(&t[0], &t[1], &t[2], &t[3], &t[4], &t[5], &t[6], &t[7], &t[8], &t[9], &t[10], &t[11], &t[12], &t[13], &t[14], &t[15]) + _P(&t[16], &t[17], &t[18], &t[19], &t[20], &t[21], &t[22], &t[23], &t[24], &t[25], &t[26], &t[27], &t[28], &t[29], &t[30], &t[31]) + _P(&t[32], &t[33], &t[34], &t[35], &t[36], &t[37], &t[38], &t[39], &t[40], &t[41], &t[42], &t[43], &t[44], &t[45], &t[46], &t[47]) + _P(&t[48], &t[49], &t[50], &t[51], &t[52], &t[53], &t[54], &t[55], &t[56], &t[57], &t[58], &t[59], &t[60], &t[61], &t[62], &t[63]) + _P(&t[64], &t[65], &t[66], &t[67], &t[68], &t[69], &t[70], &t[71], &t[72], &t[73], &t[74], &t[75], &t[76], &t[77], &t[78], &t[79]) + _P(&t[80], &t[81], &t[82], &t[83], &t[84], &t[85], &t[86], &t[87], &t[88], &t[89], &t[90], &t[91], &t[92], &t[93], &t[94], &t[95]) + _P(&t[96], &t[97], &t[98], &t[99], &t[100], &t[101], &t[102], &t[103], &t[104], &t[105], &t[106], &t[107], &t[108], &t[109], &t[110], &t[111]) + _P(&t[112], &t[113], &t[114], &t[115], &t[116], &t[117], &t[118], &t[119], &t[120], &t[121], &t[122], &t[123], &t[124], &t[125], &t[126], &t[127]) + _P(&t[0], &t[1], &t[16], &t[17], &t[32], &t[33], &t[48], &t[49], &t[64], &t[65], &t[80], &t[81], &t[96], &t[97], &t[112], &t[113]) + _P(&t[2], &t[3], &t[18], &t[19], &t[34], &t[35], &t[50], &t[51], &t[66], &t[67], &t[82], &t[83], &t[98], &t[99], &t[114], &t[115]) + _P(&t[4], &t[5], &t[20], &t[21], &t[36], &t[37], &t[52], &t[53], &t[68], &t[69], &t[84], &t[85], &t[100], &t[101], &t[116], &t[117]) + _P(&t[6], &t[7], &t[22], &t[23], &t[38], &t[39], &t[54], &t[55], &t[70], &t[71], &t[86], &t[87], &t[102], &t[103], &t[118], &t[119]) + _P(&t[8], &t[9], &t[24], &t[25], &t[40], &t[41], &t[56], &t[57], &t[72], &t[73], &t[88], &t[89], &t[104], &t[105], &t[120], &t[121]) + _P(&t[10], &t[11], &t[26], &t[27], &t[42], &t[43], &t[58], &t[59], &t[74], &t[75], &t[90], &t[91], &t[106], &t[107], &t[122], &t[123]) + _P(&t[12], &t[13], &t[28], &t[29], &t[44], &t[45], &t[60], &t[61], &t[76], &t[77], &t[92], &t[93], &t[108], &t[109], &t[124], &t[125]) + _P(&t[14], &t[15], &t[30], &t[31], &t[46], &t[47], &t[62], &t[63], &t[78], &t[79], &t[94], &t[95], &t[110], &t[111], &t[126], &t[127]) + z[0] ^= a[0] ^ b[0] ^ t[0] + z[1] ^= a[1] ^ b[1] ^ t[1] + z[2] ^= a[2] ^ b[2] ^ t[2] + z[3] ^= a[3] ^ b[3] ^ t[3] + z[4] ^= a[4] ^ b[4] ^ t[4] + z[5] ^= a[5] ^ b[5] ^ t[5] + z[6] ^= a[6] ^ b[6] ^ t[6] + z[7] ^= a[7] ^ b[7] ^ t[7] + z[8] ^= a[8] ^ b[8] ^ t[8] + z[9] ^= a[9] ^ b[9] ^ t[9] + z[10] ^= a[10] ^ b[10] ^ t[10] + z[11] ^= a[11] ^ b[11] ^ t[11] + z[12] ^= a[12] ^ b[12] ^ t[12] + z[13] ^= a[13] ^ b[13] ^ t[13] + z[14] ^= a[14] ^ b[14] ^ t[14] + z[15] ^= a[15] ^ b[15] ^ t[15] + z[16] ^= a[16] ^ b[16] ^ t[16] + z[17] ^= a[17] ^ b[17] ^ t[17] + z[18] ^= a[18] ^ b[18] ^ t[18] + z[19] ^= a[19] ^ b[19] ^ t[19] + z[20] ^= a[20] ^ b[20] ^ t[20] + z[21] ^= a[21] ^ b[21] ^ t[21] + z[22] ^= a[22] ^ b[22] ^ t[22] + z[23] ^= a[23] ^ b[23] ^ t[23] + z[24] ^= a[24] ^ b[24] ^ t[24] + z[25] ^= a[25] ^ b[25] ^ t[25] + z[26] ^= a[26] ^ b[26] ^ t[26] + z[27] ^= a[27] ^ b[27] ^ t[27] + z[28] ^= a[28] ^ b[28] ^ t[28] + z[29] ^= a[29] ^ b[29] ^ t[29] + z[30] ^= a[30] ^ b[30] ^ t[30] + z[31] ^= a[31] ^ b[31] ^ t[31] + z[32] ^= a[32] ^ b[32] ^ t[32] + z[33] ^= a[33] ^ b[33] ^ t[33] + z[34] ^= a[34] ^ b[34] ^ t[34] + z[35] ^= a[35] ^ b[35] ^ t[35] + z[36] ^= a[36] ^ b[36] ^ t[36] + z[37] ^= a[37] ^ b[37] ^ t[37] + z[38] ^= a[38] ^ b[38] ^ t[38] + z[39] ^= a[39] ^ b[39] ^ t[39] + z[40] ^= a[40] ^ b[40] ^ t[40] + z[41] ^= a[41] ^ b[41] ^ t[41] + z[42] ^= a[42] ^ b[42] ^ t[42] + z[43] ^= a[43] ^ b[43] ^ t[43] + z[44] ^= a[44] ^ b[44] ^ t[44] + z[45] ^= a[45] ^ b[45] ^ t[45] + z[46] ^= a[46] ^ b[46] ^ t[46] + z[47] ^= a[47] ^ b[47] ^ t[47] + z[48] ^= a[48] ^ b[48] ^ t[48] + z[49] ^= a[49] ^ b[49] ^ t[49] + z[50] ^= a[50] ^ b[50] ^ t[50] + z[51] ^= a[51] ^ b[51] ^ t[51] + z[52] ^= a[52] ^ b[52] ^ t[52] + z[53] ^= a[53] ^ b[53] ^ t[53] + z[54] ^= a[54] ^ b[54] ^ t[54] + z[55] ^= a[55] ^ b[55] ^ t[55] + z[56] ^= a[56] ^ b[56] ^ t[56] + z[57] ^= a[57] ^ b[57] ^ t[57] + z[58] ^= a[58] ^ b[58] ^ t[58] + z[59] ^= a[59] ^ b[59] ^ t[59] + z[60] ^= a[60] ^ b[60] ^ t[60] + z[61] ^= a[61] ^ b[61] ^ t[61] + z[62] ^= a[62] ^ b[62] ^ t[62] + z[63] ^= a[63] ^ b[63] ^ t[63] + z[64] ^= a[64] ^ b[64] ^ t[64] + z[65] ^= a[65] ^ b[65] ^ t[65] + z[66] ^= a[66] ^ b[66] ^ t[66] + z[67] ^= a[67] ^ b[67] ^ t[67] + z[68] ^= a[68] ^ b[68] ^ t[68] + z[69] ^= a[69] ^ b[69] ^ t[69] + z[70] ^= a[70] ^ b[70] ^ t[70] + z[71] ^= a[71] ^ b[71] ^ t[71] + z[72] ^= a[72] ^ b[72] ^ t[72] + z[73] ^= a[73] ^ b[73] ^ t[73] + z[74] ^= a[74] ^ b[74] ^ t[74] + z[75] ^= a[75] ^ b[75] ^ t[75] + z[76] ^= a[76] ^ b[76] ^ t[76] + z[77] ^= a[77] ^ b[77] ^ t[77] + z[78] ^= a[78] ^ b[78] ^ t[78] + z[79] ^= a[79] ^ b[79] ^ t[79] + z[80] ^= a[80] ^ b[80] ^ t[80] + z[81] ^= a[81] ^ b[81] ^ t[81] + z[82] ^= a[82] ^ b[82] ^ t[82] + z[83] ^= a[83] ^ b[83] ^ t[83] + z[84] ^= a[84] ^ b[84] ^ t[84] + z[85] ^= a[85] ^ b[85] ^ t[85] + z[86] ^= a[86] ^ b[86] ^ t[86] + z[87] ^= a[87] ^ b[87] ^ t[87] + z[88] ^= a[88] ^ b[88] ^ t[88] + z[89] ^= a[89] ^ b[89] ^ t[89] + z[90] ^= a[90] ^ b[90] ^ t[90] + z[91] ^= a[91] ^ b[91] ^ t[91] + z[92] ^= a[92] ^ b[92] ^ t[92] + z[93] ^= a[93] ^ b[93] ^ t[93] + z[94] ^= a[94] ^ b[94] ^ t[94] + z[95] ^= a[95] ^ b[95] ^ t[95] + z[96] ^= a[96] ^ b[96] ^ t[96] + z[97] ^= a[97] ^ b[97] ^ t[97] + z[98] ^= a[98] ^ b[98] ^ t[98] + z[99] ^= a[99] ^ b[99] ^ t[99] + z[100] ^= a[100] ^ b[100] ^ t[100] + z[101] ^= a[101] ^ b[101] ^ t[101] + z[102] ^= a[102] ^ b[102] ^ t[102] + z[103] ^= a[103] ^ b[103] ^ t[103] + z[104] ^= a[104] ^ b[104] ^ t[104] + z[105] ^= a[105] ^ b[105] ^ t[105] + z[106] ^= a[106] ^ b[106] ^ t[106] + z[107] ^= a[107] ^ b[107] ^ t[107] + z[108] ^= a[108] ^ b[108] ^ t[108] + z[109] ^= a[109] ^ b[109] ^ t[109] + z[110] ^= a[110] ^ b[110] ^ t[110] + z[111] ^= a[111] ^ b[111] ^ t[111] + z[112] ^= a[112] ^ b[112] ^ t[112] + z[113] ^= a[113] ^ b[113] ^ t[113] + z[114] ^= a[114] ^ b[114] ^ t[114] + z[115] ^= a[115] ^ b[115] ^ t[115] + z[116] ^= a[116] ^ b[116] ^ t[116] + z[117] ^= a[117] ^ b[117] ^ t[117] + z[118] ^= a[118] ^ b[118] ^ t[118] + z[119] ^= a[119] ^ b[119] ^ t[119] + z[120] ^= a[120] ^ b[120] ^ t[120] + z[121] ^= a[121] ^ b[121] ^ t[121] + z[122] ^= a[122] ^ b[122] ^ t[122] + z[123] ^= a[123] ^ b[123] ^ t[123] + z[124] ^= a[124] ^ b[124] ^ t[124] + z[125] ^= a[125] ^ b[125] ^ t[125] + z[126] ^= a[126] ^ b[126] ^ t[126] + z[127] ^= a[127] ^ b[127] ^ t[127] +} + +func _P(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15 *uint64) { + var v0 = *p0 + var v1 = *p1 + var v2 = *p2 + var v3 = *p3 + var v4 = *p4 + var v5 = *p5 + var v6 = *p6 + var v7 = *p7 + var v8 = *p8 + var v9 = *p9 + var v10 = *p10 + var v11 = *p11 + var v12 = *p12 + var v13 = *p13 + var v14 = *p14 + var v15 = *p15 + var t uint64 + t = uint64(uint32(v0)) * uint64(uint32(v4)) + v0 = v0 + v4 + t*2 + v12 = v12 ^ v0 + v12 = v12>>32 | v12<<32 + t = uint64(uint32(v8)) * uint64(uint32(v12)) + v8 = v8 + v12 + t*2 + v4 = v4 ^ v8 + v4 = v4>>24 | v4<<40 + t = uint64(uint32(v0)) * uint64(uint32(v4)) + v0 = v0 + v4 + t*2 + v12 = v12 ^ v0 + v12 = v12>>16 | v12<<48 + t = uint64(uint32(v8)) * uint64(uint32(v12)) + v8 = v8 + v12 + t*2 + v4 = v4 ^ v8 + v4 = v4>>63 | v4<<1 + t = uint64(uint32(v1)) * uint64(uint32(v5)) + v1 = v1 + v5 + t*2 + v13 = v13 ^ v1 + v13 = v13>>32 | v13<<32 + t = uint64(uint32(v9)) * uint64(uint32(v13)) + v9 = v9 + v13 + t*2 + v5 = v5 ^ v9 + v5 = v5>>24 | v5<<40 + t = uint64(uint32(v1)) * uint64(uint32(v5)) + v1 = v1 + v5 + t*2 + v13 = v13 ^ v1 + v13 = v13>>16 | v13<<48 + t = uint64(uint32(v9)) * uint64(uint32(v13)) + v9 = v9 + v13 + t*2 + v5 = v5 ^ v9 + v5 = v5>>63 | v5<<1 + t = uint64(uint32(v2)) * uint64(uint32(v6)) + v2 = v2 + v6 + t*2 + v14 = v14 ^ v2 + v14 = v14>>32 | v14<<32 + t = uint64(uint32(v10)) * uint64(uint32(v14)) + v10 = v10 + v14 + t*2 + v6 = v6 ^ v10 + v6 = v6>>24 | v6<<40 + t = uint64(uint32(v2)) * uint64(uint32(v6)) + v2 = v2 + v6 + t*2 + v14 = v14 ^ v2 + v14 = v14>>16 | v14<<48 + t = uint64(uint32(v10)) * uint64(uint32(v14)) + v10 = v10 + v14 + t*2 + v6 = v6 ^ v10 + v6 = v6>>63 | v6<<1 + t = uint64(uint32(v3)) * uint64(uint32(v7)) + v3 = v3 + v7 + t*2 + v15 = v15 ^ v3 + v15 = v15>>32 | v15<<32 + t = uint64(uint32(v11)) * uint64(uint32(v15)) + v11 = v11 + v15 + t*2 + v7 = v7 ^ v11 + v7 = v7>>24 | v7<<40 + t = uint64(uint32(v3)) * uint64(uint32(v7)) + v3 = v3 + v7 + t*2 + v15 = v15 ^ v3 + v15 = v15>>16 | v15<<48 + t = uint64(uint32(v11)) * uint64(uint32(v15)) + v11 = v11 + v15 + t*2 + v7 = v7 ^ v11 + v7 = v7>>63 | v7<<1 + t = uint64(uint32(v0)) * uint64(uint32(v5)) + v0 = v0 + v5 + t*2 + v15 = v15 ^ v0 + v15 = v15>>32 | v15<<32 + t = uint64(uint32(v10)) * uint64(uint32(v15)) + v10 = v10 + v15 + t*2 + v5 = v5 ^ v10 + v5 = v5>>24 | v5<<40 + t = uint64(uint32(v0)) * uint64(uint32(v5)) + v0 = v0 + v5 + t*2 + v15 = v15 ^ v0 + v15 = v15>>16 | v15<<48 + t = uint64(uint32(v10)) * uint64(uint32(v15)) + v10 = v10 + v15 + t*2 + v5 = v5 ^ v10 + v5 = v5>>63 | v5<<1 + t = uint64(uint32(v1)) * uint64(uint32(v6)) + v1 = v1 + v6 + t*2 + v12 = v12 ^ v1 + v12 = v12>>32 | v12<<32 + t = uint64(uint32(v11)) * uint64(uint32(v12)) + v11 = v11 + v12 + t*2 + v6 = v6 ^ v11 + v6 = v6>>24 | v6<<40 + t = uint64(uint32(v1)) * uint64(uint32(v6)) + v1 = v1 + v6 + t*2 + v12 = v12 ^ v1 + v12 = v12>>16 | v12<<48 + t = uint64(uint32(v11)) * uint64(uint32(v12)) + v11 = v11 + v12 + t*2 + v6 = v6 ^ v11 + v6 = v6>>63 | v6<<1 + t = uint64(uint32(v2)) * uint64(uint32(v7)) + v2 = v2 + v7 + t*2 + v13 = v13 ^ v2 + v13 = v13>>32 | v13<<32 + t = uint64(uint32(v8)) * uint64(uint32(v13)) + v8 = v8 + v13 + t*2 + v7 = v7 ^ v8 + v7 = v7>>24 | v7<<40 + t = uint64(uint32(v2)) * uint64(uint32(v7)) + v2 = v2 + v7 + t*2 + v13 = v13 ^ v2 + v13 = v13>>16 | v13<<48 + t = uint64(uint32(v8)) * uint64(uint32(v13)) + v8 = v8 + v13 + t*2 + v7 = v7 ^ v8 + v7 = v7>>63 | v7<<1 + t = uint64(uint32(v3)) * uint64(uint32(v4)) + v3 = v3 + v4 + t*2 + v14 = v14 ^ v3 + v14 = v14>>32 | v14<<32 + t = uint64(uint32(v9)) * uint64(uint32(v14)) + v9 = v9 + v14 + t*2 + v4 = v4 ^ v9 + v4 = v4>>24 | v4<<40 + t = uint64(uint32(v3)) * uint64(uint32(v4)) + v3 = v3 + v4 + t*2 + v14 = v14 ^ v3 + v14 = v14>>16 | v14<<48 + t = uint64(uint32(v9)) * uint64(uint32(v14)) + v9 = v9 + v14 + t*2 + v4 = v4 ^ v9 + v4 = v4>>63 | v4<<1 + *p0 = v0 + *p1 = v1 + *p2 = v2 + *p3 = v3 + *p4 = v4 + *p5 = v5 + *p6 = v6 + *p7 = v7 + *p8 = v8 + *p9 = v9 + *p10 = v10 + *p11 = v11 + *p12 = v12 + *p13 = v13 + *p14 = v14 + *p15 = v15 +} diff --git a/vendor/github.com/magical/argon2/round.py b/vendor/github.com/magical/argon2/round.py new file mode 100644 index 0000000..ce864ae --- /dev/null +++ b/vendor/github.com/magical/argon2/round.py @@ -0,0 +1,54 @@ +print("package argon2") +print() +print("func block(z, a, b *[128]uint64) {") + +for i in range(128): + print("\tz[%d] = a[%d] ^ b[%d]" % (i, i, i)) + +for b in range(0, 128, 16): + print("\t_P(" + ", ".join("&z[%d]" % i for i in range(b, b+16)) + ")") + +for b in range(0, 16, 2): + print("\t_P(" + ", ".join("&z[%d], &z[%d]" % (i, i+1) for i in range(b, 128, 16)) + ")") + +for i in range(128): + print("\tz[%d] ^= a[%d] ^ b[%d]" % (i, i, i)) + +print("}") +print() +print("func _P("+", ".join("p%d" % i for i in range(16))+" *uint64) {") +for i in range(16): + print("\tvar v%d = *p%d" % (i, i)) +print("\tvar t uint64") + +def G(a, b, c, d): + print("\tt = uint64(uint32(%s)) * uint64(uint32(%s))" % (a, b)) + print("\t%s = %s + %s + t*2" % (a, a, b)) + print("\t%s = %s ^ %s" % (d, d, a)) + print("\t%s = %s>>32 | %s<<32" % (d, d, d)) + print("\tt = uint64(uint32(%s)) * uint64(uint32(%s))" % (c, d)) + print("\t%s = %s + %s + t*2" % (c, c, d)) + print("\t%s = %s ^ %s" % (b, b, c)) + print("\t%s = %s>>24 | %s<<40" % (b, b, b)) + print("\tt = uint64(uint32(%s)) * uint64(uint32(%s))" % (a, b)) + print("\t%s = %s + %s + t*2" % (a, a, b)) + print("\t%s = %s ^ %s" % (d, d, a)) + print("\t%s = %s>>16 | %s<<48" % (d, d, d)) + print("\tt = uint64(uint32(%s)) * uint64(uint32(%s))" % (c, d)) + print("\t%s = %s + %s + t*2" % (c, c, d)) + print("\t%s = %s ^ %s" % (b, b, c)) + print("\t%s = %s>>63 | %s<<1" % (b, b, b)) + +G("v0", "v4", "v8", "v12") +G("v1", "v5", "v9", "v13") +G("v2", "v6", "v10", "v14") +G("v3", "v7", "v11", "v15") +G("v0", "v5", "v10", "v15") +G("v1", "v6", "v11", "v12") +G("v2", "v7", "v8", "v13") +G("v3", "v4", "v9", "v14") + +for i in range(16): + print("\t*p%d = v%d" % (i, i)) + +print("}") diff --git a/vendor/github.com/wg/ecies/aead.go b/vendor/github.com/wg/ecies/aead.go new file mode 100644 index 0000000..82287f0 --- /dev/null +++ b/vendor/github.com/wg/ecies/aead.go @@ -0,0 +1,106 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package ecies + +import ( + "crypto/cipher" + "crypto/subtle" + "errors" + + "github.com/wg/ecies/chacha20poly1305" + "github.com/wg/ecies/xchacha20poly1305" +) + +var ( + ErrInvalidKeySize = errors.New("cipher: invalid key length") + ErrAuthFailed = errors.New("cipher: message auth failed") +) + +type AEAD struct { + key []byte + nonceSize int + tagSize int + Cipher +} + +func NewXChaCha20Poly1305(key []byte) (cipher.AEAD, error) { + if len(key) != xchacha20poly1305.KeySize { + return nil, ErrInvalidKeySize + } + + core := &xchacha20poly1305.XChaCha20Poly1305{} + + return &AEAD{ + key: key, + nonceSize: xchacha20poly1305.NonceSize, + tagSize: xchacha20poly1305.TagSize, + Cipher: core, + }, nil +} + +func NewChaCha20Poly1305(key []byte) (cipher.AEAD, error) { + if len(key) != chacha20poly1305.KeySize { + return nil, ErrInvalidKeySize + } + + core := &chacha20poly1305.ChaCha20Poly1305{} + + return &AEAD{ + key: key, + nonceSize: chacha20poly1305.NonceSize, + tagSize: chacha20poly1305.TagSize, + Cipher: core, + }, nil +} + +func (a *AEAD) NonceSize() int { + return a.nonceSize +} + +func (a *AEAD) Overhead() int { + return a.tagSize +} + +func (a *AEAD) Open(dst, nonce, src, aad []byte) ([]byte, error) { + err := a.Init(a.key, nonce) + if err != nil { + return nil, err + } + + n := len(src) - a.tagSize + dst, ret := extend(dst, n) + src, tag := src[:n], src[n:] + + a.Auth(aad) + a.Decrypt(dst, src) + + if subtle.ConstantTimeCompare(tag, a.Tag(nil)) != 1 { + return nil, ErrAuthFailed + } + + return ret, nil +} + +func (a *AEAD) Seal(dst, nonce, src, aad []byte) []byte { + err := a.Init(a.key, nonce) + if err != nil { + panic(err) + } + + n := len(src) + a.tagSize + dst, ret := extend(dst, n) + tag := dst[len(src):] + + a.Auth(aad) + a.Encrypt(dst, src) + a.Tag(tag[:0]) + + return ret +} + +func extend(dst []byte, n int) ([]byte, []byte) { + if len(dst) < n { + dst = append(dst, make([]byte, n)...) + } + return dst, dst[:n] +} diff --git a/vendor/github.com/wg/ecies/aead_test.go b/vendor/github.com/wg/ecies/aead_test.go new file mode 100644 index 0000000..b830ca9 --- /dev/null +++ b/vendor/github.com/wg/ecies/aead_test.go @@ -0,0 +1,69 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package ecies + +import ( + "bytes" + "testing" +) + +func TestRFC7539(t *testing.T) { + plaintext := []byte{ + 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39, 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63, + 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f, + 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73, + 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, + 0x74, 0x2e, + } + + aad := []byte{ + 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + } + + key := []byte{ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + } + + nonce := []byte{ + 0x07, 0x00, 0x00, 0x00, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + } + + ciphertext := []byte{ + 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2, + 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe, 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6, + 0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12, 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b, + 0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29, 0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36, + 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c, 0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58, + 0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94, 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc, + 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d, 0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b, + 0x61, 0x16, + } + + tag := []byte{ + 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a, 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91, + } + + aead, err := NewChaCha20Poly1305(key) + if err != nil { + t.Fatal(err) + } + + sealed := aead.Seal(nil, nonce, plaintext, aad) + if !bytes.Equal(sealed, append(ciphertext, tag...)) { + t.Fatal("Seal: ciphertext|tag incorrect") + } + + opened, err := aead.Open(nil, nonce, append(ciphertext, tag...), aad) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(opened, plaintext) { + t.Fatal("Open: plaintext incorrect") + } +} diff --git a/vendor/github.com/wg/ecies/box.go b/vendor/github.com/wg/ecies/box.go new file mode 100644 index 0000000..b480afc --- /dev/null +++ b/vendor/github.com/wg/ecies/box.go @@ -0,0 +1,90 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package ecies + +import ( + "crypto/subtle" + "errors" + + "github.com/dchest/blake2b" + "github.com/wg/ecies/xchacha20poly1305" +) + +var ( + ErrBoxAuthFailed = errors.New("box: message auth failed") + ErrBoxTooSmall = errors.New("box: destination too small") + ErrBoxInvariant = errors.New("box: invariant violation") +) + +type Box struct { + key [xchacha20poly1305.KeySize]byte + xchacha20poly1305.XChaCha20Poly1305 +} + +func NewX25519XChaCha20Poly1305(publicKey, privateKey *[32]byte) (*Box, error) { + var secret [32]byte + if err := X25519(&secret, publicKey, privateKey); err != nil { + return nil, err + } + return newXChaCha20Poly1305Box(secret[:]) +} + +func NewX448XChaCha20Poly1305(publicKey, privateKey *[56]byte) (*Box, error) { + var secret [56]byte + if err := X448(&secret, publicKey, privateKey); err != nil { + return nil, err + } + return newXChaCha20Poly1305Box(secret[:]) +} + +func (b *Box) Seal(dst, msg, nonce []byte) error { + if cap(dst) < len(msg)+xchacha20poly1305.TagSize { + return ErrBoxTooSmall + } + + if err := b.Init(b.key[:], nonce); err != nil { + return err + } + + n := len(msg) + b.Encrypt(dst, msg) + b.Tag(dst[n:n]) + + return nil +} + +func (b *Box) Open(dst, msg, nonce []byte) error { + if cap(dst) < len(msg)-xchacha20poly1305.TagSize { + return ErrBoxTooSmall + } + + if err := b.Init(b.key[:], nonce); err != nil { + return err + } + + n := len(msg) - xchacha20poly1305.TagSize + msg, tag := msg[:n], msg[n:] + b.Decrypt(dst, msg) + + if subtle.ConstantTimeCompare(tag, b.Tag(nil)) != 1 { + return ErrBoxAuthFailed + } + + return nil +} + +func newXChaCha20Poly1305Box(secret []byte) (*Box, error) { + h, err := blake2b.New(&blake2b.Config{ + Size: xchacha20poly1305.KeySize, + }) + + if err != nil { + return nil, ErrBoxInvariant + } + + box := &Box{} + h.Write(secret) + h.Sum(box.key[:0]) + + return box, nil +} diff --git a/vendor/github.com/wg/ecies/box_test.go b/vendor/github.com/wg/ecies/box_test.go new file mode 100644 index 0000000..9c291e1 --- /dev/null +++ b/vendor/github.com/wg/ecies/box_test.go @@ -0,0 +1,124 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package ecies + +import ( + "bytes" + "crypto/rand" + "testing" + + "github.com/dchest/blake2b" + "github.com/wg/ecies/xchacha20poly1305" +) + +func TestXChaCha20Poly1305KeySetup(t *testing.T) { + secret := []byte("secret") + + cfg := blake2b.Config{Size: xchacha20poly1305.KeySize} + hash, err := blake2b.New(&cfg) + if err != nil { + t.Fatal(err) + } + + hash.Write(secret) + key := hash.Sum(nil) + + box, err := newXChaCha20Poly1305Box(secret) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(box.key[:], key) { + t.Fatal("box key initialization incorrect") + } +} + +func TestXChaCha20Poly1305Box(t *testing.T) { + const tagSize = xchacha20poly1305.TagSize + + var ( + key [xchacha20poly1305.KeySize]byte + nonce [xchacha20poly1305.NonceSize]byte + msg [64]byte + raw [len(msg) + tagSize]byte + sealed [len(msg) + tagSize]byte + opened [len(msg) + tagSize]byte + box Box + ) + + rand.Read(key[:]) + rand.Read(nonce[:]) + rand.Read(msg[:]) + copy(box.key[:], key[:]) + + c := xchacha20poly1305.New(&key, &nonce) + c.Encrypt(raw[:], msg[:]) + c.Tag(raw[len(msg):len(msg)]) + + err := box.Seal(sealed[:], msg[:], nonce[:]) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(sealed[:len(msg)], raw[:len(msg)]) { + t.Fatal("sealed ciphertext != raw ciphertext") + } + + if !bytes.Equal(sealed[len(msg):], raw[len(msg):]) { + t.Fatal("sealed auth tag != raw auth tag") + } + + err = box.Open(opened[:], sealed[:], nonce[:]) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(opened[:len(msg)], msg[:]) { + t.Fatal("opened plaintext != original plaintext") + } +} + +func TestXChaCha20Poly1305BoxInPlace(t *testing.T) { + const tagSize = xchacha20poly1305.TagSize + + var ( + key [xchacha20poly1305.KeySize]byte + nonce [xchacha20poly1305.NonceSize]byte + msg [64]byte + raw [len(msg) + tagSize]byte + dst [len(msg) + tagSize]byte + box Box + ) + + rand.Read(key[:]) + rand.Read(nonce[:]) + rand.Read(msg[:]) + copy(dst[:], msg[:]) + copy(box.key[:], key[:]) + + c := xchacha20poly1305.New(&key, &nonce) + c.Encrypt(raw[:], msg[:]) + c.Tag(raw[len(msg):len(msg)]) + + err := box.Seal(dst[:], dst[:len(msg)], nonce[:]) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(dst[:len(msg)], raw[:len(msg)]) { + t.Fatal("sealed ciphertext != raw ciphertext") + } + + if !bytes.Equal(dst[len(msg):], raw[len(msg):]) { + t.Fatal("sealed auth tag != raw auth tag") + } + + err = box.Open(dst[:], dst[:], nonce[:]) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(dst[:len(msg)], msg[:]) { + t.Fatal("opened plaintext != original plaintext") + } +} diff --git a/vendor/github.com/wg/ecies/chacha20poly1305/chacha20poly1305.go b/vendor/github.com/wg/ecies/chacha20poly1305/chacha20poly1305.go new file mode 100644 index 0000000..e04ca5b --- /dev/null +++ b/vendor/github.com/wg/ecies/chacha20poly1305/chacha20poly1305.go @@ -0,0 +1,90 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +// Package chacha20poly1305 implements the AEAD_CHACHA20_POLY1305 +// construction as specified in RFC 7539. +package chacha20poly1305 + +import ( + "encoding/binary" + + "schwanenlied.me/yawning/chacha20" + "schwanenlied.me/yawning/poly1305" +) + +const ( + KeySize = chacha20.KeySize + NonceSize = chacha20.INonceSize + TagSize = poly1305.Size +) + +var padding [16]byte + +type ChaCha20Poly1305 struct { + a, n uint64 + chacha20.Cipher + poly1305.Poly1305 +} + +func New(key *[KeySize]byte, nonce *[NonceSize]byte) *ChaCha20Poly1305 { + x := &ChaCha20Poly1305{} + x.Init(key[:], nonce[:]) + return x +} + +func (x *ChaCha20Poly1305) Init(key, nonce []byte) error { + err := x.ReKey(key, nonce) + if err == nil { + x.initPoly1305() + x.Seek(1) + x.a = 0 + x.n = 0 + } + return err +} + +func (x *ChaCha20Poly1305) Auth(src []byte) { + if n := len(src); n > 0 { + x.Poly1305.Write(src) + x.a = uint64(n) + x.Poly1305.Write(padding[:16-n%16]) + } +} + +func (x *ChaCha20Poly1305) Decrypt(dst, src []byte) { + x.Poly1305.Write(src) + x.XORKeyStream(dst, src) + x.n += uint64(len(src)) +} + +func (x *ChaCha20Poly1305) Encrypt(dst, src []byte) { + n := len(src) + x.XORKeyStream(dst, src) + x.Poly1305.Write(dst[:n]) + x.n += uint64(n) +} + +func (x *ChaCha20Poly1305) Tag(b []byte) []byte { + var lengths [16]byte + binary.LittleEndian.PutUint64(lengths[0:], uint64(x.a)) + binary.LittleEndian.PutUint64(lengths[8:], uint64(x.n)) + x.Poly1305.Write(padding[:16-x.n%16]) + x.Poly1305.Write(lengths[:]) + return x.Poly1305.Sum(b) +} + +func (x *ChaCha20Poly1305) Reset() { + x.Cipher.Reset() +} + +func (x *ChaCha20Poly1305) TagSize() int { + return TagSize +} + +func (x *ChaCha20Poly1305) initPoly1305() { + var key [poly1305.KeySize]byte + x.KeyStream(key[:]) + x.Poly1305.Init(key[:]) + for i := range key { + key[i] = 0 + } +} diff --git a/vendor/github.com/wg/ecies/chacha20poly1305/chacha20poly1305_test.go b/vendor/github.com/wg/ecies/chacha20poly1305/chacha20poly1305_test.go new file mode 100644 index 0000000..27d92f7 --- /dev/null +++ b/vendor/github.com/wg/ecies/chacha20poly1305/chacha20poly1305_test.go @@ -0,0 +1,114 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package chacha20poly1305 + +import ( + "bytes" + "testing" +) + +func TestRFC7539(t *testing.T) { + plaintext := []byte{ + 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39, 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63, + 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f, + 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73, + 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, + 0x74, 0x2e, + } + + aad := []byte{ + 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + } + + key := []byte{ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + } + + nonce := []byte{ + 0x07, 0x00, 0x00, 0x00, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + } + + ciphertext := []byte{ + 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2, + 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe, 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6, + 0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12, 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b, + 0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29, 0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36, + 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c, 0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58, + 0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94, 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc, + 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d, 0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b, + 0x61, 0x16, + } + + tag := []byte{ + 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a, 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91, + } + + c := ChaCha20Poly1305{} + + err := c.Init(key, nonce) + if err != nil { + t.Fatal(err) + } + + c.Auth(aad) + c.Encrypt(plaintext, plaintext) + + if !bytes.Equal(plaintext, ciphertext) { + t.Fatal("encrypted plaintext != ciphertext") + } + + if !bytes.Equal(c.Tag(nil), tag) { + t.Fatal("actual tag != expected tag") + } +} + +func TestRFC7539_ChaCha20(t *testing.T) { + plaintext := []byte{ + 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39, 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63, + 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f, + 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73, + 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, + 0x74, 0x2e, + } + + key := []byte{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + } + + nonce := []byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00, + } + + ciphertext := []byte{ + 0x6e, 0x2e, 0x35, 0x9a, 0x25, 0x68, 0xf9, 0x80, 0x41, 0xba, 0x07, 0x28, 0xdd, 0x0d, 0x69, 0x81, + 0xe9, 0x7e, 0x7a, 0xec, 0x1d, 0x43, 0x60, 0xc2, 0x0a, 0x27, 0xaf, 0xcc, 0xfd, 0x9f, 0xae, 0x0b, + 0xf9, 0x1b, 0x65, 0xc5, 0x52, 0x47, 0x33, 0xab, 0x8f, 0x59, 0x3d, 0xab, 0xcd, 0x62, 0xb3, 0x57, + 0x16, 0x39, 0xd6, 0x24, 0xe6, 0x51, 0x52, 0xab, 0x8f, 0x53, 0x0c, 0x35, 0x9f, 0x08, 0x61, 0xd8, + 0x07, 0xca, 0x0d, 0xbf, 0x50, 0x0d, 0x6a, 0x61, 0x56, 0xa3, 0x8e, 0x08, 0x8a, 0x22, 0xb6, 0x5e, + 0x52, 0xbc, 0x51, 0x4d, 0x16, 0xcc, 0xf8, 0x06, 0x81, 0x8c, 0xe9, 0x1a, 0xb7, 0x79, 0x37, 0x36, + 0x5a, 0xf9, 0x0b, 0xbf, 0x74, 0xa3, 0x5b, 0xe6, 0xb4, 0x0b, 0x8e, 0xed, 0xf2, 0x78, 0x5e, 0x42, + 0x87, 0x4d, + } + + c := ChaCha20Poly1305{} + + err := c.Init(key, nonce) + if err != nil { + t.Fatal(err) + } + + c.Encrypt(plaintext, plaintext) + + if !bytes.Equal(plaintext, ciphertext) { + t.Fatal("encrypted plaintext != expected ciphertext") + } +} diff --git a/vendor/github.com/wg/ecies/cipher.go b/vendor/github.com/wg/ecies/cipher.go new file mode 100644 index 0000000..e5acbc0 --- /dev/null +++ b/vendor/github.com/wg/ecies/cipher.go @@ -0,0 +1,13 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package ecies + +type Cipher interface { + Init(key, nonce []byte) error + Auth(src []byte) + Decrypt(dst, src []byte) + Encrypt(dst, src []byte) + Tag(tag []byte) []byte + Reset() + TagSize() int +} diff --git a/vendor/github.com/wg/ecies/doc.go b/vendor/github.com/wg/ecies/doc.go new file mode 100644 index 0000000..722381b --- /dev/null +++ b/vendor/github.com/wg/ecies/doc.go @@ -0,0 +1,14 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +/* +Package ecies provides a convenient interface to a number of Elliptic Curve +Integrated Encryption Schemes and their corresponding primitives: Curve25519, +Curve448 AKA Ed448-Goldilocks, XChaCha20, Poly1305, and BLAKE2b. + +This package has not been subject to peer review and the specific algorithm +combinations have not been standardized. + +The cryptographic core is provided by Yawning Angel's excellent open-source x448, +ChaCha20, and Poly1305 libraries, but any mistakes are the fault of Will Glozer. +*/ +package ecies diff --git a/vendor/github.com/wg/ecies/ecdh.go b/vendor/github.com/wg/ecies/ecdh.go new file mode 100644 index 0000000..74d1979 --- /dev/null +++ b/vendor/github.com/wg/ecies/ecdh.go @@ -0,0 +1,43 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package ecies + +import ( + "errors" + "io" + + "golang.org/x/crypto/curve25519" + "schwanenlied.me/yawning/x448" +) + +var ErrX448 = errors.New("curve448: key exchange failed") + +func GenerateCurve25519Key(rand io.Reader, public, private *[32]byte) error { + _, err := io.ReadFull(rand, private[:]) + if err != nil { + return err + } + curve25519.ScalarBaseMult(public, private) + return nil +} + +func GenerateCurve448Key(rand io.Reader, public, private *[56]byte) error { + _, err := io.ReadFull(rand, private[:]) + if err != nil { + return err + } + x448.ScalarBaseMult(public, private) + return nil +} + +func X25519(secret, public, private *[32]byte) error { + curve25519.ScalarMult(secret, private, public) + return nil +} + +func X448(secret, public, private *[56]byte) error { + if x448.ScalarMult(secret, private, public) != 0 { + return ErrX448 + } + return nil +} diff --git a/vendor/github.com/wg/ecies/ecdh_test.go b/vendor/github.com/wg/ecies/ecdh_test.go new file mode 100644 index 0000000..a739a85 --- /dev/null +++ b/vendor/github.com/wg/ecies/ecdh_test.go @@ -0,0 +1,157 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package ecies + +import ( + "bytes" + "crypto/rand" + "encoding/hex" + "testing" +) + +func Test_X25519_RFC7748(t *testing.T) { + const keySize = 32 + + unhex := func(s string) *[keySize]byte { + var out [keySize]byte + switch n, err := hex.Decode(out[:], []byte(s)); { + case err != nil: + t.Fatal(err) + case n != keySize: + t.Fatalf("%d != %d", n, keySize) + } + return &out + } + + var ( + alicePrivateKey = unhex("77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a") + alicePublicKey = unhex("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a") + bobPrivateKey = unhex("5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb") + bobPublicKey = unhex("de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f") + expectedSecret = unhex("4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742") + sharedSecret [keySize]byte + ) + + _ = alicePublicKey + _ = bobPrivateKey + + err := X25519(&sharedSecret, bobPublicKey, alicePrivateKey) + + if err != nil { + t.Fatal("key exchange failed", err) + } + + if !bytes.Equal(sharedSecret[:], expectedSecret[:]) { + t.Fatal("shared secret incorrect") + } +} + +func Test_X448_RFC7748(t *testing.T) { + const keySize = 56 + + unhex := func(s ...string) *[keySize]byte { + var out [keySize]byte + var in []byte + + for i := range s { + in = append(in, []byte(s[i])...) + } + + switch n, err := hex.Decode(out[:], in); { + case err != nil: + t.Fatal(err) + case n != keySize: + t.Fatalf("%d != %d", n, keySize) + } + return &out + } + + var ( + alicePrivateKey = unhex( + "9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28d", + "d9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b", + ) + alicePublicKey = unhex( + "9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c", + "22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0", + ) + bobPrivateKey = unhex( + "1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d", + "6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d", + ) + bobPublicKey = unhex( + "3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b430", + "27d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609", + ) + expectedSecret = unhex( + "07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282b", + "b60c0b56fd2464c335543936521c24403085d59a449a5037514a879d", + ) + sharedSecret [keySize]byte + ) + + _ = alicePublicKey + _ = bobPrivateKey + + err := X448(&sharedSecret, bobPublicKey, alicePrivateKey) + + if err != nil { + t.Fatal("key exchange failed", err) + } + + if !bytes.Equal(sharedSecret[:], expectedSecret[:]) { + t.Fatal("shared secret incorrect") + } +} + +func Test_X25519_EphemeralStatic(t *testing.T) { + const keySize = 32 + + var ( + aliceStaticPublic [keySize]byte + aliceStaticPrivate [keySize]byte + aliceEphemeralPublic [keySize]byte + aliceEphemeralPrivate [keySize]byte + bobStaticPublic [keySize]byte + bobStaticPrivate [keySize]byte + aliceSecret [keySize]byte + bobSecret [keySize]byte + ) + + GenerateCurve25519Key(rand.Reader, &aliceStaticPublic, &aliceStaticPrivate) + GenerateCurve25519Key(rand.Reader, &aliceEphemeralPublic, &aliceEphemeralPrivate) + GenerateCurve25519Key(rand.Reader, &bobStaticPublic, &bobStaticPrivate) + + X25519(&aliceSecret, &bobStaticPublic, &aliceEphemeralPrivate) + X25519(&bobSecret, &aliceEphemeralPublic, &bobStaticPrivate) + + if !bytes.Equal(aliceSecret[:], bobSecret[:]) { + t.Fatal("alice's shared secret != bob's shared secret") + } +} + +func Test_X448_EphemeralStatic(t *testing.T) { + const keySize = 56 + + var ( + aliceStaticPublic [keySize]byte + aliceStaticPrivate [keySize]byte + aliceEphemeralPublic [keySize]byte + aliceEphemeralPrivate [keySize]byte + bobStaticPublic [keySize]byte + bobStaticPrivate [keySize]byte + aliceSecret [keySize]byte + bobSecret [keySize]byte + ) + + GenerateCurve448Key(rand.Reader, &aliceStaticPublic, &aliceStaticPrivate) + GenerateCurve448Key(rand.Reader, &aliceEphemeralPublic, &aliceEphemeralPrivate) + GenerateCurve448Key(rand.Reader, &bobStaticPublic, &bobStaticPrivate) + + X448(&aliceSecret, &bobStaticPublic, &aliceEphemeralPrivate) + X448(&bobSecret, &aliceEphemeralPublic, &bobStaticPrivate) + + if !bytes.Equal(aliceSecret[:], bobSecret[:]) { + t.Fatal("alice's shared secret != bob's shared secret") + } +} diff --git a/vendor/github.com/wg/ecies/vendor/github.com/dchest/blake2b/README b/vendor/github.com/wg/ecies/vendor/github.com/dchest/blake2b/README new file mode 100644 index 0000000..09f0143 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/github.com/dchest/blake2b/README @@ -0,0 +1,23 @@ +Go implementation of BLAKE2b collision-resistant cryptographic hash function +created by Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn, and +Christian Winnerlein (https://blake2.net). + +INSTALLATION + + $ go get github.com/dchest/blake2b + + +DOCUMENTATION + + See http://godoc.org/github.com/dchest/blake2b + + +PUBLIC DOMAIN DEDICATION + +Written in 2012 by Dmitry Chestnykh. + +To the extent possible under law, the author have dedicated all copyright +and related and neighboring rights to this software to the public domain +worldwide. This software is distributed without any warranty. +http://creativecommons.org/publicdomain/zero/1.0/ + diff --git a/vendor/github.com/wg/ecies/vendor/github.com/dchest/blake2b/blake2b.go b/vendor/github.com/wg/ecies/vendor/github.com/dchest/blake2b/blake2b.go new file mode 100644 index 0000000..f3eb388 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/github.com/dchest/blake2b/blake2b.go @@ -0,0 +1,299 @@ +// Written in 2012 by Dmitry Chestnykh. +// +// To the extent possible under law, the author have dedicated all copyright +// and related and neighboring rights to this software to the public domain +// worldwide. This software is distributed without any warranty. +// http://creativecommons.org/publicdomain/zero/1.0/ + +// Package blake2b implements BLAKE2b cryptographic hash function. +package blake2b + +import ( + "encoding/binary" + "errors" + "hash" +) + +const ( + BlockSize = 128 // block size of algorithm + Size = 64 // maximum digest size + SaltSize = 16 // maximum salt size + PersonSize = 16 // maximum personalization string size + KeySize = 64 // maximum size of key +) + +type digest struct { + h [8]uint64 // current chain value + t [2]uint64 // message bytes counter + f [2]uint64 // finalization flags + x [BlockSize]byte // buffer for data not yet compressed + nx int // number of bytes in buffer + + ih [8]uint64 // initial chain value (after config) + paddedKey [BlockSize]byte // copy of key, padded with zeros + isKeyed bool // indicates whether hash was keyed + size uint8 // digest size in bytes + isLastNode bool // indicates processing of the last node in tree hashing +} + +// Initialization values. +var iv = [8]uint64{ + 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, + 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, 0x9b05688c2b3e6c1f, + 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, +} + +// Config is used to configure hash function parameters and keying. +// All parameters are optional. +type Config struct { + Size uint8 // digest size (if zero, default size of 64 bytes is used) + Key []byte // key for prefix-MAC + Salt []byte // salt (if < 16 bytes, padded with zeros) + Person []byte // personalization (if < 16 bytes, padded with zeros) + Tree *Tree // parameters for tree hashing +} + +// Tree represents parameters for tree hashing. +type Tree struct { + Fanout uint8 // fanout + MaxDepth uint8 // maximal depth + LeafSize uint32 // leaf maximal byte length (0 for unlimited) + NodeOffset uint64 // node offset (0 for first, leftmost or leaf) + NodeDepth uint8 // node depth (0 for leaves) + InnerHashSize uint8 // inner hash byte length + IsLastNode bool // indicates processing of the last node of layer +} + +var ( + defaultConfig = &Config{Size: Size} + config256 = &Config{Size: 32} +) + +func verifyConfig(c *Config) error { + if c.Size > Size { + return errors.New("digest size is too large") + } + if len(c.Key) > KeySize { + return errors.New("key is too large") + } + if len(c.Salt) > SaltSize { + // Smaller salt is okay: it will be padded with zeros. + return errors.New("salt is too large") + } + if len(c.Person) > PersonSize { + // Smaller personalization is okay: it will be padded with zeros. + return errors.New("personalization is too large") + } + if c.Tree != nil { + if c.Tree.Fanout == 1 { + return errors.New("fanout of 1 is not allowed in tree mode") + } + if c.Tree.MaxDepth < 2 { + return errors.New("incorrect tree depth") + } + if c.Tree.InnerHashSize < 1 || c.Tree.InnerHashSize > Size { + return errors.New("incorrect tree inner hash size") + } + } + return nil +} + +// New returns a new hash.Hash configured with the given Config. +// Config can be nil, in which case the default one is used, calculating 64-byte digest. +// Returns non-nil error if Config contains invalid parameters. +func New(c *Config) (hash.Hash, error) { + if c == nil { + c = defaultConfig + } else { + if c.Size == 0 { + // Set default size if it's zero. + c.Size = Size + } + if err := verifyConfig(c); err != nil { + return nil, err + } + } + d := new(digest) + d.initialize(c) + return d, nil +} + +// initialize initializes digest with the given +// config, which must be non-nil and verified. +func (d *digest) initialize(c *Config) { + // Create parameter block. + var p [BlockSize]byte + p[0] = c.Size + p[1] = uint8(len(c.Key)) + if c.Salt != nil { + copy(p[32:], c.Salt) + } + if c.Person != nil { + copy(p[48:], c.Person) + } + if c.Tree != nil { + p[2] = c.Tree.Fanout + p[3] = c.Tree.MaxDepth + binary.LittleEndian.PutUint32(p[4:], c.Tree.LeafSize) + binary.LittleEndian.PutUint64(p[8:], c.Tree.NodeOffset) + p[16] = c.Tree.NodeDepth + p[17] = c.Tree.InnerHashSize + } else { + p[2] = 1 + p[3] = 1 + } + // Initialize. + d.size = c.Size + for i := 0; i < 8; i++ { + d.h[i] = iv[i] ^ binary.LittleEndian.Uint64(p[i*8:]) + } + if c.Tree != nil && c.Tree.IsLastNode { + d.isLastNode = true + } + // Process key. + if c.Key != nil { + copy(d.paddedKey[:], c.Key) + d.Write(d.paddedKey[:]) + d.isKeyed = true + } + // Save a copy of initialized state. + copy(d.ih[:], d.h[:]) +} + +// New512 returns a new hash.Hash computing the BLAKE2b 64-byte checksum. +func New512() hash.Hash { + d := new(digest) + d.initialize(defaultConfig) + return d +} + +// New256 returns a new hash.Hash computing the BLAKE2b 32-byte checksum. +func New256() hash.Hash { + d := new(digest) + d.initialize(config256) + return d +} + +// NewMAC returns a new hash.Hash computing BLAKE2b prefix- +// Message Authentication Code of the given size in bytes +// (up to 64) with the given key (up to 64 bytes in length). +func NewMAC(outBytes uint8, key []byte) hash.Hash { + d, err := New(&Config{Size: outBytes, Key: key}) + if err != nil { + panic(err.Error()) + } + return d +} + +// Reset resets the state of digest to the initial state +// after configuration and keying. +func (d *digest) Reset() { + copy(d.h[:], d.ih[:]) + d.t[0] = 0 + d.t[1] = 0 + d.f[0] = 0 + d.f[1] = 0 + d.nx = 0 + if d.isKeyed { + d.Write(d.paddedKey[:]) + } +} + +// Size returns the digest size in bytes. +func (d *digest) Size() int { return int(d.size) } + +// BlockSize returns the algorithm block size in bytes. +func (d *digest) BlockSize() int { return BlockSize } + +func (d *digest) Write(p []byte) (nn int, err error) { + nn = len(p) + left := BlockSize - d.nx + if len(p) > left { + // Process buffer. + copy(d.x[d.nx:], p[:left]) + p = p[left:] + blocks(d, d.x[:]) + d.nx = 0 + } + // Process full blocks except for the last one. + if len(p) > BlockSize { + n := len(p) &^ (BlockSize - 1) + if n == len(p) { + n -= BlockSize + } + blocks(d, p[:n]) + p = p[n:] + } + // Fill buffer. + d.nx += copy(d.x[d.nx:], p) + return +} + +// Sum returns the calculated checksum. +func (d0 *digest) Sum(in []byte) []byte { + // Make a copy of d0 so that caller can keep writing and summing. + d := *d0 + hash := d.checkSum() + return append(in, hash[:d.size]...) +} + +func (d *digest) checkSum() [Size]byte { + // Do not create unnecessary copies of the key. + if d.isKeyed { + for i := 0; i < len(d.paddedKey); i++ { + d.paddedKey[i] = 0 + } + } + + dec := BlockSize - uint64(d.nx) + if d.t[0] < dec { + d.t[1]-- + } + d.t[0] -= dec + + // Pad buffer with zeros. + for i := d.nx; i < len(d.x); i++ { + d.x[i] = 0 + } + // Set last block flag. + d.f[0] = 0xffffffffffffffff + if d.isLastNode { + d.f[1] = 0xffffffffffffffff + } + // Compress last block. + blocks(d, d.x[:]) + + var out [Size]byte + j := 0 + for _, s := range d.h[:(d.size-1)/8+1] { + out[j+0] = byte(s >> 0) + out[j+1] = byte(s >> 8) + out[j+2] = byte(s >> 16) + out[j+3] = byte(s >> 24) + out[j+4] = byte(s >> 32) + out[j+5] = byte(s >> 40) + out[j+6] = byte(s >> 48) + out[j+7] = byte(s >> 56) + j += 8 + } + return out +} + +// Sum512 returns a 64-byte BLAKE2b hash of data. +func Sum512(data []byte) [64]byte { + var d digest + d.initialize(defaultConfig) + d.Write(data) + return d.checkSum() +} + +// Sum256 returns a 32-byte BLAKE2b hash of data. +func Sum256(data []byte) (out [32]byte) { + var d digest + d.initialize(config256) + d.Write(data) + sum := d.checkSum() + copy(out[:], sum[:32]) + return +} diff --git a/vendor/github.com/wg/ecies/vendor/github.com/dchest/blake2b/blake2b_test.go b/vendor/github.com/wg/ecies/vendor/github.com/dchest/blake2b/blake2b_test.go new file mode 100644 index 0000000..38e4c28 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/github.com/dchest/blake2b/blake2b_test.go @@ -0,0 +1,625 @@ +// Written in 2012 by Dmitry Chestnykh. +// +// To the extent possible under law, the author have dedicated all copyright +// and related and neighboring rights to this software to the public domain +// worldwide. This software is distributed without any warranty. +// http://creativecommons.org/publicdomain/zero/1.0/ + +package blake2b + +import ( + "fmt" + "testing" +) + +func TestSum(t *testing.T) { + buf := make([]byte, len(golden)) + for i := range buf { + buf[i] = byte(i) + } + h := New512() + for i, v := range golden { + if v != fmt.Sprintf("%x", Sum512(buf[:i])) { + t.Errorf("%d: Sum512(): \nexpected %s\ngot %x", i, v, Sum512(buf[:i])) + } + h.Reset() + h.Write(buf[:i]) + sum := h.Sum(nil) + if fmt.Sprintf("%x", sum) != v { + t.Errorf("%d:\nexpected %s\ngot %x", i, v, sum) + } + + } +} + +func TestSum256(t *testing.T) { + // Simple one-hash test. + in := "The cryptographic hash function BLAKE2 is an improved version of the SHA-3 finalist BLAKE" + good := "e5866d0c42b4e27e89a316fa5c3ba8cacae754e53d8267da37ba1893c2fcd92c" + if good != fmt.Sprintf("%x", Sum256([]byte(in))) { + t.Errorf("Sum256(): \nexpected %s\ngot %x", good, Sum256([]byte(in))) + } + +} + +func TestSumLength(t *testing.T) { + h, _ := New(&Config{Size: 19}) + sum := h.Sum(nil) + if len(sum) != 19 { + t.Fatalf("Sum() returned a slice larger than the given hash size") + } +} + +func TestKeyedSum(t *testing.T) { + buf := make([]byte, len(goldenKeyed)) + for i := range buf { + buf[i] = byte(i) + } + h := NewMAC(64, buf[:64]) + for i, v := range goldenKeyed { + h.Reset() + h.Write(buf[:i]) + sum := h.Sum(nil) + if fmt.Sprintf("%x", sum) != v { + t.Errorf("%d:\nexpected %s\ngot %x", i, v, sum) + } + + } +} + +var bench = New512() +var buf = make([]byte, 8<<10) + +func BenchmarkWrite1K(b *testing.B) { + b.SetBytes(1024) + for i := 0; i < b.N; i++ { + bench.Write(buf[:1024]) + } +} + +func BenchmarkWrite8K(b *testing.B) { + b.SetBytes(int64(len(buf))) + for i := 0; i < b.N; i++ { + bench.Write(buf) + } +} + +func BenchmarkHash64(b *testing.B) { + b.SetBytes(64) + for i := 0; i < b.N; i++ { + Sum512(buf[:64]) + } +} + +func BenchmarkHash128(b *testing.B) { + b.SetBytes(128) + for i := 0; i < b.N; i++ { + Sum512(buf[:128]) + } +} + +func BenchmarkHash1K(b *testing.B) { + b.SetBytes(1024) + for i := 0; i < b.N; i++ { + Sum512(buf[:1024]) + } +} + +// Test vectors taken from reference implementation in C#. +var golden = []string{ + "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce", + "2fa3f686df876995167e7c2e5d74c4c7b6e48f8068fe0e44208344d480f7904c36963e44115fe3eb2a3ac8694c28bcb4f5a0f3276f2e79487d8219057a506e4b", + "1c08798dc641aba9dee435e22519a4729a09b2bfe0ff00ef2dcd8ed6f8a07d15eaf4aee52bbf18ab5608a6190f70b90486c8a7d4873710b1115d3debbb4327b5", + "40a374727302d9a4769c17b5f409ff32f58aa24ff122d7603e4fda1509e919d4107a52c57570a6d94e50967aea573b11f86f473f537565c66f7039830a85d186", + "77ddf4b14425eb3d053c1e84e3469d92c4cd910ed20f92035e0c99d8a7a86cecaf69f9663c20a7aa230bc82f60d22fb4a00b09d3eb8fc65ef547fe63c8d3ddce", + "cbaa0ba7d482b1f301109ae41051991a3289bc1198005af226c5e4f103b66579f461361044c8ba3439ff12c515fb29c52161b7eb9c2837b76a5dc33f7cb2e2e8", + "f95d45cf69af5c2023bdb505821e62e85d7caedf7beda12c0248775b0c88205eeb35af3a90816f6608ce7dd44ec28db1140614e1ddebf3aa9cd1843e0fad2c36", + "8f945ba700f2530e5c2a7df7d5dce0f83f9efc78c073fe71ae1f88204a4fd1cf70a073f5d1f942ed623aa16e90a871246c90c45b621b3401a5ddbd9df6264165", + "e998e0dc03ec30eb99bb6bfaaf6618acc620320d7220b3af2b23d112d8e9cb1262f3c0d60d183b1ee7f096d12dae42c958418600214d04f5ed6f5e718be35566", + "6a9a090c61b3410aede7ec9138146ceb2c69662f460c3da53c6515c1eb31f41ca3d280e567882f95cf664a94147d78f42cfc714a40d22ef19470e053493508a2", + "29102511d749db3cc9b4e335fa1f5e8faca8421d558f6a3f3321d50d044a248ba595cfc3efd3d2adc97334da732413f5cbf4751c362ba1d53862ac1e8dabeee8", + "c97a4779d47e6f77729b5917d0138abb35980ab641bd73a8859eb1ac98c05362ed7d608f2e9587d6ba9e271d343125d40d933a8ed04ec1fe75ec407c7a53c34e", + "10f0dc91b9f845fb95fad6860e6ce1adfa002c7fc327116d44d047cd7d5870d772bb12b5fac00e02b08ac2a0174d0446c36ab35f14ca31894cd61c78c849b48a", + "dea9101cac62b8f6a3c650f90eea5bfae2653a4eafd63a6d1f0f132db9e4f2b1b662432ec85b17bcac41e775637881f6aab38dd66dcbd080f0990a7a6e9854fe", + "441ffaa08cd79dff4afc9b9e5b5620eec086730c25f661b1d6fbfbd1cec3148dd72258c65641f2fca5eb155fadbcabb13c6e21dc11faf72c2a281b7d56145f19", + "444b240fe3ed86d0e2ef4ce7d851edde22155582aa0914797b726cd058b6f45932e0e129516876527b1dd88fc66d7119f4ab3bed93a61a0e2d2d2aeac336d958", + "bfbabbef45554ccfa0dc83752a19cc35d5920956b301d558d772282bc867009168e9e98606bb5ba73a385de5749228c925a85019b71f72fe29b3cd37ca52efe6", + "9c4d0c3e1cdbbf485bec86f41cec7c98373f0e09f392849aaa229ebfbf397b22085529cb7ef39f9c7c2222a514182b1effaa178cc3687b1b2b6cbcb6fdeb96f8", + "477176b3bfcbadd7657c23c24625e4d0d674d1868f006006398af97aa41877c8e70d3d14c3bbc9bbcdcea801bd0e1599af1f3eec67405170f4e26c964a57a8b7", + "a78c490eda3173bb3f10dee52f110fb1c08e0302230b85ddd7c11257d92de148785ef00c039c0bb8eb9808a35b2d8c080f572859714c9d4069c5bcaf090e898e", + "58d023397beb5b4145cb2255b07d74290b36d9fd1e594afbd8eea47c205b2efbfe6f46190faf95af504ab072e36f6c85d767a321bfd7f22687a4abbf494a689c", + "4001ec74d5a46fd29c2c3cdbe5d1b9f20e51a941be98d2a4e1e2fbf866a672121db6f81a514cfd10e7358d571bdba48e4ce708b9d124894bc0b5ed554935f73a", + "ccd1b22dab6511225d2401ea2d8625d206a12473cc732b615e5640cefff0a4adf971b0e827a619e0a80f5db9ccd0962329010d07e34a2064e731c520817b2183", + "b4a0a9e3574edb9e1e72aa31e39cc5f30dbf943f8cabc408449654a39131e66d718a18819143e3ea96b4a1895988a1c0056cf2b6e04f9ac19d657383c2910c44", + "447becab16630608d39f4f058b16f7af95b85a76aa0fa7cea2b80755fb76e9c804f2ca78f02643c915fbf2fce5e19de86000de03b18861815a83126071f8a37b", + "54e6dab9977380a5665822db93374eda528d9beb626f9b94027071cb26675e112b4a7fec941ee60a81e4d2ea3ff7bc52cfc45dfbfe735a1c646b2cf6d6a49b62", + "3ea62625949e3646704d7e3c906f82f6c028f540f5f72a794b0c57bf97b7649bfeb90b01d3ca3e829de21b3826e6f87014d3c77350cb5a15ff5d468a81bec160", + "213cfe145c54a33691569980e5938c8883a46d84d149c8ff1a67cd287b4d49c6da69d3a035443db085983d0efe63706bd5b6f15a7da459e8d50a19093db55e80", + "5716c4a38f38db104e494a0a27cbe89a26a6bb6f499ec01c8c01aa7cb88497e75148cd6eee12a7168b6f78ab74e4be749251a1a74c38c86d6129177e2889e0b6", + "030460a98bdf9ff17cd96404f28fc304f2b7c04eaade53677fd28f788ca22186b8bc80dd21d17f8549c711aff0e514e19d4e15f5990252a03e082f28dc2052f6", + "19e7f1ccee88a10672333e390cf22013a8c734c6cb9eab41f17c3c8032a2e4aca0569ea36f0860c7a1af28fa476840d66011168859334a9e4ef9cc2e61a0e29e", + "29f8b8c78c80f2fcb4bdf7825ed90a70d625ff785d262677e250c04f3720c888d03f8045e4edf3f5285bd39d928a10a7d0a5df00b8484ac2868142a1e8bea351", + "5c52920a7263e39d57920ca0cb752ac6d79a04fef8a7a216a1ecb7115ce06d89fd7d735bd6f4272555dba22c2d1c96e6352322c62c5630fde0f4777a76c3de2c", + "83b098f262251bf660064a9d3511ce7687a09e6dfbb878299c30e93dfb43a9314db9a600337db26ebeedaf2256a96dabe9b29e7573ad11c3523d874dde5be7ed", + "9447d98aa5c9331352f43d3e56d0a9a9f9581865998e2885cc56dd0a0bd5a7b50595bd10f7529bcd31f37dc16a1465d594079667da2a3fcb70401498837cedeb", + "867732f2feeb23893097561ac710a4bff453be9cfbedba8ba324f9d312a82d732e1b83b829fdcd177b882ca0c1bf544b223be529924a246a63cf059bfdc50a1b", + "f15ab26d4cdfcf56e196bb6ba170a8fccc414de9285afd98a3d3cf2fb88fcbc0f19832ac433a5b2cc2392a4ce34332987d8d2c2bef6c3466138db0c6e42fa47b", + "2813516d68ed4a08b39d648aa6aacd81e9d655ecd5f0c13556c60fdf0d333ea38464b36c02baccd746e9575e96c63014f074ae34a0a25b320f0fbedd6acf7665", + "d3259afca8a48962fa892e145acf547f26923ae8d4924c8a531581526b04b44c7af83c643ef5a0bc282d36f3fb04c84e28b351f40c74b69dc7840bc717b6f15f", + "f14b061ae359fa31b989e30332bfe8de8cc8cdb568e14be214a2223b84caab7419549ecfcc96ce2acec119485d87d157d3a8734fc426597d64f36570ceaf224d", + "55e70b01d1fbf8b23b57fb62e26c2ce54f13f8fa2464e6eb98d16a6117026d8b90819012496d4071ebe2e59557ece3519a7aa45802f9615374877332b73490b3", + "25261eb296971d6e4a71b2928e64839c67d422872bf9f3c31993615222de9f8f0b2c4be8548559b4b354e736416e3218d4e8a1e219a4a6d43e1a9a521d0e75fc", + "08307f347c41294e34bb54cb42b1522d22f824f7b6e5db50fda096798e181a8f026fa27b4ae45d52a62caf9d5198e24a4913c6671775b2d723c1239bfbf016d7", + "1e5c62e7e9bfa1b118747a2de08b3ca10112af96a46e4b22c3fc06f9bfee4eb5c49e057a4a4886234324572576bb9b5ecfde0d99b0de4f98ec16e4d1b85fa947", + "c74a77395fb8bc126447454838e561e962853dc7eb49a1e3cb67c3d0851f3e39517be8c350ac910903d49cd2bfdf545c99316d0346170b739f0add5d533c2cfc", + "0dd57b423cc01eb2861391eb886a0d17079b933fc76eb3fc08a19f8a74952cb68f6bcdc644f77370966e4d13e80560bcf082ef0479d48fbbab4df03b53a4e178", + "4d8dc3923edccdfce70072398b8a3da5c31fcb3ee3b645c85f717cbaeb4b673a19394425a585bfb464d92f1597d0b754d163f97ced343b25db5a70ef48ebb34f", + "f0a50553e4dfb0c4e3e3d3ba82034857e3b1e50918f5b8a7d698e10d242b0fb544af6c92d0c3aaf9932220416117b4e78ecb8a8f430e13b82a5915290a5819c5", + "b15543f3f736086627cc5365e7e8988c2ef155c0fd4f428961b00d1526f04d6d6a658b4b8ed32c5d8621e7f4f8e8a933d9ecc9dd1b8333cbe28cfc37d9719e1c", + "7b4fa158e415fef023247264cbbe15d16d91a44424a8db707eb1e2033c30e9e1e7c8c0864595d2cb8c580eb47e9d16abbd7e44e824f7cedb7def57130e52cfe9", + "60424ff23234c34dc9687ad502869372cc31a59380186bc2361c835d972f49666eb1ac69629de646f03f9b4db9e2ace093fbfdf8f20ab5f98541978be8ef549f", + "7406018ce704d84f5eb9c79fea97da345699468a350ee0b2d0f3a4bf2070304ea862d72a51c57d3064947286f531e0eaf7563702262e6c724abf5ed8c8398d17", + "14ef5c6d647b3bd1e6e32006c231199810de5c4dc88e70240273b0ea18e651a3eb4f5ca3114b8a56716969c7cda27e0c8db832ad5e89a2dc6cb0adbe7d93abd1", + "38cf6c24e3e08bcf1f6cf3d1b1f65b905239a3118033249e448113ec632ea6dc346feeb2571c38bd9a7398b2221280328002b23e1a45adaffe66d93f6564eaa2", + "6cd7208a4bc7e7e56201bbba02a0f489cd384abe40afd4222f158b3d986ee72a54c50fb64fd4ed2530eda2c8af2928a0da6d4f830ae1c9db469dfd970f12a56f", + "659858f0b5c9edab5b94fd732f6e6b17c51cc096104f09beb3afc3aa467c2ecf885c4c6541effa9023d3b5738ae5a14d867e15db06fe1f9d1127b77e1aabb516", + "26cca0126f5d1a813c62e5c71001c046f9c92095704550be5873a495a999ad010a4f79491f24f286500adce1a137bc2084e4949f5b7294cefe51ecaff8e95cba", + "4147c1f55172788c5567c561feef876f621fff1ce87786b8467637e70dfbcd0dbdb6415cb600954ab9c04c0e457e625b407222c0fe1ae21b2143688ada94dc58", + "5b1bf154c62a8af6e93d35f18f7f90abb16a6ef0e8d1aecd118bf70167bab2af08935c6fdc0663ce74482d17a8e54b546d1c296631c65f3b522a515839d43d71", + "9f600419a4e8f4fb834c24b0f7fc13bf4e279d98e8a3c765ee934917403e3a66097182ea21453cb63ebbe8b73a9c2167596446438c57627f330badd4f569f7d6", + "457ef6466a8924fd8011a34471a5a1ac8ccd9bd0d07a97414ac943021ce4b9e4b9c8db0a28f016ed43b1542481990022147b313e194671131e708dd43a3ed7dc", + "9997b2194d9af6dfcb9143f41c0ed83d3a3f4388361103d38c2a49b280a581212715fd908d41c651f5c715ca38c0ce2830a37e00e508ced1bcdc320e5e4d1e2e", + "5c6bbf16baa180f986bd40a1287ed4c549770e7284858fc47bc21ab95ebbf3374b4ee3fd9f2af60f3395221b2acc76f2d34c132954049f8a3a996f1e32ec84e5", + "d10bf9a15b1c9fc8d41f89bb140bf0be08d2f3666176d13baac4d381358ad074c9d4748c300520eb026daeaea7c5b158892fde4e8ec17dc998dcd507df26eb63", + "2fc6e69fa26a89a5ed269092cb9b2a449a4409a7a44011eecad13d7c4b0456602d402fa5844f1a7a758136ce3d5d8d0e8b86921ffff4f692dd95bdc8e5ff0052", + "fcbe8be7dcb49a32dbdf239459e26308b84dff1ea480df8d104eeff34b46fae98627b450c2267d48c0946a697c5b59531452ac0484f1c84e3a33d0c339bb2e28", + "a19093a6e3bcf5952f850f2030f69b9606f147f90b8baee3362da71d9f35b44ef9d8f0a7712ba1877fddcd2d8ea8f1e5a773d0b745d4725605983a2de901f803", + "3c2006423f73e268fa59d2920377eb29a4f9a8b462be15983ee3b85ae8a78e992633581a9099893b63db30241c34f643027dc878279af5850d7e2d4a2653073a", + "d0f2f2e3787653f77cce2fa24835785bbd0c433fc779465a115149905a9dd1cb827a628506d457fcf124a0c2aef9ce2d2a0a0f63545570d8667ff9e2eba07334", + "78a9fc048e25c6dcb5de45667de8ffdd3a93711141d594e9fa62a959475da6075ea8f0916e84e45ad911b75467077ee52d2c9aebf4d58f20ce4a3a00458b05d4", + "45813f441769ab6ed37d349ff6e72267d76ae6bb3e3c612ec05c6e02a12af5a37c918b52bf74267c3f6a3f183a8064ff84c07b193d08066789a01accdb6f9340", + "956da1c68d83a7b881e01b9a966c3c0bf27f68606a8b71d457bd016d4c41dd8a380c709a296cb4c6544792920fd788835771a07d4a16fb52ed48050331dc4c8b", + "df186c2dc09caa48e14e942f75de5ac1b7a21e4f9f072a5b371e09e07345b0740c76177b01278808fec025eded9822c122afd1c63e6f0ce2e32631041063145c", + "87475640966a9fdcd6d3a3b5a2cca5c08f0d882b10243c0ec1bf3c6b1c37f2cd3212f19a057864477d5eaf8faed73f2937c768a0af415e84bbce6bd7de23b660", + "c3b573bbe10949a0fbd4ff884c446f2229b76902f9dfdbb8a0353da5c83ca14e8151bbaac82fd1576a009adc6f1935cf26edd4f1fb8da483e6c5cd9d8923adc3", + "b09d8d0bba8a7286e43568f7907550e42036d674e3c8fc34d8ca46f771d6466b70fb605875f6a863c877d12f07063fdc2e90ccd459b1910dcd52d8f10b2b0a15", + "af3a22bf75b21abfb0acd54422ba1b7300a952eff02ebeb65b5c234471a98df32f4f9643ce1904108a168767924280bd76c83f8c82d9a79d9259b195362a2a04", + "bf4ff2221b7e6957a724cd964aa3d5d0d9941f540413752f4699d8101b3e537508bf09f8508b317736ffd265f2847aa7d84bd2d97569c49d632aed9945e5fa5e", + "9c6b6b78199b1bdacb4300e31479fa622a6b5bc80d4678a6078f88a8268cd7206a2799e8d4621a464ef6b43dd8adffe97caf221b22b6b8778b149a822aefbb09", + "890656f09c99d280b5ecb381f56427b813751bc652c7828078b23a4af83b4e3a61fdbac61f89bee84ea6bee760c047f25c6b0a201c69a38fd6fd971af18588bb", + "31a046f7882ffe6f83ce472e9a0701832ec7b3f76fbcfd1df60fe3ea48fde1651254247c3fd95e100f9172731e17fd5297c11f4bb328363ca361624a81af797c", + "27a60b2d00e7a671d47d0aec2a686a0ac04b52f40ab6629028eb7d13f4baa99ac0fe46ee6c814944f2f4b4d20e9378e4847ea44c13178091e277b87ea7a55711", + "8b5ccef194162c1f19d68f91e0b0928f289ec5283720840c2f73d253111238dcfe94af2b59c2c1ca2591901a7bc060e7459b6c47df0f71701a35cc0aa831b5b6", + "57ab6c4b2229aeb3b70476d803cd63812f107ce6da17fed9b17875e8f86c724f49e024cbf3a1b8b119c50357652b81879d2ade2d588b9e4f7cedba0e4644c9ee", + "0190a8dac320a739f322e15731aa140ddaf5bed294d5c82e54fef29f214e18aafaa84f8be99af62950266b8f901f15dd4c5d35516fc35b4cab2e96e4695bbe1c", + "d14d7c4c415eeb0e10b159224bea127ebd84f9591c702a330f5bb7bb7aa44ea39de6ed01f18da7adf40cfb97c5d152c27528824b21e239526af8f36b214e0cfb", + "be28c4be706970488fac7d29c3bd5c4e986085c4c3332f1f3fd30973db614164ba2f31a78875ffdc150325c88327a9443ed04fdfe5be93876d1628560c764a80", + "031da1069e3a2e9c3382e436ffd79df74b1ca6a8adb2deabe676ab45994cbc054f037d2f0eace858d32c14e2d1c8b46077308e3bdc2c1b53172ecf7a8c14e349", + "4665cef8ba4db4d0acb118f2987f0bb09f8f86aa445aa3d5fc9a8b346864787489e8fcecc125d17e9b56e12988eac5ecc7286883db0661b8ff05da2afff30fe4", + "63b7032e5f930cc9939517f9e986816cfbec2be59b9568b13f2ead05bae7777cab620c6659404f7409e4199a3be5f7865aa7cbdf8c4253f7e8219b1bd5f46fea", + "9f09bf093a2b0ff8c2634b49e37f1b2135b447aa9144c9787dbfd92129316c99e88aab8a21fdef2372d1189aec500f95775f1f92bfb45545e4259fb9b7b02d14", + "f9f8493c68088807df7f6a2693d64ea59f03e9e05a223e68524ca32195a4734b654fcea4d2734c866cf95c889fb10c49159be2f5043dc98bb55e02ef7bdcb082", + "3c9a7359ab4febce07b20ac447b06a240b7fe1dae5439c49b60b5819f7812e4c172406c1aac316713cf0dded1038077258e2eff5b33913d9d95caeb4e6c6b970", + "ad6aab8084510e822cfce8625d62cf4de655f4763884c71e80bab9ac9d5318dba4a6033ed29084e65216c031606ca17615dcfe3ba11d26851ae0999ca6e232cf", + "156e9e6261374c9dc884f36e70f0fe1ab9297997b836fa7d170a9c9ebf575b881e7bcea44d6c0248d35597907154828955be19135852f9228815eca024a8adfb", + "4215407633f4cca9b6788be93e6aa3d963c7d6ce4b147247099f46a3acb500a30038cb3e788c3d29f132ad844e80e9e99251f6db96acd8a091cfc770af53847b", + "1c077e279de6548523502b6df800ffdab5e2c3e9442eb838f58c295f3b147cef9d701c41c321283f00c71affa0619310399126295b78dd4d1a74572ef9ed5135", + "f07a555f49fe481cf4cd0a87b71b82e4a95064d06677fdd90a0eb598877ba1c83d4677b393c3a3b6661c421f5b12cb99d20376ba7275c2f3a8f5a9b7821720da", + "b5911b380d20c7b04323e4026b38e200f534259233b581e02c1e3e2d8438d6c66d5a4eb201d5a8b75072c4ec29106334da70bc79521b0ced2cfd533f5ff84f95", + "01f070a09bae911296361f91aa0e8e0d09a7725478536d9d48c5fe1e5e7c3c5b9b9d6eb07796f6da57ae562a7d70e882e37adfde83f0c433c2cd363536bb22c8", + "6f793eb4374a48b0775acaf9adcf8e45e54270c9475f004ad8d5973e2aca52747ff4ed04ae967275b9f9eb0e1ff75fb4f794fa8be9add7a41304868d103fab10", + "965f20f139765fcc4ce4ba3794675863cac24db472cd2b799d035bce3dbea502da7b524865f6b811d8c5828d3a889646fe64a380da1aa7c7044e9f245dced128", + "ec295b5783601244c30e4641e3b45be222c4dce77a58700f53bc8ec52a941690b4d0b087fb6fcb3f39832b9de8f75ec20bd43079811749cdc907edb94157d180", + "61c72f8ccc91dbb54ca6750bc489672de09faedb8fdd4f94ff2320909a303f5d5a98481c0bc1a625419fb4debfbf7f8a53bb07ec3d985e8ea11e72d559940780", + "afd8145b259eefc8d12620c3c5b03e1ed8fd2ccefe0365078c80fd42c1770e28b44948f27e65a1886690110db814397b68e43d80d1ba16dfa358e739c898cfa3", + "552fc7893cf1ce933ada35c0da98844e41545e244c3157a1428d7b4c21f9cd7e4071aed77b7ca9f1c38fba32237412ef21a342742ec8324378f21e507fafdd88", + "467a33fbadf5ebc52596ef86aaaefc6faba8ee651b1ce04de368a03a5a9040ef2835e00adb09abb3fbd2bce818a2413d0b0253b5bda4fc5b2f6f85f3fd5b55f2", + "22eff8e6dd5236f5f57d94ede874d6c9428e8f5d566f17cd6d1848cd752fe13c655cb10fbaaff76872f2bf2da99e15dc624075e1ec2f58a3f64072121838569e", + "9cec6bbf62c4bce4138abae1cbec8dad31950444e90321b1347196834c114b864af3f3cc3508f83751ffb4eda7c84d140734bb4263c3625c00f04f4c8068981b", + "a8b60fa4fc2442f6f1514ad7402626920cc7c2c9f72124b8cba8ee2cb7c4586f658a4410cffcc0ab88343955e094c6af0d20d0c714fb0a988f543f300f58d389", + "8271cc45dfa5e4170e847e8630b952cf9c2aa777d06f26a7585b8381f188dacc7337391cfcc94b053dc4ec29cc17f077870428f1ac23fddda165ef5a3f155f39", + "bf23c0c25c8060e4f6995f1623a3bebecaa96e308680000a8aa3cd56bb1a6da099e10d9231b37f4519b2efd2c24de72f31a5f19535241b4a59fa3c03ceb790e7", + "877fd652c05281009c0a5250e7a3a671f8b18c108817fe4a874de22da8e45db11958a600c5f62e67d36cbf84474cf244a9c2b03a9fb9dc711cd1a2cab6f3fae0", + "29df4d87ea444baf5bcdf5f4e41579e28a67de84149f06c03f110ea84f572a9f676addd04c4878f49c5c00accda441b1a387caceb2e993bb7a10cd8c2d6717e1", + "710dacb166844639cd7b637c274209424e2449dc35d790bbfa4f76177054a36b3b76fac0ca6e61df1e687000678ac0746df75d0a3954897681fd393a155a1bb4", + "c1d5f93b8dea1f2571babccbc01764541a0cda87e444d673c50966ca559c33354b3acb26e5d5781ffb28847a4b4754d77008c62a835835f500dea7c3b58bdae2", + "a41e41271cdab8af4d72b104bfb2ad041ac4df14677da671d85640c4b187f50c2b66513c4619fbd5d5dc4fe65dd37b9042e9848dda556a504caa2b1c6afe4730", + "e7bcbacdc379c43d81ebadcb37781552fc1d753e8cf310d968392d06c91f1d64cc9e90ce1d22c32d277fc6cda433a4d442c762e9eacf2c259f32d64cf9da3a22", + "51755b4ac5456b13218a19c5b9242f57c4a981e4d4ecdce09a3193362b808a579345d4881c2607a56534dd7f21956aff72c2f4173a6e7b6cc2212ba0e3daee1f", + "dcc2c4beb9c1f2607b786c20c631972347034c1cc02fcc7d02ff01099cfe1c6989840ac213923629113aa8bad713ccf0fe4ce13264fb32b8b0fe372da382544a", + "3d55176acea4a7e3a65ffa9fb10a7a1767199cf077cee9f71532d67cd7c73c9f93cfc37ccdcc1fdef50aad46a504a650d298d597a3a9fa95c6c40cb71fa5e725", + "d07713c005de96dd21d2eb8bbeca66746ea51a31ae922a3e74864889540a48db27d7e4c90311638b224bf0201b501891754848113c266108d0adb13db71909c7", + "58983c21433d950caa23e4bc18543b8e601c204318532152daf5e159a0cd1480183d29285c05f129cb0cc3164687928086ffe380158df1d394c6ac0d4288bca8", + "8100a8dc528d2b682ab4250801ba33f02a3e94c54dac0ae1482aa21f51ef3a82f3807e6facb0aeb05947bf7aa2adcb034356f90fa4560ede02201a37e411ec1a", + "07025f1bb6c784f3fe49de5c14b936a5acacacaab33f6ac4d0e00ab6a12483d6bec00b4fe67c7ca5cc508c2a53efb5bfa5398769d843ff0d9e8b14d36a01a77f", + "ba6aefd972b6186e027a76273a4a723321a3f580cfa894da5a9ce8e721c828552c64dacee3a7fd2d743b5c35ad0c8efa71f8ce99bf96334710e2c2346e8f3c52", + "e0721e02517aedfa4e7e9ba503e025fd46e714566dc889a84cbfe56a55dfbe2fc4938ac4120588335deac8ef3fa229adc9647f54ad2e3472234f9b34efc46543", + "b6292669ccd38d5f01caae96ba272c76a879a45743afa0725d83b9ebb26665b731f1848c52f11972b6644f554c064fa90780dbbbf3a89d4fc31f67df3e5857ef", + "2319e3789c47e2daa5fe807f61bec2a1a6537fa03f19ff32e87eecbfd64b7e0e8ccff439ac333b040f19b0c4ddd11a61e24ac1fe0f10a039806c5dcc0da3d115", + "f59711d44a031d5f97a9413c065d1e614c417ede998590325f49bad2fd444d3e4418be19aec4e11449ac1a57207898bc57d76a1bcf3566292c20c683a5c4648f", + "df0a9d0c212843a6a934e3902b2dd30d17fba5f969d2030b12a546d8a6a45e80cf5635f071f0452e9c919275da99bed51eb1173c1af0518726b75b0ec3bae2b5", + "a3eb6e6c7bf2fb8b28bfe8b15e15bb500f781ecc86f778c3a4e655fc5869bf2846a245d4e33b7b14436a17e63be79b36655c226a50ffbc7124207b0202342db5", + "56d4cbcd070563426a017069425c2cd2ae540668287a5fb9dac432eb8ab1a353a30f2fe1f40d83333afe696a267795408a92fe7da07a0c1814cf77f36e105ee8", + "e59b9987d428b3eda37d80abdb16cd2b0aef674c2b1dda4432ea91ee6c935c684b48b4428a8cc740e579a30deff35a803013820dd23f14ae1d8413b5c8672aec", + "cd9fcc99f99d4cc16d031900b2a736e1508db4b586814e6345857f354a70ccecb1df3b50a19adaf43c278efa423ff4bb6c523ec7fd7859b97b168a7ebff8467c", + "0602185d8c3a78738b99164b8bc6ffb21c7debebbf806372e0da44d121545597b9c662a255dc31542cf995ecbe6a50fb5e6e0ee4ef240fe557eded1188087e86", + "c08afa5b927bf08097afc5fff9ca4e7800125c1f52f2af3553fa2b89e1e3015c4f87d5e0a48956ad31450b083dad147ffb5ec03434a26830cf37d103ab50c5da", + "36f1e1c11d6ef6bc3b536d505d544a871522c5c2a253067ec9933b6ec25464daf985525f5b9560a16d890259ac1bb5cc67c0c469cde133def000ea1d686f4f5d", + "bf2ab2e2470f5438c3b689e66e7686fffa0cb1e1798ad3a86ff99075bf6138e33d9c0ce59afb24ac67a02af34428191a9a0a6041c07471b7c3b1a752d6fc0b8b", + "d400601f9728ccc4c92342d9787d8d28ab323af375ca5624b4bb91d17271fbae862e413be73f1f68e615b8c5c391be0dbd9144746eb339ad541547ba9c468a17", + "79fe2fe157eb85a038abb8ebbc647731d2c83f51b0ac6ee14aa284cb6a3549a4dcceb300740a825f52f5fb30b03b8c4d8b0f4aa67a63f4a94e3303c4eda4c02b", + "75351313b52a8529298d8c186b1768666dcca8595317d7a4816eb88c062020c0c8efc554bb341b64688db5ccafc35f3c3cd09d6564b36d7b04a248e146980d4b", + "e3128b1d311d02179d7f25f97a5a8bee2cc8c86303644fcd664e157d1fef00f23e46f9a5e8e5c890ce565bb6abd4302ce06469d52a5bd53e1c5a54d04649dc03", + "c2382a72d2d3ace9d5933d00b60827ed380cda08d0ba5f6dd41e29ee6dbe8ecb9235f06be95d83b6816a2fb7a5ad47035e8a4b69a4884b99e4bece58cab25d44", + "6b1c69460bbd50ac2ed6f32e6e887cfed407d47dcf0aaa60387fe320d780bd03eab6d7baeb2a07d10cd552a300341354ea9a5f03183a623f92a2d4d9f00926af", + "6cda206c80cdc9c44ba990e0328c314f819b142d00630404c48c05dc76d1b00ce4d72fc6a48e1469ddef609412c364820854214b4869af090f00d3c1ba443e1b", + "7ffc8c26fbd6a0f7a609e6e1939f6a9edf1b0b066641fb76c4f9602ed748d11602496b35355b1aa255850a509d2f8ee18c8f3e1d7dcbc37a136598f56a59ed17", + "70de1f08dd4e09d5fc151f17fc991a23abfc05104290d50468882efaf582b6ec2f14f577c0d68c3ad06626916e3c86e6daab6c53e5163e82b6bd0ce49fc0d8df", + "4f81935756ed35ee2058ee0c6a6110d6fac5cb6a4f46aa9411603f99965823b6da4838276c5c06bc7880e376d92758369ee7305bcec8d3cfd28ccabb7b4f0579", + "abcb61cb3683d18f27ad527908ed2d32a0426cb7bb4bf18061903a7dc42e7e76f982382304d18af8c80d91dd58dd47af76f8e2c36e28af2476b4bccf82e89fdf", + "02d261ad56a526331b643dd2186de9a82e72a58223cd1e723686c53d869b83b94632b7b647ab2afc0d522e29da3a5615b741d82852e0df41b66007dbcba90543", + "c5832741fa30c5436823015383d297ff4c4a5d7276c3f902122066e04be5431b1a85faf73b918434f9300963d1dea9e8ac3924ef490226edeea5f743e410669f", + "cfaeab268cd075a5a6aed515023a032d54f2f2ff733ce0cbc78db51db4504d675923f82746d6594606ad5d67734b11a67cc6a468c2032e43ca1a94c6273a985e", + "860850f92eb268272b67d133609bd64e34f61bf03f4c1738645c17fec818465d7ecd2be2907641130025fda79470ab731646e7f69440e8367ea76ac4cee8a1df", + "84b154ed29bbedefa648286839046f4b5aa34430e2d67f7496e4c39f2c7ea78995f69e1292200016f16ac3b37700e6c7e7861afc396b64a59a1dbf47a55c4bbc", + "aeeec260a5d8eff5ccab8b95da435a63ed7a21ea7fc7559413fd617e33609f8c290e64bbacc528f6c080262288b0f0a3219be223c991bee92e72349593e67638", + "8ad78a9f26601d127e8d2f2f976e63d19a054a17dcf59e0f013ab54a6887bbdffde7aaae117e0fbf3271016595b9d9c712c01b2c53e9655a382bc4522e616645", + "8934159dade1ac74147dfa282c75954fcef443ef25f80dfe9fb6ea633b8545111d08b34ef43fff17026c7964f5deac6d2b3c29dacf2747f022df5967dfdc1a0a", + "cd36dd0b240614cf2fa2b9e959679dcdd72ec0cd58a43da3790a92f6cdeb9e1e795e478a0a47d371100d340c5cedcdbbc9e68b3f460818e5bdff7b4cda4c2744", + "00df4e099b807137a85990f49d3a94315e5a5f7f7a6076b303e96b056fb93800111f479628e2f8db59aeb6ac70c3b61f51f9b46e80ffdeae25ebddb4af6cb4ee", + "2b9c955e6caed4b7c9e246b86f9a1726e810c59d126cee66ed71bf015b83558a4b6d84d18dc3ff4620c2ffb722359fdef85ba0d4e2d22ecbe0ed784f99afe587", + "181df0a261a2f7d29ea5a15772715105d450a4b6c236f699f462d60ca76487feedfc9f5eb92df838e8fb5dc3694e84c5e0f4a10b761f506762be052c745a6ee8", + "21fb203458bf3a7e9a80439f9a902899cd5de0139dfd56f7110c9dec8437b26bda63de2f565926d85edb1d6c6825669743dd9992653d13979544d5dc8228bfaa", + "ef021f29c5ffb830e64b9aa9058dd660fd2fcb81c497a7e698bcfbf59de5ad4a86ff93c10a4b9d1ae5774725f9072dcde9e1f199bab91f8bff921864aa502eee", + "b3cfda40526b7f1d37569bdfcdf911e5a6efe6b2ec90a0454c47b2c046bf130fc3b352b34df4813d48d33ab8e269b69b075676cb6d00a8dcf9e1f967ec191b2c", + "b4c6c3b267071eefb9c8c72e0e2b941293641f8673cb70c1cc26ad1e73cf141755860ad19b34c2f34ed35bb52ec4507cc1fe59047743a5f0c6febde625e26091", + "57a34f2bcca60d4b85103b830c9d7952a416be5263ae429c9e5e53fe8590a8f78ec65a51109ea85dcdf7b6223f9f2b340539fad81923dbf8edabf95129e4dff6", + "9cf46662fcd61a232277b685663b8b5da832dfd9a3b8ccfeec993ec6ac415ad07e048adfe414df272770dba867da5c1224c6fd0aa0c2187d426ac647e9887361", + "5ce1042ab4d542c2f9ee9d17262af8164098935bef173d0e18489b04841746cd2f2df866bd7da6e5ef9024c648023ec723ab9c62fd80285739d84f15d2ab515a", + "8488396bd4a8729b7a473178f232dadf3f0f8e22678ba5a43e041e72da1e2cf82194c307207a54cb8156293339eaec693ff66bfcd5efc65e95e4ecaf54530abd", + "f598da901c3835bca560779037dfde9f0c51dc61c0b760fc1522d7b470ee63f5bdc6498476e86049ad86e4e21af2854a984cc905427d2f17f66b1f41c3da6f61", + "5f93269798cf02132107337660a8d7a177354c0212eb93e555e7c37a08aef3d8dce01217011cd965c04dd2c105f2e2b6cae5e4e6bcaf09dfbee3e0a6a6357c37", + "0ecf581d47bac9230986faabd70c2f5b80e91066f0ec55a842937882286d2ca007bb4e973b0b091d52167ff7c4009c7ab4ad38fff1dceacdb7be81ef4a452952", + "5aeca8abe1528582b2a307b4009585498a3d467ca6101cb0c5126f9976056e9ffc123cc20c302b2a737f492c75d21f01512c90ca0541dfa56e950a321dcb28d8", + "732fbf8f1cb2b8329263ede27858fe46f8d3354d376bcda0548e7ce1fa9dd11f85eb661fe950b543aa635ca4d3f04ede5b32d6b656e5ce1c44d35c4a6c56cff8", + "d5e938735d63788c80100aefd18648d18cf272f69f20ff24cfe2895c088ad08b0104da1672a4eb26fc52545cc7d7a01b266cf546c403c45bd129eb41bdd9200b", + "65a245b49352ee297d91af8c8be00528ac6e046dd83ac7bd465a98816dd68f3e00e1ae8f895327a7e9a8c9326598379a29c9fc91ec0c6eef08f3e2b216c11008", + "c95654b63019130ab45dd0fb4941b98aeb3af2a123913eca2ce99b3e97410a7bf8661cc7fbaa2bc1cf2b13113b1ed40a0118b88e5fffc3542759ea007ed4c58d", + "1eb262f38fa494431f017dad44c0dfb69324ac032f04b657fc91a88647bb74760f24e7c956514f0cf002990b182c1642b9b2426e96a61187e4e012f00e217d84", + "3b955aeebfa5151ac1ab8e3f5cc1e3767084c842a575d36269836e97353d41622b731dddcd5f269550a3a5b87be1e90326340b6e0e62555815d9600597ac6ef9", + "68289f6605473ba0e4f241baf7477a9885426a858f19ef2a18b0d40ef8e41282ed5526b519799e270f13881327918278755711071d8511fe963e3b5606aa3716", + "80a33787542612c38f6bcd7cd86cab460227509b1cbad5ec408a91413d51155a0476dadbf3a2518e4a6e77cc346622e347a469bf8baa5f04eb2d98705355d063", + "34629bc6d831391c4cdf8af1b4b7b6b8e8ee17cf98c70e5dd586cd99f14b11df945166236a9571e6d591bb83ee4d164d46f6b9d8ef86ff865a81bfb91b00424b", + "8b7cc339163863bb4383e542b0ef0e7cf36b84ad932cdf5a80419ec9ad692e7a7e784d2c7cb3796a18b8f800035f3aa06c824100611120a7bdeb35618ccb81b7", + "4f084e4939dd5a7f5a658fad58a18a15c25c32ec1c7fd5c5c6c3e892b3971aeaac308304ef17b1c47239ea4bb398b3fd6d4528d8de8e768ae0f1a5a5c6b5c297", + "48f407a1af5b8009b2051742e8cf5cd5656669e7d722ee8e7bd202060849442168d8facc117c012bfb7bf449d99befff6a34aea203f1d8d352722be5014ec818", + "a6aa82cd1e426f9a73bfa39a29037876114655b8c22d6d3ff8b638ae7dea6b17843e09e52eb66fa1e475e4a8a3de429b7d0f4a776fcb8bdc9b9fede7d52e815f", + "5817027d6bdd00c5dd10ac593cd560372270775a18526d7e6f13872a2e20eab664625be7168ac4bd7c9e0ce7fc4099e0f48442e2c767191c6e1284e9b2ccea8c", + "08e41028340a45c74e4052b3a8d6389e22e043a1adab5e28d97619450d723469b620caa519b81c14523854f619fd3027e3847bd03276e60604a80ddb4de876d6", + "130b8420537eb07d72abda07c85acbd8b9a44f16321dd0422145f809673d30f2b5321326e2bff317ef3fef983c51c4f8ab24a325d298e34afce569a82555774c", + "ac49b844afaa012e31c474ca263648844fd2f6307992c2f752aca02c3828965175794deee2d2ee95c61cd284f6b5a2d75e2ef2b29ee8149e77fb81447b2fd04b", + "b9d7ca81cc60bb9578e44024e5a0a0be80f27336a6a9f4e53df3999cb191280b090e2ac2d29c5baad9d71415bdc129e69aa2667af6a7fd5e189fccdcee817340", + "a755e113386572c75ced61d719706070b9146048e42a9f8cd35667a088b42f08808abdf77e618abd959afc757379ca2c00bcc1a48390fa2bff618b1e0078a613", + "a73c7debed326f1c0db0795ee7d6e3946894b826b1f8101c56c823ba17168312e7f53fc7dbe52c3e11e69852c40485e2ef182477862ea6a34ec136e2dfeea6f4", + "6cb8f9d52c56d82cac28f39ea1593e8bb2506293ac0d68376a1709b62a46df14a4ae64b2d8fab76733a1ced2d548e3f3c6fcb49d40c3d5808e449cd83d1c2aa2", + "683fa2b2369a10162c1c1c7b24bc970ee67da220564f32203f625696c0352a0b9ad96624362d952d84463c1106a2dba7a092599884b35a0b89c8f1b6a9b5a61e", + "aad9ad44610118b77d508aeb1bbcd1c1b7d0171397fb510a401bbc0ec34623670d86a2dc3c8f3ab5a2044df730256727545f0860ce21a1eac717dfc48f5d228e", + "c42578de23b4c987d5e1ac4d689ed5de4b0417f9704bc6bce969fa13471585d62c2cb1212a944f397fc9ca2c3747c3beb694ec4c5be68828dda53ef43faec6c0", + "470f00841ee8244e63ed2c7ea30e2e419897c197462ecccecf713b42a5065fff5914bc9b79affe8f6b657875e789ae213bd914cd35bd174d46e9d18bd843773d", + "34fc4213730f47a5e9a3580f643e12945cfcb31bf206f6ad450ce528da3fa432e005d6b0ecce10dca7c5995f6aacc5150e1b009e19751e8309f8859531844374", + "fb3c1f0f56a56f8e316fdf5d853c8c872c39635d083634c3904fc3ac07d1b578e85ff0e480e92d44ade33b62e893ee32343e79ddf6ef292e89b582d312502314", + "c7c97fc65dd2b9e3d3d607d31598d3f84261e9919251e9c8e57bb5f829377d5f73eabbed55c6c381180f29ad02e5be797ffec7e57bdecbc50ad3d062f0993ab0", + "a57a49cdbe67ae7d9f797bb5cc7efc2df07f4e1b15955f85dae74b76e2ecb85afb6cd9eeed8888d5ca3ec5ab65d27a7b19e578475760a045ac3c92e13a938e77", + "c7143fce9614a17fd653aeb140726dc9c3dbb1de6cc581b2726897ec24b7a50359ad492243be66d9edd8c933b5b80e0b91bb61ea98056006516976fae8d99a35", + "65bb58d07f937e2d3c7e65385f9c54730b704105ccdb691f6e146d4ee8f6c086f49511035110a9ad6031fdceb943e0f9613bcb276dd40f0624ef0f924f809783", + "e540277f683b1186dd3b5b3f61433396581a35feb12002be8c6a6231fc40ffa70f08081bc58b2d94f7649543614a435faa2d62110e13dabc7b86629b63af9c24", + "418500878c5fbcb584c432f4285e05e49f2e3e075399a0dbfcf874ebf8c03d02bf16bc6989d161c77ca0786b05053c6c709433712319192128835cf0b660595b", + "889090dbb1944bdc9433ee5ef1010c7a4a24a8e71ecea8e12a31318ce49dcab0aca5c3802334aab2cc84b14c6b9321fe586bf3f876f19cd406eb1127fb944801", + "53b6a28910aa92e27e536fb549cf9b9918791060898e0b9fe183577ff43b5e9c7689c745b32e412269837c31b89e6cc12bf76e13cad366b74ece48bb85fd09e9", + "7c092080c6a80d672409d081d3d177106bcd63567785140719490950ae07ae8fcaabbaaab330cfbcf7374482c220af2eadeeb73dcbb35ed823344e144e7d4899", + "9ccde566d2400509181111f32dde4cd63209fe59a30c114546ad2776d889a41bad8fa1bb468cb2f9d42ca9928a7770fef8e8ba4d0c812d9a1e75c3d8d2ccd75a", + "6e293bf5d03fe43977cfe3f57ccdb3ae282a85455dca33f37f4b74f8398cc612433d755cbec412f8f82a3bd3bc4a278f7ecd0dfa9bbdc40be7a787c8f159b2df", + "c56546fb2178456f336164c18b90deffc83ae2b5a3aca77b6884d36d2c1db39501b3e65e36c758c66e3188451fdb3515ee162c001f06c3e8cb573adf30f7a101", + "6f82f89f299ebca2fe014b59bffe1aa84e88b1915fe256afb646fd8448af2b8891a7fab37a4ea6f9a50e6c317039d8cf878f4c8e1a0dd464f0b4d6ff1c7ea853", + "2b8599ff9c3d6198637ad51e57d1998b0d75313fe2dd61a533c964a6dd9607c6f723e9452ce46e014b1c1d6de77ba5b88c914d1c597bf1eae13474b4290e89b2", + "08bf346d38e1df06c8260edb1da75579275948d5c0a0aa9ed2886f8856de5417a156998758f5b17e52f101ca957a71137473dfd18d7d209c4c10d9233c93691d", + "6df2156d773114d310b63db9ee5350d77e6bcf25b05fcd910f9b31bc42bb13fe8225ebcb2a23a62280777b6bf74e2cd0917c7640b43defe468cd1e18c943c66a", + "7c7038bc13a91151828a5ba82b4a96040f258a4dfb1b1373f0d359168afb0517a20b28a12d3644046be66b8d08d8ae7f6a923ea1c00187c6d11dc502bac71305", + "bcd1b30d808fb739b987cbf154bea00da9d40380b861d4c1d6377122dadd61c0e59018b71941cfb62e00dcd70aeb9abf0473e80f0a7eca6b6dea246ab229dd2b", + "7ed4468d968530fe7ab2c33540b26d8c3bd3ed44b34fbe8c2a9d7f805b5ada0ea252eeade4fce97f89728ad85bc8bb2430b1bef2cddd32c8446e59b8e8ba3c67", + "6d30b7c6ce8a3236c0ca2f8d728b1088ca06983a8043e621d5dcf0c537d13b08791edeb01a3cf0943ec1c890ab6e29b146a236cd46bcb9d93bf516fb67c63fe5", + "97fe03cef31438508911bded975980a66029305dc5e3fa8ad1b4fb22fcdf5a19a733320327d8f71ccf496cb3a44a77af56e3dde73d3a5f176896cc57c9a5ad99", + "785a9d0fbd21136dbce8fa7eafd63c9dad220052978416b31d9753eaa149097847ed9b30a65c70507eff01879149ed5cf0471d37798edc05abd56ad4a2cccb1d", + "ad408d2abddfd37b3bf34794c1a3371d928ed7fc8d966225333584c5665817832a37c07f0dc7cb5aa874cd7d20fe8fab8eabcb9b33d2e0841f6e200960899d95", + "97668f745b6032fc815d9579322769dccd9501a5080029b8ae826befb6742331bd9f76efeb3e2b8e81a9786b282f5068a3a2424697a77c41876b7e753f4c7767", + "26bb985f47e7fee0cfd252d4ef96bed42b9c370c1c6a3e8c9eb04ef7f7818b833a0d1f043ebafb911dc779e02740a02a44d3a1ea45ed4ad55e686c927cafe97e", + "5bfe2b1dcf7fe9b95088acedb575c19016c743b2e763bf5851ac407c9eda43715edfa48b4825492c5179593fff21351b76e8b7e034e4c53c79f61f29c479bd08", + "c76509ef72f4a6f9c9c40618ed52b2084f83502232e0ac8bdaf3264368e4d0180f6854c4abf4f6509c79caafc44cf3194afc57bd077bd7b3c9bda3d4b8775816", + "d66f2beab990e354ccb910e4e9c7ac618c7b63ef292a96b552341de78dc46d3ec8cfabc699b50af41fda39cf1b0173660923510ad67faedef5207cffe8641d20", + "7d8f0672992b79be3a364d8e5904f4ab713bbc8ab01b4f309ad8ccf223ce1034a860dcb0b00550612cc2fa17f2969e18f22e1427d254b4a82b3a03a3eb394adf", + "a56d6725bfb3de47c1414adf25fc8f0fc9846f6987722bc06366d5ca4e89722925ebbc881418844075397a0ca89842c7b9e9e07e1d9d183ebeb39e120b483bf7", + "af5e03d7fe60c67e10313344434e79485a03a758d6dce985574745763c1c5c77d4fb3e6fb12230368370993bf90feed0c5d1607524562d7c09c0c210ed393d7c", + "7a20540cc07bf72b582421fc342e82f52134b69841ec28ed189e2ea6a29dd2f82a640352d222b52f2911dc72a7dab31caadd80c6118f13c56b2a1e4373be0ea3", + "486f02c63e5467ea1fdde7e82bfacc2c1ba5d636d9f3d08b210da3f372f706ec218cc17ff60aef703bbe0c15c38ae55d286a684f864c78211ccab4178c92adba", + "1c7a5c1dedcd04a921788f7eb23361ca1953b04b9c7aec35d65ea3e4996db26f281278ea4ae666ad81027d98af57262cdbfa4c085f4210568c7e15eec7805114", + "9ce3fa9a860bdbd5378fd6d7b8b671c6cb7692910ce8f9b6cb4122cbcbe6ac06ca0422cef1225935053b7d193a81b9e972eb85a1d3074f14cbb5ec9f0573892d", + "a91187be5c371c4265c174fd4653b8ab708551f83d1fee1cc1479581bc006d6fb78fcc9a5dee1db3666f508f9780a37593ebcccf5fbed39667dc6361e921f779", + "4625767d7b1d3d3ed2fbc674af14e0244152f2a4021fcf3311505d89bd81e2f9f9a500c3b199914db49500b3c98d03ea93286751a686a3b875daab0ccd63b44f", + "43dfdfe1b014fed3a2acabb7f3e9a182f2aa18019d27e3e6cdcf31a15b428e91e7b08cf5e5c376fce2d8a28ff85ab0a0a1656edb4a0a91532620096d9a5a652d", + "279e3202be3989ba3112772585177487e4fe3ee3eab49c2f7fa7fe87cfe7b80d3e0355edff6d031e6c96c795db1c6f041880ec3824defacf9263820a8e7327de", + "ea2d066ac229d4d4b616a8bedec734325224e4b4e58f1ae6dad7e40c2da29196c3b1ea9571dacc81e87328caa0211e09027b0524aa3f4a849917b3586747ebbb", + "49f014f5c61822c899ab5cae51be4044a4495e777deb7da9b6d8490efbb87530adf293daf079f94c33b7044ef62e2e5bb3eb11e17304f8453ee6ce24f033ddb0", + "9233490344e5b0dc5912671b7ae54cee7730dbe1f4c7d92a4d3e3aab50571708db51dcf9c2944591db651db32d22935b86944969be77d5b5feae6c3840a8db26", + "b6e75e6f4c7f453b7465d25b5ac8c7196902eaa953875228c8634e16e2ae1f38bc3275304335f5989eccc1e34167d4e68d7719968fba8e2fe67947c35c48e806", + "cc14ca665af1483efbc3af80080e650d5046a3932f4f51f3fe90a0705ec25104adf07839265dc51d43401411246e474f0d5e5637af94767283d53e0617e981f4", + "230a1c857cb2e7852e41b647e90e4585d2d881e1734dc38955356e8dd7bff39053092c6b38e236e1899525647073dddf6895d64206325e7647f275567b255909", + "cbb65321ac436e2ffdab2936359ce49023f7dee7614ef28d173c3d27c5d1bffa51553d433f8ee3c9e49c05a2b883cce954c9a8093b80612a0cdd4732e041f995", + "3e7e570074337275efb51315588034c3cf0dddca20b4612e0bd5b881e7e5476d319ce4fe9f19186e4c0826f44f131eb048e65be242b1172c63badb123ab0cbe8", + "d32e9ec02d38d4e1b8249df8dcb00c5b9c68eb8922672e3505393b6a210ba56f9496e5ee0490ef387c3cdec061f06bc0382d9304cafbb8e0cd33d57029e62df2", + "8c1512466089f05b3775c262b62d22b83854a83218130b4ec91b3ccbd293d2a54302cecaab9b100c68d1e6ddc8f07cddbdfe6fdaaaf099cc09d6b725879c6369", + "91a7f61c97c2911e4c812ef71d780ad8fa788794561d08303fd1c1cb608a46a12563086ec5b39d471aed94fb0f6c678a43b8792932f9028d772a22768ea23a9b", + "4f6bb222a395e8b18f6ba155477aed3f0729ac9e83e16d31a2a8bc655422b837c891c6199e6f0d75799e3b691525c581953517f252c4b9e3a27a28fbaf49644c", + "5d06c07e7a646c413a501c3f4bb2fc38127de7509b7077c4d9b5613201c1aa02fd5f79d2745915dd57fbcb4ce08695f6efc0cb3d2d330e19b4b0e6004ea6471e", + "b96756e57909968f14b796a5d30f4c9d671472cf82c8cfb2caca7ac7a44ca0a14c9842d00c82e337502c94d5960aca4c492ea7b0df919ddf1aada2a275bb10d4", + "ff0a015e98db9c99f03977710aac3e658c0d896f6d71d618ba79dc6cf72ac75b7c038eb6862dede4543e145413a6368d69f5722c827ba3ef25b6ae6440d39276", + "5b21c5fd8868367612474fa2e70e9cfa2201ffeee8fafab5797ad58fefa17c9b5b107da4a3db6320baaf2c8617d5a51df914ae88da3867c2d41f0cc14fa67928", +} + +var goldenKeyed = []string{ + "10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e996e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568", + "961f6dd1e4dd30f63901690c512e78e4b45e4742ed197c3c5e45c549fd25f2e4187b0bc9fe30492b16b0d0bc4ef9b0f34c7003fac09a5ef1532e69430234cebd", + "da2cfbe2d8409a0f38026113884f84b50156371ae304c4430173d08a99d9fb1b983164a3770706d537f49e0c916d9f32b95cc37a95b99d857436f0232c88a965", + "33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1", + "beaa5a3d08f3807143cf621d95cd690514d0b49efff9c91d24b59241ec0eefa5f60196d407048bba8d2146828ebcb0488d8842fd56bb4f6df8e19c4b4daab8ac", + "098084b51fd13deae5f4320de94a688ee07baea2800486689a8636117b46c1f4c1f6af7f74ae7c857600456a58a3af251dc4723a64cc7c0a5ab6d9cac91c20bb", + "6044540d560853eb1c57df0077dd381094781cdb9073e5b1b3d3f6c7829e12066bbaca96d989a690de72ca3133a83652ba284a6d62942b271ffa2620c9e75b1f", + "7a8cfe9b90f75f7ecb3acc053aaed6193112b6f6a4aeeb3f65d3de541942deb9e2228152a3c4bbbe72fc3b12629528cfbb09fe630f0474339f54abf453e2ed52", + "380beaf6ea7cc9365e270ef0e6f3a64fb902acae51dd5512f84259ad2c91f4bc4108db73192a5bbfb0cbcf71e46c3e21aee1c5e860dc96e8eb0b7b8426e6abe9", + "60fe3c4535e1b59d9a61ea8500bfac41a69dffb1ceadd9aca323e9a625b64da5763bad7226da02b9c8c4f1a5de140ac5a6c1124e4f718ce0b28ea47393aa6637", + "4fe181f54ad63a2983feaaf77d1e7235c2beb17fa328b6d9505bda327df19fc37f02c4b6f0368ce23147313a8e5738b5fa2a95b29de1c7f8264eb77b69f585cd", + "f228773ce3f3a42b5f144d63237a72d99693adb8837d0e112a8a0f8ffff2c362857ac49c11ec740d1500749dac9b1f4548108bf3155794dcc9e4082849e2b85b", + "962452a8455cc56c8511317e3b1f3b2c37df75f588e94325fdd77070359cf63a9ae6e930936fdf8e1e08ffca440cfb72c28f06d89a2151d1c46cd5b268ef8563", + "43d44bfa18768c59896bf7ed1765cb2d14af8c260266039099b25a603e4ddc5039d6ef3a91847d1088d401c0c7e847781a8a590d33a3c6cb4df0fab1c2f22355", + "dcffa9d58c2a4ca2cdbb0c7aa4c4c1d45165190089f4e983bb1c2cab4aaeff1fa2b5ee516fecd780540240bf37e56c8bcca7fab980e1e61c9400d8a9a5b14ac6", + "6fbf31b45ab0c0b8dad1c0f5f4061379912dde5aa922099a030b725c73346c524291adef89d2f6fd8dfcda6d07dad811a9314536c2915ed45da34947e83de34e", + "a0c65bddde8adef57282b04b11e7bc8aab105b99231b750c021f4a735cb1bcfab87553bba3abb0c3e64a0b6955285185a0bd35fb8cfde557329bebb1f629ee93", + "f99d815550558e81eca2f96718aed10d86f3f1cfb675cce06b0eff02f617c5a42c5aa760270f2679da2677c5aeb94f1142277f21c7f79f3c4f0cce4ed8ee62b1", + "95391da8fc7b917a2044b3d6f5374e1ca072b41454d572c7356c05fd4bc1e0f40b8bb8b4a9f6bce9be2c4623c399b0dca0dab05cb7281b71a21b0ebcd9e55670", + "04b9cd3d20d221c09ac86913d3dc63041989a9a1e694f1e639a3ba7e451840f750c2fc191d56ad61f2e7936bc0ac8e094b60caeed878c18799045402d61ceaf9", + "ec0e0ef707e4ed6c0c66f9e089e4954b058030d2dd86398fe84059631f9ee591d9d77375355149178c0cf8f8e7c49ed2a5e4f95488a2247067c208510fadc44c", + "9a37cce273b79c09913677510eaf7688e89b3314d3532fd2764c39de022a2945b5710d13517af8ddc0316624e73bec1ce67df15228302036f330ab0cb4d218dd", + "4cf9bb8fb3d4de8b38b2f262d3c40f46dfe747e8fc0a414c193d9fcf753106ce47a18f172f12e8a2f1c26726545358e5ee28c9e2213a8787aafbc516d2343152", + "64e0c63af9c808fd893137129867fd91939d53f2af04be4fa268006100069b2d69daa5c5d8ed7fddcb2a70eeecdf2b105dd46a1e3b7311728f639ab489326bc9", + "5e9c93158d659b2def06b0c3c7565045542662d6eee8a96a89b78ade09fe8b3dcc096d4fe48815d88d8f82620156602af541955e1f6ca30dce14e254c326b88f", + "7775dff889458dd11aef417276853e21335eb88e4dec9cfb4e9edb49820088551a2ca60339f12066101169f0dfe84b098fddb148d9da6b3d613df263889ad64b", + "f0d2805afbb91f743951351a6d024f9353a23c7ce1fc2b051b3a8b968c233f46f50f806ecb1568ffaa0b60661e334b21dde04f8fa155ac740eeb42e20b60d764", + "86a2af316e7d7754201b942e275364ac12ea8962ab5bd8d7fb276dc5fbffc8f9a28cae4e4867df6780d9b72524160927c855da5b6078e0b554aa91e31cb9ca1d", + "10bdf0caa0802705e706369baf8a3f79d72c0a03a80675a7bbb00be3a45e516424d1ee88efb56f6d5777545ae6e27765c3a8f5e493fc308915638933a1dfee55", + "b01781092b1748459e2e4ec178696627bf4ebafebba774ecf018b79a68aeb84917bf0b84bb79d17b743151144cd66b7b33a4b9e52c76c4e112050ff5385b7f0b", + "c6dbc61dec6eaeac81e3d5f755203c8e220551534a0b2fd105a91889945a638550204f44093dd998c076205dffad703a0e5cd3c7f438a7e634cd59fededb539e", + "eba51acffb4cea31db4b8d87e9bf7dd48fe97b0253ae67aa580f9ac4a9d941f2bea518ee286818cc9f633f2a3b9fb68e594b48cdd6d515bf1d52ba6c85a203a7", + "86221f3ada52037b72224f105d7999231c5e5534d03da9d9c0a12acb68460cd375daf8e24386286f9668f72326dbf99ba094392437d398e95bb8161d717f8991", + "5595e05c13a7ec4dc8f41fb70cb50a71bce17c024ff6de7af618d0cc4e9c32d9570d6d3ea45b86525491030c0d8f2b1836d5778c1ce735c17707df364d054347", + "ce0f4f6aca89590a37fe034dd74dd5fa65eb1cbd0a41508aaddc09351a3cea6d18cb2189c54b700c009f4cbf0521c7ea01be61c5ae09cb54f27bc1b44d658c82", + "7ee80b06a215a3bca970c77cda8761822bc103d44fa4b33f4d07dcb997e36d55298bceae12241b3fa07fa63be5576068da387b8d5859aeab701369848b176d42", + "940a84b6a84d109aab208c024c6ce9647676ba0aaa11f86dbb7018f9fd2220a6d901a9027f9abcf935372727cbf09ebd61a2a2eeb87653e8ecad1bab85dc8327", + "2020b78264a82d9f4151141adba8d44bf20c5ec062eee9b595a11f9e84901bf148f298e0c9f8777dcdbc7cc4670aac356cc2ad8ccb1629f16f6a76bcefbee760", + "d1b897b0e075ba68ab572adf9d9c436663e43eb3d8e62d92fc49c9be214e6f27873fe215a65170e6bea902408a25b49506f47babd07cecf7113ec10c5dd31252", + "b14d0c62abfa469a357177e594c10c194243ed2025ab8aa5ad2fa41ad318e0ff48cd5e60bec07b13634a711d2326e488a985f31e31153399e73088efc86a5c55", + "4169c5cc808d2697dc2a82430dc23e3cd356dc70a94566810502b8d655b39abf9e7f902fe717e0389219859e1945df1af6ada42e4ccda55a197b7100a30c30a1", + "258a4edb113d66c839c8b1c91f15f35ade609f11cd7f8681a4045b9fef7b0b24c82cda06a5f2067b368825e3914e53d6948ede92efd6e8387fa2e537239b5bee", + "79d2d8696d30f30fb34657761171a11e6c3f1e64cbe7bebee159cb95bfaf812b4f411e2f26d9c421dc2c284a3342d823ec293849e42d1e46b0a4ac1e3c86abaa", + "8b9436010dc5dee992ae38aea97f2cd63b946d94fedd2ec9671dcde3bd4ce9564d555c66c15bb2b900df72edb6b891ebcadfeff63c9ea4036a998be7973981e7", + "c8f68e696ed28242bf997f5b3b34959508e42d613810f1e2a435c96ed2ff560c7022f361a9234b9837feee90bf47922ee0fd5f8ddf823718d86d1e16c6090071", + "b02d3eee4860d5868b2c39ce39bfe81011290564dd678c85e8783f29302dfc1399ba95b6b53cd9ebbf400cca1db0ab67e19a325f2d115812d25d00978ad1bca4", + "7693ea73af3ac4dad21ca0d8da85b3118a7d1c6024cfaf557699868217bc0c2f44a199bc6c0edd519798ba05bd5b1b4484346a47c2cadf6bf30b785cc88b2baf", + "a0e5c1c0031c02e48b7f09a5e896ee9aef2f17fc9e18e997d7f6cac7ae316422c2b1e77984e5f3a73cb45deed5d3f84600105e6ee38f2d090c7d0442ea34c46d", + "41daa6adcfdb69f1440c37b596440165c15ada596813e2e22f060fcd551f24dee8e04ba6890387886ceec4a7a0d7fc6b44506392ec3822c0d8c1acfc7d5aebe8", + "14d4d40d5984d84c5cf7523b7798b254e275a3a8cc0a1bd06ebc0bee726856acc3cbf516ff667cda2058ad5c3412254460a82c92187041363cc77a4dc215e487", + "d0e7a1e2b9a447fee83e2277e9ff8010c2f375ae12fa7aaa8ca5a6317868a26a367a0b69fbc1cf32a55d34eb370663016f3d2110230eba754028a56f54acf57c", + "e771aa8db5a3e043e8178f39a0857ba04a3f18e4aa05743cf8d222b0b095825350ba422f63382a23d92e4149074e816a36c1cd28284d146267940b31f8818ea2", + "feb4fd6f9e87a56bef398b3284d2bda5b5b0e166583a66b61e538457ff0584872c21a32962b9928ffab58de4af2edd4e15d8b35570523207ff4e2a5aa7754caa", + "462f17bf005fb1c1b9e671779f665209ec2873e3e411f98dabf240a1d5ec3f95ce6796b6fc23fe171903b502023467dec7273ff74879b92967a2a43a5a183d33", + "d3338193b64553dbd38d144bea71c5915bb110e2d88180dbc5db364fd6171df317fc7268831b5aef75e4342b2fad8797ba39eddcef80e6ec08159350b1ad696d", + "e1590d585a3d39f7cb599abd479070966409a6846d4377acf4471d065d5db94129cc9be92573b05ed226be1e9b7cb0cabe87918589f80dadd4ef5ef25a93d28e", + "f8f3726ac5a26cc80132493a6fedcb0e60760c09cfc84cad178175986819665e76842d7b9fedf76dddebf5d3f56faaad4477587af21606d396ae570d8e719af2", + "30186055c07949948183c850e9a756cc09937e247d9d928e869e20bafc3cd9721719d34e04a0899b92c736084550186886efba2e790d8be6ebf040b209c439a4", + "f3c4276cb863637712c241c444c5cc1e3554e0fddb174d035819dd83eb700b4ce88df3ab3841ba02085e1a99b4e17310c5341075c0458ba376c95a6818fbb3e2", + "0aa007c4dd9d5832393040a1583c930bca7dc5e77ea53add7e2b3f7c8e231368043520d4a3ef53c969b6bbfd025946f632bd7f765d53c21003b8f983f75e2a6a", + "08e9464720533b23a04ec24f7ae8c103145f765387d738777d3d343477fd1c58db052142cab754ea674378e18766c53542f71970171cc4f81694246b717d7564", + "d37ff7ad297993e7ec21e0f1b4b5ae719cdc83c5db687527f27516cbffa822888a6810ee5c1ca7bfe3321119be1ab7bfa0a502671c8329494df7ad6f522d440f", + "dd9042f6e464dcf86b1262f6accfafbd8cfd902ed3ed89abf78ffa482dbdeeb6969842394c9a1168ae3d481a017842f660002d42447c6b22f7b72f21aae021c9", + "bd965bf31e87d70327536f2a341cebc4768eca275fa05ef98f7f1b71a0351298de006fba73fe6733ed01d75801b4a928e54231b38e38c562b2e33ea1284992fa", + "65676d800617972fbd87e4b9514e1c67402b7a331096d3bfac22f1abb95374abc942f16e9ab0ead33b87c91968a6e509e119ff07787b3ef483e1dcdccf6e3022", + "939fa189699c5d2c81ddd1ffc1fa207c970b6a3685bb29ce1d3e99d42f2f7442da53e95a72907314f4588399a3ff5b0a92beb3f6be2694f9f86ecf2952d5b41c", + "c516541701863f91005f314108ceece3c643e04fc8c42fd2ff556220e616aaa6a48aeb97a84bad74782e8dff96a1a2fa949339d722edcaa32b57067041df88cc", + "987fd6e0d6857c553eaebb3d34970a2c2f6e89a3548f492521722b80a1c21a153892346d2cba6444212d56da9a26e324dccbc0dcde85d4d2ee4399eec5a64e8f", + "ae56deb1c2328d9c4017706bce6e99d41349053ba9d336d677c4c27d9fd50ae6aee17e853154e1f4fe7672346da2eaa31eea53fcf24a22804f11d03da6abfc2b", + "49d6a608c9bde4491870498572ac31aac3fa40938b38a7818f72383eb040ad39532bc06571e13d767e6945ab77c0bdc3b0284253343f9f6c1244ebf2ff0df866", + "da582ad8c5370b4469af862aa6467a2293b2b28bd80ae0e91f425ad3d47249fdf98825cc86f14028c3308c9804c78bfeeeee461444ce243687e1a50522456a1d", + "d5266aa3331194aef852eed86d7b5b2633a0af1c735906f2e13279f14931a9fc3b0eac5ce9245273bd1aa92905abe16278ef7efd47694789a7283b77da3c70f8", + "2962734c28252186a9a1111c732ad4de4506d4b4480916303eb7991d659ccda07a9911914bc75c418ab7a4541757ad054796e26797feaf36e9f6ad43f14b35a4", + "e8b79ec5d06e111bdfafd71e9f5760f00ac8ac5d8bf768f9ff6f08b8f026096b1cc3a4c973333019f1e3553e77da3f98cb9f542e0a90e5f8a940cc58e59844b3", + "dfb320c44f9d41d1efdcc015f08dd5539e526e39c87d509ae6812a969e5431bf4fa7d91ffd03b981e0d544cf72d7b1c0374f8801482e6dea2ef903877eba675e", + "d88675118fdb55a5fb365ac2af1d217bf526ce1ee9c94b2f0090b2c58a06ca58187d7fe57c7bed9d26fca067b4110eefcd9a0a345de872abe20de368001b0745", + "b893f2fc41f7b0dd6e2f6aa2e0370c0cff7df09e3acfcc0e920b6e6fad0ef747c40668417d342b80d2351e8c175f20897a062e9765e6c67b539b6ba8b9170545", + "6c67ec5697accd235c59b486d7b70baeedcbd4aa64ebd4eef3c7eac189561a726250aec4d48cadcafbbe2ce3c16ce2d691a8cce06e8879556d4483ed7165c063", + "f1aa2b044f8f0c638a3f362e677b5d891d6fd2ab0765f6ee1e4987de057ead357883d9b405b9d609eea1b869d97fb16d9b51017c553f3b93c0a1e0f1296fedcd", + "cbaa259572d4aebfc1917acddc582b9f8dfaa928a198ca7acd0f2aa76a134a90252e6298a65b08186a350d5b7626699f8cb721a3ea5921b753ae3a2dce24ba3a", + "fa1549c9796cd4d303dcf452c1fbd5744fd9b9b47003d920b92de34839d07ef2a29ded68f6fc9e6c45e071a2e48bd50c5084e96b657dd0404045a1ddefe282ed", + "5cf2ac897ab444dcb5c8d87c495dbdb34e1838b6b629427caa51702ad0f9688525f13bec503a3c3a2c80a65e0b5715e8afab00ffa56ec455a49a1ad30aa24fcd", + "9aaf80207bace17bb7ab145757d5696bde32406ef22b44292ef65d4519c3bb2ad41a59b62cc3e94b6fa96d32a7faadae28af7d35097219aa3fd8cda31e40c275", + "af88b163402c86745cb650c2988fb95211b94b03ef290eed9662034241fd51cf398f8073e369354c43eae1052f9b63b08191caa138aa54fea889cc7024236897", + "48fa7d64e1ceee27b9864db5ada4b53d00c9bc7626555813d3cd6730ab3cc06ff342d727905e33171bde6e8476e77fb1720861e94b73a2c538d254746285f430", + "0e6fd97a85e904f87bfe85bbeb34f69e1f18105cf4ed4f87aec36c6e8b5f68bd2a6f3dc8a9ecb2b61db4eedb6b2ea10bf9cb0251fb0f8b344abf7f366b6de5ab", + "06622da5787176287fdc8fed440bad187d830099c94e6d04c8e9c954cda70c8bb9e1fc4a6d0baa831b9b78ef6648681a4867a11da93ee36e5e6a37d87fc63f6f", + "1da6772b58fabf9c61f68d412c82f182c0236d7d575ef0b58dd22458d643cd1dfc93b03871c316d8430d312995d4197f0874c99172ba004a01ee295abac24e46", + "3cd2d9320b7b1d5fb9aab951a76023fa667be14a9124e394513918a3f44096ae4904ba0ffc150b63bc7ab1eeb9a6e257e5c8f000a70394a5afd842715de15f29", + "04cdc14f7434e0b4be70cb41db4c779a88eaef6accebcb41f2d42fffe7f32a8e281b5c103a27021d0d08362250753cdf70292195a53a48728ceb5844c2d98bab", + "9071b7a8a075d0095b8fb3ae5113785735ab98e2b52faf91d5b89e44aac5b5d4ebbf91223b0ff4c71905da55342e64655d6ef8c89a4768c3f93a6dc0366b5bc8", + "ebb30240dd96c7bc8d0abe49aa4edcbb4afdc51ff9aaf720d3f9e7fbb0f9c6d6571350501769fc4ebd0b2141247ff400d4fd4be414edf37757bb90a32ac5c65a", + "8532c58bf3c8015d9d1cbe00eef1f5082f8f3632fbe9f1ed4f9dfb1fa79e8283066d77c44c4af943d76b300364aecbd0648c8a8939bd204123f4b56260422dec", + "fe9846d64f7c7708696f840e2d76cb4408b6595c2f81ec6a28a7f2f20cb88cfe6ac0b9e9b8244f08bd7095c350c1d0842f64fb01bb7f532dfcd47371b0aeeb79", + "28f17ea6fb6c42092dc264257e29746321fb5bdaea9873c2a7fa9d8f53818e899e161bc77dfe8090afd82bf2266c5c1bc930a8d1547624439e662ef695f26f24", + "ec6b7d7f030d4850acae3cb615c21dd25206d63e84d1db8d957370737ba0e98467ea0ce274c66199901eaec18a08525715f53bfdb0aacb613d342ebdceeddc3b", + "b403d3691c03b0d3418df327d5860d34bbfcc4519bfbce36bf33b208385fadb9186bc78a76c489d89fd57e7dc75412d23bcd1dae8470ce9274754bb8585b13c5", + "31fc79738b8772b3f55cd8178813b3b52d0db5a419d30ba9495c4b9da0219fac6df8e7c23a811551a62b827f256ecdb8124ac8a6792ccfecc3b3012722e94463", + "bb2039ec287091bcc9642fc90049e73732e02e577e2862b32216ae9bedcd730c4c284ef3968c368b7d37584f97bd4b4dc6ef6127acfe2e6ae2509124e66c8af4", + "f53d68d13f45edfcb9bd415e2831e938350d5380d3432278fc1c0c381fcb7c65c82dafe051d8c8b0d44e0974a0e59ec7bf7ed0459f86e96f329fc79752510fd3", + "8d568c7984f0ecdf7640fbc483b5d8c9f86634f6f43291841b309a350ab9c1137d24066b09da9944bac54d5bb6580d836047aac74ab724b887ebf93d4b32eca9", + "c0b65ce5a96ff774c456cac3b5f2c4cd359b4ff53ef93a3da0778be4900d1e8da1601e769e8f1b02d2a2f8c5b9fa10b44f1c186985468feeb008730283a6657d", + "4900bba6f5fb103ece8ec96ada13a5c3c85488e05551da6b6b33d988e611ec0fe2e3c2aa48ea6ae8986a3a231b223c5d27cec2eadde91ce07981ee652862d1e4", + "c7f5c37c7285f927f76443414d4357ff789647d7a005a5a787e03c346b57f49f21b64fa9cf4b7e45573e23049017567121a9c3d4b2b73ec5e9413577525db45a", + "ec7096330736fdb2d64b5653e7475da746c23a4613a82687a28062d3236364284ac01720ffb406cfe265c0df626a188c9e5963ace5d3d5bb363e32c38c2190a6", + "82e744c75f4649ec52b80771a77d475a3bc091989556960e276a5f9ead92a03f718742cdcfeaee5cb85c44af198adc43a4a428f5f0c2ddb0be36059f06d7df73", + "2834b7a7170f1f5b68559ab78c1050ec21c919740b784a9072f6e5d69f828d70c919c5039fb148e39e2c8a52118378b064ca8d5001cd10a5478387b966715ed6", + "16b4ada883f72f853bb7ef253efcab0c3e2161687ad61543a0d2824f91c1f81347d86be709b16996e17f2dd486927b0288ad38d13063c4a9672c39397d3789b6", + "78d048f3a69d8b54ae0ed63a573ae350d89f7c6cf1f3688930de899afa037697629b314e5cd303aa62feea72a25bf42b304b6c6bcb27fae21c16d925e1fbdac3", + "0f746a48749287ada77a82961f05a4da4abdb7d77b1220f836d09ec814359c0ec0239b8c7b9ff9e02f569d1b301ef67c4612d1de4f730f81c12c40cc063c5caa", + "f0fc859d3bd195fbdc2d591e4cdac15179ec0f1dc821c11df1f0c1d26e6260aaa65b79fafacafd7d3ad61e600f250905f5878c87452897647a35b995bcadc3a3", + "2620f687e8625f6a412460b42e2cef67634208ce10a0cbd4dff7044a41b7880077e9f8dc3b8d1216d3376a21e015b58fb279b521d83f9388c7382c8505590b9b", + "227e3aed8d2cb10b918fcb04f9de3e6d0a57e08476d93759cd7b2ed54a1cbf0239c528fb04bbf288253e601d3bc38b21794afef90b17094a182cac557745e75f", + "1a929901b09c25f27d6b35be7b2f1c4745131fdebca7f3e2451926720434e0db6e74fd693ad29b777dc3355c592a361c4873b01133a57c2e3b7075cbdb86f4fc", + "5fd7968bc2fe34f220b5e3dc5af9571742d73b7d60819f2888b629072b96a9d8ab2d91b82d0a9aaba61bbd39958132fcc4257023d1eca591b3054e2dc81c8200", + "dfcce8cf32870cc6a503eadafc87fd6f78918b9b4d0737db6810be996b5497e7e5cc80e312f61e71ff3e9624436073156403f735f56b0b01845c18f6caf772e6", + "02f7ef3a9ce0fff960f67032b296efca3061f4934d690749f2d01c35c81c14f39a67fa350bc8a0359bf1724bffc3bca6d7c7bba4791fd522a3ad353c02ec5aa8", + "64be5c6aba65d594844ae78bb022e5bebe127fd6b6ffa5a13703855ab63b624dcd1a363f99203f632ec386f3ea767fc992e8ed9686586aa27555a8599d5b808f", + "f78585505c4eaa54a8b5be70a61e735e0ff97af944ddb3001e35d86c4e2199d976104b6ae31750a36a726ed285064f5981b503889fef822fcdc2898dddb7889a", + "e4b5566033869572edfd87479a5bb73c80e8759b91232879d96b1dda36c012076ee5a2ed7ae2de63ef8406a06aea82c188031b560beafb583fb3de9e57952a7e", + "e1b3e7ed867f6c9484a2a97f7715f25e25294e992e41f6a7c161ffc2adc6daaeb7113102d5e6090287fe6ad94ce5d6b739c6ca240b05c76fb73f25dd024bf935", + "85fd085fdc12a080983df07bd7012b0d402a0f4043fcb2775adf0bad174f9b08d1676e476985785c0a5dcc41dbff6d95ef4d66a3fbdc4a74b82ba52da0512b74", + "aed8fa764b0fbff821e05233d2f7b0900ec44d826f95e93c343c1bc3ba5a24374b1d616e7e7aba453a0ada5e4fab5382409e0d42ce9c2bc7fb39a99c340c20f0", + "7ba3b2e297233522eeb343bd3ebcfd835a04007735e87f0ca300cbee6d416565162171581e4020ff4cf176450f1291ea2285cb9ebffe4c56660627685145051c", + "de748bcf89ec88084721e16b85f30adb1a6134d664b5843569babc5bbd1a15ca9b61803c901a4fef32965a1749c9f3a4e243e173939dc5a8dc495c671ab52145", + "aaf4d2bdf200a919706d9842dce16c98140d34bc433df320aba9bd429e549aa7a3397652a4d768277786cf993cde2338673ed2e6b66c961fefb82cd20c93338f", + "c408218968b788bf864f0997e6bc4c3dba68b276e2125a4843296052ff93bf5767b8cdce7131f0876430c1165fec6c4f47adaa4fd8bcfacef463b5d3d0fa61a0", + "76d2d819c92bce55fa8e092ab1bf9b9eab237a25267986cacf2b8ee14d214d730dc9a5aa2d7b596e86a1fd8fa0804c77402d2fcd45083688b218b1cdfa0dcbcb", + "72065ee4dd91c2d8509fa1fc28a37c7fc9fa7d5b3f8ad3d0d7a25626b57b1b44788d4caf806290425f9890a3a2a35a905ab4b37acfd0da6e4517b2525c9651e4", + "64475dfe7600d7171bea0b394e27c9b00d8e74dd1e416a79473682ad3dfdbb706631558055cfc8a40e07bd015a4540dcdea15883cbbf31412df1de1cd4152b91", + "12cd1674a4488a5d7c2b3160d2e2c4b58371bedad793418d6f19c6ee385d70b3e06739369d4df910edb0b0a54cbff43d54544cd37ab3a06cfa0a3ddac8b66c89", + "60756966479dedc6dd4bcff8ea7d1d4ce4d4af2e7b097e32e3763518441147cc12b3c0ee6d2ecabf1198cec92e86a3616fba4f4e872f5825330adbb4c1dee444", + "a7803bcb71bc1d0f4383dde1e0612e04f872b715ad30815c2249cf34abb8b024915cb2fc9f4e7cc4c8cfd45be2d5a91eab0941c7d270e2da4ca4a9f7ac68663a", + "b84ef6a7229a34a750d9a98ee2529871816b87fbe3bc45b45fa5ae82d5141540211165c3c5d7a7476ba5a4aa06d66476f0d9dc49a3f1ee72c3acabd498967414", + "fae4b6d8efc3f8c8e64d001dabec3a21f544e82714745251b2b4b393f2f43e0da3d403c64db95a2cb6e23ebb7b9e94cdd5ddac54f07c4a61bd3cb10aa6f93b49", + "34f7286605a122369540141ded79b8957255da2d4155abbf5a8dbb89c8eb7ede8eeef1daa46dc29d751d045dc3b1d658bb64b80ff8589eddb3824b13da235a6b", + "3b3b48434be27b9eababba43bf6b35f14b30f6a88dc2e750c358470d6b3aa3c18e47db4017fa55106d8252f016371a00f5f8b070b74ba5f23cffc5511c9f09f0", + "ba289ebd6562c48c3e10a8ad6ce02e73433d1e93d7c9279d4d60a7e879ee11f441a000f48ed9f7c4ed87a45136d7dccdca482109c78a51062b3ba4044ada2469", + "022939e2386c5a37049856c850a2bb10a13dfea4212b4c732a8840a9ffa5faf54875c5448816b2785a007da8a8d2bc7d71a54e4e6571f10b600cbdb25d13ede3", + "e6fec19d89ce8717b1a087024670fe026f6c7cbda11caef959bb2d351bf856f8055d1c0ebdaaa9d1b17886fc2c562b5e99642fc064710c0d3488a02b5ed7f6fd", + "94c96f02a8f576aca32ba61c2b206f907285d9299b83ac175c209a8d43d53bfe683dd1d83e7549cb906c28f59ab7c46f8751366a28c39dd5fe2693c9019666c8", + "31a0cd215ebd2cb61de5b9edc91e6195e31c59a5648d5c9f737e125b2605708f2e325ab3381c8dce1a3e958886f1ecdc60318f882cfe20a24191352e617b0f21", + "91ab504a522dce78779f4c6c6ba2e6b6db5565c76d3e7e7c920caf7f757ef9db7c8fcf10e57f03379ea9bf75eb59895d96e149800b6aae01db778bb90afbc989", + "d85cabc6bd5b1a01a5afd8c6734740da9fd1c1acc6db29bfc8a2e5b668b028b6b3154bfb8703fa3180251d589ad38040ceb707c4bad1b5343cb426b61eaa49c1", + "d62efbec2ca9c1f8bd66ce8b3f6a898cb3f7566ba6568c618ad1feb2b65b76c3ce1dd20f7395372faf28427f61c9278049cf0140df434f5633048c86b81e0399", + "7c8fdc6175439e2c3db15bafa7fb06143a6a23bc90f449e79deef73c3d492a671715c193b6fea9f036050b946069856b897e08c00768f5ee5ddcf70b7cd6d0e0", + "58602ee7468e6bc9df21bd51b23c005f72d6cb013f0a1b48cbec5eca299299f97f09f54a9a01483eaeb315a6478bad37ba47ca1347c7c8fc9e6695592c91d723", + "27f5b79ed256b050993d793496edf4807c1d85a7b0a67c9c4fa99860750b0ae66989670a8ffd7856d7ce411599e58c4d77b232a62bef64d15275be46a68235ff", + "3957a976b9f1887bf004a8dca942c92d2b37ea52600f25e0c9bc5707d0279c00c6e85a839b0d2d8eb59c51d94788ebe62474a791cadf52cccf20f5070b6573fc", + "eaa2376d55380bf772ecca9cb0aa4668c95c707162fa86d518c8ce0ca9bf7362b9f2a0adc3ff59922df921b94567e81e452f6c1a07fc817cebe99604b3505d38", + "c1e2c78b6b2734e2480ec550434cb5d613111adcc21d475545c3b1b7e6ff12444476e5c055132e2229dc0f807044bb919b1a5662dd38a9ee65e243a3911aed1a", + "8ab48713389dd0fcf9f965d3ce66b1e559a1f8c58741d67683cd971354f452e62d0207a65e436c5d5d8f8ee71c6abfe50e669004c302b31a7ea8311d4a916051", + "24ce0addaa4c65038bd1b1c0f1452a0b128777aabc94a29df2fd6c7e2f85f8ab9ac7eff516b0e0a825c84a24cfe492eaad0a6308e46dd42fe8333ab971bb30ca", + "5154f929ee03045b6b0c0004fa778edee1d139893267cc84825ad7b36c63de32798e4a166d24686561354f63b00709a1364b3c241de3febf0754045897467cd4", + "e74e907920fd87bd5ad636dd11085e50ee70459c443e1ce5809af2bc2eba39f9e6d7128e0e3712c316da06f4705d78a4838e28121d4344a2c79c5e0db307a677", + "bf91a22334bac20f3fd80663b3cd06c4e8802f30e6b59f90d3035cc9798a217ed5a31abbda7fa6842827bdf2a7a1c21f6fcfccbb54c6c52926f32da816269be1", + "d9d5c74be5121b0bd742f26bffb8c89f89171f3f934913492b0903c271bbe2b3395ef259669bef43b57f7fcc3027db01823f6baee66e4f9fead4d6726c741fce", + "50c8b8cf34cd879f80e2faab3230b0c0e1cc3e9dcadeb1b9d97ab923415dd9a1fe38addd5c11756c67990b256e95ad6d8f9fedce10bf1c90679cde0ecf1be347", + "0a386e7cd5dd9b77a035e09fe6fee2c8ce61b5383c87ea43205059c5e4cd4f4408319bb0a82360f6a58e6c9ce3f487c446063bf813bc6ba535e17fc1826cfc91", + "1f1459cb6b61cbac5f0efe8fc487538f42548987fcd56221cfa7beb22504769e792c45adfb1d6b3d60d7b749c8a75b0bdf14e8ea721b95dca538ca6e25711209", + "e58b3836b7d8fedbb50ca5725c6571e74c0785e97821dab8b6298c10e4c079d4a6cdf22f0fedb55032925c16748115f01a105e77e00cee3d07924dc0d8f90659", + "b929cc6505f020158672deda56d0db081a2ee34c00c1100029bdf8ea98034fa4bf3e8655ec697fe36f40553c5bb46801644a627d3342f4fc92b61f03290fb381", + "72d353994b49d3e03153929a1e4d4f188ee58ab9e72ee8e512f29bc773913819ce057ddd7002c0433ee0a16114e3d156dd2c4a7e80ee53378b8670f23e33ef56", + "c70ef9bfd775d408176737a0736d68517ce1aaad7e81a93c8c1ed967ea214f56c8a377b1763e676615b60f3988241eae6eab9685a5124929d28188f29eab06f7", + "c230f0802679cb33822ef8b3b21bf7a9a28942092901d7dac3760300831026cf354c9232df3e084d9903130c601f63c1f4a4a4b8106e468cd443bbe5a734f45f", + "6f43094cafb5ebf1f7a4937ec50f56a4c9da303cbb55ac1f27f1f1976cd96beda9464f0e7b9c54620b8a9fba983164b8be3578425a024f5fe199c36356b88972", + "3745273f4c38225db2337381871a0c6aafd3af9b018c88aa02025850a5dc3a42a1a3e03e56cbf1b0876d63a441f1d2856a39b8801eb5af325201c415d65e97fe", + "c50c44cca3ec3edaae779a7e179450ebdda2f97067c690aa6c5a4ac7c30139bb27c0df4db3220e63cb110d64f37ffe078db72653e2daacf93ae3f0a2d1a7eb2e", + "8aef263e385cbc61e19b28914243262af5afe8726af3ce39a79c27028cf3ecd3f8d2dfd9cfc9ad91b58f6f20778fd5f02894a3d91c7d57d1e4b866a7f364b6be", + "28696141de6e2d9bcb3235578a66166c1448d3e905a1b482d423be4bc5369bc8c74dae0acc9cc123e1d8ddce9f97917e8c019c552da32d39d2219b9abf0fa8c8", + "2fb9eb2085830181903a9dafe3db428ee15be7662224efd643371fb25646aee716e531eca69b2bdc8233f1a8081fa43da1500302975a77f42fa592136710e9dc", + "66f9a7143f7a3314a669bf2e24bbb35014261d639f495b6c9c1f104fe8e320aca60d4550d69d52edbd5a3cdeb4014ae65b1d87aa770b69ae5c15f4330b0b0ad8", + "f4c4dd1d594c3565e3e25ca43dad82f62abea4835ed4cd811bcd975e46279828d44d4c62c3679f1b7f7b9dd4571d7b49557347b8c5460cbdc1bef690fb2a08c0", + "8f1dc9649c3a84551f8f6e91cac68242a43b1f8f328ee92280257387fa7559aa6db12e4aeadc2d26099178749c6864b357f3f83b2fb3efa8d2a8db056bed6bcc", + "3139c1a7f97afd1675d460ebbc07f2728aa150df849624511ee04b743ba0a833092f18c12dc91b4dd243f333402f59fe28abdbbbae301e7b659c7a26d5c0f979", + "06f94a2996158a819fe34c40de3cf0379fd9fb85b3e363ba3926a0e7d960e3f4c2e0c70c7ce0ccb2a64fc29869f6e7ab12bd4d3f14fce943279027e785fb5c29", + "c29c399ef3eee8961e87565c1ce263925fc3d0ce267d13e48dd9e732ee67b0f69fad56401b0f10fcaac119201046cca28c5b14abdea3212ae65562f7f138db3d", + "4cec4c9df52eef05c3f6faaa9791bc7445937183224ecc37a1e58d0132d35617531d7e795f52af7b1eb9d147de1292d345fe341823f8e6bc1e5badca5c656108", + "898bfbae93b3e18d00697eab7d9704fa36ec339d076131cefdf30edbe8d9cc81c3a80b129659b163a323bab9793d4feed92d54dae966c77529764a09be88db45", + "ee9bd0469d3aaf4f14035be48a2c3b84d9b4b1fff1d945e1f1c1d38980a951be197b25fe22c731f20aeacc930ba9c4a1f4762227617ad350fdabb4e80273a0f4", + "3d4d3113300581cd96acbf091c3d0f3c310138cd6979e6026cde623e2dd1b24d4a8638bed1073344783ad0649cc6305ccec04beb49f31c633088a99b65130267", + "95c0591ad91f921ac7be6d9ce37e0663ed8011c1cfd6d0162a5572e94368bac02024485e6a39854aa46fe38e97d6c6b1947cd272d86b06bb5b2f78b9b68d559d", + "227b79ded368153bf46c0a3ca978bfdbef31f3024a5665842468490b0ff748ae04e7832ed4c9f49de9b1706709d623e5c8c15e3caecae8d5e433430ff72f20eb", + "5d34f3952f0105eef88ae8b64c6ce95ebfade0e02c69b08762a8712d2e4911ad3f941fc4034dc9b2e479fdbcd279b902faf5d838bb2e0c6495d372b5b7029813", + "7f939bf8353abce49e77f14f3750af20b7b03902e1a1e7fb6aaf76d0259cd401a83190f15640e74f3e6c5a90e839c7821f6474757f75c7bf9002084ddc7a62dc", + "062b61a2f9a33a71d7d0a06119644c70b0716a504de7e5e1be49bd7b86e7ed6817714f9f0fc313d06129597e9a2235ec8521de36f7290a90ccfc1ffa6d0aee29", + "f29e01eeae64311eb7f1c6422f946bf7bea36379523e7b2bbaba7d1d34a22d5ea5f1c5a09d5ce1fe682cced9a4798d1a05b46cd72dff5c1b355440b2a2d476bc", + "ec38cd3bbab3ef35d7cb6d5c914298351d8a9dc97fcee051a8a02f58e3ed6184d0b7810a5615411ab1b95209c3c810114fdeb22452084e77f3f847c6dbaafe16", + "c2aef5e0ca43e82641565b8cb943aa8ba53550caef793b6532fafad94b816082f0113a3ea2f63608ab40437ecc0f0229cb8fa224dcf1c478a67d9b64162b92d1", + "15f534efff7105cd1c254d074e27d5898b89313b7d366dc2d7d87113fa7d53aae13f6dba487ad8103d5e854c91fdb6e1e74b2ef6d1431769c30767dde067a35c", + "89acbca0b169897a0a2714c2df8c95b5b79cb69390142b7d6018bb3e3076b099b79a964152a9d912b1b86412b7e372e9cecad7f25d4cbab8a317be36492a67d7", + "e3c0739190ed849c9c962fd9dbb55e207e624fcac1eb417691515499eea8d8267b7e8f1287a63633af5011fde8c4ddf55bfdf722edf88831414f2cfaed59cb9a", + "8d6cf87c08380d2d1506eee46fd4222d21d8c04e585fbfd08269c98f702833a156326a0724656400ee09351d57b440175e2a5de93cc5f80db6daf83576cf75fa", + "da24bede383666d563eeed37f6319baf20d5c75d1635a6ba5ef4cfa1ac95487e96f8c08af600aab87c986ebad49fc70a58b4890b9c876e091016daf49e1d322e", + "f9d1d1b1e87ea7ae753a029750cc1cf3d0157d41805e245c5617bb934e732f0ae3180b78e05bfe76c7c3051e3e3ac78b9b50c05142657e1e03215d6ec7bfd0fc", + "11b7bc1668032048aa43343de476395e814bbbc223678db951a1b03a021efac948cfbe215f97fe9a72a2f6bc039e3956bfa417c1a9f10d6d7ba5d3d32ff323e5", + "b8d9000e4fc2b066edb91afee8e7eb0f24e3a201db8b6793c0608581e628ed0bcc4e5aa6787992a4bcc44e288093e63ee83abd0bc3ec6d0934a674a4da13838a", + "ce325e294f9b6719d6b61278276ae06a2564c03bb0b783fafe785bdf89c7d5acd83e78756d301b445699024eaeb77b54d477336ec2a4f332f2b3f88765ddb0c3", + "29acc30e9603ae2fccf90bf97e6cc463ebe28c1b2f9b4b765e70537c25c702a29dcbfbf14c99c54345ba2b51f17b77b5f15db92bbad8fa95c471f5d070a137cc", + "3379cbaae562a87b4c0425550ffdd6bfe1203f0d666cc7ea095be407a5dfe61ee91441cd5154b3e53b4f5fb31ad4c7a9ad5c7af4ae679aa51a54003a54ca6b2d", + "3095a349d245708c7cf550118703d7302c27b60af5d4e67fc978f8a4e60953c7a04f92fcf41aee64321ccb707a895851552b1e37b00bc5e6b72fa5bcef9e3fff", + "07262d738b09321f4dbccec4bb26f48cb0f0ed246ce0b31b9a6e7bc683049f1f3e5545f28ce932dd985c5ab0f43bd6de0770560af329065ed2e49d34624c2cbb", + "b6405eca8ee3316c87061cc6ec18dba53e6c250c63ba1f3bae9e55dd3498036af08cd272aa24d713c6020d77ab2f3919af1a32f307420618ab97e73953994fb4", + "7ee682f63148ee45f6e5315da81e5c6e557c2c34641fc509c7a5701088c38a74756168e2cd8d351e88fd1a451f360a01f5b2580f9b5a2e8cfc138f3dd59a3ffc", + "1d263c179d6b268f6fa016f3a4f29e943891125ed8593c81256059f5a7b44af2dcb2030d175c00e62ecaf7ee96682aa07ab20a611024a28532b1c25b86657902", + "106d132cbdb4cd2597812846e2bc1bf732fec5f0a5f65dbb39ec4e6dc64ab2ce6d24630d0f15a805c3540025d84afa98e36703c3dbee713e72dde8465bc1be7e", + "0e79968226650667a8d862ea8da4891af56a4e3a8b6d1750e394f0dea76d640d85077bcec2cc86886e506751b4f6a5838f7f0b5fef765d9dc90dcdcbaf079f08", + "521156a82ab0c4e566e5844d5e31ad9aaf144bbd5a464fdca34dbd5717e8ff711d3ffebbfa085d67fe996a34f6d3e4e60b1396bf4b1610c263bdbb834d560816", + "1aba88befc55bc25efbce02db8b9933e46f57661baeabeb21cc2574d2a518a3cba5dc5a38e49713440b25f9c744e75f6b85c9d8f4681f676160f6105357b8406", + "5a9949fcb2c473cda968ac1b5d08566dc2d816d960f57e63b898fa701cf8ebd3f59b124d95bfbbedc5f1cf0e17d5eaed0c02c50b69d8a402cabcca4433b51fd4", + "b0cead09807c672af2eb2b0f06dde46cf5370e15a4096b1a7d7cbb36ec31c205fbefca00b7a4162fa89fb4fb3eb78d79770c23f44e7206664ce3cd931c291e5d", + "bb6664931ec97044e45b2ae420ae1c551a8874bc937d08e969399c3964ebdba8346cdd5d09caafe4c28ba7ec788191ceca65ddd6f95f18583e040d0f30d0364d", + "65bc770a5faa3792369803683e844b0be7ee96f29f6d6a35568006bd5590f9a4ef639b7a8061c7b0424b66b60ac34af3119905f33a9d8c3ae18382ca9b689900", + "ea9b4dca333336aaf839a45c6eaa48b8cb4c7ddabffea4f643d6357ea6628a480a5b45f2b052c1b07d1fedca918b6f1139d80f74c24510dcbaa4be70eacc1b06", + "e6342fb4a780ad975d0e24bce149989b91d360557e87994f6b457b895575cc02d0c15bad3ce7577f4c63927ff13f3e381ff7e72bdbe745324844a9d27e3f1c01", + "3e209c9b33e8e461178ab46b1c64b49a07fb745f1c8bc95fbfb94c6b87c69516651b264ef980937fad41238b91ddc011a5dd777c7efd4494b4b6ecd3a9c22ac0", + "fd6a3d5b1875d80486d6e69694a56dbb04a99a4d051f15db2689776ba1c4882e6d462a603b7015dc9f4b7450f05394303b8652cfb404a266962c41bae6e18a94", + "951e27517e6bad9e4195fc8671dee3e7e9be69cee1422cb9fecfce0dba875f7b310b93ee3a3d558f941f635f668ff832d2c1d033c5e2f0997e4c66f147344e02", + "8eba2f874f1ae84041903c7c4253c82292530fc8509550bfdc34c95c7e2889d5650b0ad8cb988e5c4894cb87fbfbb19612ea93ccc4c5cad17158b9763464b492", + "16f712eaa1b7c6354719a8e7dbdfaf55e4063a4d277d947550019b38dfb564830911057d50506136e2394c3b28945cc964967d54e3000c2181626cfb9b73efd2", + "c39639e7d5c7fb8cdd0fd3e6a52096039437122f21c78f1679cea9d78a734c56ecbeb28654b4f18e342c331f6f7229ec4b4bc281b2d80a6eb50043f31796c88c", + "72d081af99f8a173dcc9a0ac4eb3557405639a29084b54a40172912a2f8a395129d5536f0918e902f9e8fa6000995f4168ddc5f893011be6a0dbc9b8a1a3f5bb", + "c11aa81e5efd24d5fc27ee586cfd8847fbb0e27601ccece5ecca0198e3c7765393bb74457c7e7a27eb9170350e1fb53857177506be3e762cc0f14d8c3afe9077", + "c28f2150b452e6c0c424bcde6f8d72007f9310fed7f2f87de0dbb64f4479d6c1441ba66f44b2accee61609177ed340128b407ecec7c64bbe50d63d22d8627727", + "f63d88122877ec30b8c8b00d22e89000a966426112bd44166e2f525b769ccbe9b286d437a0129130dde1a86c43e04bedb594e671d98283afe64ce331de9828fd", + "348b0532880b88a6614a8d7408c3f913357fbb60e995c60205be9139e74998aede7f4581e42f6b52698f7fa1219708c14498067fd1e09502de83a77dd281150c", + "5133dc8bef725359dff59792d85eaf75b7e1dcd1978b01c35b1b85fcebc63388ad99a17b6346a217dc1a9622ebd122ecf6913c4d31a6b52a695b86af00d741a0", + "2753c4c0e98ecad806e88780ec27fccd0f5c1ab547f9e4bf1659d192c23aa2cc971b58b6802580baef8adc3b776ef7086b2545c2987f348ee3719cdef258c403", + "b1663573ce4b9d8caefc865012f3e39714b9898a5da6ce17c25a6a47931a9ddb9bbe98adaa553beed436e89578455416c2a52a525cf2862b8d1d49a2531b7391", + "64f58bd6bfc856f5e873b2a2956ea0eda0d6db0da39c8c7fc67c9f9feefcff3072cdf9e6ea37f69a44f0c61aa0da3693c2db5b54960c0281a088151db42b11e8", + "0764c7be28125d9065c4b98a69d60aede703547c66a12e17e1c618994132f5ef82482c1e3fe3146cc65376cc109f0138ed9a80e49f1f3c7d610d2f2432f20605", + "f748784398a2ff03ebeb07e155e66116a839741a336e32da71ec696001f0ad1b25cd48c69cfca7265eca1dd71904a0ce748ac4124f3571076dfa7116a9cf00e9", + "3f0dbc0186bceb6b785ba78d2a2a013c910be157bdaffae81bb6663b1a73722f7f1228795f3ecada87cf6ef0078474af73f31eca0cc200ed975b6893f761cb6d", + "d4762cd4599876ca75b2b8fe249944dbd27ace741fdab93616cbc6e425460feb51d4e7adcc38180e7fc47c89024a7f56191adb878dfde4ead62223f5a2610efe", + "cd36b3d5b4c91b90fcbba79513cfee1907d8645a162afd0cd4cf4192d4a5f4c892183a8eacdb2b6b6a9d9aa8c11ac1b261b380dbee24ca468f1bfd043c58eefe", + "98593452281661a53c48a9d8cd790826c1a1ce567738053d0bee4a91a3d5bd92eefdbabebe3204f2031ca5f781bda99ef5d8ae56e5b04a9e1ecd21b0eb05d3e1", + "771f57dd2775ccdab55921d3e8e30ccf484d61fe1c1b9c2ae819d0fb2a12fab9be70c4a7a138da84e8280435daade5bbe66af0836a154f817fb17f3397e725a3", + "c60897c6f828e21f16fbb5f15b323f87b6c8955eabf1d38061f707f608abdd993fac3070633e286cf8339ce295dd352df4b4b40b2f29da1dd50b3a05d079e6bb", + "8210cd2c2d3b135c2cf07fa0d1433cd771f325d075c6469d9c7f1ba0943cd4ab09808cabf4acb9ce5bb88b498929b4b847f681ad2c490d042db2aec94214b06b", + "1d4edfffd8fd80f7e4107840fa3aa31e32598491e4af7013c197a65b7f36dd3ac4b478456111cd4309d9243510782fa31b7c4c95fa951520d020eb7e5c36e4ef", + "af8e6e91fab46ce4873e1a50a8ef448cc29121f7f74deef34a71ef89cc00d9274bc6c2454bbb3230d8b2ec94c62b1dec85f3593bfa30ea6f7a44d7c09465a253", + "29fd384ed4906f2d13aa9fe7af905990938bed807f1832454a372ab412eea1f5625a1fcc9ac8343b7c67c5aba6e0b1cc4644654913692c6b39eb9187ceacd3ec", + "a268c7885d9874a51c44dffed8ea53e94f78456e0b2ed99ff5a3924760813826d960a15edbedbb5de5226ba4b074e71b05c55b9756bb79e55c02754c2c7b6c8a", + "0cf8545488d56a86817cd7ecb10f7116b7ea530a45b6ea497b6c72c997e09e3d0da8698f46bb006fc977c2cd3d1177463ac9057fdd1662c85d0c126443c10473", + "b39614268fdd8781515e2cfebf89b4d5402bab10c226e6344e6b9ae000fb0d6c79cb2f3ec80e80eaeb1980d2f8698916bd2e9f747236655116649cd3ca23a837", + "74bef092fc6f1e5dba3663a3fb003b2a5ba257496536d99f62b9d73f8f9eb3ce9ff3eec709eb883655ec9eb896b9128f2afc89cf7d1ab58a72f4a3bf034d2b4a", + "3a988d38d75611f3ef38b8774980b33e573b6c57bee0469ba5eed9b44f29945e7347967fba2c162e1c3be7f310f2f75ee2381e7bfd6b3f0baea8d95dfb1dafb1", + "58aedfce6f67ddc85a28c992f1c0bd0969f041e66f1ee88020a125cbfcfebcd61709c9c4eba192c15e69f020d462486019fa8dea0cd7a42921a19d2fe546d43d", + "9347bd291473e6b4e368437b8e561e065f649a6d8ada479ad09b1999a8f26b91cf6120fd3bfe014e83f23acfa4c0ad7b3712b2c3c0733270663112ccd9285cd9", + "b32163e7c5dbb5f51fdc11d2eac875efbbcb7e7699090a7e7ff8a8d50795af5d74d9ff98543ef8cdf89ac13d0485278756e0ef00c817745661e1d59fe38e7537", + "1085d78307b1c4b008c57a2e7e5b234658a0a82e4ff1e4aaac72b312fda0fe27d233bc5b10e9cc17fdc7697b540c7d95eb215a19a1a0e20e1abfa126efd568c7", + "4e5c734c7dde011d83eac2b7347b373594f92d7091b9ca34cb9c6f39bdf5a8d2f134379e16d822f6522170ccf2ddd55c84b9e6c64fc927ac4cf8dfb2a17701f2", + "695d83bd990a1117b3d0ce06cc888027d12a054c2677fd82f0d4fbfc93575523e7991a5e35a3752e9b70ce62992e268a877744cdd435f5f130869c9a2074b338", + "a6213743568e3b3158b9184301f3690847554c68457cb40fc9a4b8cfd8d4a118c301a07737aeda0f929c68913c5f51c80394f53bff1c3e83b2e40ca97eba9e15", + "d444bfa2362a96df213d070e33fa841f51334e4e76866b8139e8af3bb3398be2dfaddcbc56b9146de9f68118dc5829e74b0c28d7711907b121f9161cb92b69a9", + "142709d62e28fcccd0af97fad0f8465b971e82201dc51070faa0372aa43e92484be1c1e73ba10906d5d1853db6a4106e0a7bf9800d373d6dee2d46d62ef2a461", +} diff --git a/vendor/github.com/wg/ecies/vendor/github.com/dchest/blake2b/block.go b/vendor/github.com/wg/ecies/vendor/github.com/dchest/blake2b/block.go new file mode 100644 index 0000000..2f04bb7 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/github.com/dchest/blake2b/block.go @@ -0,0 +1,1420 @@ +// Written in 2012 by Dmitry Chestnykh. +// +// To the extent possible under law, the author have dedicated all copyright +// and related and neighboring rights to this software to the public domain +// worldwide. This software is distributed without any warranty. +// http://creativecommons.org/publicdomain/zero/1.0/ + +// BLAKE2b compression of message blocks. + +package blake2b + +func blocks(d *digest, p []uint8) { + h0, h1, h2, h3, h4, h5, h6, h7 := d.h[0], d.h[1], d.h[2], d.h[3], d.h[4], d.h[5], d.h[6], d.h[7] + + for len(p) >= BlockSize { + // Increment counter. + d.t[0] += BlockSize + if d.t[0] < BlockSize { + d.t[1]++ + } + // Initialize compression function. + v0, v1, v2, v3, v4, v5, v6, v7 := h0, h1, h2, h3, h4, h5, h6, h7 + v8 := iv[0] + v9 := iv[1] + v10 := iv[2] + v11 := iv[3] + v12 := iv[4] ^ d.t[0] + v13 := iv[5] ^ d.t[1] + v14 := iv[6] ^ d.f[0] + v15 := iv[7] ^ d.f[1] + var m [16]uint64 + + j := 0 + for i := 0; i < 16; i++ { + m[i] = uint64(p[j]) | uint64(p[j+1])<<8 | uint64(p[j+2])<<16 | uint64(p[j+3])<<24 | + uint64(p[j+4])<<32 | uint64(p[j+5])<<40 | uint64(p[j+6])<<48 | uint64(p[j+7])<<56 + j += 8 + } + + // Round 1. + v0 += m[0] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[2] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[4] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[6] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[5] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[7] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[3] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[1] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[8] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[10] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[12] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[14] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[13] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[15] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[11] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[9] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 2. + v0 += m[14] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[4] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[9] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[13] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[15] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[6] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[8] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[10] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[1] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[0] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[11] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[5] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[7] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[3] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[2] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[12] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 3. + v0 += m[11] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[12] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[5] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[15] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[2] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[13] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[0] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[8] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[10] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[3] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[7] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[9] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[1] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[4] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[6] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[14] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 4. + v0 += m[7] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[3] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[13] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[11] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[12] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[14] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[1] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[9] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[2] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[5] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[4] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[15] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[0] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[8] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[10] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[6] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 5. + v0 += m[9] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[5] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[2] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[10] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[4] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[15] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[7] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[0] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[14] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[11] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[6] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[3] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[8] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[13] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[12] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[1] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 6. + v0 += m[2] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[6] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[0] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[8] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[11] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[3] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[10] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[12] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[4] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[7] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[15] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[1] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[14] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[9] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[5] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[13] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 7. + v0 += m[12] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[1] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[14] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[4] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[13] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[10] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[15] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[5] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[0] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[6] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[9] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[8] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[2] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[11] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[3] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[7] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 8. + v0 += m[13] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[7] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[12] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[3] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[1] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[9] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[14] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[11] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[5] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[15] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[8] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[2] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[6] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[10] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[4] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[0] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 9. + v0 += m[6] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[14] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[11] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[0] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[3] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[8] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[9] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[15] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[12] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[13] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[1] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[10] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[4] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[5] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[7] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[2] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 10. + v0 += m[10] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[8] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[7] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[1] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[6] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[5] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[4] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[2] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[15] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[9] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[3] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[13] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[12] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[0] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[14] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[11] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 11. + v0 += m[0] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[2] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[4] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[6] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[5] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[7] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[3] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[1] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[8] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[10] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[12] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[14] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[13] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[15] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[11] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[9] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + // Round 12. + v0 += m[14] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[4] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[9] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[13] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + v2 += m[15] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[6] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + v1 += m[8] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v0 += m[10] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v0 += m[1] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[0] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[11] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[5] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + v2 += m[7] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[3] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + v1 += m[2] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v0 += m[12] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + + h0 ^= v0 ^ v8 + h1 ^= v1 ^ v9 + h2 ^= v2 ^ v10 + h3 ^= v3 ^ v11 + h4 ^= v4 ^ v12 + h5 ^= v5 ^ v13 + h6 ^= v6 ^ v14 + h7 ^= v7 ^ v15 + + p = p[BlockSize:] + } + d.h[0], d.h[1], d.h[2], d.h[3], d.h[4], d.h[5], d.h[6], d.h[7] = h0, h1, h2, h3, h4, h5, h6, h7 +} diff --git a/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/AUTHORS b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/AUTHORS new file mode 100644 index 0000000..15167cd --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/AUTHORS @@ -0,0 +1,3 @@ +# This source code refers to The Go Authors for copyright purposes. +# The master list of authors is in the main Go distribution, +# visible at http://tip.golang.org/AUTHORS. diff --git a/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/CONTRIBUTORS b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/CONTRIBUTORS new file mode 100644 index 0000000..1c4577e --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/CONTRIBUTORS @@ -0,0 +1,3 @@ +# This source code was written by the Go contributors. +# The master list of contributors is in the main Go distribution, +# visible at http://tip.golang.org/CONTRIBUTORS. diff --git a/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/LICENSE b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/LICENSE new file mode 100644 index 0000000..6a66aea --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/PATENTS b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/PATENTS new file mode 100644 index 0000000..7330990 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google 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, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/README b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/README new file mode 100644 index 0000000..f1e0cbf --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/README @@ -0,0 +1,3 @@ +This repository holds supplementary Go cryptography libraries. + +To submit changes to this repository, see http://golang.org/doc/contribute.html. diff --git a/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/const_amd64.s b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/const_amd64.s new file mode 100644 index 0000000..797f9b0 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/const_amd64.s @@ -0,0 +1,20 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This code was translated into a form compatible with 6a from the public +// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html + +// +build amd64,!gccgo,!appengine + +DATA ·REDMASK51(SB)/8, $0x0007FFFFFFFFFFFF +GLOBL ·REDMASK51(SB), 8, $8 + +DATA ·_121666_213(SB)/8, $996687872 +GLOBL ·_121666_213(SB), 8, $8 + +DATA ·_2P0(SB)/8, $0xFFFFFFFFFFFDA +GLOBL ·_2P0(SB), 8, $8 + +DATA ·_2P1234(SB)/8, $0xFFFFFFFFFFFFE +GLOBL ·_2P1234(SB), 8, $8 diff --git a/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s new file mode 100644 index 0000000..45484d1 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s @@ -0,0 +1,88 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This code was translated into a form compatible with 6a from the public +// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html + +// +build amd64,!gccgo,!appengine + +// func cswap(inout *[5]uint64, v uint64) +TEXT ·cswap(SB),7,$0 + MOVQ inout+0(FP),DI + MOVQ v+8(FP),SI + + CMPQ SI,$1 + MOVQ 0(DI),SI + MOVQ 80(DI),DX + MOVQ 8(DI),CX + MOVQ 88(DI),R8 + MOVQ SI,R9 + CMOVQEQ DX,SI + CMOVQEQ R9,DX + MOVQ CX,R9 + CMOVQEQ R8,CX + CMOVQEQ R9,R8 + MOVQ SI,0(DI) + MOVQ DX,80(DI) + MOVQ CX,8(DI) + MOVQ R8,88(DI) + MOVQ 16(DI),SI + MOVQ 96(DI),DX + MOVQ 24(DI),CX + MOVQ 104(DI),R8 + MOVQ SI,R9 + CMOVQEQ DX,SI + CMOVQEQ R9,DX + MOVQ CX,R9 + CMOVQEQ R8,CX + CMOVQEQ R9,R8 + MOVQ SI,16(DI) + MOVQ DX,96(DI) + MOVQ CX,24(DI) + MOVQ R8,104(DI) + MOVQ 32(DI),SI + MOVQ 112(DI),DX + MOVQ 40(DI),CX + MOVQ 120(DI),R8 + MOVQ SI,R9 + CMOVQEQ DX,SI + CMOVQEQ R9,DX + MOVQ CX,R9 + CMOVQEQ R8,CX + CMOVQEQ R9,R8 + MOVQ SI,32(DI) + MOVQ DX,112(DI) + MOVQ CX,40(DI) + MOVQ R8,120(DI) + MOVQ 48(DI),SI + MOVQ 128(DI),DX + MOVQ 56(DI),CX + MOVQ 136(DI),R8 + MOVQ SI,R9 + CMOVQEQ DX,SI + CMOVQEQ R9,DX + MOVQ CX,R9 + CMOVQEQ R8,CX + CMOVQEQ R9,R8 + MOVQ SI,48(DI) + MOVQ DX,128(DI) + MOVQ CX,56(DI) + MOVQ R8,136(DI) + MOVQ 64(DI),SI + MOVQ 144(DI),DX + MOVQ 72(DI),CX + MOVQ 152(DI),R8 + MOVQ SI,R9 + CMOVQEQ DX,SI + CMOVQEQ R9,DX + MOVQ CX,R9 + CMOVQEQ R8,CX + CMOVQEQ R9,R8 + MOVQ SI,64(DI) + MOVQ DX,144(DI) + MOVQ CX,72(DI) + MOVQ R8,152(DI) + MOVQ DI,AX + MOVQ SI,DX + RET diff --git a/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/curve25519.go b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/curve25519.go new file mode 100644 index 0000000..6918c47 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/curve25519.go @@ -0,0 +1,841 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// We have a implementation in amd64 assembly so this code is only run on +// non-amd64 platforms. The amd64 assembly does not support gccgo. +// +build !amd64 gccgo appengine + +package curve25519 + +// This code is a port of the public domain, "ref10" implementation of +// curve25519 from SUPERCOP 20130419 by D. J. Bernstein. + +// fieldElement represents an element of the field GF(2^255 - 19). An element +// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77 +// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on +// context. +type fieldElement [10]int32 + +func feZero(fe *fieldElement) { + for i := range fe { + fe[i] = 0 + } +} + +func feOne(fe *fieldElement) { + feZero(fe) + fe[0] = 1 +} + +func feAdd(dst, a, b *fieldElement) { + for i := range dst { + dst[i] = a[i] + b[i] + } +} + +func feSub(dst, a, b *fieldElement) { + for i := range dst { + dst[i] = a[i] - b[i] + } +} + +func feCopy(dst, src *fieldElement) { + for i := range dst { + dst[i] = src[i] + } +} + +// feCSwap replaces (f,g) with (g,f) if b == 1; replaces (f,g) with (f,g) if b == 0. +// +// Preconditions: b in {0,1}. +func feCSwap(f, g *fieldElement, b int32) { + var x fieldElement + b = -b + for i := range x { + x[i] = b & (f[i] ^ g[i]) + } + + for i := range f { + f[i] ^= x[i] + } + for i := range g { + g[i] ^= x[i] + } +} + +// load3 reads a 24-bit, little-endian value from in. +func load3(in []byte) int64 { + var r int64 + r = int64(in[0]) + r |= int64(in[1]) << 8 + r |= int64(in[2]) << 16 + return r +} + +// load4 reads a 32-bit, little-endian value from in. +func load4(in []byte) int64 { + var r int64 + r = int64(in[0]) + r |= int64(in[1]) << 8 + r |= int64(in[2]) << 16 + r |= int64(in[3]) << 24 + return r +} + +func feFromBytes(dst *fieldElement, src *[32]byte) { + h0 := load4(src[:]) + h1 := load3(src[4:]) << 6 + h2 := load3(src[7:]) << 5 + h3 := load3(src[10:]) << 3 + h4 := load3(src[13:]) << 2 + h5 := load4(src[16:]) + h6 := load3(src[20:]) << 7 + h7 := load3(src[23:]) << 5 + h8 := load3(src[26:]) << 4 + h9 := load3(src[29:]) << 2 + + var carry [10]int64 + carry[9] = (h9 + 1<<24) >> 25 + h0 += carry[9] * 19 + h9 -= carry[9] << 25 + carry[1] = (h1 + 1<<24) >> 25 + h2 += carry[1] + h1 -= carry[1] << 25 + carry[3] = (h3 + 1<<24) >> 25 + h4 += carry[3] + h3 -= carry[3] << 25 + carry[5] = (h5 + 1<<24) >> 25 + h6 += carry[5] + h5 -= carry[5] << 25 + carry[7] = (h7 + 1<<24) >> 25 + h8 += carry[7] + h7 -= carry[7] << 25 + + carry[0] = (h0 + 1<<25) >> 26 + h1 += carry[0] + h0 -= carry[0] << 26 + carry[2] = (h2 + 1<<25) >> 26 + h3 += carry[2] + h2 -= carry[2] << 26 + carry[4] = (h4 + 1<<25) >> 26 + h5 += carry[4] + h4 -= carry[4] << 26 + carry[6] = (h6 + 1<<25) >> 26 + h7 += carry[6] + h6 -= carry[6] << 26 + carry[8] = (h8 + 1<<25) >> 26 + h9 += carry[8] + h8 -= carry[8] << 26 + + dst[0] = int32(h0) + dst[1] = int32(h1) + dst[2] = int32(h2) + dst[3] = int32(h3) + dst[4] = int32(h4) + dst[5] = int32(h5) + dst[6] = int32(h6) + dst[7] = int32(h7) + dst[8] = int32(h8) + dst[9] = int32(h9) +} + +// feToBytes marshals h to s. +// Preconditions: +// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +// +// Write p=2^255-19; q=floor(h/p). +// Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). +// +// Proof: +// Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. +// Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4. +// +// Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). +// Then 0> 25 + q = (h[0] + q) >> 26 + q = (h[1] + q) >> 25 + q = (h[2] + q) >> 26 + q = (h[3] + q) >> 25 + q = (h[4] + q) >> 26 + q = (h[5] + q) >> 25 + q = (h[6] + q) >> 26 + q = (h[7] + q) >> 25 + q = (h[8] + q) >> 26 + q = (h[9] + q) >> 25 + + // Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. + h[0] += 19 * q + // Goal: Output h-2^255 q, which is between 0 and 2^255-20. + + carry[0] = h[0] >> 26 + h[1] += carry[0] + h[0] -= carry[0] << 26 + carry[1] = h[1] >> 25 + h[2] += carry[1] + h[1] -= carry[1] << 25 + carry[2] = h[2] >> 26 + h[3] += carry[2] + h[2] -= carry[2] << 26 + carry[3] = h[3] >> 25 + h[4] += carry[3] + h[3] -= carry[3] << 25 + carry[4] = h[4] >> 26 + h[5] += carry[4] + h[4] -= carry[4] << 26 + carry[5] = h[5] >> 25 + h[6] += carry[5] + h[5] -= carry[5] << 25 + carry[6] = h[6] >> 26 + h[7] += carry[6] + h[6] -= carry[6] << 26 + carry[7] = h[7] >> 25 + h[8] += carry[7] + h[7] -= carry[7] << 25 + carry[8] = h[8] >> 26 + h[9] += carry[8] + h[8] -= carry[8] << 26 + carry[9] = h[9] >> 25 + h[9] -= carry[9] << 25 + // h10 = carry9 + + // Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. + // Have h[0]+...+2^230 h[9] between 0 and 2^255-1; + // evidently 2^255 h10-2^255 q = 0. + // Goal: Output h[0]+...+2^230 h[9]. + + s[0] = byte(h[0] >> 0) + s[1] = byte(h[0] >> 8) + s[2] = byte(h[0] >> 16) + s[3] = byte((h[0] >> 24) | (h[1] << 2)) + s[4] = byte(h[1] >> 6) + s[5] = byte(h[1] >> 14) + s[6] = byte((h[1] >> 22) | (h[2] << 3)) + s[7] = byte(h[2] >> 5) + s[8] = byte(h[2] >> 13) + s[9] = byte((h[2] >> 21) | (h[3] << 5)) + s[10] = byte(h[3] >> 3) + s[11] = byte(h[3] >> 11) + s[12] = byte((h[3] >> 19) | (h[4] << 6)) + s[13] = byte(h[4] >> 2) + s[14] = byte(h[4] >> 10) + s[15] = byte(h[4] >> 18) + s[16] = byte(h[5] >> 0) + s[17] = byte(h[5] >> 8) + s[18] = byte(h[5] >> 16) + s[19] = byte((h[5] >> 24) | (h[6] << 1)) + s[20] = byte(h[6] >> 7) + s[21] = byte(h[6] >> 15) + s[22] = byte((h[6] >> 23) | (h[7] << 3)) + s[23] = byte(h[7] >> 5) + s[24] = byte(h[7] >> 13) + s[25] = byte((h[7] >> 21) | (h[8] << 4)) + s[26] = byte(h[8] >> 4) + s[27] = byte(h[8] >> 12) + s[28] = byte((h[8] >> 20) | (h[9] << 6)) + s[29] = byte(h[9] >> 2) + s[30] = byte(h[9] >> 10) + s[31] = byte(h[9] >> 18) +} + +// feMul calculates h = f * g +// Can overlap h with f or g. +// +// Preconditions: +// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +// |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +// +// Postconditions: +// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +// +// Notes on implementation strategy: +// +// Using schoolbook multiplication. +// Karatsuba would save a little in some cost models. +// +// Most multiplications by 2 and 19 are 32-bit precomputations; +// cheaper than 64-bit postcomputations. +// +// There is one remaining multiplication by 19 in the carry chain; +// one *19 precomputation can be merged into this, +// but the resulting data flow is considerably less clean. +// +// There are 12 carries below. +// 10 of them are 2-way parallelizable and vectorizable. +// Can get away with 11 carries, but then data flow is much deeper. +// +// With tighter constraints on inputs can squeeze carries into int32. +func feMul(h, f, g *fieldElement) { + f0 := f[0] + f1 := f[1] + f2 := f[2] + f3 := f[3] + f4 := f[4] + f5 := f[5] + f6 := f[6] + f7 := f[7] + f8 := f[8] + f9 := f[9] + g0 := g[0] + g1 := g[1] + g2 := g[2] + g3 := g[3] + g4 := g[4] + g5 := g[5] + g6 := g[6] + g7 := g[7] + g8 := g[8] + g9 := g[9] + g1_19 := 19 * g1 // 1.4*2^29 + g2_19 := 19 * g2 // 1.4*2^30; still ok + g3_19 := 19 * g3 + g4_19 := 19 * g4 + g5_19 := 19 * g5 + g6_19 := 19 * g6 + g7_19 := 19 * g7 + g8_19 := 19 * g8 + g9_19 := 19 * g9 + f1_2 := 2 * f1 + f3_2 := 2 * f3 + f5_2 := 2 * f5 + f7_2 := 2 * f7 + f9_2 := 2 * f9 + f0g0 := int64(f0) * int64(g0) + f0g1 := int64(f0) * int64(g1) + f0g2 := int64(f0) * int64(g2) + f0g3 := int64(f0) * int64(g3) + f0g4 := int64(f0) * int64(g4) + f0g5 := int64(f0) * int64(g5) + f0g6 := int64(f0) * int64(g6) + f0g7 := int64(f0) * int64(g7) + f0g8 := int64(f0) * int64(g8) + f0g9 := int64(f0) * int64(g9) + f1g0 := int64(f1) * int64(g0) + f1g1_2 := int64(f1_2) * int64(g1) + f1g2 := int64(f1) * int64(g2) + f1g3_2 := int64(f1_2) * int64(g3) + f1g4 := int64(f1) * int64(g4) + f1g5_2 := int64(f1_2) * int64(g5) + f1g6 := int64(f1) * int64(g6) + f1g7_2 := int64(f1_2) * int64(g7) + f1g8 := int64(f1) * int64(g8) + f1g9_38 := int64(f1_2) * int64(g9_19) + f2g0 := int64(f2) * int64(g0) + f2g1 := int64(f2) * int64(g1) + f2g2 := int64(f2) * int64(g2) + f2g3 := int64(f2) * int64(g3) + f2g4 := int64(f2) * int64(g4) + f2g5 := int64(f2) * int64(g5) + f2g6 := int64(f2) * int64(g6) + f2g7 := int64(f2) * int64(g7) + f2g8_19 := int64(f2) * int64(g8_19) + f2g9_19 := int64(f2) * int64(g9_19) + f3g0 := int64(f3) * int64(g0) + f3g1_2 := int64(f3_2) * int64(g1) + f3g2 := int64(f3) * int64(g2) + f3g3_2 := int64(f3_2) * int64(g3) + f3g4 := int64(f3) * int64(g4) + f3g5_2 := int64(f3_2) * int64(g5) + f3g6 := int64(f3) * int64(g6) + f3g7_38 := int64(f3_2) * int64(g7_19) + f3g8_19 := int64(f3) * int64(g8_19) + f3g9_38 := int64(f3_2) * int64(g9_19) + f4g0 := int64(f4) * int64(g0) + f4g1 := int64(f4) * int64(g1) + f4g2 := int64(f4) * int64(g2) + f4g3 := int64(f4) * int64(g3) + f4g4 := int64(f4) * int64(g4) + f4g5 := int64(f4) * int64(g5) + f4g6_19 := int64(f4) * int64(g6_19) + f4g7_19 := int64(f4) * int64(g7_19) + f4g8_19 := int64(f4) * int64(g8_19) + f4g9_19 := int64(f4) * int64(g9_19) + f5g0 := int64(f5) * int64(g0) + f5g1_2 := int64(f5_2) * int64(g1) + f5g2 := int64(f5) * int64(g2) + f5g3_2 := int64(f5_2) * int64(g3) + f5g4 := int64(f5) * int64(g4) + f5g5_38 := int64(f5_2) * int64(g5_19) + f5g6_19 := int64(f5) * int64(g6_19) + f5g7_38 := int64(f5_2) * int64(g7_19) + f5g8_19 := int64(f5) * int64(g8_19) + f5g9_38 := int64(f5_2) * int64(g9_19) + f6g0 := int64(f6) * int64(g0) + f6g1 := int64(f6) * int64(g1) + f6g2 := int64(f6) * int64(g2) + f6g3 := int64(f6) * int64(g3) + f6g4_19 := int64(f6) * int64(g4_19) + f6g5_19 := int64(f6) * int64(g5_19) + f6g6_19 := int64(f6) * int64(g6_19) + f6g7_19 := int64(f6) * int64(g7_19) + f6g8_19 := int64(f6) * int64(g8_19) + f6g9_19 := int64(f6) * int64(g9_19) + f7g0 := int64(f7) * int64(g0) + f7g1_2 := int64(f7_2) * int64(g1) + f7g2 := int64(f7) * int64(g2) + f7g3_38 := int64(f7_2) * int64(g3_19) + f7g4_19 := int64(f7) * int64(g4_19) + f7g5_38 := int64(f7_2) * int64(g5_19) + f7g6_19 := int64(f7) * int64(g6_19) + f7g7_38 := int64(f7_2) * int64(g7_19) + f7g8_19 := int64(f7) * int64(g8_19) + f7g9_38 := int64(f7_2) * int64(g9_19) + f8g0 := int64(f8) * int64(g0) + f8g1 := int64(f8) * int64(g1) + f8g2_19 := int64(f8) * int64(g2_19) + f8g3_19 := int64(f8) * int64(g3_19) + f8g4_19 := int64(f8) * int64(g4_19) + f8g5_19 := int64(f8) * int64(g5_19) + f8g6_19 := int64(f8) * int64(g6_19) + f8g7_19 := int64(f8) * int64(g7_19) + f8g8_19 := int64(f8) * int64(g8_19) + f8g9_19 := int64(f8) * int64(g9_19) + f9g0 := int64(f9) * int64(g0) + f9g1_38 := int64(f9_2) * int64(g1_19) + f9g2_19 := int64(f9) * int64(g2_19) + f9g3_38 := int64(f9_2) * int64(g3_19) + f9g4_19 := int64(f9) * int64(g4_19) + f9g5_38 := int64(f9_2) * int64(g5_19) + f9g6_19 := int64(f9) * int64(g6_19) + f9g7_38 := int64(f9_2) * int64(g7_19) + f9g8_19 := int64(f9) * int64(g8_19) + f9g9_38 := int64(f9_2) * int64(g9_19) + h0 := f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38 + h1 := f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19 + h2 := f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38 + h3 := f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19 + h4 := f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38 + h5 := f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19 + h6 := f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38 + h7 := f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19 + h8 := f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38 + h9 := f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0 + var carry [10]int64 + + // |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38)) + // i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8 + // |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19)) + // i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9 + + carry[0] = (h0 + (1 << 25)) >> 26 + h1 += carry[0] + h0 -= carry[0] << 26 + carry[4] = (h4 + (1 << 25)) >> 26 + h5 += carry[4] + h4 -= carry[4] << 26 + // |h0| <= 2^25 + // |h4| <= 2^25 + // |h1| <= 1.51*2^58 + // |h5| <= 1.51*2^58 + + carry[1] = (h1 + (1 << 24)) >> 25 + h2 += carry[1] + h1 -= carry[1] << 25 + carry[5] = (h5 + (1 << 24)) >> 25 + h6 += carry[5] + h5 -= carry[5] << 25 + // |h1| <= 2^24; from now on fits into int32 + // |h5| <= 2^24; from now on fits into int32 + // |h2| <= 1.21*2^59 + // |h6| <= 1.21*2^59 + + carry[2] = (h2 + (1 << 25)) >> 26 + h3 += carry[2] + h2 -= carry[2] << 26 + carry[6] = (h6 + (1 << 25)) >> 26 + h7 += carry[6] + h6 -= carry[6] << 26 + // |h2| <= 2^25; from now on fits into int32 unchanged + // |h6| <= 2^25; from now on fits into int32 unchanged + // |h3| <= 1.51*2^58 + // |h7| <= 1.51*2^58 + + carry[3] = (h3 + (1 << 24)) >> 25 + h4 += carry[3] + h3 -= carry[3] << 25 + carry[7] = (h7 + (1 << 24)) >> 25 + h8 += carry[7] + h7 -= carry[7] << 25 + // |h3| <= 2^24; from now on fits into int32 unchanged + // |h7| <= 2^24; from now on fits into int32 unchanged + // |h4| <= 1.52*2^33 + // |h8| <= 1.52*2^33 + + carry[4] = (h4 + (1 << 25)) >> 26 + h5 += carry[4] + h4 -= carry[4] << 26 + carry[8] = (h8 + (1 << 25)) >> 26 + h9 += carry[8] + h8 -= carry[8] << 26 + // |h4| <= 2^25; from now on fits into int32 unchanged + // |h8| <= 2^25; from now on fits into int32 unchanged + // |h5| <= 1.01*2^24 + // |h9| <= 1.51*2^58 + + carry[9] = (h9 + (1 << 24)) >> 25 + h0 += carry[9] * 19 + h9 -= carry[9] << 25 + // |h9| <= 2^24; from now on fits into int32 unchanged + // |h0| <= 1.8*2^37 + + carry[0] = (h0 + (1 << 25)) >> 26 + h1 += carry[0] + h0 -= carry[0] << 26 + // |h0| <= 2^25; from now on fits into int32 unchanged + // |h1| <= 1.01*2^24 + + h[0] = int32(h0) + h[1] = int32(h1) + h[2] = int32(h2) + h[3] = int32(h3) + h[4] = int32(h4) + h[5] = int32(h5) + h[6] = int32(h6) + h[7] = int32(h7) + h[8] = int32(h8) + h[9] = int32(h9) +} + +// feSquare calculates h = f*f. Can overlap h with f. +// +// Preconditions: +// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +// +// Postconditions: +// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +func feSquare(h, f *fieldElement) { + f0 := f[0] + f1 := f[1] + f2 := f[2] + f3 := f[3] + f4 := f[4] + f5 := f[5] + f6 := f[6] + f7 := f[7] + f8 := f[8] + f9 := f[9] + f0_2 := 2 * f0 + f1_2 := 2 * f1 + f2_2 := 2 * f2 + f3_2 := 2 * f3 + f4_2 := 2 * f4 + f5_2 := 2 * f5 + f6_2 := 2 * f6 + f7_2 := 2 * f7 + f5_38 := 38 * f5 // 1.31*2^30 + f6_19 := 19 * f6 // 1.31*2^30 + f7_38 := 38 * f7 // 1.31*2^30 + f8_19 := 19 * f8 // 1.31*2^30 + f9_38 := 38 * f9 // 1.31*2^30 + f0f0 := int64(f0) * int64(f0) + f0f1_2 := int64(f0_2) * int64(f1) + f0f2_2 := int64(f0_2) * int64(f2) + f0f3_2 := int64(f0_2) * int64(f3) + f0f4_2 := int64(f0_2) * int64(f4) + f0f5_2 := int64(f0_2) * int64(f5) + f0f6_2 := int64(f0_2) * int64(f6) + f0f7_2 := int64(f0_2) * int64(f7) + f0f8_2 := int64(f0_2) * int64(f8) + f0f9_2 := int64(f0_2) * int64(f9) + f1f1_2 := int64(f1_2) * int64(f1) + f1f2_2 := int64(f1_2) * int64(f2) + f1f3_4 := int64(f1_2) * int64(f3_2) + f1f4_2 := int64(f1_2) * int64(f4) + f1f5_4 := int64(f1_2) * int64(f5_2) + f1f6_2 := int64(f1_2) * int64(f6) + f1f7_4 := int64(f1_2) * int64(f7_2) + f1f8_2 := int64(f1_2) * int64(f8) + f1f9_76 := int64(f1_2) * int64(f9_38) + f2f2 := int64(f2) * int64(f2) + f2f3_2 := int64(f2_2) * int64(f3) + f2f4_2 := int64(f2_2) * int64(f4) + f2f5_2 := int64(f2_2) * int64(f5) + f2f6_2 := int64(f2_2) * int64(f6) + f2f7_2 := int64(f2_2) * int64(f7) + f2f8_38 := int64(f2_2) * int64(f8_19) + f2f9_38 := int64(f2) * int64(f9_38) + f3f3_2 := int64(f3_2) * int64(f3) + f3f4_2 := int64(f3_2) * int64(f4) + f3f5_4 := int64(f3_2) * int64(f5_2) + f3f6_2 := int64(f3_2) * int64(f6) + f3f7_76 := int64(f3_2) * int64(f7_38) + f3f8_38 := int64(f3_2) * int64(f8_19) + f3f9_76 := int64(f3_2) * int64(f9_38) + f4f4 := int64(f4) * int64(f4) + f4f5_2 := int64(f4_2) * int64(f5) + f4f6_38 := int64(f4_2) * int64(f6_19) + f4f7_38 := int64(f4) * int64(f7_38) + f4f8_38 := int64(f4_2) * int64(f8_19) + f4f9_38 := int64(f4) * int64(f9_38) + f5f5_38 := int64(f5) * int64(f5_38) + f5f6_38 := int64(f5_2) * int64(f6_19) + f5f7_76 := int64(f5_2) * int64(f7_38) + f5f8_38 := int64(f5_2) * int64(f8_19) + f5f9_76 := int64(f5_2) * int64(f9_38) + f6f6_19 := int64(f6) * int64(f6_19) + f6f7_38 := int64(f6) * int64(f7_38) + f6f8_38 := int64(f6_2) * int64(f8_19) + f6f9_38 := int64(f6) * int64(f9_38) + f7f7_38 := int64(f7) * int64(f7_38) + f7f8_38 := int64(f7_2) * int64(f8_19) + f7f9_76 := int64(f7_2) * int64(f9_38) + f8f8_19 := int64(f8) * int64(f8_19) + f8f9_38 := int64(f8) * int64(f9_38) + f9f9_38 := int64(f9) * int64(f9_38) + h0 := f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38 + h1 := f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38 + h2 := f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19 + h3 := f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38 + h4 := f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38 + h5 := f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38 + h6 := f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19 + h7 := f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38 + h8 := f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38 + h9 := f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2 + var carry [10]int64 + + carry[0] = (h0 + (1 << 25)) >> 26 + h1 += carry[0] + h0 -= carry[0] << 26 + carry[4] = (h4 + (1 << 25)) >> 26 + h5 += carry[4] + h4 -= carry[4] << 26 + + carry[1] = (h1 + (1 << 24)) >> 25 + h2 += carry[1] + h1 -= carry[1] << 25 + carry[5] = (h5 + (1 << 24)) >> 25 + h6 += carry[5] + h5 -= carry[5] << 25 + + carry[2] = (h2 + (1 << 25)) >> 26 + h3 += carry[2] + h2 -= carry[2] << 26 + carry[6] = (h6 + (1 << 25)) >> 26 + h7 += carry[6] + h6 -= carry[6] << 26 + + carry[3] = (h3 + (1 << 24)) >> 25 + h4 += carry[3] + h3 -= carry[3] << 25 + carry[7] = (h7 + (1 << 24)) >> 25 + h8 += carry[7] + h7 -= carry[7] << 25 + + carry[4] = (h4 + (1 << 25)) >> 26 + h5 += carry[4] + h4 -= carry[4] << 26 + carry[8] = (h8 + (1 << 25)) >> 26 + h9 += carry[8] + h8 -= carry[8] << 26 + + carry[9] = (h9 + (1 << 24)) >> 25 + h0 += carry[9] * 19 + h9 -= carry[9] << 25 + + carry[0] = (h0 + (1 << 25)) >> 26 + h1 += carry[0] + h0 -= carry[0] << 26 + + h[0] = int32(h0) + h[1] = int32(h1) + h[2] = int32(h2) + h[3] = int32(h3) + h[4] = int32(h4) + h[5] = int32(h5) + h[6] = int32(h6) + h[7] = int32(h7) + h[8] = int32(h8) + h[9] = int32(h9) +} + +// feMul121666 calculates h = f * 121666. Can overlap h with f. +// +// Preconditions: +// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +// +// Postconditions: +// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +func feMul121666(h, f *fieldElement) { + h0 := int64(f[0]) * 121666 + h1 := int64(f[1]) * 121666 + h2 := int64(f[2]) * 121666 + h3 := int64(f[3]) * 121666 + h4 := int64(f[4]) * 121666 + h5 := int64(f[5]) * 121666 + h6 := int64(f[6]) * 121666 + h7 := int64(f[7]) * 121666 + h8 := int64(f[8]) * 121666 + h9 := int64(f[9]) * 121666 + var carry [10]int64 + + carry[9] = (h9 + (1 << 24)) >> 25 + h0 += carry[9] * 19 + h9 -= carry[9] << 25 + carry[1] = (h1 + (1 << 24)) >> 25 + h2 += carry[1] + h1 -= carry[1] << 25 + carry[3] = (h3 + (1 << 24)) >> 25 + h4 += carry[3] + h3 -= carry[3] << 25 + carry[5] = (h5 + (1 << 24)) >> 25 + h6 += carry[5] + h5 -= carry[5] << 25 + carry[7] = (h7 + (1 << 24)) >> 25 + h8 += carry[7] + h7 -= carry[7] << 25 + + carry[0] = (h0 + (1 << 25)) >> 26 + h1 += carry[0] + h0 -= carry[0] << 26 + carry[2] = (h2 + (1 << 25)) >> 26 + h3 += carry[2] + h2 -= carry[2] << 26 + carry[4] = (h4 + (1 << 25)) >> 26 + h5 += carry[4] + h4 -= carry[4] << 26 + carry[6] = (h6 + (1 << 25)) >> 26 + h7 += carry[6] + h6 -= carry[6] << 26 + carry[8] = (h8 + (1 << 25)) >> 26 + h9 += carry[8] + h8 -= carry[8] << 26 + + h[0] = int32(h0) + h[1] = int32(h1) + h[2] = int32(h2) + h[3] = int32(h3) + h[4] = int32(h4) + h[5] = int32(h5) + h[6] = int32(h6) + h[7] = int32(h7) + h[8] = int32(h8) + h[9] = int32(h9) +} + +// feInvert sets out = z^-1. +func feInvert(out, z *fieldElement) { + var t0, t1, t2, t3 fieldElement + var i int + + feSquare(&t0, z) + for i = 1; i < 1; i++ { + feSquare(&t0, &t0) + } + feSquare(&t1, &t0) + for i = 1; i < 2; i++ { + feSquare(&t1, &t1) + } + feMul(&t1, z, &t1) + feMul(&t0, &t0, &t1) + feSquare(&t2, &t0) + for i = 1; i < 1; i++ { + feSquare(&t2, &t2) + } + feMul(&t1, &t1, &t2) + feSquare(&t2, &t1) + for i = 1; i < 5; i++ { + feSquare(&t2, &t2) + } + feMul(&t1, &t2, &t1) + feSquare(&t2, &t1) + for i = 1; i < 10; i++ { + feSquare(&t2, &t2) + } + feMul(&t2, &t2, &t1) + feSquare(&t3, &t2) + for i = 1; i < 20; i++ { + feSquare(&t3, &t3) + } + feMul(&t2, &t3, &t2) + feSquare(&t2, &t2) + for i = 1; i < 10; i++ { + feSquare(&t2, &t2) + } + feMul(&t1, &t2, &t1) + feSquare(&t2, &t1) + for i = 1; i < 50; i++ { + feSquare(&t2, &t2) + } + feMul(&t2, &t2, &t1) + feSquare(&t3, &t2) + for i = 1; i < 100; i++ { + feSquare(&t3, &t3) + } + feMul(&t2, &t3, &t2) + feSquare(&t2, &t2) + for i = 1; i < 50; i++ { + feSquare(&t2, &t2) + } + feMul(&t1, &t2, &t1) + feSquare(&t1, &t1) + for i = 1; i < 5; i++ { + feSquare(&t1, &t1) + } + feMul(out, &t1, &t0) +} + +func scalarMult(out, in, base *[32]byte) { + var e [32]byte + + copy(e[:], in[:]) + e[0] &= 248 + e[31] &= 127 + e[31] |= 64 + + var x1, x2, z2, x3, z3, tmp0, tmp1 fieldElement + feFromBytes(&x1, base) + feOne(&x2) + feCopy(&x3, &x1) + feOne(&z3) + + swap := int32(0) + for pos := 254; pos >= 0; pos-- { + b := e[pos/8] >> uint(pos&7) + b &= 1 + swap ^= int32(b) + feCSwap(&x2, &x3, swap) + feCSwap(&z2, &z3, swap) + swap = int32(b) + + feSub(&tmp0, &x3, &z3) + feSub(&tmp1, &x2, &z2) + feAdd(&x2, &x2, &z2) + feAdd(&z2, &x3, &z3) + feMul(&z3, &tmp0, &x2) + feMul(&z2, &z2, &tmp1) + feSquare(&tmp0, &tmp1) + feSquare(&tmp1, &x2) + feAdd(&x3, &z3, &z2) + feSub(&z2, &z3, &z2) + feMul(&x2, &tmp1, &tmp0) + feSub(&tmp1, &tmp1, &tmp0) + feSquare(&z2, &z2) + feMul121666(&z3, &tmp1) + feSquare(&x3, &x3) + feAdd(&tmp0, &tmp0, &z3) + feMul(&z3, &x1, &z2) + feMul(&z2, &tmp1, &tmp0) + } + + feCSwap(&x2, &x3, swap) + feCSwap(&z2, &z3, swap) + + feInvert(&z2, &z2) + feMul(&x2, &x2, &z2) + feToBytes(out, &x2) +} diff --git a/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/curve25519_test.go b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/curve25519_test.go new file mode 100644 index 0000000..14b0ee8 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/curve25519_test.go @@ -0,0 +1,29 @@ +// Copyright 2012 The Go 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 curve25519 + +import ( + "fmt" + "testing" +) + +const expectedHex = "89161fde887b2b53de549af483940106ecc114d6982daa98256de23bdf77661a" + +func TestBaseScalarMult(t *testing.T) { + var a, b [32]byte + in := &a + out := &b + a[0] = 1 + + for i := 0; i < 200; i++ { + ScalarBaseMult(out, in) + in, out = out, in + } + + result := fmt.Sprintf("%x", in[:]) + if result != expectedHex { + t.Errorf("incorrect result: got %s, want %s", result, expectedHex) + } +} diff --git a/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/doc.go b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/doc.go new file mode 100644 index 0000000..ebeea3c --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/doc.go @@ -0,0 +1,23 @@ +// Copyright 2012 The Go 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 curve25519 provides an implementation of scalar multiplication on +// the elliptic curve known as curve25519. See http://cr.yp.to/ecdh.html +package curve25519 // import "golang.org/x/crypto/curve25519" + +// basePoint is the x coordinate of the generator of the curve. +var basePoint = [32]byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + +// ScalarMult sets dst to the product in*base where dst and base are the x +// coordinates of group points and all values are in little-endian form. +func ScalarMult(dst, in, base *[32]byte) { + scalarMult(dst, in, base) +} + +// ScalarBaseMult sets dst to the product in*base where dst and base are the x +// coordinates of group points, base is the standard generator and all values +// are in little-endian form. +func ScalarBaseMult(dst, in *[32]byte) { + ScalarMult(dst, in, &basePoint) +} diff --git a/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/freeze_amd64.s b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/freeze_amd64.s new file mode 100644 index 0000000..37599fa --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/freeze_amd64.s @@ -0,0 +1,94 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This code was translated into a form compatible with 6a from the public +// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html + +// +build amd64,!gccgo,!appengine + +// func freeze(inout *[5]uint64) +TEXT ·freeze(SB),7,$96-8 + MOVQ inout+0(FP), DI + + MOVQ SP,R11 + MOVQ $31,CX + NOTQ CX + ANDQ CX,SP + ADDQ $32,SP + + MOVQ R11,0(SP) + MOVQ R12,8(SP) + MOVQ R13,16(SP) + MOVQ R14,24(SP) + MOVQ R15,32(SP) + MOVQ BX,40(SP) + MOVQ BP,48(SP) + MOVQ 0(DI),SI + MOVQ 8(DI),DX + MOVQ 16(DI),CX + MOVQ 24(DI),R8 + MOVQ 32(DI),R9 + MOVQ ·REDMASK51(SB),AX + MOVQ AX,R10 + SUBQ $18,R10 + MOVQ $3,R11 +REDUCELOOP: + MOVQ SI,R12 + SHRQ $51,R12 + ANDQ AX,SI + ADDQ R12,DX + MOVQ DX,R12 + SHRQ $51,R12 + ANDQ AX,DX + ADDQ R12,CX + MOVQ CX,R12 + SHRQ $51,R12 + ANDQ AX,CX + ADDQ R12,R8 + MOVQ R8,R12 + SHRQ $51,R12 + ANDQ AX,R8 + ADDQ R12,R9 + MOVQ R9,R12 + SHRQ $51,R12 + ANDQ AX,R9 + IMUL3Q $19,R12,R12 + ADDQ R12,SI + SUBQ $1,R11 + JA REDUCELOOP + MOVQ $1,R12 + CMPQ R10,SI + CMOVQLT R11,R12 + CMPQ AX,DX + CMOVQNE R11,R12 + CMPQ AX,CX + CMOVQNE R11,R12 + CMPQ AX,R8 + CMOVQNE R11,R12 + CMPQ AX,R9 + CMOVQNE R11,R12 + NEGQ R12 + ANDQ R12,AX + ANDQ R12,R10 + SUBQ R10,SI + SUBQ AX,DX + SUBQ AX,CX + SUBQ AX,R8 + SUBQ AX,R9 + MOVQ SI,0(DI) + MOVQ DX,8(DI) + MOVQ CX,16(DI) + MOVQ R8,24(DI) + MOVQ R9,32(DI) + MOVQ 0(SP),R11 + MOVQ 8(SP),R12 + MOVQ 16(SP),R13 + MOVQ 24(SP),R14 + MOVQ 32(SP),R15 + MOVQ 40(SP),BX + MOVQ 48(SP),BP + MOVQ R11,SP + MOVQ DI,AX + MOVQ SI,DX + RET diff --git a/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s new file mode 100644 index 0000000..3949f9c --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s @@ -0,0 +1,1398 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This code was translated into a form compatible with 6a from the public +// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html + +// +build amd64,!gccgo,!appengine + +// func ladderstep(inout *[5][5]uint64) +TEXT ·ladderstep(SB),0,$384-8 + MOVQ inout+0(FP),DI + + MOVQ SP,R11 + MOVQ $31,CX + NOTQ CX + ANDQ CX,SP + ADDQ $32,SP + + MOVQ R11,0(SP) + MOVQ R12,8(SP) + MOVQ R13,16(SP) + MOVQ R14,24(SP) + MOVQ R15,32(SP) + MOVQ BX,40(SP) + MOVQ BP,48(SP) + MOVQ 40(DI),SI + MOVQ 48(DI),DX + MOVQ 56(DI),CX + MOVQ 64(DI),R8 + MOVQ 72(DI),R9 + MOVQ SI,AX + MOVQ DX,R10 + MOVQ CX,R11 + MOVQ R8,R12 + MOVQ R9,R13 + ADDQ ·_2P0(SB),AX + ADDQ ·_2P1234(SB),R10 + ADDQ ·_2P1234(SB),R11 + ADDQ ·_2P1234(SB),R12 + ADDQ ·_2P1234(SB),R13 + ADDQ 80(DI),SI + ADDQ 88(DI),DX + ADDQ 96(DI),CX + ADDQ 104(DI),R8 + ADDQ 112(DI),R9 + SUBQ 80(DI),AX + SUBQ 88(DI),R10 + SUBQ 96(DI),R11 + SUBQ 104(DI),R12 + SUBQ 112(DI),R13 + MOVQ SI,56(SP) + MOVQ DX,64(SP) + MOVQ CX,72(SP) + MOVQ R8,80(SP) + MOVQ R9,88(SP) + MOVQ AX,96(SP) + MOVQ R10,104(SP) + MOVQ R11,112(SP) + MOVQ R12,120(SP) + MOVQ R13,128(SP) + MOVQ 96(SP),AX + MULQ 96(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 96(SP),AX + SHLQ $1,AX + MULQ 104(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 96(SP),AX + SHLQ $1,AX + MULQ 112(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 96(SP),AX + SHLQ $1,AX + MULQ 120(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 96(SP),AX + SHLQ $1,AX + MULQ 128(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 104(SP),AX + MULQ 104(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 104(SP),AX + SHLQ $1,AX + MULQ 112(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 104(SP),AX + SHLQ $1,AX + MULQ 120(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 104(SP),DX + IMUL3Q $38,DX,AX + MULQ 128(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 112(SP),AX + MULQ 112(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 112(SP),DX + IMUL3Q $38,DX,AX + MULQ 120(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 112(SP),DX + IMUL3Q $38,DX,AX + MULQ 128(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 120(SP),DX + IMUL3Q $19,DX,AX + MULQ 120(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 120(SP),DX + IMUL3Q $38,DX,AX + MULQ 128(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 128(SP),DX + IMUL3Q $19,DX,AX + MULQ 128(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ ·REDMASK51(SB),DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + ANDQ DX,SI + MOVQ CX,R8 + SHRQ $51,CX + ADDQ R10,CX + ANDQ DX,R8 + MOVQ CX,R9 + SHRQ $51,CX + ADDQ R12,CX + ANDQ DX,R9 + MOVQ CX,AX + SHRQ $51,CX + ADDQ R14,CX + ANDQ DX,AX + MOVQ CX,R10 + SHRQ $51,CX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,136(SP) + MOVQ R8,144(SP) + MOVQ R9,152(SP) + MOVQ AX,160(SP) + MOVQ R10,168(SP) + MOVQ 56(SP),AX + MULQ 56(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 56(SP),AX + SHLQ $1,AX + MULQ 64(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 56(SP),AX + SHLQ $1,AX + MULQ 72(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 56(SP),AX + SHLQ $1,AX + MULQ 80(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 56(SP),AX + SHLQ $1,AX + MULQ 88(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 64(SP),AX + MULQ 64(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 64(SP),AX + SHLQ $1,AX + MULQ 72(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 64(SP),AX + SHLQ $1,AX + MULQ 80(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 64(SP),DX + IMUL3Q $38,DX,AX + MULQ 88(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 72(SP),AX + MULQ 72(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 72(SP),DX + IMUL3Q $38,DX,AX + MULQ 80(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 72(SP),DX + IMUL3Q $38,DX,AX + MULQ 88(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 80(SP),DX + IMUL3Q $19,DX,AX + MULQ 80(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 80(SP),DX + IMUL3Q $38,DX,AX + MULQ 88(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 88(SP),DX + IMUL3Q $19,DX,AX + MULQ 88(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ ·REDMASK51(SB),DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + ANDQ DX,SI + MOVQ CX,R8 + SHRQ $51,CX + ADDQ R10,CX + ANDQ DX,R8 + MOVQ CX,R9 + SHRQ $51,CX + ADDQ R12,CX + ANDQ DX,R9 + MOVQ CX,AX + SHRQ $51,CX + ADDQ R14,CX + ANDQ DX,AX + MOVQ CX,R10 + SHRQ $51,CX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,176(SP) + MOVQ R8,184(SP) + MOVQ R9,192(SP) + MOVQ AX,200(SP) + MOVQ R10,208(SP) + MOVQ SI,SI + MOVQ R8,DX + MOVQ R9,CX + MOVQ AX,R8 + MOVQ R10,R9 + ADDQ ·_2P0(SB),SI + ADDQ ·_2P1234(SB),DX + ADDQ ·_2P1234(SB),CX + ADDQ ·_2P1234(SB),R8 + ADDQ ·_2P1234(SB),R9 + SUBQ 136(SP),SI + SUBQ 144(SP),DX + SUBQ 152(SP),CX + SUBQ 160(SP),R8 + SUBQ 168(SP),R9 + MOVQ SI,216(SP) + MOVQ DX,224(SP) + MOVQ CX,232(SP) + MOVQ R8,240(SP) + MOVQ R9,248(SP) + MOVQ 120(DI),SI + MOVQ 128(DI),DX + MOVQ 136(DI),CX + MOVQ 144(DI),R8 + MOVQ 152(DI),R9 + MOVQ SI,AX + MOVQ DX,R10 + MOVQ CX,R11 + MOVQ R8,R12 + MOVQ R9,R13 + ADDQ ·_2P0(SB),AX + ADDQ ·_2P1234(SB),R10 + ADDQ ·_2P1234(SB),R11 + ADDQ ·_2P1234(SB),R12 + ADDQ ·_2P1234(SB),R13 + ADDQ 160(DI),SI + ADDQ 168(DI),DX + ADDQ 176(DI),CX + ADDQ 184(DI),R8 + ADDQ 192(DI),R9 + SUBQ 160(DI),AX + SUBQ 168(DI),R10 + SUBQ 176(DI),R11 + SUBQ 184(DI),R12 + SUBQ 192(DI),R13 + MOVQ SI,256(SP) + MOVQ DX,264(SP) + MOVQ CX,272(SP) + MOVQ R8,280(SP) + MOVQ R9,288(SP) + MOVQ AX,296(SP) + MOVQ R10,304(SP) + MOVQ R11,312(SP) + MOVQ R12,320(SP) + MOVQ R13,328(SP) + MOVQ 280(SP),SI + IMUL3Q $19,SI,AX + MOVQ AX,336(SP) + MULQ 112(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 288(SP),DX + IMUL3Q $19,DX,AX + MOVQ AX,344(SP) + MULQ 104(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 256(SP),AX + MULQ 96(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 256(SP),AX + MULQ 104(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 256(SP),AX + MULQ 112(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 256(SP),AX + MULQ 120(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 256(SP),AX + MULQ 128(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 264(SP),AX + MULQ 96(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 264(SP),AX + MULQ 104(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 264(SP),AX + MULQ 112(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 264(SP),AX + MULQ 120(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 264(SP),DX + IMUL3Q $19,DX,AX + MULQ 128(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 272(SP),AX + MULQ 96(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 272(SP),AX + MULQ 104(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 272(SP),AX + MULQ 112(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 272(SP),DX + IMUL3Q $19,DX,AX + MULQ 120(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 272(SP),DX + IMUL3Q $19,DX,AX + MULQ 128(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 280(SP),AX + MULQ 96(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 280(SP),AX + MULQ 104(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 336(SP),AX + MULQ 120(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 336(SP),AX + MULQ 128(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 288(SP),AX + MULQ 96(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 344(SP),AX + MULQ 112(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 344(SP),AX + MULQ 120(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 344(SP),AX + MULQ 128(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ ·REDMASK51(SB),DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + MOVQ CX,R8 + SHRQ $51,CX + ANDQ DX,SI + ADDQ R10,CX + MOVQ CX,R9 + SHRQ $51,CX + ANDQ DX,R8 + ADDQ R12,CX + MOVQ CX,AX + SHRQ $51,CX + ANDQ DX,R9 + ADDQ R14,CX + MOVQ CX,R10 + SHRQ $51,CX + ANDQ DX,AX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,96(SP) + MOVQ R8,104(SP) + MOVQ R9,112(SP) + MOVQ AX,120(SP) + MOVQ R10,128(SP) + MOVQ 320(SP),SI + IMUL3Q $19,SI,AX + MOVQ AX,256(SP) + MULQ 72(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 328(SP),DX + IMUL3Q $19,DX,AX + MOVQ AX,264(SP) + MULQ 64(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 296(SP),AX + MULQ 56(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 296(SP),AX + MULQ 64(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 296(SP),AX + MULQ 72(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 296(SP),AX + MULQ 80(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 296(SP),AX + MULQ 88(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 304(SP),AX + MULQ 56(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 304(SP),AX + MULQ 64(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 304(SP),AX + MULQ 72(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 304(SP),AX + MULQ 80(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 304(SP),DX + IMUL3Q $19,DX,AX + MULQ 88(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 312(SP),AX + MULQ 56(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 312(SP),AX + MULQ 64(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 312(SP),AX + MULQ 72(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 312(SP),DX + IMUL3Q $19,DX,AX + MULQ 80(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 312(SP),DX + IMUL3Q $19,DX,AX + MULQ 88(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 320(SP),AX + MULQ 56(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 320(SP),AX + MULQ 64(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 256(SP),AX + MULQ 80(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 256(SP),AX + MULQ 88(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 328(SP),AX + MULQ 56(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 264(SP),AX + MULQ 72(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 264(SP),AX + MULQ 80(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 264(SP),AX + MULQ 88(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ ·REDMASK51(SB),DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + MOVQ CX,R8 + SHRQ $51,CX + ANDQ DX,SI + ADDQ R10,CX + MOVQ CX,R9 + SHRQ $51,CX + ANDQ DX,R8 + ADDQ R12,CX + MOVQ CX,AX + SHRQ $51,CX + ANDQ DX,R9 + ADDQ R14,CX + MOVQ CX,R10 + SHRQ $51,CX + ANDQ DX,AX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,DX + MOVQ R8,CX + MOVQ R9,R11 + MOVQ AX,R12 + MOVQ R10,R13 + ADDQ ·_2P0(SB),DX + ADDQ ·_2P1234(SB),CX + ADDQ ·_2P1234(SB),R11 + ADDQ ·_2P1234(SB),R12 + ADDQ ·_2P1234(SB),R13 + ADDQ 96(SP),SI + ADDQ 104(SP),R8 + ADDQ 112(SP),R9 + ADDQ 120(SP),AX + ADDQ 128(SP),R10 + SUBQ 96(SP),DX + SUBQ 104(SP),CX + SUBQ 112(SP),R11 + SUBQ 120(SP),R12 + SUBQ 128(SP),R13 + MOVQ SI,120(DI) + MOVQ R8,128(DI) + MOVQ R9,136(DI) + MOVQ AX,144(DI) + MOVQ R10,152(DI) + MOVQ DX,160(DI) + MOVQ CX,168(DI) + MOVQ R11,176(DI) + MOVQ R12,184(DI) + MOVQ R13,192(DI) + MOVQ 120(DI),AX + MULQ 120(DI) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 120(DI),AX + SHLQ $1,AX + MULQ 128(DI) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 120(DI),AX + SHLQ $1,AX + MULQ 136(DI) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 120(DI),AX + SHLQ $1,AX + MULQ 144(DI) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 120(DI),AX + SHLQ $1,AX + MULQ 152(DI) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 128(DI),AX + MULQ 128(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 128(DI),AX + SHLQ $1,AX + MULQ 136(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 128(DI),AX + SHLQ $1,AX + MULQ 144(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 128(DI),DX + IMUL3Q $38,DX,AX + MULQ 152(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 136(DI),AX + MULQ 136(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 136(DI),DX + IMUL3Q $38,DX,AX + MULQ 144(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 136(DI),DX + IMUL3Q $38,DX,AX + MULQ 152(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 144(DI),DX + IMUL3Q $19,DX,AX + MULQ 144(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 144(DI),DX + IMUL3Q $38,DX,AX + MULQ 152(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 152(DI),DX + IMUL3Q $19,DX,AX + MULQ 152(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ ·REDMASK51(SB),DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + ANDQ DX,SI + MOVQ CX,R8 + SHRQ $51,CX + ADDQ R10,CX + ANDQ DX,R8 + MOVQ CX,R9 + SHRQ $51,CX + ADDQ R12,CX + ANDQ DX,R9 + MOVQ CX,AX + SHRQ $51,CX + ADDQ R14,CX + ANDQ DX,AX + MOVQ CX,R10 + SHRQ $51,CX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,120(DI) + MOVQ R8,128(DI) + MOVQ R9,136(DI) + MOVQ AX,144(DI) + MOVQ R10,152(DI) + MOVQ 160(DI),AX + MULQ 160(DI) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 160(DI),AX + SHLQ $1,AX + MULQ 168(DI) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 160(DI),AX + SHLQ $1,AX + MULQ 176(DI) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 160(DI),AX + SHLQ $1,AX + MULQ 184(DI) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 160(DI),AX + SHLQ $1,AX + MULQ 192(DI) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 168(DI),AX + MULQ 168(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 168(DI),AX + SHLQ $1,AX + MULQ 176(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 168(DI),AX + SHLQ $1,AX + MULQ 184(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 168(DI),DX + IMUL3Q $38,DX,AX + MULQ 192(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 176(DI),AX + MULQ 176(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 176(DI),DX + IMUL3Q $38,DX,AX + MULQ 184(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 176(DI),DX + IMUL3Q $38,DX,AX + MULQ 192(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 184(DI),DX + IMUL3Q $19,DX,AX + MULQ 184(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 184(DI),DX + IMUL3Q $38,DX,AX + MULQ 192(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 192(DI),DX + IMUL3Q $19,DX,AX + MULQ 192(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ ·REDMASK51(SB),DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + ANDQ DX,SI + MOVQ CX,R8 + SHRQ $51,CX + ADDQ R10,CX + ANDQ DX,R8 + MOVQ CX,R9 + SHRQ $51,CX + ADDQ R12,CX + ANDQ DX,R9 + MOVQ CX,AX + SHRQ $51,CX + ADDQ R14,CX + ANDQ DX,AX + MOVQ CX,R10 + SHRQ $51,CX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,160(DI) + MOVQ R8,168(DI) + MOVQ R9,176(DI) + MOVQ AX,184(DI) + MOVQ R10,192(DI) + MOVQ 184(DI),SI + IMUL3Q $19,SI,AX + MOVQ AX,56(SP) + MULQ 16(DI) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 192(DI),DX + IMUL3Q $19,DX,AX + MOVQ AX,64(SP) + MULQ 8(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 160(DI),AX + MULQ 0(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 160(DI),AX + MULQ 8(DI) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 160(DI),AX + MULQ 16(DI) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 160(DI),AX + MULQ 24(DI) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 160(DI),AX + MULQ 32(DI) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 168(DI),AX + MULQ 0(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 168(DI),AX + MULQ 8(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 168(DI),AX + MULQ 16(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 168(DI),AX + MULQ 24(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 168(DI),DX + IMUL3Q $19,DX,AX + MULQ 32(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 176(DI),AX + MULQ 0(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 176(DI),AX + MULQ 8(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 176(DI),AX + MULQ 16(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 176(DI),DX + IMUL3Q $19,DX,AX + MULQ 24(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 176(DI),DX + IMUL3Q $19,DX,AX + MULQ 32(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 184(DI),AX + MULQ 0(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 184(DI),AX + MULQ 8(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 56(SP),AX + MULQ 24(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 56(SP),AX + MULQ 32(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 192(DI),AX + MULQ 0(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 64(SP),AX + MULQ 16(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 64(SP),AX + MULQ 24(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 64(SP),AX + MULQ 32(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ ·REDMASK51(SB),DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + MOVQ CX,R8 + SHRQ $51,CX + ANDQ DX,SI + ADDQ R10,CX + MOVQ CX,R9 + SHRQ $51,CX + ANDQ DX,R8 + ADDQ R12,CX + MOVQ CX,AX + SHRQ $51,CX + ANDQ DX,R9 + ADDQ R14,CX + MOVQ CX,R10 + SHRQ $51,CX + ANDQ DX,AX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,160(DI) + MOVQ R8,168(DI) + MOVQ R9,176(DI) + MOVQ AX,184(DI) + MOVQ R10,192(DI) + MOVQ 200(SP),SI + IMUL3Q $19,SI,AX + MOVQ AX,56(SP) + MULQ 152(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 208(SP),DX + IMUL3Q $19,DX,AX + MOVQ AX,64(SP) + MULQ 144(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 176(SP),AX + MULQ 136(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 176(SP),AX + MULQ 144(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 176(SP),AX + MULQ 152(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 176(SP),AX + MULQ 160(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 176(SP),AX + MULQ 168(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 184(SP),AX + MULQ 136(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 184(SP),AX + MULQ 144(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 184(SP),AX + MULQ 152(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 184(SP),AX + MULQ 160(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 184(SP),DX + IMUL3Q $19,DX,AX + MULQ 168(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 192(SP),AX + MULQ 136(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 192(SP),AX + MULQ 144(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 192(SP),AX + MULQ 152(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 192(SP),DX + IMUL3Q $19,DX,AX + MULQ 160(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 192(SP),DX + IMUL3Q $19,DX,AX + MULQ 168(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 200(SP),AX + MULQ 136(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 200(SP),AX + MULQ 144(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 56(SP),AX + MULQ 160(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 56(SP),AX + MULQ 168(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 208(SP),AX + MULQ 136(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 64(SP),AX + MULQ 152(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 64(SP),AX + MULQ 160(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 64(SP),AX + MULQ 168(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ ·REDMASK51(SB),DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + MOVQ CX,R8 + SHRQ $51,CX + ANDQ DX,SI + ADDQ R10,CX + MOVQ CX,R9 + SHRQ $51,CX + ANDQ DX,R8 + ADDQ R12,CX + MOVQ CX,AX + SHRQ $51,CX + ANDQ DX,R9 + ADDQ R14,CX + MOVQ CX,R10 + SHRQ $51,CX + ANDQ DX,AX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,40(DI) + MOVQ R8,48(DI) + MOVQ R9,56(DI) + MOVQ AX,64(DI) + MOVQ R10,72(DI) + MOVQ 216(SP),AX + MULQ ·_121666_213(SB) + SHRQ $13,AX + MOVQ AX,SI + MOVQ DX,CX + MOVQ 224(SP),AX + MULQ ·_121666_213(SB) + SHRQ $13,AX + ADDQ AX,CX + MOVQ DX,R8 + MOVQ 232(SP),AX + MULQ ·_121666_213(SB) + SHRQ $13,AX + ADDQ AX,R8 + MOVQ DX,R9 + MOVQ 240(SP),AX + MULQ ·_121666_213(SB) + SHRQ $13,AX + ADDQ AX,R9 + MOVQ DX,R10 + MOVQ 248(SP),AX + MULQ ·_121666_213(SB) + SHRQ $13,AX + ADDQ AX,R10 + IMUL3Q $19,DX,DX + ADDQ DX,SI + ADDQ 136(SP),SI + ADDQ 144(SP),CX + ADDQ 152(SP),R8 + ADDQ 160(SP),R9 + ADDQ 168(SP),R10 + MOVQ SI,80(DI) + MOVQ CX,88(DI) + MOVQ R8,96(DI) + MOVQ R9,104(DI) + MOVQ R10,112(DI) + MOVQ 104(DI),SI + IMUL3Q $19,SI,AX + MOVQ AX,56(SP) + MULQ 232(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 112(DI),DX + IMUL3Q $19,DX,AX + MOVQ AX,64(SP) + MULQ 224(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 80(DI),AX + MULQ 216(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 80(DI),AX + MULQ 224(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 80(DI),AX + MULQ 232(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 80(DI),AX + MULQ 240(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 80(DI),AX + MULQ 248(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 88(DI),AX + MULQ 216(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 88(DI),AX + MULQ 224(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 88(DI),AX + MULQ 232(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 88(DI),AX + MULQ 240(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 88(DI),DX + IMUL3Q $19,DX,AX + MULQ 248(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 96(DI),AX + MULQ 216(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 96(DI),AX + MULQ 224(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 96(DI),AX + MULQ 232(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 96(DI),DX + IMUL3Q $19,DX,AX + MULQ 240(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 96(DI),DX + IMUL3Q $19,DX,AX + MULQ 248(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 104(DI),AX + MULQ 216(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 104(DI),AX + MULQ 224(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 56(SP),AX + MULQ 240(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 56(SP),AX + MULQ 248(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 112(DI),AX + MULQ 216(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 64(SP),AX + MULQ 232(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 64(SP),AX + MULQ 240(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 64(SP),AX + MULQ 248(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ ·REDMASK51(SB),DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + MOVQ CX,R8 + SHRQ $51,CX + ANDQ DX,SI + ADDQ R10,CX + MOVQ CX,R9 + SHRQ $51,CX + ANDQ DX,R8 + ADDQ R12,CX + MOVQ CX,AX + SHRQ $51,CX + ANDQ DX,R9 + ADDQ R14,CX + MOVQ CX,R10 + SHRQ $51,CX + ANDQ DX,AX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,80(DI) + MOVQ R8,88(DI) + MOVQ R9,96(DI) + MOVQ AX,104(DI) + MOVQ R10,112(DI) + MOVQ 0(SP),R11 + MOVQ 8(SP),R12 + MOVQ 16(SP),R13 + MOVQ 24(SP),R14 + MOVQ 32(SP),R15 + MOVQ 40(SP),BX + MOVQ 48(SP),BP + MOVQ R11,SP + MOVQ DI,AX + MOVQ SI,DX + RET diff --git a/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go new file mode 100644 index 0000000..5822bd5 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go @@ -0,0 +1,240 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build amd64,!gccgo,!appengine + +package curve25519 + +// These functions are implemented in the .s files. The names of the functions +// in the rest of the file are also taken from the SUPERCOP sources to help +// people following along. + +//go:noescape + +func cswap(inout *[5]uint64, v uint64) + +//go:noescape + +func ladderstep(inout *[5][5]uint64) + +//go:noescape + +func freeze(inout *[5]uint64) + +//go:noescape + +func mul(dest, a, b *[5]uint64) + +//go:noescape + +func square(out, in *[5]uint64) + +// mladder uses a Montgomery ladder to calculate (xr/zr) *= s. +func mladder(xr, zr *[5]uint64, s *[32]byte) { + var work [5][5]uint64 + + work[0] = *xr + setint(&work[1], 1) + setint(&work[2], 0) + work[3] = *xr + setint(&work[4], 1) + + j := uint(6) + var prevbit byte + + for i := 31; i >= 0; i-- { + for j < 8 { + bit := ((*s)[i] >> j) & 1 + swap := bit ^ prevbit + prevbit = bit + cswap(&work[1], uint64(swap)) + ladderstep(&work) + j-- + } + j = 7 + } + + *xr = work[1] + *zr = work[2] +} + +func scalarMult(out, in, base *[32]byte) { + var e [32]byte + copy(e[:], (*in)[:]) + e[0] &= 248 + e[31] &= 127 + e[31] |= 64 + + var t, z [5]uint64 + unpack(&t, base) + mladder(&t, &z, &e) + invert(&z, &z) + mul(&t, &t, &z) + pack(out, &t) +} + +func setint(r *[5]uint64, v uint64) { + r[0] = v + r[1] = 0 + r[2] = 0 + r[3] = 0 + r[4] = 0 +} + +// unpack sets r = x where r consists of 5, 51-bit limbs in little-endian +// order. +func unpack(r *[5]uint64, x *[32]byte) { + r[0] = uint64(x[0]) | + uint64(x[1])<<8 | + uint64(x[2])<<16 | + uint64(x[3])<<24 | + uint64(x[4])<<32 | + uint64(x[5])<<40 | + uint64(x[6]&7)<<48 + + r[1] = uint64(x[6])>>3 | + uint64(x[7])<<5 | + uint64(x[8])<<13 | + uint64(x[9])<<21 | + uint64(x[10])<<29 | + uint64(x[11])<<37 | + uint64(x[12]&63)<<45 + + r[2] = uint64(x[12])>>6 | + uint64(x[13])<<2 | + uint64(x[14])<<10 | + uint64(x[15])<<18 | + uint64(x[16])<<26 | + uint64(x[17])<<34 | + uint64(x[18])<<42 | + uint64(x[19]&1)<<50 + + r[3] = uint64(x[19])>>1 | + uint64(x[20])<<7 | + uint64(x[21])<<15 | + uint64(x[22])<<23 | + uint64(x[23])<<31 | + uint64(x[24])<<39 | + uint64(x[25]&15)<<47 + + r[4] = uint64(x[25])>>4 | + uint64(x[26])<<4 | + uint64(x[27])<<12 | + uint64(x[28])<<20 | + uint64(x[29])<<28 | + uint64(x[30])<<36 | + uint64(x[31]&127)<<44 +} + +// pack sets out = x where out is the usual, little-endian form of the 5, +// 51-bit limbs in x. +func pack(out *[32]byte, x *[5]uint64) { + t := *x + freeze(&t) + + out[0] = byte(t[0]) + out[1] = byte(t[0] >> 8) + out[2] = byte(t[0] >> 16) + out[3] = byte(t[0] >> 24) + out[4] = byte(t[0] >> 32) + out[5] = byte(t[0] >> 40) + out[6] = byte(t[0] >> 48) + + out[6] ^= byte(t[1]<<3) & 0xf8 + out[7] = byte(t[1] >> 5) + out[8] = byte(t[1] >> 13) + out[9] = byte(t[1] >> 21) + out[10] = byte(t[1] >> 29) + out[11] = byte(t[1] >> 37) + out[12] = byte(t[1] >> 45) + + out[12] ^= byte(t[2]<<6) & 0xc0 + out[13] = byte(t[2] >> 2) + out[14] = byte(t[2] >> 10) + out[15] = byte(t[2] >> 18) + out[16] = byte(t[2] >> 26) + out[17] = byte(t[2] >> 34) + out[18] = byte(t[2] >> 42) + out[19] = byte(t[2] >> 50) + + out[19] ^= byte(t[3]<<1) & 0xfe + out[20] = byte(t[3] >> 7) + out[21] = byte(t[3] >> 15) + out[22] = byte(t[3] >> 23) + out[23] = byte(t[3] >> 31) + out[24] = byte(t[3] >> 39) + out[25] = byte(t[3] >> 47) + + out[25] ^= byte(t[4]<<4) & 0xf0 + out[26] = byte(t[4] >> 4) + out[27] = byte(t[4] >> 12) + out[28] = byte(t[4] >> 20) + out[29] = byte(t[4] >> 28) + out[30] = byte(t[4] >> 36) + out[31] = byte(t[4] >> 44) +} + +// invert calculates r = x^-1 mod p using Fermat's little theorem. +func invert(r *[5]uint64, x *[5]uint64) { + var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t [5]uint64 + + square(&z2, x) /* 2 */ + square(&t, &z2) /* 4 */ + square(&t, &t) /* 8 */ + mul(&z9, &t, x) /* 9 */ + mul(&z11, &z9, &z2) /* 11 */ + square(&t, &z11) /* 22 */ + mul(&z2_5_0, &t, &z9) /* 2^5 - 2^0 = 31 */ + + square(&t, &z2_5_0) /* 2^6 - 2^1 */ + for i := 1; i < 5; i++ { /* 2^20 - 2^10 */ + square(&t, &t) + } + mul(&z2_10_0, &t, &z2_5_0) /* 2^10 - 2^0 */ + + square(&t, &z2_10_0) /* 2^11 - 2^1 */ + for i := 1; i < 10; i++ { /* 2^20 - 2^10 */ + square(&t, &t) + } + mul(&z2_20_0, &t, &z2_10_0) /* 2^20 - 2^0 */ + + square(&t, &z2_20_0) /* 2^21 - 2^1 */ + for i := 1; i < 20; i++ { /* 2^40 - 2^20 */ + square(&t, &t) + } + mul(&t, &t, &z2_20_0) /* 2^40 - 2^0 */ + + square(&t, &t) /* 2^41 - 2^1 */ + for i := 1; i < 10; i++ { /* 2^50 - 2^10 */ + square(&t, &t) + } + mul(&z2_50_0, &t, &z2_10_0) /* 2^50 - 2^0 */ + + square(&t, &z2_50_0) /* 2^51 - 2^1 */ + for i := 1; i < 50; i++ { /* 2^100 - 2^50 */ + square(&t, &t) + } + mul(&z2_100_0, &t, &z2_50_0) /* 2^100 - 2^0 */ + + square(&t, &z2_100_0) /* 2^101 - 2^1 */ + for i := 1; i < 100; i++ { /* 2^200 - 2^100 */ + square(&t, &t) + } + mul(&t, &t, &z2_100_0) /* 2^200 - 2^0 */ + + square(&t, &t) /* 2^201 - 2^1 */ + for i := 1; i < 50; i++ { /* 2^250 - 2^50 */ + square(&t, &t) + } + mul(&t, &t, &z2_50_0) /* 2^250 - 2^0 */ + + square(&t, &t) /* 2^251 - 2^1 */ + square(&t, &t) /* 2^252 - 2^2 */ + square(&t, &t) /* 2^253 - 2^3 */ + + square(&t, &t) /* 2^254 - 2^4 */ + + square(&t, &t) /* 2^255 - 2^5 */ + mul(r, &t, &z11) /* 2^255 - 21 */ +} diff --git a/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/mul_amd64.s b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/mul_amd64.s new file mode 100644 index 0000000..e48d183 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/mul_amd64.s @@ -0,0 +1,191 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This code was translated into a form compatible with 6a from the public +// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html + +// +build amd64,!gccgo,!appengine + +// func mul(dest, a, b *[5]uint64) +TEXT ·mul(SB),0,$128-24 + MOVQ dest+0(FP), DI + MOVQ a+8(FP), SI + MOVQ b+16(FP), DX + + MOVQ SP,R11 + MOVQ $31,CX + NOTQ CX + ANDQ CX,SP + ADDQ $32,SP + + MOVQ R11,0(SP) + MOVQ R12,8(SP) + MOVQ R13,16(SP) + MOVQ R14,24(SP) + MOVQ R15,32(SP) + MOVQ BX,40(SP) + MOVQ BP,48(SP) + MOVQ DI,56(SP) + MOVQ DX,CX + MOVQ 24(SI),DX + IMUL3Q $19,DX,AX + MOVQ AX,64(SP) + MULQ 16(CX) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 32(SI),DX + IMUL3Q $19,DX,AX + MOVQ AX,72(SP) + MULQ 8(CX) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 0(SI),AX + MULQ 0(CX) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 0(SI),AX + MULQ 8(CX) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 0(SI),AX + MULQ 16(CX) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 0(SI),AX + MULQ 24(CX) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 0(SI),AX + MULQ 32(CX) + MOVQ AX,BX + MOVQ DX,BP + MOVQ 8(SI),AX + MULQ 0(CX) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 8(SI),AX + MULQ 8(CX) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 8(SI),AX + MULQ 16(CX) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 8(SI),AX + MULQ 24(CX) + ADDQ AX,BX + ADCQ DX,BP + MOVQ 8(SI),DX + IMUL3Q $19,DX,AX + MULQ 32(CX) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 16(SI),AX + MULQ 0(CX) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 16(SI),AX + MULQ 8(CX) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 16(SI),AX + MULQ 16(CX) + ADDQ AX,BX + ADCQ DX,BP + MOVQ 16(SI),DX + IMUL3Q $19,DX,AX + MULQ 24(CX) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 16(SI),DX + IMUL3Q $19,DX,AX + MULQ 32(CX) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 24(SI),AX + MULQ 0(CX) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 24(SI),AX + MULQ 8(CX) + ADDQ AX,BX + ADCQ DX,BP + MOVQ 64(SP),AX + MULQ 24(CX) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 64(SP),AX + MULQ 32(CX) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 32(SI),AX + MULQ 0(CX) + ADDQ AX,BX + ADCQ DX,BP + MOVQ 72(SP),AX + MULQ 16(CX) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 72(SP),AX + MULQ 24(CX) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 72(SP),AX + MULQ 32(CX) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ ·REDMASK51(SB),SI + SHLQ $13,R9:R8 + ANDQ SI,R8 + SHLQ $13,R11:R10 + ANDQ SI,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ SI,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ SI,R14 + ADDQ R13,R14 + SHLQ $13,BP:BX + ANDQ SI,BX + ADDQ R15,BX + IMUL3Q $19,BP,DX + ADDQ DX,R8 + MOVQ R8,DX + SHRQ $51,DX + ADDQ R10,DX + MOVQ DX,CX + SHRQ $51,DX + ANDQ SI,R8 + ADDQ R12,DX + MOVQ DX,R9 + SHRQ $51,DX + ANDQ SI,CX + ADDQ R14,DX + MOVQ DX,AX + SHRQ $51,DX + ANDQ SI,R9 + ADDQ BX,DX + MOVQ DX,R10 + SHRQ $51,DX + ANDQ SI,AX + IMUL3Q $19,DX,DX + ADDQ DX,R8 + ANDQ SI,R10 + MOVQ R8,0(DI) + MOVQ CX,8(DI) + MOVQ R9,16(DI) + MOVQ AX,24(DI) + MOVQ R10,32(DI) + MOVQ 0(SP),R11 + MOVQ 8(SP),R12 + MOVQ 16(SP),R13 + MOVQ 24(SP),R14 + MOVQ 32(SP),R15 + MOVQ 40(SP),BX + MOVQ 48(SP),BP + MOVQ R11,SP + MOVQ DI,AX + MOVQ SI,DX + RET diff --git a/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/square_amd64.s b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/square_amd64.s new file mode 100644 index 0000000..78d1a50 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/golang.org/x/crypto/curve25519/square_amd64.s @@ -0,0 +1,153 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This code was translated into a form compatible with 6a from the public +// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html + +// +build amd64,!gccgo,!appengine + +// func square(out, in *[5]uint64) +TEXT ·square(SB),7,$96-16 + MOVQ out+0(FP), DI + MOVQ in+8(FP), SI + + MOVQ SP,R11 + MOVQ $31,CX + NOTQ CX + ANDQ CX,SP + ADDQ $32, SP + + MOVQ R11,0(SP) + MOVQ R12,8(SP) + MOVQ R13,16(SP) + MOVQ R14,24(SP) + MOVQ R15,32(SP) + MOVQ BX,40(SP) + MOVQ BP,48(SP) + MOVQ 0(SI),AX + MULQ 0(SI) + MOVQ AX,CX + MOVQ DX,R8 + MOVQ 0(SI),AX + SHLQ $1,AX + MULQ 8(SI) + MOVQ AX,R9 + MOVQ DX,R10 + MOVQ 0(SI),AX + SHLQ $1,AX + MULQ 16(SI) + MOVQ AX,R11 + MOVQ DX,R12 + MOVQ 0(SI),AX + SHLQ $1,AX + MULQ 24(SI) + MOVQ AX,R13 + MOVQ DX,R14 + MOVQ 0(SI),AX + SHLQ $1,AX + MULQ 32(SI) + MOVQ AX,R15 + MOVQ DX,BX + MOVQ 8(SI),AX + MULQ 8(SI) + ADDQ AX,R11 + ADCQ DX,R12 + MOVQ 8(SI),AX + SHLQ $1,AX + MULQ 16(SI) + ADDQ AX,R13 + ADCQ DX,R14 + MOVQ 8(SI),AX + SHLQ $1,AX + MULQ 24(SI) + ADDQ AX,R15 + ADCQ DX,BX + MOVQ 8(SI),DX + IMUL3Q $38,DX,AX + MULQ 32(SI) + ADDQ AX,CX + ADCQ DX,R8 + MOVQ 16(SI),AX + MULQ 16(SI) + ADDQ AX,R15 + ADCQ DX,BX + MOVQ 16(SI),DX + IMUL3Q $38,DX,AX + MULQ 24(SI) + ADDQ AX,CX + ADCQ DX,R8 + MOVQ 16(SI),DX + IMUL3Q $38,DX,AX + MULQ 32(SI) + ADDQ AX,R9 + ADCQ DX,R10 + MOVQ 24(SI),DX + IMUL3Q $19,DX,AX + MULQ 24(SI) + ADDQ AX,R9 + ADCQ DX,R10 + MOVQ 24(SI),DX + IMUL3Q $38,DX,AX + MULQ 32(SI) + ADDQ AX,R11 + ADCQ DX,R12 + MOVQ 32(SI),DX + IMUL3Q $19,DX,AX + MULQ 32(SI) + ADDQ AX,R13 + ADCQ DX,R14 + MOVQ ·REDMASK51(SB),SI + SHLQ $13,R8:CX + ANDQ SI,CX + SHLQ $13,R10:R9 + ANDQ SI,R9 + ADDQ R8,R9 + SHLQ $13,R12:R11 + ANDQ SI,R11 + ADDQ R10,R11 + SHLQ $13,R14:R13 + ANDQ SI,R13 + ADDQ R12,R13 + SHLQ $13,BX:R15 + ANDQ SI,R15 + ADDQ R14,R15 + IMUL3Q $19,BX,DX + ADDQ DX,CX + MOVQ CX,DX + SHRQ $51,DX + ADDQ R9,DX + ANDQ SI,CX + MOVQ DX,R8 + SHRQ $51,DX + ADDQ R11,DX + ANDQ SI,R8 + MOVQ DX,R9 + SHRQ $51,DX + ADDQ R13,DX + ANDQ SI,R9 + MOVQ DX,AX + SHRQ $51,DX + ADDQ R15,DX + ANDQ SI,AX + MOVQ DX,R10 + SHRQ $51,DX + IMUL3Q $19,DX,DX + ADDQ DX,CX + ANDQ SI,R10 + MOVQ CX,0(DI) + MOVQ R8,8(DI) + MOVQ R9,16(DI) + MOVQ AX,24(DI) + MOVQ R10,32(DI) + MOVQ 0(SP),R11 + MOVQ 8(SP),R12 + MOVQ 16(SP),R13 + MOVQ 24(SP),R14 + MOVQ 32(SP),R15 + MOVQ 40(SP),BX + MOVQ 48(SP),BP + MOVQ R11,SP + MOVQ DI,AX + MOVQ SI,DX + RET diff --git a/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/LICENSE b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/LICENSE new file mode 100644 index 0000000..6ca207e --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/LICENSE @@ -0,0 +1,122 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. + diff --git a/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/README.md b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/README.md new file mode 100644 index 0000000..9080a84 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/README.md @@ -0,0 +1,14 @@ +### chacha20 - ChaCha20 +#### Yawning Angel (yawning at schwanenlied dot me) + +Yet another Go ChaCha20 implementation. Everything else I found was slow, +didn't support all the variants I need to use, or relied on cgo to go fast. + +Features: + + * 20 round, 256 bit key only. Everything else is pointless and stupid. + * IETF 96 bit nonce variant. + * XChaCha 24 byte nonce variant. + * SSE2 and AVX2 support on amd64 targets. + * Incremental encrypt/decrypt support, unlike golang.org/x/crypto/salsa20. + diff --git a/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20.go b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20.go new file mode 100644 index 0000000..07d5e4b --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20.go @@ -0,0 +1,273 @@ +// chacha20.go - A ChaCha stream cipher implementation. +// +// To the extent possible under law, Yawning Angel has waived all copyright +// and related or neighboring rights to chacha20, using the Creative +// Commons "CC0" public domain dedication. See LICENSE or +// for full details. + +package chacha20 + +import ( + "crypto/cipher" + "encoding/binary" + "errors" + "math" + "runtime" +) + +const ( + // KeySize is the ChaCha20 key size in bytes. + KeySize = 32 + + // NonceSize is the ChaCha20 nonce size in bytes. + NonceSize = 8 + + // INonceSize is the IETF ChaCha20 nonce size in bytes. + INonceSize = 12 + + // XNonceSize is the XChaCha20 nonce size in bytes. + XNonceSize = 24 + + // HNonceSize is the HChaCha20 nonce size in bytes. + HNonceSize = 16 + + // BlockSize is the ChaCha20 block size in bytes. + BlockSize = 64 + + stateSize = 16 + chachaRounds = 20 + + // The constant "expand 32-byte k" as little endian uint32s. + sigma0 = uint32(0x61707865) + sigma1 = uint32(0x3320646e) + sigma2 = uint32(0x79622d32) + sigma3 = uint32(0x6b206574) +) + +var ( + // ErrInvalidKey is the error returned when the key is invalid. + ErrInvalidKey = errors.New("key length must be KeySize bytes") + + // ErrInvalidNonce is the error returned when the nonce is invalid. + ErrInvalidNonce = errors.New("nonce length must be NonceSize/INonceSize/XNonceSize bytes") + + // ErrInvalidCounter is the error returned when the counter is invalid. + ErrInvalidCounter = errors.New("block counter is invalid (out of range)") + + useUnsafe = false + usingVectors = false + blocksFn = blocksRef +) + +// A Cipher is an instance of ChaCha20/XChaCha20 using a particular key and +// nonce. +type Cipher struct { + state [stateSize]uint32 + + buf [BlockSize]byte + off int + ietf bool +} + +// Reset zeros the key data so that it will no longer appear in the process's +// memory. +func (c *Cipher) Reset() { + for i := range c.state { + c.state[i] = 0 + } + for i := range c.buf { + c.buf[i] = 0 + } +} + +// XORKeyStream sets dst to the result of XORing src with the key stream. Dst +// and src may be the same slice but otherwise should not overlap. +func (c *Cipher) XORKeyStream(dst, src []byte) { + if len(dst) < len(src) { + src = src[:len(dst)] + } + + for remaining := len(src); remaining > 0; { + // Process multiple blocks at once. + if c.off == BlockSize { + nrBlocks := remaining / BlockSize + directBytes := nrBlocks * BlockSize + if nrBlocks > 0 { + blocksFn(&c.state, src, dst, nrBlocks, c.ietf) + remaining -= directBytes + if remaining == 0 { + return + } + dst = dst[directBytes:] + src = src[directBytes:] + } + + // If there's a partial block, generate 1 block of keystream into + // the internal buffer. + blocksFn(&c.state, nil, c.buf[:], 1, c.ietf) + c.off = 0 + } + + // Process partial blocks from the buffered keystream. + toXor := BlockSize - c.off + if remaining < toXor { + toXor = remaining + } + if toXor > 0 { + for i, v := range src[:toXor] { + dst[i] = v ^ c.buf[c.off+i] + } + dst = dst[toXor:] + src = src[toXor:] + + remaining -= toXor + c.off += toXor + } + } +} + +// KeyStream sets dst to the raw keystream. +func (c *Cipher) KeyStream(dst []byte) { + for remaining := len(dst); remaining > 0; { + // Process multiple blocks at once. + if c.off == BlockSize { + nrBlocks := remaining / BlockSize + directBytes := nrBlocks * BlockSize + if nrBlocks > 0 { + blocksFn(&c.state, nil, dst, nrBlocks, c.ietf) + remaining -= directBytes + if remaining == 0 { + return + } + dst = dst[directBytes:] + } + + // If there's a partial block, generate 1 block of keystream into + // the internal buffer. + blocksFn(&c.state, nil, c.buf[:], 1, c.ietf) + c.off = 0 + } + + // Process partial blocks from the buffered keystream. + toCopy := BlockSize - c.off + if remaining < toCopy { + toCopy = remaining + } + if toCopy > 0 { + copy(dst[:toCopy], c.buf[c.off:c.off+toCopy]) + dst = dst[toCopy:] + remaining -= toCopy + c.off += toCopy + } + } +} + +// ReKey reinitializes the ChaCha20/XChaCha20 instance with the provided key +// and nonce. +func (c *Cipher) ReKey(key, nonce []byte) error { + if len(key) != KeySize { + return ErrInvalidKey + } + + switch len(nonce) { + case NonceSize: + case INonceSize: + case XNonceSize: + var subkey [KeySize]byte + var subnonce [HNonceSize]byte + copy(subnonce[:], nonce[0:16]) + HChaCha(key, &subnonce, &subkey) + key = subkey[:] + nonce = nonce[16:24] + defer func() { + for i := range subkey { + subkey[i] = 0 + } + }() + default: + return ErrInvalidNonce + } + + c.Reset() + c.state[0] = sigma0 + c.state[1] = sigma1 + c.state[2] = sigma2 + c.state[3] = sigma3 + c.state[4] = binary.LittleEndian.Uint32(key[0:4]) + c.state[5] = binary.LittleEndian.Uint32(key[4:8]) + c.state[6] = binary.LittleEndian.Uint32(key[8:12]) + c.state[7] = binary.LittleEndian.Uint32(key[12:16]) + c.state[8] = binary.LittleEndian.Uint32(key[16:20]) + c.state[9] = binary.LittleEndian.Uint32(key[20:24]) + c.state[10] = binary.LittleEndian.Uint32(key[24:28]) + c.state[11] = binary.LittleEndian.Uint32(key[28:32]) + c.state[12] = 0 + if len(nonce) == INonceSize { + c.state[13] = binary.LittleEndian.Uint32(nonce[0:4]) + c.state[14] = binary.LittleEndian.Uint32(nonce[4:8]) + c.state[15] = binary.LittleEndian.Uint32(nonce[8:12]) + c.ietf = true + } else { + c.state[13] = 0 + c.state[14] = binary.LittleEndian.Uint32(nonce[0:4]) + c.state[15] = binary.LittleEndian.Uint32(nonce[4:8]) + c.ietf = false + } + c.off = BlockSize + return nil + +} + +// Seek sets the block counter to a given offset. +func (c *Cipher) Seek(blockCounter uint64) error { + if c.ietf { + if blockCounter > math.MaxUint32 { + return ErrInvalidCounter + } + c.state[12] = uint32(blockCounter) + } else { + c.state[12] = uint32(blockCounter) + c.state[13] = uint32(blockCounter >> 32) + } + c.off = BlockSize + return nil +} + +// NewCipher returns a new ChaCha20/XChaCha20 instance. +func NewCipher(key, nonce []byte) (*Cipher, error) { + c := new(Cipher) + if err := c.ReKey(key, nonce); err != nil { + return nil, err + } + return c, nil +} + +// HChaCha is the HChaCha20 hash function used to make XChaCha. +func HChaCha(key []byte, nonce *[HNonceSize]byte, out *[32]byte) { + var x [stateSize]uint32 // Last 4 slots unused, sigma hardcoded. + x[0] = binary.LittleEndian.Uint32(key[0:4]) + x[1] = binary.LittleEndian.Uint32(key[4:8]) + x[2] = binary.LittleEndian.Uint32(key[8:12]) + x[3] = binary.LittleEndian.Uint32(key[12:16]) + x[4] = binary.LittleEndian.Uint32(key[16:20]) + x[5] = binary.LittleEndian.Uint32(key[20:24]) + x[6] = binary.LittleEndian.Uint32(key[24:28]) + x[7] = binary.LittleEndian.Uint32(key[28:32]) + x[8] = binary.LittleEndian.Uint32(nonce[0:4]) + x[9] = binary.LittleEndian.Uint32(nonce[4:8]) + x[10] = binary.LittleEndian.Uint32(nonce[8:12]) + x[11] = binary.LittleEndian.Uint32(nonce[12:16]) + hChaChaRef(&x, out) +} + +func init() { + switch runtime.GOARCH { + case "386", "amd64": + // Abuse unsafe to skip calling binary.LittleEndian.PutUint32 + // in the critical path. This is a big boost on systems that are + // little endian and not overly picky about alignment. + useUnsafe = true + } +} + +var _ cipher.Stream = (*Cipher)(nil) diff --git a/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20_amd64.go b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20_amd64.go new file mode 100644 index 0000000..b2c8623 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20_amd64.go @@ -0,0 +1,95 @@ +// chacha20_amd64.go - AMD64 optimized chacha20. +// +// To the extent possible under law, Yawning Angel has waived all copyright +// and related or neighboring rights to chacha20, using the Creative +// Commons "CC0" public domain dedication. See LICENSE or +// for full details. + +// +build amd64,!gccgo,!appengine + +package chacha20 + +import ( + "math" +) + +var usingAVX2 = false + +func blocksAmd64SSE2(x *uint32, inp, outp *byte, nrBlocks uint) + +func blocksAmd64AVX2(x *uint32, inp, outp *byte, nrBlocks uint) + +func cpuidAmd64(cpuidParams *uint32) + +func xgetbv0Amd64(xcrVec *uint32) + +func blocksAmd64(x *[stateSize]uint32, in []byte, out []byte, nrBlocks int, isIetf bool) { + // Probably unneeded, but stating this explicitly simplifies the assembly. + if nrBlocks == 0 { + return + } + + if isIetf { + var totalBlocks uint64 + totalBlocks = uint64(x[8]) + uint64(nrBlocks) + if totalBlocks > math.MaxUint32 { + panic("chacha20: Exceeded keystream per nonce limit") + } + } + + if in == nil { + for i := range out { + out[i] = 0 + } + in = out + } + + // Pointless to call the AVX2 code for just a single block, since half of + // the output gets discarded... + if usingAVX2 && nrBlocks > 1 { + blocksAmd64AVX2(&x[0], &in[0], &out[0], uint(nrBlocks)) + } else { + blocksAmd64SSE2(&x[0], &in[0], &out[0], uint(nrBlocks)) + } +} + +func supportsAVX2() bool { + // https://software.intel.com/en-us/articles/how-to-detect-new-instruction-support-in-the-4th-generation-intel-core-processor-family + const ( + osXsaveBit = 1 << 27 + avx2Bit = 1 << 5 + ) + + // Check to see if CPUID actually supports the leaf that indicates AVX2. + // CPUID.(EAX=0H, ECX=0H) >= 7 + regs := [4]uint32{0x00} + cpuidAmd64(®s[0]) + if regs[0] < 7 { + return false + } + + // Check to see if the OS knows how to save/restore XMM/YMM state. + // CPUID.(EAX=01H, ECX=0H):ECX.OSXSAVE[bit 27]==1 + regs = [4]uint32{0x01} + cpuidAmd64(®s[0]) + if regs[2]&osXsaveBit == 0 { + return false + } + xcrRegs := [2]uint32{} + xgetbv0Amd64(&xcrRegs[0]) + if xcrRegs[0]&6 != 6 { + return false + } + + // Check for AVX2 support. + // CPUID.(EAX=07H, ECX=0H):EBX.AVX2[bit 5]==1 + regs = [4]uint32{0x07} + cpuidAmd64(®s[0]) + return regs[1]&avx2Bit != 0 +} + +func init() { + blocksFn = blocksAmd64 + usingVectors = true + usingAVX2 = supportsAVX2() +} diff --git a/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20_amd64.py b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20_amd64.py new file mode 100644 index 0000000..5b689d1 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20_amd64.py @@ -0,0 +1,1303 @@ +#!/usr/bin/env python3 +# +# To the extent possible under law, Yawning Angel has waived all copyright +# and related or neighboring rights to chacha20, using the Creative +# Commons "CC0" public domain dedication. See LICENSE or +# for full details. + +# +# cgo sucks. Plan 9 assembly sucks. Real languages have SIMD intrinsics. +# The least terrible/retarded option is to use a Python code generator, so +# that's what I did. +# +# Code based on Ted Krovetz's vec128 C implementation, with corrections +# to use a 64 bit counter instead of 32 bit, and to allow unaligned input and +# output pointers. +# +# Dependencies: https://github.com/Maratyszcza/PeachPy +# +# python3 -m peachpy.x86_64 -mabi=goasm -S -o chacha20_amd64.s chacha20_amd64.py +# + +from peachpy import * +from peachpy.x86_64 import * + +x = Argument(ptr(uint32_t)) +inp = Argument(ptr(const_uint8_t)) +outp = Argument(ptr(uint8_t)) +nrBlocks = Argument(ptr(size_t)) + +# +# SSE2 helper functions. A temporary register is explicitly passed in because +# the main fast loop uses every single register (and even spills) so manual +# control is needed. +# +# This used to also have a DQROUNDS helper that did 2 rounds of ChaCha like +# in the C code, but the C code has the luxury of an optimizer reordering +# everything, while this does not. +# + +def ROTW16_sse2(tmp, d): + MOVDQA(tmp, d) + PSLLD(tmp, 16) + PSRLD(d, 16) + PXOR(d, tmp) + +def ROTW12_sse2(tmp, b): + MOVDQA(tmp, b) + PSLLD(tmp, 12) + PSRLD(b, 20) + PXOR(b, tmp) + +def ROTW8_sse2(tmp, d): + MOVDQA(tmp, d) + PSLLD(tmp, 8) + PSRLD(d, 24) + PXOR(d, tmp) + +def ROTW7_sse2(tmp, b): + MOVDQA(tmp, b) + PSLLD(tmp, 7) + PSRLD(b, 25) + PXOR(b, tmp) + +def WriteXor_sse2(tmp, inp, outp, d, v0, v1, v2, v3): + MOVDQU(tmp, [inp+d]) + PXOR(tmp, v0) + MOVDQU([outp+d], tmp) + MOVDQU(tmp, [inp+d+16]) + PXOR(tmp, v1) + MOVDQU([outp+d+16], tmp) + MOVDQU(tmp, [inp+d+32]) + PXOR(tmp, v2) + MOVDQU([outp+d+32], tmp) + MOVDQU(tmp, [inp+d+48]) + PXOR(tmp, v3) + MOVDQU([outp+d+48], tmp) + +# SSE2 ChaCha20 (aka vec128). Does not handle partial blocks, and will +# process 4/2/1 blocks at a time. x (the ChaCha20 state) must be 16 byte +# aligned. +with Function("blocksAmd64SSE2", (x, inp, outp, nrBlocks)): + reg_x = GeneralPurposeRegister64() + reg_inp = GeneralPurposeRegister64() + reg_outp = GeneralPurposeRegister64() + reg_blocks = GeneralPurposeRegister64() + reg_sp_save = GeneralPurposeRegister64() + + LOAD.ARGUMENT(reg_x, x) + LOAD.ARGUMENT(reg_inp, inp) + LOAD.ARGUMENT(reg_outp, outp) + LOAD.ARGUMENT(reg_blocks, nrBlocks) + + # Align the stack to a 32 byte boundary. + reg_align = GeneralPurposeRegister64() + MOV(reg_sp_save, registers.rsp) + MOV(reg_align, 0x1f) + NOT(reg_align) + AND(registers.rsp, reg_align) + SUB(registers.rsp, 0x20) + + # Build the counter increment vector on the stack, and allocate the scratch + # space + xmm_v0 = XMMRegister() + PXOR(xmm_v0, xmm_v0) + SUB(registers.rsp, 16+16) + MOVDQA([registers.rsp], xmm_v0) + reg_tmp = GeneralPurposeRegister32() + MOV(reg_tmp, 0x00000001) + MOV([registers.rsp], reg_tmp) + mem_one = [registers.rsp] # (Stack) Counter increment vector + mem_tmp0 = [registers.rsp+16] # (Stack) Scratch space. + + mem_s0 = [reg_x] # (Memory) Cipher state [0..3] + mem_s1 = [reg_x+16] # (Memory) Cipher state [4..7] + mem_s2 = [reg_x+32] # (Memory) Cipher state [8..11] + mem_s3 = [reg_x+48] # (Memory) Cipher state [12..15] + + # xmm_v0 allocated above... + xmm_v1 = XMMRegister() + xmm_v2 = XMMRegister() + xmm_v3 = XMMRegister() + + xmm_v4 = XMMRegister() + xmm_v5 = XMMRegister() + xmm_v6 = XMMRegister() + xmm_v7 = XMMRegister() + + xmm_v8 = XMMRegister() + xmm_v9 = XMMRegister() + xmm_v10 = XMMRegister() + xmm_v11 = XMMRegister() + + xmm_v12 = XMMRegister() + xmm_v13 = XMMRegister() + xmm_v14 = XMMRegister() + xmm_v15 = XMMRegister() + + xmm_tmp = xmm_v12 + + # + # 4 blocks at a time. + # + + vector_loop4 = Loop() + SUB(reg_blocks, 4) + JB(vector_loop4.end) + with vector_loop4: + MOVDQA(xmm_v0, mem_s0) + MOVDQA(xmm_v1, mem_s1) + MOVDQA(xmm_v2, mem_s2) + MOVDQA(xmm_v3, mem_s3) + + MOVDQA(xmm_v4, xmm_v0) + MOVDQA(xmm_v5, xmm_v1) + MOVDQA(xmm_v6, xmm_v2) + MOVDQA(xmm_v7, xmm_v3) + PADDQ(xmm_v7, mem_one) + + MOVDQA(xmm_v8, xmm_v0) + MOVDQA(xmm_v9, xmm_v1) + MOVDQA(xmm_v10, xmm_v2) + MOVDQA(xmm_v11, xmm_v7) + PADDQ(xmm_v11, mem_one) + + MOVDQA(xmm_v12, xmm_v0) + MOVDQA(xmm_v13, xmm_v1) + MOVDQA(xmm_v14, xmm_v2) + MOVDQA(xmm_v15, xmm_v11) + PADDQ(xmm_v15, mem_one) + + reg_rounds = GeneralPurposeRegister64() + MOV(reg_rounds, 20) + rounds_loop4 = Loop() + with rounds_loop4: + # a += b; d ^= a; d = ROTW16(d); + PADDD(xmm_v0, xmm_v1) + PADDD(xmm_v4, xmm_v5) + PADDD(xmm_v8, xmm_v9) + PADDD(xmm_v12, xmm_v13) + PXOR(xmm_v3, xmm_v0) + PXOR(xmm_v7, xmm_v4) + PXOR(xmm_v11, xmm_v8) + PXOR(xmm_v15, xmm_v12) + + MOVDQA(mem_tmp0, xmm_tmp) # Save + + ROTW16_sse2(xmm_tmp, xmm_v3) + ROTW16_sse2(xmm_tmp, xmm_v7) + ROTW16_sse2(xmm_tmp, xmm_v11) + ROTW16_sse2(xmm_tmp, xmm_v15) + + # c += d; b ^= c; b = ROTW12(b); + PADDD(xmm_v2, xmm_v3) + PADDD(xmm_v6, xmm_v7) + PADDD(xmm_v10, xmm_v11) + PADDD(xmm_v14, xmm_v15) + PXOR(xmm_v1, xmm_v2) + PXOR(xmm_v5, xmm_v6) + PXOR(xmm_v9, xmm_v10) + PXOR(xmm_v13, xmm_v14) + ROTW12_sse2(xmm_tmp, xmm_v1) + ROTW12_sse2(xmm_tmp, xmm_v5) + ROTW12_sse2(xmm_tmp, xmm_v9) + ROTW12_sse2(xmm_tmp, xmm_v13) + + # a += b; d ^= a; d = ROTW8(d); + MOVDQA(xmm_tmp, mem_tmp0) # Restore + + PADDD(xmm_v0, xmm_v1) + PADDD(xmm_v4, xmm_v5) + PADDD(xmm_v8, xmm_v9) + PADDD(xmm_v12, xmm_v13) + PXOR(xmm_v3, xmm_v0) + PXOR(xmm_v7, xmm_v4) + PXOR(xmm_v11, xmm_v8) + PXOR(xmm_v15, xmm_v12) + + MOVDQA(mem_tmp0, xmm_tmp) # Save + + ROTW8_sse2(xmm_tmp, xmm_v3) + ROTW8_sse2(xmm_tmp, xmm_v7) + ROTW8_sse2(xmm_tmp, xmm_v11) + ROTW8_sse2(xmm_tmp, xmm_v15) + + # c += d; b ^= c; b = ROTW7(b) + PADDD(xmm_v2, xmm_v3) + PADDD(xmm_v6, xmm_v7) + PADDD(xmm_v10, xmm_v11) + PADDD(xmm_v14, xmm_v15) + PXOR(xmm_v1, xmm_v2) + PXOR(xmm_v5, xmm_v6) + PXOR(xmm_v9, xmm_v10) + PXOR(xmm_v13, xmm_v14) + ROTW7_sse2(xmm_tmp, xmm_v1) + ROTW7_sse2(xmm_tmp, xmm_v5) + ROTW7_sse2(xmm_tmp, xmm_v9) + ROTW7_sse2(xmm_tmp, xmm_v13) + + # b = ROTV1(b); c = ROTV2(c); d = ROTV3(d); + PSHUFD(xmm_v1, xmm_v1, 0x39) + PSHUFD(xmm_v5, xmm_v5, 0x39) + PSHUFD(xmm_v9, xmm_v9, 0x39) + PSHUFD(xmm_v13, xmm_v13, 0x39) + PSHUFD(xmm_v2, xmm_v2, 0x4e) + PSHUFD(xmm_v6, xmm_v6, 0x4e) + PSHUFD(xmm_v10, xmm_v10, 0x4e) + PSHUFD(xmm_v14, xmm_v14, 0x4e) + PSHUFD(xmm_v3, xmm_v3, 0x93) + PSHUFD(xmm_v7, xmm_v7, 0x93) + PSHUFD(xmm_v11, xmm_v11, 0x93) + PSHUFD(xmm_v15, xmm_v15, 0x93) + + MOVDQA(xmm_tmp, mem_tmp0) # Restore + + # a += b; d ^= a; d = ROTW16(d); + PADDD(xmm_v0, xmm_v1) + PADDD(xmm_v4, xmm_v5) + PADDD(xmm_v8, xmm_v9) + PADDD(xmm_v12, xmm_v13) + PXOR(xmm_v3, xmm_v0) + PXOR(xmm_v7, xmm_v4) + PXOR(xmm_v11, xmm_v8) + PXOR(xmm_v15, xmm_v12) + + MOVDQA(mem_tmp0, xmm_tmp) # Save + + ROTW16_sse2(xmm_tmp, xmm_v3) + ROTW16_sse2(xmm_tmp, xmm_v7) + ROTW16_sse2(xmm_tmp, xmm_v11) + ROTW16_sse2(xmm_tmp, xmm_v15) + + # c += d; b ^= c; b = ROTW12(b); + PADDD(xmm_v2, xmm_v3) + PADDD(xmm_v6, xmm_v7) + PADDD(xmm_v10, xmm_v11) + PADDD(xmm_v14, xmm_v15) + PXOR(xmm_v1, xmm_v2) + PXOR(xmm_v5, xmm_v6) + PXOR(xmm_v9, xmm_v10) + PXOR(xmm_v13, xmm_v14) + ROTW12_sse2(xmm_tmp, xmm_v1) + ROTW12_sse2(xmm_tmp, xmm_v5) + ROTW12_sse2(xmm_tmp, xmm_v9) + ROTW12_sse2(xmm_tmp, xmm_v13) + + # a += b; d ^= a; d = ROTW8(d); + MOVDQA(xmm_tmp, mem_tmp0) # Restore + + PADDD(xmm_v0, xmm_v1) + PADDD(xmm_v4, xmm_v5) + PADDD(xmm_v8, xmm_v9) + PADDD(xmm_v12, xmm_v13) + PXOR(xmm_v3, xmm_v0) + PXOR(xmm_v7, xmm_v4) + PXOR(xmm_v11, xmm_v8) + PXOR(xmm_v15, xmm_v12) + + MOVDQA(mem_tmp0, xmm_tmp) # Save + + ROTW8_sse2(xmm_tmp, xmm_v3) + ROTW8_sse2(xmm_tmp, xmm_v7) + ROTW8_sse2(xmm_tmp, xmm_v11) + ROTW8_sse2(xmm_tmp, xmm_v15) + + # c += d; b ^= c; b = ROTW7(b) + PADDD(xmm_v2, xmm_v3) + PADDD(xmm_v6, xmm_v7) + PADDD(xmm_v10, xmm_v11) + PADDD(xmm_v14, xmm_v15) + PXOR(xmm_v1, xmm_v2) + PXOR(xmm_v5, xmm_v6) + PXOR(xmm_v9, xmm_v10) + PXOR(xmm_v13, xmm_v14) + ROTW7_sse2(xmm_tmp, xmm_v1) + ROTW7_sse2(xmm_tmp, xmm_v5) + ROTW7_sse2(xmm_tmp, xmm_v9) + ROTW7_sse2(xmm_tmp, xmm_v13) + + # b = ROTV1(b); c = ROTV2(c); d = ROTV3(d); + PSHUFD(xmm_v1, xmm_v1, 0x93) + PSHUFD(xmm_v5, xmm_v5, 0x93) + PSHUFD(xmm_v9, xmm_v9, 0x93) + PSHUFD(xmm_v13, xmm_v13, 0x93) + PSHUFD(xmm_v2, xmm_v2, 0x4e) + PSHUFD(xmm_v6, xmm_v6, 0x4e) + PSHUFD(xmm_v10, xmm_v10, 0x4e) + PSHUFD(xmm_v14, xmm_v14, 0x4e) + PSHUFD(xmm_v3, xmm_v3, 0x39) + PSHUFD(xmm_v7, xmm_v7, 0x39) + PSHUFD(xmm_v11, xmm_v11, 0x39) + PSHUFD(xmm_v15, xmm_v15, 0x39) + + MOVDQA(xmm_tmp, mem_tmp0) # Restore + + SUB(reg_rounds, 2) + JNZ(rounds_loop4.begin) + + MOVDQA(mem_tmp0, xmm_tmp) + + PADDD(xmm_v0, mem_s0) + PADDD(xmm_v1, mem_s1) + PADDD(xmm_v2, mem_s2) + PADDD(xmm_v3, mem_s3) + WriteXor_sse2(xmm_tmp, reg_inp, reg_outp, 0, xmm_v0, xmm_v1, xmm_v2, xmm_v3) + MOVDQA(xmm_v3, mem_s3) + PADDQ(xmm_v3, mem_one) + + PADDD(xmm_v4, mem_s0) + PADDD(xmm_v5, mem_s1) + PADDD(xmm_v6, mem_s2) + PADDD(xmm_v7, xmm_v3) + WriteXor_sse2(xmm_tmp, reg_inp, reg_outp, 64, xmm_v4, xmm_v5, xmm_v6, xmm_v7) + PADDQ(xmm_v3, mem_one) + + PADDD(xmm_v8, mem_s0) + PADDD(xmm_v9, mem_s1) + PADDD(xmm_v10, mem_s2) + PADDD(xmm_v11, xmm_v3) + WriteXor_sse2(xmm_tmp, reg_inp, reg_outp, 128, xmm_v8, xmm_v9, xmm_v10, xmm_v11) + PADDQ(xmm_v3, mem_one) + + MOVDQA(xmm_tmp, mem_tmp0) + + PADDD(xmm_v12, mem_s0) + PADDD(xmm_v13, mem_s1) + PADDD(xmm_v14, mem_s2) + PADDD(xmm_v15, xmm_v3) + WriteXor_sse2(xmm_v0, reg_inp, reg_outp, 192, xmm_v12, xmm_v13, xmm_v14, xmm_v15) + PADDQ(xmm_v3, mem_one) + + MOVDQA(mem_s3, xmm_v3) + + ADD(reg_inp, 4 * 64) + ADD(reg_outp, 4 * 64) + + SUB(reg_blocks, 4) + JAE(vector_loop4.begin) + + ADD(reg_blocks, 4) + out = Label() + JZ(out) + + # Past this point, we no longer need to use every single register to hold + # the in progress state. + + xmm_s0 = xmm_v8 + xmm_s1 = xmm_v9 + xmm_s2 = xmm_v10 + xmm_s3 = xmm_v11 + xmm_one = xmm_v13 + MOVDQA(xmm_s0, mem_s0) + MOVDQA(xmm_s1, mem_s1) + MOVDQA(xmm_s2, mem_s2) + MOVDQA(xmm_s3, mem_s3) + MOVDQA(xmm_one, mem_one) + + # + # 2 blocks at a time. + # + + SUB(reg_blocks, 2) + vector_loop2 = Loop() + JB(vector_loop2.end) + with vector_loop2: + MOVDQA(xmm_v0, xmm_s0) + MOVDQA(xmm_v1, xmm_s1) + MOVDQA(xmm_v2, xmm_s2) + MOVDQA(xmm_v3, xmm_s3) + + MOVDQA(xmm_v4, xmm_v0) + MOVDQA(xmm_v5, xmm_v1) + MOVDQA(xmm_v6, xmm_v2) + MOVDQA(xmm_v7, xmm_v3) + PADDQ(xmm_v7, xmm_one) + + reg_rounds = GeneralPurposeRegister64() + MOV(reg_rounds, 20) + rounds_loop2 = Loop() + with rounds_loop2: + # a += b; d ^= a; d = ROTW16(d); + PADDD(xmm_v0, xmm_v1) + PADDD(xmm_v4, xmm_v5) + PXOR(xmm_v3, xmm_v0) + PXOR(xmm_v7, xmm_v4) + ROTW16_sse2(xmm_tmp, xmm_v3) + ROTW16_sse2(xmm_tmp, xmm_v7) + + # c += d; b ^= c; b = ROTW12(b); + PADDD(xmm_v2, xmm_v3) + PADDD(xmm_v6, xmm_v7) + PXOR(xmm_v1, xmm_v2) + PXOR(xmm_v5, xmm_v6) + ROTW12_sse2(xmm_tmp, xmm_v1) + ROTW12_sse2(xmm_tmp, xmm_v5) + + # a += b; d ^= a; d = ROTW8(d); + PADDD(xmm_v0, xmm_v1) + PADDD(xmm_v4, xmm_v5) + PXOR(xmm_v3, xmm_v0) + PXOR(xmm_v7, xmm_v4) + ROTW8_sse2(xmm_tmp, xmm_v3) + ROTW8_sse2(xmm_tmp, xmm_v7) + + # c += d; b ^= c; b = ROTW7(b) + PADDD(xmm_v2, xmm_v3) + PADDD(xmm_v6, xmm_v7) + PXOR(xmm_v1, xmm_v2) + PXOR(xmm_v5, xmm_v6) + ROTW7_sse2(xmm_tmp, xmm_v1) + ROTW7_sse2(xmm_tmp, xmm_v5) + + # b = ROTV1(b); c = ROTV2(c); d = ROTV3(d); + PSHUFD(xmm_v1, xmm_v1, 0x39) + PSHUFD(xmm_v5, xmm_v5, 0x39) + PSHUFD(xmm_v2, xmm_v2, 0x4e) + PSHUFD(xmm_v6, xmm_v6, 0x4e) + PSHUFD(xmm_v3, xmm_v3, 0x93) + PSHUFD(xmm_v7, xmm_v7, 0x93) + + # a += b; d ^= a; d = ROTW16(d); + PADDD(xmm_v0, xmm_v1) + PADDD(xmm_v4, xmm_v5) + PXOR(xmm_v3, xmm_v0) + PXOR(xmm_v7, xmm_v4) + ROTW16_sse2(xmm_tmp, xmm_v3) + ROTW16_sse2(xmm_tmp, xmm_v7) + + # c += d; b ^= c; b = ROTW12(b); + PADDD(xmm_v2, xmm_v3) + PADDD(xmm_v6, xmm_v7) + PXOR(xmm_v1, xmm_v2) + PXOR(xmm_v5, xmm_v6) + ROTW12_sse2(xmm_tmp, xmm_v1) + ROTW12_sse2(xmm_tmp, xmm_v5) + + # a += b; d ^= a; d = ROTW8(d); + PADDD(xmm_v0, xmm_v1) + PADDD(xmm_v4, xmm_v5) + PXOR(xmm_v3, xmm_v0) + PXOR(xmm_v7, xmm_v4) + ROTW8_sse2(xmm_tmp, xmm_v3) + ROTW8_sse2(xmm_tmp, xmm_v7) + + # c += d; b ^= c; b = ROTW7(b) + PADDD(xmm_v2, xmm_v3) + PADDD(xmm_v6, xmm_v7) + PXOR(xmm_v1, xmm_v2) + PXOR(xmm_v5, xmm_v6) + ROTW7_sse2(xmm_tmp, xmm_v1) + ROTW7_sse2(xmm_tmp, xmm_v5) + + # b = ROTV1(b); c = ROTV2(c); d = ROTV3(d); + PSHUFD(xmm_v1, xmm_v1, 0x93) + PSHUFD(xmm_v5, xmm_v5, 0x93) + PSHUFD(xmm_v2, xmm_v2, 0x4e) + PSHUFD(xmm_v6, xmm_v6, 0x4e) + PSHUFD(xmm_v3, xmm_v3, 0x39) + PSHUFD(xmm_v7, xmm_v7, 0x39) + + SUB(reg_rounds, 2) + JNZ(rounds_loop2.begin) + + PADDD(xmm_v0, xmm_s0) + PADDD(xmm_v1, xmm_s1) + PADDD(xmm_v2, xmm_s2) + PADDD(xmm_v3, xmm_s3) + WriteXor_sse2(xmm_tmp, reg_inp, reg_outp, 0, xmm_v0, xmm_v1, xmm_v2, xmm_v3) + PADDQ(xmm_s3, xmm_one) + + PADDD(xmm_v4, xmm_s0) + PADDD(xmm_v5, xmm_s1) + PADDD(xmm_v6, xmm_s2) + PADDD(xmm_v7, xmm_s3) + WriteXor_sse2(xmm_tmp, reg_inp, reg_outp, 64, xmm_v4, xmm_v5, xmm_v6, xmm_v7) + PADDQ(xmm_s3, xmm_one) + + ADD(reg_inp, 2 * 64) + ADD(reg_outp, 2 * 64) + + SUB(reg_blocks, 2) + JAE(vector_loop2.begin) + + ADD(reg_blocks, 2) + out_serial = Label() + JZ(out_serial) + + # + # 1 block at a time. Only executed once, because if there was > 1, + # the parallel code would have processed it already. + # + + MOVDQA(xmm_v0, xmm_s0) + MOVDQA(xmm_v1, xmm_s1) + MOVDQA(xmm_v2, xmm_s2) + MOVDQA(xmm_v3, xmm_s3) + + reg_rounds = GeneralPurposeRegister64() + MOV(reg_rounds, 20) + rounds_loop1 = Loop() + with rounds_loop1: + # a += b; d ^= a; d = ROTW16(d); + PADDD(xmm_v0, xmm_v1) + PXOR(xmm_v3, xmm_v0) + ROTW16_sse2(xmm_tmp, xmm_v3) + + # c += d; b ^= c; b = ROTW12(b); + PADDD(xmm_v2, xmm_v3) + PXOR(xmm_v1, xmm_v2) + ROTW12_sse2(xmm_tmp, xmm_v1) + + # a += b; d ^= a; d = ROTW8(d); + PADDD(xmm_v0, xmm_v1) + PXOR(xmm_v3, xmm_v0) + ROTW8_sse2(xmm_tmp, xmm_v3) + + # c += d; b ^= c; b = ROTW7(b) + PADDD(xmm_v2, xmm_v3) + PXOR(xmm_v1, xmm_v2) + ROTW7_sse2(xmm_tmp, xmm_v1) + + # b = ROTV1(b); c = ROTV2(c); d = ROTV3(d); + PSHUFD(xmm_v1, xmm_v1, 0x39) + PSHUFD(xmm_v2, xmm_v2, 0x4e) + PSHUFD(xmm_v3, xmm_v3, 0x93) + + # a += b; d ^= a; d = ROTW16(d); + PADDD(xmm_v0, xmm_v1) + PXOR(xmm_v3, xmm_v0) + ROTW16_sse2(xmm_tmp, xmm_v3) + + # c += d; b ^= c; b = ROTW12(b); + PADDD(xmm_v2, xmm_v3) + PXOR(xmm_v1, xmm_v2) + ROTW12_sse2(xmm_tmp, xmm_v1) + + # a += b; d ^= a; d = ROTW8(d); + PADDD(xmm_v0, xmm_v1) + PXOR(xmm_v3, xmm_v0) + ROTW8_sse2(xmm_tmp, xmm_v3) + + # c += d; b ^= c; b = ROTW7(b) + PADDD(xmm_v2, xmm_v3) + PXOR(xmm_v1, xmm_v2) + ROTW7_sse2(xmm_tmp, xmm_v1) + + # b = ROTV1(b); c = ROTV2(c); d = ROTV3(d); + PSHUFD(xmm_v1, xmm_v1, 0x93) + PSHUFD(xmm_v2, xmm_v2, 0x4e) + PSHUFD(xmm_v3, xmm_v3, 0x39) + + SUB(reg_rounds, 2) + JNZ(rounds_loop1.begin) + + PADDD(xmm_v0, xmm_s0) + PADDD(xmm_v1, xmm_s1) + PADDD(xmm_v2, xmm_s2) + PADDD(xmm_v3, xmm_s3) + WriteXor_sse2(xmm_tmp, reg_inp, reg_outp, 0, xmm_v0, xmm_v1, xmm_v2, xmm_v3) + PADDQ(xmm_s3, xmm_one) + + LABEL(out_serial) + + # Write back the updated counter. Stoping at 2^70 bytes is the user's + # problem, not mine. (Skipped if there's exactly a multiple of 4 blocks + # because the counter is incremented in memory while looping.) + MOVDQA(mem_s3, xmm_s3) + + LABEL(out) + + # Paranoia, cleanse the scratch space. + PXOR(xmm_v0, xmm_v0) + MOVDQA(mem_tmp0, xmm_v0) + + # Remove our stack allocation. + MOV(registers.rsp, reg_sp_save) + + RETURN() + +# +# AVX2 helpers. Like the SSE2 equivalents, the scratch register is explicit, +# and more helpers are used to increase readability for destructive operations. +# +# XXX/Performance: ROTW16_avx2/ROTW8_avx2 both can use VPSHUFFB. +# + +def ADD_avx2(dst, src): + VPADDD(dst, dst, src) + +def XOR_avx2(dst, src): + VPXOR(dst, dst, src) + +def ROTW16_avx2(tmp, d): + VPSLLD(tmp, d, 16) + VPSRLD(d, d, 16) + XOR_avx2(d, tmp) + +def ROTW12_avx2(tmp, b): + VPSLLD(tmp, b, 12) + VPSRLD(b, b, 20) + XOR_avx2(b, tmp) + +def ROTW8_avx2(tmp, d): + VPSLLD(tmp, d, 8) + VPSRLD(d, d, 24) + XOR_avx2(d, tmp) + +def ROTW7_avx2(tmp, b): + VPSLLD(tmp, b, 7) + VPSRLD(b, b, 25) + XOR_avx2(b, tmp) + +def WriteXor_avx2(tmp, inp, outp, d, v0, v1, v2, v3): + # XOR_WRITE(out+ 0, in+ 0, _mm256_permute2x128_si256(v0,v1,0x20)); + VPERM2I128(tmp, v0, v1, 0x20) + VPXOR(tmp, tmp, [inp+d]) + VMOVDQU([outp+d], tmp) + + # XOR_WRITE(out+32, in+32, _mm256_permute2x128_si256(v2,v3,0x20)); + VPERM2I128(tmp, v2, v3, 0x20) + VPXOR(tmp, tmp, [inp+d+32]) + VMOVDQU([outp+d+32], tmp) + + # XOR_WRITE(out+64, in+64, _mm256_permute2x128_si256(v0,v1,0x31)); + VPERM2I128(tmp, v0, v1, 0x31) + VPXOR(tmp, tmp, [inp+d+64]) + VMOVDQU([outp+d+64], tmp) + + # XOR_WRITE(out+96, in+96, _mm256_permute2x128_si256(v2,v3,0x31)); + VPERM2I128(tmp, v2, v3, 0x31) + VPXOR(tmp, tmp, [inp+d+96]) + VMOVDQU([outp+d+96], tmp) + +# AVX2 ChaCha20 (aka avx2). Does not handle partial blocks, will process +# 8/4/2 blocks at a time. Alignment blah blah blah fuck you. +with Function("blocksAmd64AVX2", (x, inp, outp, nrBlocks), target=uarch.broadwell): + reg_x = GeneralPurposeRegister64() + reg_inp = GeneralPurposeRegister64() + reg_outp = GeneralPurposeRegister64() + reg_blocks = GeneralPurposeRegister64() + reg_sp_save = GeneralPurposeRegister64() + + LOAD.ARGUMENT(reg_x, x) + LOAD.ARGUMENT(reg_inp, inp) + LOAD.ARGUMENT(reg_outp, outp) + LOAD.ARGUMENT(reg_blocks, nrBlocks) + + # Align the stack to a 32 byte boundary. + reg_align = GeneralPurposeRegister64() + MOV(reg_sp_save, registers.rsp) + MOV(reg_align, 0x1f) + NOT(reg_align) + AND(registers.rsp, reg_align) + SUB(registers.rsp, 0x20) + + x_s0 = [reg_x] # (Memory) Cipher state [0..3] + x_s1 = [reg_x+16] # (Memory) Cipher state [4..7] + x_s2 = [reg_x+32] # (Memory) Cipher state [8..11] + x_s3 = [reg_x+48] # (Memory) Cipher state [12..15] + + ymm_v0 = YMMRegister() + ymm_v1 = YMMRegister() + ymm_v2 = YMMRegister() + ymm_v3 = YMMRegister() + + ymm_v4 = YMMRegister() + ymm_v5 = YMMRegister() + ymm_v6 = YMMRegister() + ymm_v7 = YMMRegister() + + ymm_v8 = YMMRegister() + ymm_v9 = YMMRegister() + ymm_v10 = YMMRegister() + ymm_v11 = YMMRegister() + + ymm_v12 = YMMRegister() + ymm_v13 = YMMRegister() + ymm_v14 = YMMRegister() + ymm_v15 = YMMRegister() + + ymm_tmp0 = ymm_v12 + + # Allocate the neccecary stack space for the counter vector and two ymm + # registers that we will spill. + SUB(registers.rsp, 96) + mem_tmp0 = [registers.rsp+64] # (Stack) Scratch space. + mem_s3 = [registers.rsp+32] # (Stack) Working copy of s3. (8x) + mem_inc = [registers.rsp] # (Stack) Counter increment vector. + + # Increment the counter for one side of the state vector. + VPXOR(ymm_tmp0, ymm_tmp0, ymm_tmp0) + VMOVDQU(mem_inc, ymm_tmp0) + reg_tmp = GeneralPurposeRegister32() + MOV(reg_tmp, 0x00000001) + MOV([registers.rsp+16], reg_tmp) + VBROADCASTI128(ymm_v3, x_s3) + VPADDQ(ymm_v3, ymm_v3, [registers.rsp]) + VMOVDQA(mem_s3, ymm_v3) + + # As we process 2xN blocks at a time, so the counter increment for both + # sides of the state vector is 2. + MOV(reg_tmp, 0x00000002) + MOV([registers.rsp], reg_tmp) + MOV([registers.rsp+16], reg_tmp) + + out_write_even = Label() + out_write_odd = Label() + + # + # 8 blocks at a time. Ted Krovetz's avx2 code does not do this, but it's + # a decent gain despite all the pain... + # + + vector_loop8 = Loop() + SUB(reg_blocks, 8) + JB(vector_loop8.end) + with vector_loop8: + VBROADCASTI128(ymm_v0, x_s0) + VBROADCASTI128(ymm_v1, x_s1) + VBROADCASTI128(ymm_v2, x_s2) + VMOVDQA(ymm_v3, mem_s3) + + VMOVDQA(ymm_v4, ymm_v0) + VMOVDQA(ymm_v5, ymm_v1) + VMOVDQA(ymm_v6, ymm_v2) + VPADDQ(ymm_v7, ymm_v3, mem_inc) + + VMOVDQA(ymm_v8, ymm_v0) + VMOVDQA(ymm_v9, ymm_v1) + VMOVDQA(ymm_v10, ymm_v2) + VPADDQ(ymm_v11, ymm_v7, mem_inc) + + VMOVDQA(ymm_v12, ymm_v0) + VMOVDQA(ymm_v13, ymm_v1) + VMOVDQA(ymm_v14, ymm_v2) + VPADDQ(ymm_v15, ymm_v11, mem_inc) + + reg_rounds = GeneralPurposeRegister64() + MOV(reg_rounds, 20) + rounds_loop8 = Loop() + with rounds_loop8: + # a += b; d ^= a; d = ROTW16(d); + ADD_avx2(ymm_v0, ymm_v1) + ADD_avx2(ymm_v4, ymm_v5) + ADD_avx2(ymm_v8, ymm_v9) + ADD_avx2(ymm_v12, ymm_v13) + XOR_avx2(ymm_v3, ymm_v0) + XOR_avx2(ymm_v7, ymm_v4) + XOR_avx2(ymm_v11, ymm_v8) + XOR_avx2(ymm_v15, ymm_v12) + + VMOVDQA(mem_tmp0, ymm_tmp0) # Save + + ROTW16_avx2(ymm_tmp0, ymm_v3) + ROTW16_avx2(ymm_tmp0, ymm_v7) + ROTW16_avx2(ymm_tmp0, ymm_v11) + ROTW16_avx2(ymm_tmp0, ymm_v15) + + # c += d; b ^= c; b = ROTW12(b); + ADD_avx2(ymm_v2, ymm_v3) + ADD_avx2(ymm_v6, ymm_v7) + ADD_avx2(ymm_v10, ymm_v11) + ADD_avx2(ymm_v14, ymm_v15) + XOR_avx2(ymm_v1, ymm_v2) + XOR_avx2(ymm_v5, ymm_v6) + XOR_avx2(ymm_v9, ymm_v10) + XOR_avx2(ymm_v13, ymm_v14) + ROTW12_avx2(ymm_tmp0, ymm_v1) + ROTW12_avx2(ymm_tmp0, ymm_v5) + ROTW12_avx2(ymm_tmp0, ymm_v9) + ROTW12_avx2(ymm_tmp0, ymm_v13) + + # a += b; d ^= a; d = ROTW8(d); + VMOVDQA(ymm_tmp0, mem_tmp0) # Restore + + ADD_avx2(ymm_v0, ymm_v1) + ADD_avx2(ymm_v4, ymm_v5) + ADD_avx2(ymm_v8, ymm_v9) + ADD_avx2(ymm_v12, ymm_v13) + XOR_avx2(ymm_v3, ymm_v0) + XOR_avx2(ymm_v7, ymm_v4) + XOR_avx2(ymm_v11, ymm_v8) + XOR_avx2(ymm_v15, ymm_v12) + + VMOVDQA(mem_tmp0, ymm_tmp0) # Save + + ROTW8_avx2(ymm_tmp0, ymm_v3) + ROTW8_avx2(ymm_tmp0, ymm_v7) + ROTW8_avx2(ymm_tmp0, ymm_v11) + ROTW8_avx2(ymm_tmp0, ymm_v15) + + # c += d; b ^= c; b = ROTW7(b) + ADD_avx2(ymm_v2, ymm_v3) + ADD_avx2(ymm_v6, ymm_v7) + ADD_avx2(ymm_v10, ymm_v11) + ADD_avx2(ymm_v14, ymm_v15) + XOR_avx2(ymm_v1, ymm_v2) + XOR_avx2(ymm_v5, ymm_v6) + XOR_avx2(ymm_v9, ymm_v10) + XOR_avx2(ymm_v13, ymm_v14) + ROTW7_avx2(ymm_tmp0, ymm_v1) + ROTW7_avx2(ymm_tmp0, ymm_v5) + ROTW7_avx2(ymm_tmp0, ymm_v9) + ROTW7_avx2(ymm_tmp0, ymm_v13) + + # b = ROTV1(b); c = ROTV2(c); d = ROTV3(d); + VPSHUFD(ymm_v1, ymm_v1, 0x39) + VPSHUFD(ymm_v5, ymm_v5, 0x39) + VPSHUFD(ymm_v9, ymm_v9, 0x39) + VPSHUFD(ymm_v13, ymm_v13, 0x39) + VPSHUFD(ymm_v2, ymm_v2, 0x4e) + VPSHUFD(ymm_v6, ymm_v6, 0x4e) + VPSHUFD(ymm_v10, ymm_v10, 0x4e) + VPSHUFD(ymm_v14, ymm_v14, 0x4e) + VPSHUFD(ymm_v3, ymm_v3, 0x93) + VPSHUFD(ymm_v7, ymm_v7, 0x93) + VPSHUFD(ymm_v11, ymm_v11, 0x93) + VPSHUFD(ymm_v15, ymm_v15, 0x93) + + # a += b; d ^= a; d = ROTW16(d); + VMOVDQA(ymm_tmp0, mem_tmp0) # Restore + + ADD_avx2(ymm_v0, ymm_v1) + ADD_avx2(ymm_v4, ymm_v5) + ADD_avx2(ymm_v8, ymm_v9) + ADD_avx2(ymm_v12, ymm_v13) + XOR_avx2(ymm_v3, ymm_v0) + XOR_avx2(ymm_v7, ymm_v4) + XOR_avx2(ymm_v11, ymm_v8) + XOR_avx2(ymm_v15, ymm_v12) + + VMOVDQA(mem_tmp0, ymm_tmp0) # Save + + ROTW16_avx2(ymm_tmp0, ymm_v3) + ROTW16_avx2(ymm_tmp0, ymm_v7) + ROTW16_avx2(ymm_tmp0, ymm_v11) + ROTW16_avx2(ymm_tmp0, ymm_v15) + + # c += d; b ^= c; b = ROTW12(b); + ADD_avx2(ymm_v2, ymm_v3) + ADD_avx2(ymm_v6, ymm_v7) + ADD_avx2(ymm_v10, ymm_v11) + ADD_avx2(ymm_v14, ymm_v15) + XOR_avx2(ymm_v1, ymm_v2) + XOR_avx2(ymm_v5, ymm_v6) + XOR_avx2(ymm_v9, ymm_v10) + XOR_avx2(ymm_v13, ymm_v14) + ROTW12_avx2(ymm_tmp0, ymm_v1) + ROTW12_avx2(ymm_tmp0, ymm_v5) + ROTW12_avx2(ymm_tmp0, ymm_v9) + ROTW12_avx2(ymm_tmp0, ymm_v13) + + # a += b; d ^= a; d = ROTW8(d); + VMOVDQA(ymm_tmp0, mem_tmp0) # Restore + + ADD_avx2(ymm_v0, ymm_v1) + ADD_avx2(ymm_v4, ymm_v5) + ADD_avx2(ymm_v8, ymm_v9) + ADD_avx2(ymm_v12, ymm_v13) + XOR_avx2(ymm_v3, ymm_v0) + XOR_avx2(ymm_v7, ymm_v4) + XOR_avx2(ymm_v11, ymm_v8) + XOR_avx2(ymm_v15, ymm_v12) + + VMOVDQA(mem_tmp0, ymm_tmp0) # Save + + ROTW8_avx2(ymm_tmp0, ymm_v3) + ROTW8_avx2(ymm_tmp0, ymm_v7) + ROTW8_avx2(ymm_tmp0, ymm_v11) + ROTW8_avx2(ymm_tmp0, ymm_v15) + + # c += d; b ^= c; b = ROTW7(b) + ADD_avx2(ymm_v2, ymm_v3) + ADD_avx2(ymm_v6, ymm_v7) + ADD_avx2(ymm_v10, ymm_v11) + ADD_avx2(ymm_v14, ymm_v15) + XOR_avx2(ymm_v1, ymm_v2) + XOR_avx2(ymm_v5, ymm_v6) + XOR_avx2(ymm_v9, ymm_v10) + XOR_avx2(ymm_v13, ymm_v14) + ROTW7_avx2(ymm_tmp0, ymm_v1) + ROTW7_avx2(ymm_tmp0, ymm_v5) + ROTW7_avx2(ymm_tmp0, ymm_v9) + ROTW7_avx2(ymm_tmp0, ymm_v13) + + # b = ROTV1(b); c = ROTV2(c); d = ROTV3(d); + VPSHUFD(ymm_v1, ymm_v1, 0x93) + VPSHUFD(ymm_v5, ymm_v5, 0x93) + VPSHUFD(ymm_v9, ymm_v9, 0x93) + VPSHUFD(ymm_v13, ymm_v13, 0x93) + VPSHUFD(ymm_v2, ymm_v2, 0x4e) + VPSHUFD(ymm_v6, ymm_v6, 0x4e) + VPSHUFD(ymm_v10, ymm_v10, 0x4e) + VPSHUFD(ymm_v14, ymm_v14, 0x4e) + VPSHUFD(ymm_v3, ymm_v3, 0x39) + VPSHUFD(ymm_v7, ymm_v7, 0x39) + VPSHUFD(ymm_v11, ymm_v11, 0x39) + VPSHUFD(ymm_v15, ymm_v15, 0x39) + + VMOVDQA(ymm_tmp0, mem_tmp0) # Restore + + SUB(reg_rounds, 2) + JNZ(rounds_loop8.begin) + + # ymm_v12 is in mem_tmp0 and is current.... + + # XXX: I assume VBROADCASTI128 is about as fast as VMOVDQA.... + VBROADCASTI128(ymm_tmp0, x_s0) + ADD_avx2(ymm_v0, ymm_tmp0) + ADD_avx2(ymm_v4, ymm_tmp0) + ADD_avx2(ymm_v8, ymm_tmp0) + ADD_avx2(ymm_tmp0, mem_tmp0) + VMOVDQA(mem_tmp0, ymm_tmp0) + + VBROADCASTI128(ymm_tmp0, x_s1) + ADD_avx2(ymm_v1, ymm_tmp0) + ADD_avx2(ymm_v5, ymm_tmp0) + ADD_avx2(ymm_v9, ymm_tmp0) + ADD_avx2(ymm_v13, ymm_tmp0) + + VBROADCASTI128(ymm_tmp0, x_s2) + ADD_avx2(ymm_v2, ymm_tmp0) + ADD_avx2(ymm_v6, ymm_tmp0) + ADD_avx2(ymm_v10, ymm_tmp0) + ADD_avx2(ymm_v14, ymm_tmp0) + + ADD_avx2(ymm_v3, mem_s3) + WriteXor_avx2(ymm_tmp0, reg_inp, reg_outp, 0, ymm_v0, ymm_v1, ymm_v2, ymm_v3) + VMOVDQA(ymm_v3, mem_s3) + ADD_avx2(ymm_v3, mem_inc) + + ADD_avx2(ymm_v7, ymm_v3) + WriteXor_avx2(ymm_tmp0, reg_inp, reg_outp, 128, ymm_v4, ymm_v5, ymm_v6, ymm_v7) + ADD_avx2(ymm_v3, mem_inc) + + ADD_avx2(ymm_v11, ymm_v3) + WriteXor_avx2(ymm_tmp0, reg_inp, reg_outp, 256, ymm_v8, ymm_v9, ymm_v10, ymm_v11) + ADD_avx2(ymm_v3, mem_inc) + + VMOVDQA(ymm_v12, mem_tmp0) + ADD_avx2(ymm_v15, ymm_v3) + WriteXor_avx2(ymm_v0, reg_inp, reg_outp, 384, ymm_v12, ymm_v13, ymm_v14, ymm_v15) + ADD_avx2(ymm_v3, mem_inc) + + VMOVDQA(mem_s3, ymm_v3) + + ADD(reg_inp, 8 * 64) + ADD(reg_outp, 8 * 64) + + SUB(reg_blocks, 8) + JAE(vector_loop8.begin) + + # ymm_v3 contains a current copy of mem_s3 either from when it was built, + # or because the loop updates it. Copy this before we mess with the block + # counter in case we need to write it back and return. + ymm_s3 = ymm_v11 + VMOVDQA(ymm_s3, ymm_v3) + + ADD(reg_blocks, 8) + JZ(out_write_even) + + # We now actually can do everything in registers. + ymm_s0 = ymm_v8 + VBROADCASTI128(ymm_s0, x_s0) + ymm_s1 = ymm_v9 + VBROADCASTI128(ymm_s1, x_s1) + ymm_s2 = ymm_v10 + VBROADCASTI128(ymm_s2, x_s2) + ymm_inc = ymm_v14 + VMOVDQA(ymm_inc, mem_inc) + + # + # 4 blocks at a time. + # + + SUB(reg_blocks, 4) + vector_loop4 = Loop() + JB(vector_loop4.end) + with vector_loop4: + VMOVDQA(ymm_v0, ymm_s0) + VMOVDQA(ymm_v1, ymm_s1) + VMOVDQA(ymm_v2, ymm_s2) + VMOVDQA(ymm_v3, ymm_s3) + + VMOVDQA(ymm_v4, ymm_v0) + VMOVDQA(ymm_v5, ymm_v1) + VMOVDQA(ymm_v6, ymm_v2) + VPADDQ(ymm_v7, ymm_v3, ymm_inc) + + reg_rounds = GeneralPurposeRegister64() + MOV(reg_rounds, 20) + rounds_loop4 = Loop() + with rounds_loop4: + # a += b; d ^= a; d = ROTW16(d); + ADD_avx2(ymm_v0, ymm_v1) + ADD_avx2(ymm_v4, ymm_v5) + XOR_avx2(ymm_v3, ymm_v0) + XOR_avx2(ymm_v7, ymm_v4) + ROTW16_avx2(ymm_tmp0, ymm_v3) + ROTW16_avx2(ymm_tmp0, ymm_v7) + + # c += d; b ^= c; b = ROTW12(b); + ADD_avx2(ymm_v2, ymm_v3) + ADD_avx2(ymm_v6, ymm_v7) + XOR_avx2(ymm_v1, ymm_v2) + XOR_avx2(ymm_v5, ymm_v6) + ROTW12_avx2(ymm_tmp0, ymm_v1) + ROTW12_avx2(ymm_tmp0, ymm_v5) + + # a += b; d ^= a; d = ROTW8(d); + ADD_avx2(ymm_v0, ymm_v1) + ADD_avx2(ymm_v4, ymm_v5) + XOR_avx2(ymm_v3, ymm_v0) + XOR_avx2(ymm_v7, ymm_v4) + ROTW8_avx2(ymm_tmp0, ymm_v3) + ROTW8_avx2(ymm_tmp0, ymm_v7) + + # c += d; b ^= c; b = ROTW7(b) + ADD_avx2(ymm_v2, ymm_v3) + ADD_avx2(ymm_v6, ymm_v7) + XOR_avx2(ymm_v1, ymm_v2) + XOR_avx2(ymm_v5, ymm_v6) + ROTW7_avx2(ymm_tmp0, ymm_v1) + ROTW7_avx2(ymm_tmp0, ymm_v5) + + # b = ROTV1(b); c = ROTV2(c); d = ROTV3(d); + VPSHUFD(ymm_v1, ymm_v1, 0x39) + VPSHUFD(ymm_v5, ymm_v5, 0x39) + VPSHUFD(ymm_v2, ymm_v2, 0x4e) + VPSHUFD(ymm_v6, ymm_v6, 0x4e) + VPSHUFD(ymm_v3, ymm_v3, 0x93) + VPSHUFD(ymm_v7, ymm_v7, 0x93) + + # a += b; d ^= a; d = ROTW16(d); + ADD_avx2(ymm_v0, ymm_v1) + ADD_avx2(ymm_v4, ymm_v5) + XOR_avx2(ymm_v3, ymm_v0) + XOR_avx2(ymm_v7, ymm_v4) + ROTW16_avx2(ymm_tmp0, ymm_v3) + ROTW16_avx2(ymm_tmp0, ymm_v7) + + # c += d; b ^= c; b = ROTW12(b); + ADD_avx2(ymm_v2, ymm_v3) + ADD_avx2(ymm_v6, ymm_v7) + XOR_avx2(ymm_v1, ymm_v2) + XOR_avx2(ymm_v5, ymm_v6) + ROTW12_avx2(ymm_tmp0, ymm_v1) + ROTW12_avx2(ymm_tmp0, ymm_v5) + + # a += b; d ^= a; d = ROTW8(d); + ADD_avx2(ymm_v0, ymm_v1) + ADD_avx2(ymm_v4, ymm_v5) + XOR_avx2(ymm_v3, ymm_v0) + XOR_avx2(ymm_v7, ymm_v4) + ROTW8_avx2(ymm_tmp0, ymm_v3) + ROTW8_avx2(ymm_tmp0, ymm_v7) + + # c += d; b ^= c; b = ROTW7(b) + ADD_avx2(ymm_v2, ymm_v3) + ADD_avx2(ymm_v6, ymm_v7) + XOR_avx2(ymm_v1, ymm_v2) + XOR_avx2(ymm_v5, ymm_v6) + ROTW7_avx2(ymm_tmp0, ymm_v1) + ROTW7_avx2(ymm_tmp0, ymm_v5) + + # b = ROTV1(b); c = ROTV2(c); d = ROTV3(d); + VPSHUFD(ymm_v1, ymm_v1, 0x93) + VPSHUFD(ymm_v5, ymm_v5, 0x93) + VPSHUFD(ymm_v2, ymm_v2, 0x4e) + VPSHUFD(ymm_v6, ymm_v6, 0x4e) + VPSHUFD(ymm_v3, ymm_v3, 0x39) + VPSHUFD(ymm_v7, ymm_v7, 0x39) + + SUB(reg_rounds, 2) + JNZ(rounds_loop4.begin) + + ADD_avx2(ymm_v0, ymm_s0) + ADD_avx2(ymm_v1, ymm_s1) + ADD_avx2(ymm_v2, ymm_s2) + ADD_avx2(ymm_v3, ymm_s3) + WriteXor_avx2(ymm_tmp0, reg_inp, reg_outp, 0, ymm_v0, ymm_v1, ymm_v2, ymm_v3) + ADD_avx2(ymm_s3, ymm_inc) + + ADD_avx2(ymm_v4, ymm_s0) + ADD_avx2(ymm_v5, ymm_s1) + ADD_avx2(ymm_v6, ymm_s2) + ADD_avx2(ymm_v7, ymm_s3) + WriteXor_avx2(ymm_tmp0, reg_inp, reg_outp, 128, ymm_v4, ymm_v5, ymm_v6, ymm_v7) + ADD_avx2(ymm_s3, ymm_inc) + + ADD(reg_inp, 4 * 64) + ADD(reg_outp, 4 * 64) + + SUB(reg_blocks, 4) + JAE(vector_loop4.begin) + + ADD(reg_blocks, 4) + JZ(out_write_even) + + # + # 2/1 blocks at a time. The two codepaths are unified because + # with AVX2 we do 2 blocks at a time anyway, and this only gets called + # if 3/2/1 blocks are remaining, so the extra branches don't hurt that + # much. + # + + vector_loop2 = Loop() + with vector_loop2: + VMOVDQA(ymm_v0, ymm_s0) + VMOVDQA(ymm_v1, ymm_s1) + VMOVDQA(ymm_v2, ymm_s2) + VMOVDQA(ymm_v3, ymm_s3) + + reg_rounds = GeneralPurposeRegister64() + MOV(reg_rounds, 20) + rounds_loop2 = Loop() + with rounds_loop2: + # a += b; d ^= a; d = ROTW16(d); + ADD_avx2(ymm_v0, ymm_v1) + XOR_avx2(ymm_v3, ymm_v0) + ROTW16_avx2(ymm_tmp0, ymm_v3) + + # c += d; b ^= c; b = ROTW12(b); + ADD_avx2(ymm_v2, ymm_v3) + XOR_avx2(ymm_v1, ymm_v2) + ROTW12_avx2(ymm_tmp0, ymm_v1) + + # a += b; d ^= a; d = ROTW8(d); + ADD_avx2(ymm_v0, ymm_v1) + XOR_avx2(ymm_v3, ymm_v0) + ROTW8_avx2(ymm_tmp0, ymm_v3) + + # c += d; b ^= c; b = ROTW7(b) + ADD_avx2(ymm_v2, ymm_v3) + XOR_avx2(ymm_v1, ymm_v2) + ROTW7_avx2(ymm_tmp0, ymm_v1) + + # b = ROTV1(b); c = ROTV2(c); d = ROTV3(d); + VPSHUFD(ymm_v1, ymm_v1, 0x39) + VPSHUFD(ymm_v2, ymm_v2, 0x4e) + VPSHUFD(ymm_v3, ymm_v3, 0x93) + + # a += b; d ^= a; d = ROTW16(d); + ADD_avx2(ymm_v0, ymm_v1) + XOR_avx2(ymm_v3, ymm_v0) + ROTW16_avx2(ymm_tmp0, ymm_v3) + + # c += d; b ^= c; b = ROTW12(b); + ADD_avx2(ymm_v2, ymm_v3) + XOR_avx2(ymm_v1, ymm_v2) + ROTW12_avx2(ymm_tmp0, ymm_v1) + + # a += b; d ^= a; d = ROTW8(d); + ADD_avx2(ymm_v0, ymm_v1) + XOR_avx2(ymm_v3, ymm_v0) + ROTW8_avx2(ymm_tmp0, ymm_v3) + + # c += d; b ^= c; b = ROTW7(b) + ADD_avx2(ymm_v2, ymm_v3) + XOR_avx2(ymm_v1, ymm_v2) + ROTW7_avx2(ymm_tmp0, ymm_v1) + + # b = ROTV1(b); c = ROTV2(c); d = ROTV3(d); + VPSHUFD(ymm_v1, ymm_v1, 0x93) + VPSHUFD(ymm_v2, ymm_v2, 0x4e) + VPSHUFD(ymm_v3, ymm_v3, 0x39) + + SUB(reg_rounds, 2) + JNZ(rounds_loop2.begin) + + ADD_avx2(ymm_v0, ymm_s0) + ADD_avx2(ymm_v1, ymm_s1) + ADD_avx2(ymm_v2, ymm_s2) + ADD_avx2(ymm_v3, ymm_s3) + + # XOR_WRITE(out+ 0, in+ 0, _mm256_permute2x128_si256(v0,v1,0x20)); + VPERM2I128(ymm_tmp0, ymm_v0, ymm_v1, 0x20) + VPXOR(ymm_tmp0, ymm_tmp0, [reg_inp]) + VMOVDQU([reg_outp], ymm_tmp0) + + # XOR_WRITE(out+32, in+32, _mm256_permute2x128_si256(v2,v3,0x20)); + VPERM2I128(ymm_tmp0, ymm_v2, ymm_v3, 0x20) + VPXOR(ymm_tmp0, ymm_tmp0, [reg_inp+32]) + VMOVDQU([reg_outp+32], ymm_tmp0) + + SUB(reg_blocks, 1) + JZ(out_write_odd) + + ADD_avx2(ymm_s3, ymm_inc) + + # XOR_WRITE(out+64, in+64, _mm256_permute2x128_si256(v0,v1,0x31)); + VPERM2I128(ymm_tmp0, ymm_v0, ymm_v1, 0x31) + VPXOR(ymm_tmp0, ymm_tmp0, [reg_inp+64]) + VMOVDQU([reg_outp+64], ymm_tmp0) + + # XOR_WRITE(out+96, in+96, _mm256_permute2x128_si256(v2,v3,0x31)); + VPERM2I128(ymm_tmp0, ymm_v2, ymm_v3, 0x31) + VPXOR(ymm_tmp0, ymm_tmp0, [reg_inp+96]) + VMOVDQU([reg_outp+96], ymm_tmp0) + + SUB(reg_blocks, 1) + JZ(out_write_even) + + ADD(reg_inp, 2 * 64) + ADD(reg_outp, 2 * 64) + JMP(vector_loop2.begin) + + LABEL(out_write_odd) + VPERM2I128(ymm_s3, ymm_s3, ymm_s3, 0x01) # Odd number of blocks. + + LABEL(out_write_even) + VMOVDQA(x_s3, ymm_s3.as_xmm) # Write back ymm_s3 to x_v3 + + # Paranoia, cleanse the scratch space. + VPXOR(ymm_v0, ymm_v0, ymm_v0) + VMOVDQA(mem_tmp0, ymm_v0) + VMOVDQA(mem_s3, ymm_v0) + + # Remove our stack allocation. + MOV(registers.rsp, reg_sp_save) + + RETURN() + +# +# CPUID +# + +cpuidParams = Argument(ptr(uint32_t)) + +with Function("cpuidAmd64", (cpuidParams,)): + reg_params = registers.r15 + LOAD.ARGUMENT(reg_params, cpuidParams) + + MOV(registers.eax, [reg_params]) + MOV(registers.ecx, [reg_params+4]) + + CPUID() + + MOV([reg_params], registers.eax) + MOV([reg_params+4], registers.ebx) + MOV([reg_params+8], registers.ecx) + MOV([reg_params+12], registers.edx) + + RETURN() + +# +# XGETBV (ECX = 0) +# + +xcrVec = Argument(ptr(uint32_t)) + +with Function("xgetbv0Amd64", (xcrVec,)): + reg_vec = GeneralPurposeRegister64() + + LOAD.ARGUMENT(reg_vec, xcrVec) + + XOR(registers.ecx, registers.ecx) + + XGETBV() + + MOV([reg_vec], registers.eax) + MOV([reg_vec+4], registers.edx) + + RETURN() diff --git a/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20_amd64.s b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20_amd64.s new file mode 100644 index 0000000..4970397 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20_amd64.s @@ -0,0 +1,1187 @@ +// Generated by PeachPy 0.2.0 from chacha20_amd64.py + + +// func blocksAmd64SSE2(x *uint32, inp *uint8, outp *uint8, nrBlocks *uint) +TEXT ·blocksAmd64SSE2(SB),4,$0-32 + MOVQ x+0(FP), AX + MOVQ inp+8(FP), BX + MOVQ outp+16(FP), CX + MOVQ nrBlocks+24(FP), DX + MOVQ SP, DI + MOVQ $31, SI + NOTQ SI + ANDQ SI, SP + SUBQ $32, SP + PXOR X0, X0 + SUBQ $32, SP + MOVO X0, 0(SP) + MOVL $1, SI + MOVL SI, 0(SP) + SUBQ $4, DX + JCS vector_loop4_end +vector_loop4_begin: + MOVO 0(AX), X0 + MOVO 16(AX), X1 + MOVO 32(AX), X2 + MOVO 48(AX), X3 + MOVO X0, X4 + MOVO X1, X5 + MOVO X2, X6 + MOVO X3, X7 + PADDQ 0(SP), X7 + MOVO X0, X8 + MOVO X1, X9 + MOVO X2, X10 + MOVO X7, X11 + PADDQ 0(SP), X11 + MOVO X0, X12 + MOVO X1, X13 + MOVO X2, X14 + MOVO X11, X15 + PADDQ 0(SP), X15 + MOVQ $20, SI +rounds_loop4_begin: + PADDL X1, X0 + PADDL X5, X4 + PADDL X9, X8 + PADDL X13, X12 + PXOR X0, X3 + PXOR X4, X7 + PXOR X8, X11 + PXOR X12, X15 + MOVO X12, 16(SP) + MOVO X3, X12 + PSLLL $16, X12 + PSRLL $16, X3 + PXOR X12, X3 + MOVO X7, X12 + PSLLL $16, X12 + PSRLL $16, X7 + PXOR X12, X7 + MOVO X11, X12 + PSLLL $16, X12 + PSRLL $16, X11 + PXOR X12, X11 + MOVO X15, X12 + PSLLL $16, X12 + PSRLL $16, X15 + PXOR X12, X15 + PADDL X3, X2 + PADDL X7, X6 + PADDL X11, X10 + PADDL X15, X14 + PXOR X2, X1 + PXOR X6, X5 + PXOR X10, X9 + PXOR X14, X13 + MOVO X1, X12 + PSLLL $12, X12 + PSRLL $20, X1 + PXOR X12, X1 + MOVO X5, X12 + PSLLL $12, X12 + PSRLL $20, X5 + PXOR X12, X5 + MOVO X9, X12 + PSLLL $12, X12 + PSRLL $20, X9 + PXOR X12, X9 + MOVO X13, X12 + PSLLL $12, X12 + PSRLL $20, X13 + PXOR X12, X13 + MOVO 16(SP), X12 + PADDL X1, X0 + PADDL X5, X4 + PADDL X9, X8 + PADDL X13, X12 + PXOR X0, X3 + PXOR X4, X7 + PXOR X8, X11 + PXOR X12, X15 + MOVO X12, 16(SP) + MOVO X3, X12 + PSLLL $8, X12 + PSRLL $24, X3 + PXOR X12, X3 + MOVO X7, X12 + PSLLL $8, X12 + PSRLL $24, X7 + PXOR X12, X7 + MOVO X11, X12 + PSLLL $8, X12 + PSRLL $24, X11 + PXOR X12, X11 + MOVO X15, X12 + PSLLL $8, X12 + PSRLL $24, X15 + PXOR X12, X15 + PADDL X3, X2 + PADDL X7, X6 + PADDL X11, X10 + PADDL X15, X14 + PXOR X2, X1 + PXOR X6, X5 + PXOR X10, X9 + PXOR X14, X13 + MOVO X1, X12 + PSLLL $7, X12 + PSRLL $25, X1 + PXOR X12, X1 + MOVO X5, X12 + PSLLL $7, X12 + PSRLL $25, X5 + PXOR X12, X5 + MOVO X9, X12 + PSLLL $7, X12 + PSRLL $25, X9 + PXOR X12, X9 + MOVO X13, X12 + PSLLL $7, X12 + PSRLL $25, X13 + PXOR X12, X13 + PSHUFL $57, X1, X1 + PSHUFL $57, X5, X5 + PSHUFL $57, X9, X9 + PSHUFL $57, X13, X13 + PSHUFL $78, X2, X2 + PSHUFL $78, X6, X6 + PSHUFL $78, X10, X10 + PSHUFL $78, X14, X14 + PSHUFL $147, X3, X3 + PSHUFL $147, X7, X7 + PSHUFL $147, X11, X11 + PSHUFL $147, X15, X15 + MOVO 16(SP), X12 + PADDL X1, X0 + PADDL X5, X4 + PADDL X9, X8 + PADDL X13, X12 + PXOR X0, X3 + PXOR X4, X7 + PXOR X8, X11 + PXOR X12, X15 + MOVO X12, 16(SP) + MOVO X3, X12 + PSLLL $16, X12 + PSRLL $16, X3 + PXOR X12, X3 + MOVO X7, X12 + PSLLL $16, X12 + PSRLL $16, X7 + PXOR X12, X7 + MOVO X11, X12 + PSLLL $16, X12 + PSRLL $16, X11 + PXOR X12, X11 + MOVO X15, X12 + PSLLL $16, X12 + PSRLL $16, X15 + PXOR X12, X15 + PADDL X3, X2 + PADDL X7, X6 + PADDL X11, X10 + PADDL X15, X14 + PXOR X2, X1 + PXOR X6, X5 + PXOR X10, X9 + PXOR X14, X13 + MOVO X1, X12 + PSLLL $12, X12 + PSRLL $20, X1 + PXOR X12, X1 + MOVO X5, X12 + PSLLL $12, X12 + PSRLL $20, X5 + PXOR X12, X5 + MOVO X9, X12 + PSLLL $12, X12 + PSRLL $20, X9 + PXOR X12, X9 + MOVO X13, X12 + PSLLL $12, X12 + PSRLL $20, X13 + PXOR X12, X13 + MOVO 16(SP), X12 + PADDL X1, X0 + PADDL X5, X4 + PADDL X9, X8 + PADDL X13, X12 + PXOR X0, X3 + PXOR X4, X7 + PXOR X8, X11 + PXOR X12, X15 + MOVO X12, 16(SP) + MOVO X3, X12 + PSLLL $8, X12 + PSRLL $24, X3 + PXOR X12, X3 + MOVO X7, X12 + PSLLL $8, X12 + PSRLL $24, X7 + PXOR X12, X7 + MOVO X11, X12 + PSLLL $8, X12 + PSRLL $24, X11 + PXOR X12, X11 + MOVO X15, X12 + PSLLL $8, X12 + PSRLL $24, X15 + PXOR X12, X15 + PADDL X3, X2 + PADDL X7, X6 + PADDL X11, X10 + PADDL X15, X14 + PXOR X2, X1 + PXOR X6, X5 + PXOR X10, X9 + PXOR X14, X13 + MOVO X1, X12 + PSLLL $7, X12 + PSRLL $25, X1 + PXOR X12, X1 + MOVO X5, X12 + PSLLL $7, X12 + PSRLL $25, X5 + PXOR X12, X5 + MOVO X9, X12 + PSLLL $7, X12 + PSRLL $25, X9 + PXOR X12, X9 + MOVO X13, X12 + PSLLL $7, X12 + PSRLL $25, X13 + PXOR X12, X13 + PSHUFL $147, X1, X1 + PSHUFL $147, X5, X5 + PSHUFL $147, X9, X9 + PSHUFL $147, X13, X13 + PSHUFL $78, X2, X2 + PSHUFL $78, X6, X6 + PSHUFL $78, X10, X10 + PSHUFL $78, X14, X14 + PSHUFL $57, X3, X3 + PSHUFL $57, X7, X7 + PSHUFL $57, X11, X11 + PSHUFL $57, X15, X15 + MOVO 16(SP), X12 + SUBQ $2, SI + JNE rounds_loop4_begin + MOVO X12, 16(SP) + PADDL 0(AX), X0 + PADDL 16(AX), X1 + PADDL 32(AX), X2 + PADDL 48(AX), X3 + MOVOU 0(BX), X12 + PXOR X0, X12 + MOVOU X12, 0(CX) + MOVOU 16(BX), X12 + PXOR X1, X12 + MOVOU X12, 16(CX) + MOVOU 32(BX), X12 + PXOR X2, X12 + MOVOU X12, 32(CX) + MOVOU 48(BX), X12 + PXOR X3, X12 + MOVOU X12, 48(CX) + MOVO 48(AX), X3 + PADDQ 0(SP), X3 + PADDL 0(AX), X4 + PADDL 16(AX), X5 + PADDL 32(AX), X6 + PADDL X3, X7 + MOVOU 64(BX), X12 + PXOR X4, X12 + MOVOU X12, 64(CX) + MOVOU 80(BX), X12 + PXOR X5, X12 + MOVOU X12, 80(CX) + MOVOU 96(BX), X12 + PXOR X6, X12 + MOVOU X12, 96(CX) + MOVOU 112(BX), X12 + PXOR X7, X12 + MOVOU X12, 112(CX) + PADDQ 0(SP), X3 + PADDL 0(AX), X8 + PADDL 16(AX), X9 + PADDL 32(AX), X10 + PADDL X3, X11 + MOVOU 128(BX), X12 + PXOR X8, X12 + MOVOU X12, 128(CX) + MOVOU 144(BX), X12 + PXOR X9, X12 + MOVOU X12, 144(CX) + MOVOU 160(BX), X12 + PXOR X10, X12 + MOVOU X12, 160(CX) + MOVOU 176(BX), X12 + PXOR X11, X12 + MOVOU X12, 176(CX) + PADDQ 0(SP), X3 + MOVO 16(SP), X12 + PADDL 0(AX), X12 + PADDL 16(AX), X13 + PADDL 32(AX), X14 + PADDL X3, X15 + MOVOU 192(BX), X0 + PXOR X12, X0 + MOVOU X0, 192(CX) + MOVOU 208(BX), X0 + PXOR X13, X0 + MOVOU X0, 208(CX) + MOVOU 224(BX), X0 + PXOR X14, X0 + MOVOU X0, 224(CX) + MOVOU 240(BX), X0 + PXOR X15, X0 + MOVOU X0, 240(CX) + PADDQ 0(SP), X3 + MOVO X3, 48(AX) + ADDQ $256, BX + ADDQ $256, CX + SUBQ $4, DX + JCC vector_loop4_begin +vector_loop4_end: + ADDQ $4, DX + JEQ out + MOVO 0(AX), X8 + MOVO 16(AX), X9 + MOVO 32(AX), X10 + MOVO 48(AX), X11 + MOVO 0(SP), X13 + SUBQ $2, DX + JCS vector_loop2_end +vector_loop2_begin: + MOVO X8, X0 + MOVO X9, X1 + MOVO X10, X2 + MOVO X11, X3 + MOVO X0, X4 + MOVO X1, X5 + MOVO X2, X6 + MOVO X3, X7 + PADDQ X13, X7 + MOVQ $20, SI +rounds_loop2_begin: + PADDL X1, X0 + PADDL X5, X4 + PXOR X0, X3 + PXOR X4, X7 + MOVO X3, X12 + PSLLL $16, X12 + PSRLL $16, X3 + PXOR X12, X3 + MOVO X7, X12 + PSLLL $16, X12 + PSRLL $16, X7 + PXOR X12, X7 + PADDL X3, X2 + PADDL X7, X6 + PXOR X2, X1 + PXOR X6, X5 + MOVO X1, X12 + PSLLL $12, X12 + PSRLL $20, X1 + PXOR X12, X1 + MOVO X5, X12 + PSLLL $12, X12 + PSRLL $20, X5 + PXOR X12, X5 + PADDL X1, X0 + PADDL X5, X4 + PXOR X0, X3 + PXOR X4, X7 + MOVO X3, X12 + PSLLL $8, X12 + PSRLL $24, X3 + PXOR X12, X3 + MOVO X7, X12 + PSLLL $8, X12 + PSRLL $24, X7 + PXOR X12, X7 + PADDL X3, X2 + PADDL X7, X6 + PXOR X2, X1 + PXOR X6, X5 + MOVO X1, X12 + PSLLL $7, X12 + PSRLL $25, X1 + PXOR X12, X1 + MOVO X5, X12 + PSLLL $7, X12 + PSRLL $25, X5 + PXOR X12, X5 + PSHUFL $57, X1, X1 + PSHUFL $57, X5, X5 + PSHUFL $78, X2, X2 + PSHUFL $78, X6, X6 + PSHUFL $147, X3, X3 + PSHUFL $147, X7, X7 + PADDL X1, X0 + PADDL X5, X4 + PXOR X0, X3 + PXOR X4, X7 + MOVO X3, X12 + PSLLL $16, X12 + PSRLL $16, X3 + PXOR X12, X3 + MOVO X7, X12 + PSLLL $16, X12 + PSRLL $16, X7 + PXOR X12, X7 + PADDL X3, X2 + PADDL X7, X6 + PXOR X2, X1 + PXOR X6, X5 + MOVO X1, X12 + PSLLL $12, X12 + PSRLL $20, X1 + PXOR X12, X1 + MOVO X5, X12 + PSLLL $12, X12 + PSRLL $20, X5 + PXOR X12, X5 + PADDL X1, X0 + PADDL X5, X4 + PXOR X0, X3 + PXOR X4, X7 + MOVO X3, X12 + PSLLL $8, X12 + PSRLL $24, X3 + PXOR X12, X3 + MOVO X7, X12 + PSLLL $8, X12 + PSRLL $24, X7 + PXOR X12, X7 + PADDL X3, X2 + PADDL X7, X6 + PXOR X2, X1 + PXOR X6, X5 + MOVO X1, X12 + PSLLL $7, X12 + PSRLL $25, X1 + PXOR X12, X1 + MOVO X5, X12 + PSLLL $7, X12 + PSRLL $25, X5 + PXOR X12, X5 + PSHUFL $147, X1, X1 + PSHUFL $147, X5, X5 + PSHUFL $78, X2, X2 + PSHUFL $78, X6, X6 + PSHUFL $57, X3, X3 + PSHUFL $57, X7, X7 + SUBQ $2, SI + JNE rounds_loop2_begin + PADDL X8, X0 + PADDL X9, X1 + PADDL X10, X2 + PADDL X11, X3 + MOVOU 0(BX), X12 + PXOR X0, X12 + MOVOU X12, 0(CX) + MOVOU 16(BX), X12 + PXOR X1, X12 + MOVOU X12, 16(CX) + MOVOU 32(BX), X12 + PXOR X2, X12 + MOVOU X12, 32(CX) + MOVOU 48(BX), X12 + PXOR X3, X12 + MOVOU X12, 48(CX) + PADDQ X13, X11 + PADDL X8, X4 + PADDL X9, X5 + PADDL X10, X6 + PADDL X11, X7 + MOVOU 64(BX), X12 + PXOR X4, X12 + MOVOU X12, 64(CX) + MOVOU 80(BX), X12 + PXOR X5, X12 + MOVOU X12, 80(CX) + MOVOU 96(BX), X12 + PXOR X6, X12 + MOVOU X12, 96(CX) + MOVOU 112(BX), X12 + PXOR X7, X12 + MOVOU X12, 112(CX) + PADDQ X13, X11 + ADDQ $128, BX + ADDQ $128, CX + SUBQ $2, DX + JCC vector_loop2_begin +vector_loop2_end: + ADDQ $2, DX + JEQ out_serial + MOVO X8, X0 + MOVO X9, X1 + MOVO X10, X2 + MOVO X11, X3 + MOVQ $20, DX +rounds_loop1_begin: + PADDL X1, X0 + PXOR X0, X3 + MOVO X3, X12 + PSLLL $16, X12 + PSRLL $16, X3 + PXOR X12, X3 + PADDL X3, X2 + PXOR X2, X1 + MOVO X1, X12 + PSLLL $12, X12 + PSRLL $20, X1 + PXOR X12, X1 + PADDL X1, X0 + PXOR X0, X3 + MOVO X3, X12 + PSLLL $8, X12 + PSRLL $24, X3 + PXOR X12, X3 + PADDL X3, X2 + PXOR X2, X1 + MOVO X1, X12 + PSLLL $7, X12 + PSRLL $25, X1 + PXOR X12, X1 + PSHUFL $57, X1, X1 + PSHUFL $78, X2, X2 + PSHUFL $147, X3, X3 + PADDL X1, X0 + PXOR X0, X3 + MOVO X3, X12 + PSLLL $16, X12 + PSRLL $16, X3 + PXOR X12, X3 + PADDL X3, X2 + PXOR X2, X1 + MOVO X1, X12 + PSLLL $12, X12 + PSRLL $20, X1 + PXOR X12, X1 + PADDL X1, X0 + PXOR X0, X3 + MOVO X3, X12 + PSLLL $8, X12 + PSRLL $24, X3 + PXOR X12, X3 + PADDL X3, X2 + PXOR X2, X1 + MOVO X1, X12 + PSLLL $7, X12 + PSRLL $25, X1 + PXOR X12, X1 + PSHUFL $147, X1, X1 + PSHUFL $78, X2, X2 + PSHUFL $57, X3, X3 + SUBQ $2, DX + JNE rounds_loop1_begin + PADDL X8, X0 + PADDL X9, X1 + PADDL X10, X2 + PADDL X11, X3 + MOVOU 0(BX), X12 + PXOR X0, X12 + MOVOU X12, 0(CX) + MOVOU 16(BX), X12 + PXOR X1, X12 + MOVOU X12, 16(CX) + MOVOU 32(BX), X12 + PXOR X2, X12 + MOVOU X12, 32(CX) + MOVOU 48(BX), X12 + PXOR X3, X12 + MOVOU X12, 48(CX) + PADDQ X13, X11 +out_serial: + MOVO X11, 48(AX) +out: + PXOR X0, X0 + MOVO X0, 16(SP) + MOVQ DI, SP + RET + +// func blocksAmd64AVX2(x *uint32, inp *uint8, outp *uint8, nrBlocks *uint) +TEXT ·blocksAmd64AVX2(SB),4,$0-32 + MOVQ x+0(FP), AX + MOVQ inp+8(FP), BX + MOVQ outp+16(FP), CX + MOVQ nrBlocks+24(FP), DX + MOVQ SP, DI + MOVQ $31, SI + NOTQ SI + ANDQ SI, SP + SUBQ $32, SP + SUBQ $96, SP + BYTE $0xC4; BYTE $0x41; BYTE $0x1D; BYTE $0xEF; BYTE $0xE4 // VPXOR ymm12, ymm12, ymm12 + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0x24; BYTE $0x24 // VMOVDQU [rsp], ymm12 + MOVL $1, SI + MOVL SI, 16(SP) + BYTE $0xC4; BYTE $0xE2; BYTE $0x7D; BYTE $0x5A; BYTE $0x58; BYTE $0x30 // VBROADCASTI128 ymm3, [rax + 48] + BYTE $0xC5; BYTE $0xE5; BYTE $0xD4; BYTE $0x1C; BYTE $0x24 // VPADDQ ymm3, ymm3, [rsp] + BYTE $0xC5; BYTE $0xFD; BYTE $0x7F; BYTE $0x5C; BYTE $0x24; BYTE $0x20 // VMOVDQA [rsp + 32], ymm3 + MOVL $2, SI + MOVL SI, 0(SP) + MOVL SI, 16(SP) + SUBQ $8, DX + JCS vector_loop8_end +vector_loop8_begin: + BYTE $0xC4; BYTE $0xE2; BYTE $0x7D; BYTE $0x5A; BYTE $0x00 // VBROADCASTI128 ymm0, [rax] + BYTE $0xC4; BYTE $0xE2; BYTE $0x7D; BYTE $0x5A; BYTE $0x48; BYTE $0x10 // VBROADCASTI128 ymm1, [rax + 16] + BYTE $0xC4; BYTE $0xE2; BYTE $0x7D; BYTE $0x5A; BYTE $0x50; BYTE $0x20 // VBROADCASTI128 ymm2, [rax + 32] + BYTE $0xC5; BYTE $0xFD; BYTE $0x6F; BYTE $0x5C; BYTE $0x24; BYTE $0x20 // VMOVDQA ymm3, [rsp + 32] + BYTE $0xC5; BYTE $0xFD; BYTE $0x6F; BYTE $0xE0 // VMOVDQA ymm4, ymm0 + BYTE $0xC5; BYTE $0xFD; BYTE $0x6F; BYTE $0xE9 // VMOVDQA ymm5, ymm1 + BYTE $0xC5; BYTE $0xFD; BYTE $0x6F; BYTE $0xF2 // VMOVDQA ymm6, ymm2 + BYTE $0xC5; BYTE $0xE5; BYTE $0xD4; BYTE $0x3C; BYTE $0x24 // VPADDQ ymm7, ymm3, [rsp] + BYTE $0xC5; BYTE $0x7D; BYTE $0x6F; BYTE $0xC0 // VMOVDQA ymm8, ymm0 + BYTE $0xC5; BYTE $0x7D; BYTE $0x6F; BYTE $0xC9 // VMOVDQA ymm9, ymm1 + BYTE $0xC5; BYTE $0x7D; BYTE $0x6F; BYTE $0xD2 // VMOVDQA ymm10, ymm2 + BYTE $0xC5; BYTE $0x45; BYTE $0xD4; BYTE $0x1C; BYTE $0x24 // VPADDQ ymm11, ymm7, [rsp] + BYTE $0xC5; BYTE $0x7D; BYTE $0x6F; BYTE $0xE0 // VMOVDQA ymm12, ymm0 + BYTE $0xC5; BYTE $0x7D; BYTE $0x6F; BYTE $0xE9 // VMOVDQA ymm13, ymm1 + BYTE $0xC5; BYTE $0x7D; BYTE $0x6F; BYTE $0xF2 // VMOVDQA ymm14, ymm2 + BYTE $0xC5; BYTE $0x25; BYTE $0xD4; BYTE $0x3C; BYTE $0x24 // VPADDQ ymm15, ymm11, [rsp] + MOVQ $20, SI +rounds_loop8_begin: + BYTE $0xC5; BYTE $0xFD; BYTE $0xFE; BYTE $0xC1 // VPADDD ymm0, ymm0, ymm1 + BYTE $0xC5; BYTE $0xDD; BYTE $0xFE; BYTE $0xE5 // VPADDD ymm4, ymm4, ymm5 + BYTE $0xC4; BYTE $0x41; BYTE $0x3D; BYTE $0xFE; BYTE $0xC1 // VPADDD ymm8, ymm8, ymm9 + BYTE $0xC4; BYTE $0x41; BYTE $0x1D; BYTE $0xFE; BYTE $0xE5 // VPADDD ymm12, ymm12, ymm13 + BYTE $0xC5; BYTE $0xE5; BYTE $0xEF; BYTE $0xD8 // VPXOR ymm3, ymm3, ymm0 + BYTE $0xC5; BYTE $0xC5; BYTE $0xEF; BYTE $0xFC // VPXOR ymm7, ymm7, ymm4 + BYTE $0xC4; BYTE $0x41; BYTE $0x25; BYTE $0xEF; BYTE $0xD8 // VPXOR ymm11, ymm11, ymm8 + BYTE $0xC4; BYTE $0x41; BYTE $0x05; BYTE $0xEF; BYTE $0xFC // VPXOR ymm15, ymm15, ymm12 + BYTE $0xC5; BYTE $0x7D; BYTE $0x7F; BYTE $0x64; BYTE $0x24; BYTE $0x40 // VMOVDQA [rsp + 64], ymm12 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF3; BYTE $0x10 // VPSLLD ymm12, ymm3, 16 + BYTE $0xC5; BYTE $0xE5; BYTE $0x72; BYTE $0xD3; BYTE $0x10 // VPSRLD ymm3, ymm3, 16 + BYTE $0xC4; BYTE $0xC1; BYTE $0x65; BYTE $0xEF; BYTE $0xDC // VPXOR ymm3, ymm3, ymm12 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF7; BYTE $0x10 // VPSLLD ymm12, ymm7, 16 + BYTE $0xC5; BYTE $0xC5; BYTE $0x72; BYTE $0xD7; BYTE $0x10 // VPSRLD ymm7, ymm7, 16 + BYTE $0xC4; BYTE $0xC1; BYTE $0x45; BYTE $0xEF; BYTE $0xFC // VPXOR ymm7, ymm7, ymm12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x1D; BYTE $0x72; BYTE $0xF3; BYTE $0x10 // VPSLLD ymm12, ymm11, 16 + BYTE $0xC4; BYTE $0xC1; BYTE $0x25; BYTE $0x72; BYTE $0xD3; BYTE $0x10 // VPSRLD ymm11, ymm11, 16 + BYTE $0xC4; BYTE $0x41; BYTE $0x25; BYTE $0xEF; BYTE $0xDC // VPXOR ymm11, ymm11, ymm12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x1D; BYTE $0x72; BYTE $0xF7; BYTE $0x10 // VPSLLD ymm12, ymm15, 16 + BYTE $0xC4; BYTE $0xC1; BYTE $0x05; BYTE $0x72; BYTE $0xD7; BYTE $0x10 // VPSRLD ymm15, ymm15, 16 + BYTE $0xC4; BYTE $0x41; BYTE $0x05; BYTE $0xEF; BYTE $0xFC // VPXOR ymm15, ymm15, ymm12 + BYTE $0xC5; BYTE $0xED; BYTE $0xFE; BYTE $0xD3 // VPADDD ymm2, ymm2, ymm3 + BYTE $0xC5; BYTE $0xCD; BYTE $0xFE; BYTE $0xF7 // VPADDD ymm6, ymm6, ymm7 + BYTE $0xC4; BYTE $0x41; BYTE $0x2D; BYTE $0xFE; BYTE $0xD3 // VPADDD ymm10, ymm10, ymm11 + BYTE $0xC4; BYTE $0x41; BYTE $0x0D; BYTE $0xFE; BYTE $0xF7 // VPADDD ymm14, ymm14, ymm15 + BYTE $0xC5; BYTE $0xF5; BYTE $0xEF; BYTE $0xCA // VPXOR ymm1, ymm1, ymm2 + BYTE $0xC5; BYTE $0xD5; BYTE $0xEF; BYTE $0xEE // VPXOR ymm5, ymm5, ymm6 + BYTE $0xC4; BYTE $0x41; BYTE $0x35; BYTE $0xEF; BYTE $0xCA // VPXOR ymm9, ymm9, ymm10 + BYTE $0xC4; BYTE $0x41; BYTE $0x15; BYTE $0xEF; BYTE $0xEE // VPXOR ymm13, ymm13, ymm14 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF1; BYTE $0x0C // VPSLLD ymm12, ymm1, 12 + BYTE $0xC5; BYTE $0xF5; BYTE $0x72; BYTE $0xD1; BYTE $0x14 // VPSRLD ymm1, ymm1, 20 + BYTE $0xC4; BYTE $0xC1; BYTE $0x75; BYTE $0xEF; BYTE $0xCC // VPXOR ymm1, ymm1, ymm12 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF5; BYTE $0x0C // VPSLLD ymm12, ymm5, 12 + BYTE $0xC5; BYTE $0xD5; BYTE $0x72; BYTE $0xD5; BYTE $0x14 // VPSRLD ymm5, ymm5, 20 + BYTE $0xC4; BYTE $0xC1; BYTE $0x55; BYTE $0xEF; BYTE $0xEC // VPXOR ymm5, ymm5, ymm12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x1D; BYTE $0x72; BYTE $0xF1; BYTE $0x0C // VPSLLD ymm12, ymm9, 12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x35; BYTE $0x72; BYTE $0xD1; BYTE $0x14 // VPSRLD ymm9, ymm9, 20 + BYTE $0xC4; BYTE $0x41; BYTE $0x35; BYTE $0xEF; BYTE $0xCC // VPXOR ymm9, ymm9, ymm12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x1D; BYTE $0x72; BYTE $0xF5; BYTE $0x0C // VPSLLD ymm12, ymm13, 12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x15; BYTE $0x72; BYTE $0xD5; BYTE $0x14 // VPSRLD ymm13, ymm13, 20 + BYTE $0xC4; BYTE $0x41; BYTE $0x15; BYTE $0xEF; BYTE $0xEC // VPXOR ymm13, ymm13, ymm12 + BYTE $0xC5; BYTE $0x7D; BYTE $0x6F; BYTE $0x64; BYTE $0x24; BYTE $0x40 // VMOVDQA ymm12, [rsp + 64] + BYTE $0xC5; BYTE $0xFD; BYTE $0xFE; BYTE $0xC1 // VPADDD ymm0, ymm0, ymm1 + BYTE $0xC5; BYTE $0xDD; BYTE $0xFE; BYTE $0xE5 // VPADDD ymm4, ymm4, ymm5 + BYTE $0xC4; BYTE $0x41; BYTE $0x3D; BYTE $0xFE; BYTE $0xC1 // VPADDD ymm8, ymm8, ymm9 + BYTE $0xC4; BYTE $0x41; BYTE $0x1D; BYTE $0xFE; BYTE $0xE5 // VPADDD ymm12, ymm12, ymm13 + BYTE $0xC5; BYTE $0xE5; BYTE $0xEF; BYTE $0xD8 // VPXOR ymm3, ymm3, ymm0 + BYTE $0xC5; BYTE $0xC5; BYTE $0xEF; BYTE $0xFC // VPXOR ymm7, ymm7, ymm4 + BYTE $0xC4; BYTE $0x41; BYTE $0x25; BYTE $0xEF; BYTE $0xD8 // VPXOR ymm11, ymm11, ymm8 + BYTE $0xC4; BYTE $0x41; BYTE $0x05; BYTE $0xEF; BYTE $0xFC // VPXOR ymm15, ymm15, ymm12 + BYTE $0xC5; BYTE $0x7D; BYTE $0x7F; BYTE $0x64; BYTE $0x24; BYTE $0x40 // VMOVDQA [rsp + 64], ymm12 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF3; BYTE $0x08 // VPSLLD ymm12, ymm3, 8 + BYTE $0xC5; BYTE $0xE5; BYTE $0x72; BYTE $0xD3; BYTE $0x18 // VPSRLD ymm3, ymm3, 24 + BYTE $0xC4; BYTE $0xC1; BYTE $0x65; BYTE $0xEF; BYTE $0xDC // VPXOR ymm3, ymm3, ymm12 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF7; BYTE $0x08 // VPSLLD ymm12, ymm7, 8 + BYTE $0xC5; BYTE $0xC5; BYTE $0x72; BYTE $0xD7; BYTE $0x18 // VPSRLD ymm7, ymm7, 24 + BYTE $0xC4; BYTE $0xC1; BYTE $0x45; BYTE $0xEF; BYTE $0xFC // VPXOR ymm7, ymm7, ymm12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x1D; BYTE $0x72; BYTE $0xF3; BYTE $0x08 // VPSLLD ymm12, ymm11, 8 + BYTE $0xC4; BYTE $0xC1; BYTE $0x25; BYTE $0x72; BYTE $0xD3; BYTE $0x18 // VPSRLD ymm11, ymm11, 24 + BYTE $0xC4; BYTE $0x41; BYTE $0x25; BYTE $0xEF; BYTE $0xDC // VPXOR ymm11, ymm11, ymm12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x1D; BYTE $0x72; BYTE $0xF7; BYTE $0x08 // VPSLLD ymm12, ymm15, 8 + BYTE $0xC4; BYTE $0xC1; BYTE $0x05; BYTE $0x72; BYTE $0xD7; BYTE $0x18 // VPSRLD ymm15, ymm15, 24 + BYTE $0xC4; BYTE $0x41; BYTE $0x05; BYTE $0xEF; BYTE $0xFC // VPXOR ymm15, ymm15, ymm12 + BYTE $0xC5; BYTE $0xED; BYTE $0xFE; BYTE $0xD3 // VPADDD ymm2, ymm2, ymm3 + BYTE $0xC5; BYTE $0xCD; BYTE $0xFE; BYTE $0xF7 // VPADDD ymm6, ymm6, ymm7 + BYTE $0xC4; BYTE $0x41; BYTE $0x2D; BYTE $0xFE; BYTE $0xD3 // VPADDD ymm10, ymm10, ymm11 + BYTE $0xC4; BYTE $0x41; BYTE $0x0D; BYTE $0xFE; BYTE $0xF7 // VPADDD ymm14, ymm14, ymm15 + BYTE $0xC5; BYTE $0xF5; BYTE $0xEF; BYTE $0xCA // VPXOR ymm1, ymm1, ymm2 + BYTE $0xC5; BYTE $0xD5; BYTE $0xEF; BYTE $0xEE // VPXOR ymm5, ymm5, ymm6 + BYTE $0xC4; BYTE $0x41; BYTE $0x35; BYTE $0xEF; BYTE $0xCA // VPXOR ymm9, ymm9, ymm10 + BYTE $0xC4; BYTE $0x41; BYTE $0x15; BYTE $0xEF; BYTE $0xEE // VPXOR ymm13, ymm13, ymm14 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF1; BYTE $0x07 // VPSLLD ymm12, ymm1, 7 + BYTE $0xC5; BYTE $0xF5; BYTE $0x72; BYTE $0xD1; BYTE $0x19 // VPSRLD ymm1, ymm1, 25 + BYTE $0xC4; BYTE $0xC1; BYTE $0x75; BYTE $0xEF; BYTE $0xCC // VPXOR ymm1, ymm1, ymm12 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF5; BYTE $0x07 // VPSLLD ymm12, ymm5, 7 + BYTE $0xC5; BYTE $0xD5; BYTE $0x72; BYTE $0xD5; BYTE $0x19 // VPSRLD ymm5, ymm5, 25 + BYTE $0xC4; BYTE $0xC1; BYTE $0x55; BYTE $0xEF; BYTE $0xEC // VPXOR ymm5, ymm5, ymm12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x1D; BYTE $0x72; BYTE $0xF1; BYTE $0x07 // VPSLLD ymm12, ymm9, 7 + BYTE $0xC4; BYTE $0xC1; BYTE $0x35; BYTE $0x72; BYTE $0xD1; BYTE $0x19 // VPSRLD ymm9, ymm9, 25 + BYTE $0xC4; BYTE $0x41; BYTE $0x35; BYTE $0xEF; BYTE $0xCC // VPXOR ymm9, ymm9, ymm12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x1D; BYTE $0x72; BYTE $0xF5; BYTE $0x07 // VPSLLD ymm12, ymm13, 7 + BYTE $0xC4; BYTE $0xC1; BYTE $0x15; BYTE $0x72; BYTE $0xD5; BYTE $0x19 // VPSRLD ymm13, ymm13, 25 + BYTE $0xC4; BYTE $0x41; BYTE $0x15; BYTE $0xEF; BYTE $0xEC // VPXOR ymm13, ymm13, ymm12 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xC9; BYTE $0x39 // VPSHUFD ymm1, ymm1, 57 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xED; BYTE $0x39 // VPSHUFD ymm5, ymm5, 57 + BYTE $0xC4; BYTE $0x41; BYTE $0x7D; BYTE $0x70; BYTE $0xC9; BYTE $0x39 // VPSHUFD ymm9, ymm9, 57 + BYTE $0xC4; BYTE $0x41; BYTE $0x7D; BYTE $0x70; BYTE $0xED; BYTE $0x39 // VPSHUFD ymm13, ymm13, 57 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xD2; BYTE $0x4E // VPSHUFD ymm2, ymm2, 78 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xF6; BYTE $0x4E // VPSHUFD ymm6, ymm6, 78 + BYTE $0xC4; BYTE $0x41; BYTE $0x7D; BYTE $0x70; BYTE $0xD2; BYTE $0x4E // VPSHUFD ymm10, ymm10, 78 + BYTE $0xC4; BYTE $0x41; BYTE $0x7D; BYTE $0x70; BYTE $0xF6; BYTE $0x4E // VPSHUFD ymm14, ymm14, 78 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xDB; BYTE $0x93 // VPSHUFD ymm3, ymm3, 147 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xFF; BYTE $0x93 // VPSHUFD ymm7, ymm7, 147 + BYTE $0xC4; BYTE $0x41; BYTE $0x7D; BYTE $0x70; BYTE $0xDB; BYTE $0x93 // VPSHUFD ymm11, ymm11, 147 + BYTE $0xC4; BYTE $0x41; BYTE $0x7D; BYTE $0x70; BYTE $0xFF; BYTE $0x93 // VPSHUFD ymm15, ymm15, 147 + BYTE $0xC5; BYTE $0x7D; BYTE $0x6F; BYTE $0x64; BYTE $0x24; BYTE $0x40 // VMOVDQA ymm12, [rsp + 64] + BYTE $0xC5; BYTE $0xFD; BYTE $0xFE; BYTE $0xC1 // VPADDD ymm0, ymm0, ymm1 + BYTE $0xC5; BYTE $0xDD; BYTE $0xFE; BYTE $0xE5 // VPADDD ymm4, ymm4, ymm5 + BYTE $0xC4; BYTE $0x41; BYTE $0x3D; BYTE $0xFE; BYTE $0xC1 // VPADDD ymm8, ymm8, ymm9 + BYTE $0xC4; BYTE $0x41; BYTE $0x1D; BYTE $0xFE; BYTE $0xE5 // VPADDD ymm12, ymm12, ymm13 + BYTE $0xC5; BYTE $0xE5; BYTE $0xEF; BYTE $0xD8 // VPXOR ymm3, ymm3, ymm0 + BYTE $0xC5; BYTE $0xC5; BYTE $0xEF; BYTE $0xFC // VPXOR ymm7, ymm7, ymm4 + BYTE $0xC4; BYTE $0x41; BYTE $0x25; BYTE $0xEF; BYTE $0xD8 // VPXOR ymm11, ymm11, ymm8 + BYTE $0xC4; BYTE $0x41; BYTE $0x05; BYTE $0xEF; BYTE $0xFC // VPXOR ymm15, ymm15, ymm12 + BYTE $0xC5; BYTE $0x7D; BYTE $0x7F; BYTE $0x64; BYTE $0x24; BYTE $0x40 // VMOVDQA [rsp + 64], ymm12 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF3; BYTE $0x10 // VPSLLD ymm12, ymm3, 16 + BYTE $0xC5; BYTE $0xE5; BYTE $0x72; BYTE $0xD3; BYTE $0x10 // VPSRLD ymm3, ymm3, 16 + BYTE $0xC4; BYTE $0xC1; BYTE $0x65; BYTE $0xEF; BYTE $0xDC // VPXOR ymm3, ymm3, ymm12 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF7; BYTE $0x10 // VPSLLD ymm12, ymm7, 16 + BYTE $0xC5; BYTE $0xC5; BYTE $0x72; BYTE $0xD7; BYTE $0x10 // VPSRLD ymm7, ymm7, 16 + BYTE $0xC4; BYTE $0xC1; BYTE $0x45; BYTE $0xEF; BYTE $0xFC // VPXOR ymm7, ymm7, ymm12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x1D; BYTE $0x72; BYTE $0xF3; BYTE $0x10 // VPSLLD ymm12, ymm11, 16 + BYTE $0xC4; BYTE $0xC1; BYTE $0x25; BYTE $0x72; BYTE $0xD3; BYTE $0x10 // VPSRLD ymm11, ymm11, 16 + BYTE $0xC4; BYTE $0x41; BYTE $0x25; BYTE $0xEF; BYTE $0xDC // VPXOR ymm11, ymm11, ymm12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x1D; BYTE $0x72; BYTE $0xF7; BYTE $0x10 // VPSLLD ymm12, ymm15, 16 + BYTE $0xC4; BYTE $0xC1; BYTE $0x05; BYTE $0x72; BYTE $0xD7; BYTE $0x10 // VPSRLD ymm15, ymm15, 16 + BYTE $0xC4; BYTE $0x41; BYTE $0x05; BYTE $0xEF; BYTE $0xFC // VPXOR ymm15, ymm15, ymm12 + BYTE $0xC5; BYTE $0xED; BYTE $0xFE; BYTE $0xD3 // VPADDD ymm2, ymm2, ymm3 + BYTE $0xC5; BYTE $0xCD; BYTE $0xFE; BYTE $0xF7 // VPADDD ymm6, ymm6, ymm7 + BYTE $0xC4; BYTE $0x41; BYTE $0x2D; BYTE $0xFE; BYTE $0xD3 // VPADDD ymm10, ymm10, ymm11 + BYTE $0xC4; BYTE $0x41; BYTE $0x0D; BYTE $0xFE; BYTE $0xF7 // VPADDD ymm14, ymm14, ymm15 + BYTE $0xC5; BYTE $0xF5; BYTE $0xEF; BYTE $0xCA // VPXOR ymm1, ymm1, ymm2 + BYTE $0xC5; BYTE $0xD5; BYTE $0xEF; BYTE $0xEE // VPXOR ymm5, ymm5, ymm6 + BYTE $0xC4; BYTE $0x41; BYTE $0x35; BYTE $0xEF; BYTE $0xCA // VPXOR ymm9, ymm9, ymm10 + BYTE $0xC4; BYTE $0x41; BYTE $0x15; BYTE $0xEF; BYTE $0xEE // VPXOR ymm13, ymm13, ymm14 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF1; BYTE $0x0C // VPSLLD ymm12, ymm1, 12 + BYTE $0xC5; BYTE $0xF5; BYTE $0x72; BYTE $0xD1; BYTE $0x14 // VPSRLD ymm1, ymm1, 20 + BYTE $0xC4; BYTE $0xC1; BYTE $0x75; BYTE $0xEF; BYTE $0xCC // VPXOR ymm1, ymm1, ymm12 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF5; BYTE $0x0C // VPSLLD ymm12, ymm5, 12 + BYTE $0xC5; BYTE $0xD5; BYTE $0x72; BYTE $0xD5; BYTE $0x14 // VPSRLD ymm5, ymm5, 20 + BYTE $0xC4; BYTE $0xC1; BYTE $0x55; BYTE $0xEF; BYTE $0xEC // VPXOR ymm5, ymm5, ymm12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x1D; BYTE $0x72; BYTE $0xF1; BYTE $0x0C // VPSLLD ymm12, ymm9, 12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x35; BYTE $0x72; BYTE $0xD1; BYTE $0x14 // VPSRLD ymm9, ymm9, 20 + BYTE $0xC4; BYTE $0x41; BYTE $0x35; BYTE $0xEF; BYTE $0xCC // VPXOR ymm9, ymm9, ymm12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x1D; BYTE $0x72; BYTE $0xF5; BYTE $0x0C // VPSLLD ymm12, ymm13, 12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x15; BYTE $0x72; BYTE $0xD5; BYTE $0x14 // VPSRLD ymm13, ymm13, 20 + BYTE $0xC4; BYTE $0x41; BYTE $0x15; BYTE $0xEF; BYTE $0xEC // VPXOR ymm13, ymm13, ymm12 + BYTE $0xC5; BYTE $0x7D; BYTE $0x6F; BYTE $0x64; BYTE $0x24; BYTE $0x40 // VMOVDQA ymm12, [rsp + 64] + BYTE $0xC5; BYTE $0xFD; BYTE $0xFE; BYTE $0xC1 // VPADDD ymm0, ymm0, ymm1 + BYTE $0xC5; BYTE $0xDD; BYTE $0xFE; BYTE $0xE5 // VPADDD ymm4, ymm4, ymm5 + BYTE $0xC4; BYTE $0x41; BYTE $0x3D; BYTE $0xFE; BYTE $0xC1 // VPADDD ymm8, ymm8, ymm9 + BYTE $0xC4; BYTE $0x41; BYTE $0x1D; BYTE $0xFE; BYTE $0xE5 // VPADDD ymm12, ymm12, ymm13 + BYTE $0xC5; BYTE $0xE5; BYTE $0xEF; BYTE $0xD8 // VPXOR ymm3, ymm3, ymm0 + BYTE $0xC5; BYTE $0xC5; BYTE $0xEF; BYTE $0xFC // VPXOR ymm7, ymm7, ymm4 + BYTE $0xC4; BYTE $0x41; BYTE $0x25; BYTE $0xEF; BYTE $0xD8 // VPXOR ymm11, ymm11, ymm8 + BYTE $0xC4; BYTE $0x41; BYTE $0x05; BYTE $0xEF; BYTE $0xFC // VPXOR ymm15, ymm15, ymm12 + BYTE $0xC5; BYTE $0x7D; BYTE $0x7F; BYTE $0x64; BYTE $0x24; BYTE $0x40 // VMOVDQA [rsp + 64], ymm12 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF3; BYTE $0x08 // VPSLLD ymm12, ymm3, 8 + BYTE $0xC5; BYTE $0xE5; BYTE $0x72; BYTE $0xD3; BYTE $0x18 // VPSRLD ymm3, ymm3, 24 + BYTE $0xC4; BYTE $0xC1; BYTE $0x65; BYTE $0xEF; BYTE $0xDC // VPXOR ymm3, ymm3, ymm12 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF7; BYTE $0x08 // VPSLLD ymm12, ymm7, 8 + BYTE $0xC5; BYTE $0xC5; BYTE $0x72; BYTE $0xD7; BYTE $0x18 // VPSRLD ymm7, ymm7, 24 + BYTE $0xC4; BYTE $0xC1; BYTE $0x45; BYTE $0xEF; BYTE $0xFC // VPXOR ymm7, ymm7, ymm12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x1D; BYTE $0x72; BYTE $0xF3; BYTE $0x08 // VPSLLD ymm12, ymm11, 8 + BYTE $0xC4; BYTE $0xC1; BYTE $0x25; BYTE $0x72; BYTE $0xD3; BYTE $0x18 // VPSRLD ymm11, ymm11, 24 + BYTE $0xC4; BYTE $0x41; BYTE $0x25; BYTE $0xEF; BYTE $0xDC // VPXOR ymm11, ymm11, ymm12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x1D; BYTE $0x72; BYTE $0xF7; BYTE $0x08 // VPSLLD ymm12, ymm15, 8 + BYTE $0xC4; BYTE $0xC1; BYTE $0x05; BYTE $0x72; BYTE $0xD7; BYTE $0x18 // VPSRLD ymm15, ymm15, 24 + BYTE $0xC4; BYTE $0x41; BYTE $0x05; BYTE $0xEF; BYTE $0xFC // VPXOR ymm15, ymm15, ymm12 + BYTE $0xC5; BYTE $0xED; BYTE $0xFE; BYTE $0xD3 // VPADDD ymm2, ymm2, ymm3 + BYTE $0xC5; BYTE $0xCD; BYTE $0xFE; BYTE $0xF7 // VPADDD ymm6, ymm6, ymm7 + BYTE $0xC4; BYTE $0x41; BYTE $0x2D; BYTE $0xFE; BYTE $0xD3 // VPADDD ymm10, ymm10, ymm11 + BYTE $0xC4; BYTE $0x41; BYTE $0x0D; BYTE $0xFE; BYTE $0xF7 // VPADDD ymm14, ymm14, ymm15 + BYTE $0xC5; BYTE $0xF5; BYTE $0xEF; BYTE $0xCA // VPXOR ymm1, ymm1, ymm2 + BYTE $0xC5; BYTE $0xD5; BYTE $0xEF; BYTE $0xEE // VPXOR ymm5, ymm5, ymm6 + BYTE $0xC4; BYTE $0x41; BYTE $0x35; BYTE $0xEF; BYTE $0xCA // VPXOR ymm9, ymm9, ymm10 + BYTE $0xC4; BYTE $0x41; BYTE $0x15; BYTE $0xEF; BYTE $0xEE // VPXOR ymm13, ymm13, ymm14 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF1; BYTE $0x07 // VPSLLD ymm12, ymm1, 7 + BYTE $0xC5; BYTE $0xF5; BYTE $0x72; BYTE $0xD1; BYTE $0x19 // VPSRLD ymm1, ymm1, 25 + BYTE $0xC4; BYTE $0xC1; BYTE $0x75; BYTE $0xEF; BYTE $0xCC // VPXOR ymm1, ymm1, ymm12 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF5; BYTE $0x07 // VPSLLD ymm12, ymm5, 7 + BYTE $0xC5; BYTE $0xD5; BYTE $0x72; BYTE $0xD5; BYTE $0x19 // VPSRLD ymm5, ymm5, 25 + BYTE $0xC4; BYTE $0xC1; BYTE $0x55; BYTE $0xEF; BYTE $0xEC // VPXOR ymm5, ymm5, ymm12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x1D; BYTE $0x72; BYTE $0xF1; BYTE $0x07 // VPSLLD ymm12, ymm9, 7 + BYTE $0xC4; BYTE $0xC1; BYTE $0x35; BYTE $0x72; BYTE $0xD1; BYTE $0x19 // VPSRLD ymm9, ymm9, 25 + BYTE $0xC4; BYTE $0x41; BYTE $0x35; BYTE $0xEF; BYTE $0xCC // VPXOR ymm9, ymm9, ymm12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x1D; BYTE $0x72; BYTE $0xF5; BYTE $0x07 // VPSLLD ymm12, ymm13, 7 + BYTE $0xC4; BYTE $0xC1; BYTE $0x15; BYTE $0x72; BYTE $0xD5; BYTE $0x19 // VPSRLD ymm13, ymm13, 25 + BYTE $0xC4; BYTE $0x41; BYTE $0x15; BYTE $0xEF; BYTE $0xEC // VPXOR ymm13, ymm13, ymm12 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xC9; BYTE $0x93 // VPSHUFD ymm1, ymm1, 147 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xED; BYTE $0x93 // VPSHUFD ymm5, ymm5, 147 + BYTE $0xC4; BYTE $0x41; BYTE $0x7D; BYTE $0x70; BYTE $0xC9; BYTE $0x93 // VPSHUFD ymm9, ymm9, 147 + BYTE $0xC4; BYTE $0x41; BYTE $0x7D; BYTE $0x70; BYTE $0xED; BYTE $0x93 // VPSHUFD ymm13, ymm13, 147 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xD2; BYTE $0x4E // VPSHUFD ymm2, ymm2, 78 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xF6; BYTE $0x4E // VPSHUFD ymm6, ymm6, 78 + BYTE $0xC4; BYTE $0x41; BYTE $0x7D; BYTE $0x70; BYTE $0xD2; BYTE $0x4E // VPSHUFD ymm10, ymm10, 78 + BYTE $0xC4; BYTE $0x41; BYTE $0x7D; BYTE $0x70; BYTE $0xF6; BYTE $0x4E // VPSHUFD ymm14, ymm14, 78 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xDB; BYTE $0x39 // VPSHUFD ymm3, ymm3, 57 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xFF; BYTE $0x39 // VPSHUFD ymm7, ymm7, 57 + BYTE $0xC4; BYTE $0x41; BYTE $0x7D; BYTE $0x70; BYTE $0xDB; BYTE $0x39 // VPSHUFD ymm11, ymm11, 57 + BYTE $0xC4; BYTE $0x41; BYTE $0x7D; BYTE $0x70; BYTE $0xFF; BYTE $0x39 // VPSHUFD ymm15, ymm15, 57 + BYTE $0xC5; BYTE $0x7D; BYTE $0x6F; BYTE $0x64; BYTE $0x24; BYTE $0x40 // VMOVDQA ymm12, [rsp + 64] + SUBQ $2, SI + JNE rounds_loop8_begin + BYTE $0xC4; BYTE $0x62; BYTE $0x7D; BYTE $0x5A; BYTE $0x20 // VBROADCASTI128 ymm12, [rax] + BYTE $0xC4; BYTE $0xC1; BYTE $0x7D; BYTE $0xFE; BYTE $0xC4 // VPADDD ymm0, ymm0, ymm12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x5D; BYTE $0xFE; BYTE $0xE4 // VPADDD ymm4, ymm4, ymm12 + BYTE $0xC4; BYTE $0x41; BYTE $0x3D; BYTE $0xFE; BYTE $0xC4 // VPADDD ymm8, ymm8, ymm12 + BYTE $0xC5; BYTE $0x1D; BYTE $0xFE; BYTE $0x64; BYTE $0x24; BYTE $0x40 // VPADDD ymm12, ymm12, [rsp + 64] + BYTE $0xC5; BYTE $0x7D; BYTE $0x7F; BYTE $0x64; BYTE $0x24; BYTE $0x40 // VMOVDQA [rsp + 64], ymm12 + BYTE $0xC4; BYTE $0x62; BYTE $0x7D; BYTE $0x5A; BYTE $0x60; BYTE $0x10 // VBROADCASTI128 ymm12, [rax + 16] + BYTE $0xC4; BYTE $0xC1; BYTE $0x75; BYTE $0xFE; BYTE $0xCC // VPADDD ymm1, ymm1, ymm12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x55; BYTE $0xFE; BYTE $0xEC // VPADDD ymm5, ymm5, ymm12 + BYTE $0xC4; BYTE $0x41; BYTE $0x35; BYTE $0xFE; BYTE $0xCC // VPADDD ymm9, ymm9, ymm12 + BYTE $0xC4; BYTE $0x41; BYTE $0x15; BYTE $0xFE; BYTE $0xEC // VPADDD ymm13, ymm13, ymm12 + BYTE $0xC4; BYTE $0x62; BYTE $0x7D; BYTE $0x5A; BYTE $0x60; BYTE $0x20 // VBROADCASTI128 ymm12, [rax + 32] + BYTE $0xC4; BYTE $0xC1; BYTE $0x6D; BYTE $0xFE; BYTE $0xD4 // VPADDD ymm2, ymm2, ymm12 + BYTE $0xC4; BYTE $0xC1; BYTE $0x4D; BYTE $0xFE; BYTE $0xF4 // VPADDD ymm6, ymm6, ymm12 + BYTE $0xC4; BYTE $0x41; BYTE $0x2D; BYTE $0xFE; BYTE $0xD4 // VPADDD ymm10, ymm10, ymm12 + BYTE $0xC4; BYTE $0x41; BYTE $0x0D; BYTE $0xFE; BYTE $0xF4 // VPADDD ymm14, ymm14, ymm12 + BYTE $0xC5; BYTE $0xE5; BYTE $0xFE; BYTE $0x5C; BYTE $0x24; BYTE $0x20 // VPADDD ymm3, ymm3, [rsp + 32] + BYTE $0xC4; BYTE $0x63; BYTE $0x7D; BYTE $0x46; BYTE $0xE1; BYTE $0x20 // VPERM2I128 ymm12, ymm0, ymm1, 32 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0x23 // VPXOR ymm12, ymm12, [rbx] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0x21 // VMOVDQU [rcx], ymm12 + BYTE $0xC4; BYTE $0x63; BYTE $0x6D; BYTE $0x46; BYTE $0xE3; BYTE $0x20 // VPERM2I128 ymm12, ymm2, ymm3, 32 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0x63; BYTE $0x20 // VPXOR ymm12, ymm12, [rbx + 32] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0x61; BYTE $0x20 // VMOVDQU [rcx + 32], ymm12 + BYTE $0xC4; BYTE $0x63; BYTE $0x7D; BYTE $0x46; BYTE $0xE1; BYTE $0x31 // VPERM2I128 ymm12, ymm0, ymm1, 49 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0x63; BYTE $0x40 // VPXOR ymm12, ymm12, [rbx + 64] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0x61; BYTE $0x40 // VMOVDQU [rcx + 64], ymm12 + BYTE $0xC4; BYTE $0x63; BYTE $0x6D; BYTE $0x46; BYTE $0xE3; BYTE $0x31 // VPERM2I128 ymm12, ymm2, ymm3, 49 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0x63; BYTE $0x60 // VPXOR ymm12, ymm12, [rbx + 96] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0x61; BYTE $0x60 // VMOVDQU [rcx + 96], ymm12 + BYTE $0xC5; BYTE $0xFD; BYTE $0x6F; BYTE $0x5C; BYTE $0x24; BYTE $0x20 // VMOVDQA ymm3, [rsp + 32] + BYTE $0xC5; BYTE $0xE5; BYTE $0xFE; BYTE $0x1C; BYTE $0x24 // VPADDD ymm3, ymm3, [rsp] + BYTE $0xC5; BYTE $0xC5; BYTE $0xFE; BYTE $0xFB // VPADDD ymm7, ymm7, ymm3 + BYTE $0xC4; BYTE $0x63; BYTE $0x5D; BYTE $0x46; BYTE $0xE5; BYTE $0x20 // VPERM2I128 ymm12, ymm4, ymm5, 32 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0xA3; BYTE $0x80; BYTE $0x00; BYTE $0x00; BYTE $0x00 // VPXOR ymm12, ymm12, [rbx + 128] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0xA1; BYTE $0x80; BYTE $0x00; BYTE $0x00; BYTE $0x00 // VMOVDQU [rcx + 128], ymm12 + BYTE $0xC4; BYTE $0x63; BYTE $0x4D; BYTE $0x46; BYTE $0xE7; BYTE $0x20 // VPERM2I128 ymm12, ymm6, ymm7, 32 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0xA3; BYTE $0xA0; BYTE $0x00; BYTE $0x00; BYTE $0x00 // VPXOR ymm12, ymm12, [rbx + 160] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0xA1; BYTE $0xA0; BYTE $0x00; BYTE $0x00; BYTE $0x00 // VMOVDQU [rcx + 160], ymm12 + BYTE $0xC4; BYTE $0x63; BYTE $0x5D; BYTE $0x46; BYTE $0xE5; BYTE $0x31 // VPERM2I128 ymm12, ymm4, ymm5, 49 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0xA3; BYTE $0xC0; BYTE $0x00; BYTE $0x00; BYTE $0x00 // VPXOR ymm12, ymm12, [rbx + 192] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0xA1; BYTE $0xC0; BYTE $0x00; BYTE $0x00; BYTE $0x00 // VMOVDQU [rcx + 192], ymm12 + BYTE $0xC4; BYTE $0x63; BYTE $0x4D; BYTE $0x46; BYTE $0xE7; BYTE $0x31 // VPERM2I128 ymm12, ymm6, ymm7, 49 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0xA3; BYTE $0xE0; BYTE $0x00; BYTE $0x00; BYTE $0x00 // VPXOR ymm12, ymm12, [rbx + 224] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0xA1; BYTE $0xE0; BYTE $0x00; BYTE $0x00; BYTE $0x00 // VMOVDQU [rcx + 224], ymm12 + BYTE $0xC5; BYTE $0xE5; BYTE $0xFE; BYTE $0x1C; BYTE $0x24 // VPADDD ymm3, ymm3, [rsp] + BYTE $0xC5; BYTE $0x25; BYTE $0xFE; BYTE $0xDB // VPADDD ymm11, ymm11, ymm3 + BYTE $0xC4; BYTE $0x43; BYTE $0x3D; BYTE $0x46; BYTE $0xE1; BYTE $0x20 // VPERM2I128 ymm12, ymm8, ymm9, 32 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0xA3; BYTE $0x00; BYTE $0x01; BYTE $0x00; BYTE $0x00 // VPXOR ymm12, ymm12, [rbx + 256] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0xA1; BYTE $0x00; BYTE $0x01; BYTE $0x00; BYTE $0x00 // VMOVDQU [rcx + 256], ymm12 + BYTE $0xC4; BYTE $0x43; BYTE $0x2D; BYTE $0x46; BYTE $0xE3; BYTE $0x20 // VPERM2I128 ymm12, ymm10, ymm11, 32 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0xA3; BYTE $0x20; BYTE $0x01; BYTE $0x00; BYTE $0x00 // VPXOR ymm12, ymm12, [rbx + 288] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0xA1; BYTE $0x20; BYTE $0x01; BYTE $0x00; BYTE $0x00 // VMOVDQU [rcx + 288], ymm12 + BYTE $0xC4; BYTE $0x43; BYTE $0x3D; BYTE $0x46; BYTE $0xE1; BYTE $0x31 // VPERM2I128 ymm12, ymm8, ymm9, 49 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0xA3; BYTE $0x40; BYTE $0x01; BYTE $0x00; BYTE $0x00 // VPXOR ymm12, ymm12, [rbx + 320] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0xA1; BYTE $0x40; BYTE $0x01; BYTE $0x00; BYTE $0x00 // VMOVDQU [rcx + 320], ymm12 + BYTE $0xC4; BYTE $0x43; BYTE $0x2D; BYTE $0x46; BYTE $0xE3; BYTE $0x31 // VPERM2I128 ymm12, ymm10, ymm11, 49 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0xA3; BYTE $0x60; BYTE $0x01; BYTE $0x00; BYTE $0x00 // VPXOR ymm12, ymm12, [rbx + 352] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0xA1; BYTE $0x60; BYTE $0x01; BYTE $0x00; BYTE $0x00 // VMOVDQU [rcx + 352], ymm12 + BYTE $0xC5; BYTE $0xE5; BYTE $0xFE; BYTE $0x1C; BYTE $0x24 // VPADDD ymm3, ymm3, [rsp] + BYTE $0xC5; BYTE $0x7D; BYTE $0x6F; BYTE $0x64; BYTE $0x24; BYTE $0x40 // VMOVDQA ymm12, [rsp + 64] + BYTE $0xC5; BYTE $0x05; BYTE $0xFE; BYTE $0xFB // VPADDD ymm15, ymm15, ymm3 + BYTE $0xC4; BYTE $0xC3; BYTE $0x1D; BYTE $0x46; BYTE $0xC5; BYTE $0x20 // VPERM2I128 ymm0, ymm12, ymm13, 32 + BYTE $0xC5; BYTE $0xFD; BYTE $0xEF; BYTE $0x83; BYTE $0x80; BYTE $0x01; BYTE $0x00; BYTE $0x00 // VPXOR ymm0, ymm0, [rbx + 384] + BYTE $0xC5; BYTE $0xFE; BYTE $0x7F; BYTE $0x81; BYTE $0x80; BYTE $0x01; BYTE $0x00; BYTE $0x00 // VMOVDQU [rcx + 384], ymm0 + BYTE $0xC4; BYTE $0xC3; BYTE $0x0D; BYTE $0x46; BYTE $0xC7; BYTE $0x20 // VPERM2I128 ymm0, ymm14, ymm15, 32 + BYTE $0xC5; BYTE $0xFD; BYTE $0xEF; BYTE $0x83; BYTE $0xA0; BYTE $0x01; BYTE $0x00; BYTE $0x00 // VPXOR ymm0, ymm0, [rbx + 416] + BYTE $0xC5; BYTE $0xFE; BYTE $0x7F; BYTE $0x81; BYTE $0xA0; BYTE $0x01; BYTE $0x00; BYTE $0x00 // VMOVDQU [rcx + 416], ymm0 + BYTE $0xC4; BYTE $0xC3; BYTE $0x1D; BYTE $0x46; BYTE $0xC5; BYTE $0x31 // VPERM2I128 ymm0, ymm12, ymm13, 49 + BYTE $0xC5; BYTE $0xFD; BYTE $0xEF; BYTE $0x83; BYTE $0xC0; BYTE $0x01; BYTE $0x00; BYTE $0x00 // VPXOR ymm0, ymm0, [rbx + 448] + BYTE $0xC5; BYTE $0xFE; BYTE $0x7F; BYTE $0x81; BYTE $0xC0; BYTE $0x01; BYTE $0x00; BYTE $0x00 // VMOVDQU [rcx + 448], ymm0 + BYTE $0xC4; BYTE $0xC3; BYTE $0x0D; BYTE $0x46; BYTE $0xC7; BYTE $0x31 // VPERM2I128 ymm0, ymm14, ymm15, 49 + BYTE $0xC5; BYTE $0xFD; BYTE $0xEF; BYTE $0x83; BYTE $0xE0; BYTE $0x01; BYTE $0x00; BYTE $0x00 // VPXOR ymm0, ymm0, [rbx + 480] + BYTE $0xC5; BYTE $0xFE; BYTE $0x7F; BYTE $0x81; BYTE $0xE0; BYTE $0x01; BYTE $0x00; BYTE $0x00 // VMOVDQU [rcx + 480], ymm0 + BYTE $0xC5; BYTE $0xE5; BYTE $0xFE; BYTE $0x1C; BYTE $0x24 // VPADDD ymm3, ymm3, [rsp] + BYTE $0xC5; BYTE $0xFD; BYTE $0x7F; BYTE $0x5C; BYTE $0x24; BYTE $0x20 // VMOVDQA [rsp + 32], ymm3 + ADDQ $512, BX + ADDQ $512, CX + SUBQ $8, DX + JCC vector_loop8_begin +vector_loop8_end: + BYTE $0xC5; BYTE $0x7D; BYTE $0x6F; BYTE $0xDB // VMOVDQA ymm11, ymm3 + ADDQ $8, DX + JEQ out_write_even + BYTE $0xC4; BYTE $0x62; BYTE $0x7D; BYTE $0x5A; BYTE $0x00 // VBROADCASTI128 ymm8, [rax] + BYTE $0xC4; BYTE $0x62; BYTE $0x7D; BYTE $0x5A; BYTE $0x48; BYTE $0x10 // VBROADCASTI128 ymm9, [rax + 16] + BYTE $0xC4; BYTE $0x62; BYTE $0x7D; BYTE $0x5A; BYTE $0x50; BYTE $0x20 // VBROADCASTI128 ymm10, [rax + 32] + BYTE $0xC5; BYTE $0x7D; BYTE $0x6F; BYTE $0x34; BYTE $0x24 // VMOVDQA ymm14, [rsp] + SUBQ $4, DX + JCS vector_loop4_end +vector_loop4_begin: + BYTE $0xC5; BYTE $0x7D; BYTE $0x7F; BYTE $0xC0 // VMOVDQA ymm0, ymm8 + BYTE $0xC5; BYTE $0x7D; BYTE $0x7F; BYTE $0xC9 // VMOVDQA ymm1, ymm9 + BYTE $0xC5; BYTE $0x7D; BYTE $0x7F; BYTE $0xD2 // VMOVDQA ymm2, ymm10 + BYTE $0xC5; BYTE $0x7D; BYTE $0x7F; BYTE $0xDB // VMOVDQA ymm3, ymm11 + BYTE $0xC5; BYTE $0xFD; BYTE $0x6F; BYTE $0xE0 // VMOVDQA ymm4, ymm0 + BYTE $0xC5; BYTE $0xFD; BYTE $0x6F; BYTE $0xE9 // VMOVDQA ymm5, ymm1 + BYTE $0xC5; BYTE $0xFD; BYTE $0x6F; BYTE $0xF2 // VMOVDQA ymm6, ymm2 + BYTE $0xC4; BYTE $0xC1; BYTE $0x65; BYTE $0xD4; BYTE $0xFE // VPADDQ ymm7, ymm3, ymm14 + MOVQ $20, SI +rounds_loop4_begin: + BYTE $0xC5; BYTE $0xFD; BYTE $0xFE; BYTE $0xC1 // VPADDD ymm0, ymm0, ymm1 + BYTE $0xC5; BYTE $0xDD; BYTE $0xFE; BYTE $0xE5 // VPADDD ymm4, ymm4, ymm5 + BYTE $0xC5; BYTE $0xE5; BYTE $0xEF; BYTE $0xD8 // VPXOR ymm3, ymm3, ymm0 + BYTE $0xC5; BYTE $0xC5; BYTE $0xEF; BYTE $0xFC // VPXOR ymm7, ymm7, ymm4 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF3; BYTE $0x10 // VPSLLD ymm12, ymm3, 16 + BYTE $0xC5; BYTE $0xE5; BYTE $0x72; BYTE $0xD3; BYTE $0x10 // VPSRLD ymm3, ymm3, 16 + BYTE $0xC4; BYTE $0xC1; BYTE $0x65; BYTE $0xEF; BYTE $0xDC // VPXOR ymm3, ymm3, ymm12 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF7; BYTE $0x10 // VPSLLD ymm12, ymm7, 16 + BYTE $0xC5; BYTE $0xC5; BYTE $0x72; BYTE $0xD7; BYTE $0x10 // VPSRLD ymm7, ymm7, 16 + BYTE $0xC4; BYTE $0xC1; BYTE $0x45; BYTE $0xEF; BYTE $0xFC // VPXOR ymm7, ymm7, ymm12 + BYTE $0xC5; BYTE $0xED; BYTE $0xFE; BYTE $0xD3 // VPADDD ymm2, ymm2, ymm3 + BYTE $0xC5; BYTE $0xCD; BYTE $0xFE; BYTE $0xF7 // VPADDD ymm6, ymm6, ymm7 + BYTE $0xC5; BYTE $0xF5; BYTE $0xEF; BYTE $0xCA // VPXOR ymm1, ymm1, ymm2 + BYTE $0xC5; BYTE $0xD5; BYTE $0xEF; BYTE $0xEE // VPXOR ymm5, ymm5, ymm6 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF1; BYTE $0x0C // VPSLLD ymm12, ymm1, 12 + BYTE $0xC5; BYTE $0xF5; BYTE $0x72; BYTE $0xD1; BYTE $0x14 // VPSRLD ymm1, ymm1, 20 + BYTE $0xC4; BYTE $0xC1; BYTE $0x75; BYTE $0xEF; BYTE $0xCC // VPXOR ymm1, ymm1, ymm12 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF5; BYTE $0x0C // VPSLLD ymm12, ymm5, 12 + BYTE $0xC5; BYTE $0xD5; BYTE $0x72; BYTE $0xD5; BYTE $0x14 // VPSRLD ymm5, ymm5, 20 + BYTE $0xC4; BYTE $0xC1; BYTE $0x55; BYTE $0xEF; BYTE $0xEC // VPXOR ymm5, ymm5, ymm12 + BYTE $0xC5; BYTE $0xFD; BYTE $0xFE; BYTE $0xC1 // VPADDD ymm0, ymm0, ymm1 + BYTE $0xC5; BYTE $0xDD; BYTE $0xFE; BYTE $0xE5 // VPADDD ymm4, ymm4, ymm5 + BYTE $0xC5; BYTE $0xE5; BYTE $0xEF; BYTE $0xD8 // VPXOR ymm3, ymm3, ymm0 + BYTE $0xC5; BYTE $0xC5; BYTE $0xEF; BYTE $0xFC // VPXOR ymm7, ymm7, ymm4 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF3; BYTE $0x08 // VPSLLD ymm12, ymm3, 8 + BYTE $0xC5; BYTE $0xE5; BYTE $0x72; BYTE $0xD3; BYTE $0x18 // VPSRLD ymm3, ymm3, 24 + BYTE $0xC4; BYTE $0xC1; BYTE $0x65; BYTE $0xEF; BYTE $0xDC // VPXOR ymm3, ymm3, ymm12 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF7; BYTE $0x08 // VPSLLD ymm12, ymm7, 8 + BYTE $0xC5; BYTE $0xC5; BYTE $0x72; BYTE $0xD7; BYTE $0x18 // VPSRLD ymm7, ymm7, 24 + BYTE $0xC4; BYTE $0xC1; BYTE $0x45; BYTE $0xEF; BYTE $0xFC // VPXOR ymm7, ymm7, ymm12 + BYTE $0xC5; BYTE $0xED; BYTE $0xFE; BYTE $0xD3 // VPADDD ymm2, ymm2, ymm3 + BYTE $0xC5; BYTE $0xCD; BYTE $0xFE; BYTE $0xF7 // VPADDD ymm6, ymm6, ymm7 + BYTE $0xC5; BYTE $0xF5; BYTE $0xEF; BYTE $0xCA // VPXOR ymm1, ymm1, ymm2 + BYTE $0xC5; BYTE $0xD5; BYTE $0xEF; BYTE $0xEE // VPXOR ymm5, ymm5, ymm6 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF1; BYTE $0x07 // VPSLLD ymm12, ymm1, 7 + BYTE $0xC5; BYTE $0xF5; BYTE $0x72; BYTE $0xD1; BYTE $0x19 // VPSRLD ymm1, ymm1, 25 + BYTE $0xC4; BYTE $0xC1; BYTE $0x75; BYTE $0xEF; BYTE $0xCC // VPXOR ymm1, ymm1, ymm12 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF5; BYTE $0x07 // VPSLLD ymm12, ymm5, 7 + BYTE $0xC5; BYTE $0xD5; BYTE $0x72; BYTE $0xD5; BYTE $0x19 // VPSRLD ymm5, ymm5, 25 + BYTE $0xC4; BYTE $0xC1; BYTE $0x55; BYTE $0xEF; BYTE $0xEC // VPXOR ymm5, ymm5, ymm12 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xC9; BYTE $0x39 // VPSHUFD ymm1, ymm1, 57 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xED; BYTE $0x39 // VPSHUFD ymm5, ymm5, 57 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xD2; BYTE $0x4E // VPSHUFD ymm2, ymm2, 78 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xF6; BYTE $0x4E // VPSHUFD ymm6, ymm6, 78 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xDB; BYTE $0x93 // VPSHUFD ymm3, ymm3, 147 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xFF; BYTE $0x93 // VPSHUFD ymm7, ymm7, 147 + BYTE $0xC5; BYTE $0xFD; BYTE $0xFE; BYTE $0xC1 // VPADDD ymm0, ymm0, ymm1 + BYTE $0xC5; BYTE $0xDD; BYTE $0xFE; BYTE $0xE5 // VPADDD ymm4, ymm4, ymm5 + BYTE $0xC5; BYTE $0xE5; BYTE $0xEF; BYTE $0xD8 // VPXOR ymm3, ymm3, ymm0 + BYTE $0xC5; BYTE $0xC5; BYTE $0xEF; BYTE $0xFC // VPXOR ymm7, ymm7, ymm4 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF3; BYTE $0x10 // VPSLLD ymm12, ymm3, 16 + BYTE $0xC5; BYTE $0xE5; BYTE $0x72; BYTE $0xD3; BYTE $0x10 // VPSRLD ymm3, ymm3, 16 + BYTE $0xC4; BYTE $0xC1; BYTE $0x65; BYTE $0xEF; BYTE $0xDC // VPXOR ymm3, ymm3, ymm12 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF7; BYTE $0x10 // VPSLLD ymm12, ymm7, 16 + BYTE $0xC5; BYTE $0xC5; BYTE $0x72; BYTE $0xD7; BYTE $0x10 // VPSRLD ymm7, ymm7, 16 + BYTE $0xC4; BYTE $0xC1; BYTE $0x45; BYTE $0xEF; BYTE $0xFC // VPXOR ymm7, ymm7, ymm12 + BYTE $0xC5; BYTE $0xED; BYTE $0xFE; BYTE $0xD3 // VPADDD ymm2, ymm2, ymm3 + BYTE $0xC5; BYTE $0xCD; BYTE $0xFE; BYTE $0xF7 // VPADDD ymm6, ymm6, ymm7 + BYTE $0xC5; BYTE $0xF5; BYTE $0xEF; BYTE $0xCA // VPXOR ymm1, ymm1, ymm2 + BYTE $0xC5; BYTE $0xD5; BYTE $0xEF; BYTE $0xEE // VPXOR ymm5, ymm5, ymm6 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF1; BYTE $0x0C // VPSLLD ymm12, ymm1, 12 + BYTE $0xC5; BYTE $0xF5; BYTE $0x72; BYTE $0xD1; BYTE $0x14 // VPSRLD ymm1, ymm1, 20 + BYTE $0xC4; BYTE $0xC1; BYTE $0x75; BYTE $0xEF; BYTE $0xCC // VPXOR ymm1, ymm1, ymm12 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF5; BYTE $0x0C // VPSLLD ymm12, ymm5, 12 + BYTE $0xC5; BYTE $0xD5; BYTE $0x72; BYTE $0xD5; BYTE $0x14 // VPSRLD ymm5, ymm5, 20 + BYTE $0xC4; BYTE $0xC1; BYTE $0x55; BYTE $0xEF; BYTE $0xEC // VPXOR ymm5, ymm5, ymm12 + BYTE $0xC5; BYTE $0xFD; BYTE $0xFE; BYTE $0xC1 // VPADDD ymm0, ymm0, ymm1 + BYTE $0xC5; BYTE $0xDD; BYTE $0xFE; BYTE $0xE5 // VPADDD ymm4, ymm4, ymm5 + BYTE $0xC5; BYTE $0xE5; BYTE $0xEF; BYTE $0xD8 // VPXOR ymm3, ymm3, ymm0 + BYTE $0xC5; BYTE $0xC5; BYTE $0xEF; BYTE $0xFC // VPXOR ymm7, ymm7, ymm4 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF3; BYTE $0x08 // VPSLLD ymm12, ymm3, 8 + BYTE $0xC5; BYTE $0xE5; BYTE $0x72; BYTE $0xD3; BYTE $0x18 // VPSRLD ymm3, ymm3, 24 + BYTE $0xC4; BYTE $0xC1; BYTE $0x65; BYTE $0xEF; BYTE $0xDC // VPXOR ymm3, ymm3, ymm12 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF7; BYTE $0x08 // VPSLLD ymm12, ymm7, 8 + BYTE $0xC5; BYTE $0xC5; BYTE $0x72; BYTE $0xD7; BYTE $0x18 // VPSRLD ymm7, ymm7, 24 + BYTE $0xC4; BYTE $0xC1; BYTE $0x45; BYTE $0xEF; BYTE $0xFC // VPXOR ymm7, ymm7, ymm12 + BYTE $0xC5; BYTE $0xED; BYTE $0xFE; BYTE $0xD3 // VPADDD ymm2, ymm2, ymm3 + BYTE $0xC5; BYTE $0xCD; BYTE $0xFE; BYTE $0xF7 // VPADDD ymm6, ymm6, ymm7 + BYTE $0xC5; BYTE $0xF5; BYTE $0xEF; BYTE $0xCA // VPXOR ymm1, ymm1, ymm2 + BYTE $0xC5; BYTE $0xD5; BYTE $0xEF; BYTE $0xEE // VPXOR ymm5, ymm5, ymm6 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF1; BYTE $0x07 // VPSLLD ymm12, ymm1, 7 + BYTE $0xC5; BYTE $0xF5; BYTE $0x72; BYTE $0xD1; BYTE $0x19 // VPSRLD ymm1, ymm1, 25 + BYTE $0xC4; BYTE $0xC1; BYTE $0x75; BYTE $0xEF; BYTE $0xCC // VPXOR ymm1, ymm1, ymm12 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF5; BYTE $0x07 // VPSLLD ymm12, ymm5, 7 + BYTE $0xC5; BYTE $0xD5; BYTE $0x72; BYTE $0xD5; BYTE $0x19 // VPSRLD ymm5, ymm5, 25 + BYTE $0xC4; BYTE $0xC1; BYTE $0x55; BYTE $0xEF; BYTE $0xEC // VPXOR ymm5, ymm5, ymm12 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xC9; BYTE $0x93 // VPSHUFD ymm1, ymm1, 147 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xED; BYTE $0x93 // VPSHUFD ymm5, ymm5, 147 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xD2; BYTE $0x4E // VPSHUFD ymm2, ymm2, 78 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xF6; BYTE $0x4E // VPSHUFD ymm6, ymm6, 78 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xDB; BYTE $0x39 // VPSHUFD ymm3, ymm3, 57 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xFF; BYTE $0x39 // VPSHUFD ymm7, ymm7, 57 + SUBQ $2, SI + JNE rounds_loop4_begin + BYTE $0xC4; BYTE $0xC1; BYTE $0x7D; BYTE $0xFE; BYTE $0xC0 // VPADDD ymm0, ymm0, ymm8 + BYTE $0xC4; BYTE $0xC1; BYTE $0x75; BYTE $0xFE; BYTE $0xC9 // VPADDD ymm1, ymm1, ymm9 + BYTE $0xC4; BYTE $0xC1; BYTE $0x6D; BYTE $0xFE; BYTE $0xD2 // VPADDD ymm2, ymm2, ymm10 + BYTE $0xC4; BYTE $0xC1; BYTE $0x65; BYTE $0xFE; BYTE $0xDB // VPADDD ymm3, ymm3, ymm11 + BYTE $0xC4; BYTE $0x63; BYTE $0x7D; BYTE $0x46; BYTE $0xE1; BYTE $0x20 // VPERM2I128 ymm12, ymm0, ymm1, 32 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0x23 // VPXOR ymm12, ymm12, [rbx] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0x21 // VMOVDQU [rcx], ymm12 + BYTE $0xC4; BYTE $0x63; BYTE $0x6D; BYTE $0x46; BYTE $0xE3; BYTE $0x20 // VPERM2I128 ymm12, ymm2, ymm3, 32 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0x63; BYTE $0x20 // VPXOR ymm12, ymm12, [rbx + 32] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0x61; BYTE $0x20 // VMOVDQU [rcx + 32], ymm12 + BYTE $0xC4; BYTE $0x63; BYTE $0x7D; BYTE $0x46; BYTE $0xE1; BYTE $0x31 // VPERM2I128 ymm12, ymm0, ymm1, 49 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0x63; BYTE $0x40 // VPXOR ymm12, ymm12, [rbx + 64] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0x61; BYTE $0x40 // VMOVDQU [rcx + 64], ymm12 + BYTE $0xC4; BYTE $0x63; BYTE $0x6D; BYTE $0x46; BYTE $0xE3; BYTE $0x31 // VPERM2I128 ymm12, ymm2, ymm3, 49 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0x63; BYTE $0x60 // VPXOR ymm12, ymm12, [rbx + 96] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0x61; BYTE $0x60 // VMOVDQU [rcx + 96], ymm12 + BYTE $0xC4; BYTE $0x41; BYTE $0x25; BYTE $0xFE; BYTE $0xDE // VPADDD ymm11, ymm11, ymm14 + BYTE $0xC4; BYTE $0xC1; BYTE $0x5D; BYTE $0xFE; BYTE $0xE0 // VPADDD ymm4, ymm4, ymm8 + BYTE $0xC4; BYTE $0xC1; BYTE $0x55; BYTE $0xFE; BYTE $0xE9 // VPADDD ymm5, ymm5, ymm9 + BYTE $0xC4; BYTE $0xC1; BYTE $0x4D; BYTE $0xFE; BYTE $0xF2 // VPADDD ymm6, ymm6, ymm10 + BYTE $0xC4; BYTE $0xC1; BYTE $0x45; BYTE $0xFE; BYTE $0xFB // VPADDD ymm7, ymm7, ymm11 + BYTE $0xC4; BYTE $0x63; BYTE $0x5D; BYTE $0x46; BYTE $0xE5; BYTE $0x20 // VPERM2I128 ymm12, ymm4, ymm5, 32 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0xA3; BYTE $0x80; BYTE $0x00; BYTE $0x00; BYTE $0x00 // VPXOR ymm12, ymm12, [rbx + 128] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0xA1; BYTE $0x80; BYTE $0x00; BYTE $0x00; BYTE $0x00 // VMOVDQU [rcx + 128], ymm12 + BYTE $0xC4; BYTE $0x63; BYTE $0x4D; BYTE $0x46; BYTE $0xE7; BYTE $0x20 // VPERM2I128 ymm12, ymm6, ymm7, 32 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0xA3; BYTE $0xA0; BYTE $0x00; BYTE $0x00; BYTE $0x00 // VPXOR ymm12, ymm12, [rbx + 160] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0xA1; BYTE $0xA0; BYTE $0x00; BYTE $0x00; BYTE $0x00 // VMOVDQU [rcx + 160], ymm12 + BYTE $0xC4; BYTE $0x63; BYTE $0x5D; BYTE $0x46; BYTE $0xE5; BYTE $0x31 // VPERM2I128 ymm12, ymm4, ymm5, 49 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0xA3; BYTE $0xC0; BYTE $0x00; BYTE $0x00; BYTE $0x00 // VPXOR ymm12, ymm12, [rbx + 192] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0xA1; BYTE $0xC0; BYTE $0x00; BYTE $0x00; BYTE $0x00 // VMOVDQU [rcx + 192], ymm12 + BYTE $0xC4; BYTE $0x63; BYTE $0x4D; BYTE $0x46; BYTE $0xE7; BYTE $0x31 // VPERM2I128 ymm12, ymm6, ymm7, 49 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0xA3; BYTE $0xE0; BYTE $0x00; BYTE $0x00; BYTE $0x00 // VPXOR ymm12, ymm12, [rbx + 224] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0xA1; BYTE $0xE0; BYTE $0x00; BYTE $0x00; BYTE $0x00 // VMOVDQU [rcx + 224], ymm12 + BYTE $0xC4; BYTE $0x41; BYTE $0x25; BYTE $0xFE; BYTE $0xDE // VPADDD ymm11, ymm11, ymm14 + ADDQ $256, BX + ADDQ $256, CX + SUBQ $4, DX + JCC vector_loop4_begin +vector_loop4_end: + ADDQ $4, DX + JEQ out_write_even +vector_loop2_begin: + BYTE $0xC5; BYTE $0x7D; BYTE $0x7F; BYTE $0xC0 // VMOVDQA ymm0, ymm8 + BYTE $0xC5; BYTE $0x7D; BYTE $0x7F; BYTE $0xC9 // VMOVDQA ymm1, ymm9 + BYTE $0xC5; BYTE $0x7D; BYTE $0x7F; BYTE $0xD2 // VMOVDQA ymm2, ymm10 + BYTE $0xC5; BYTE $0x7D; BYTE $0x7F; BYTE $0xDB // VMOVDQA ymm3, ymm11 + MOVQ $20, SI +rounds_loop2_begin: + BYTE $0xC5; BYTE $0xFD; BYTE $0xFE; BYTE $0xC1 // VPADDD ymm0, ymm0, ymm1 + BYTE $0xC5; BYTE $0xE5; BYTE $0xEF; BYTE $0xD8 // VPXOR ymm3, ymm3, ymm0 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF3; BYTE $0x10 // VPSLLD ymm12, ymm3, 16 + BYTE $0xC5; BYTE $0xE5; BYTE $0x72; BYTE $0xD3; BYTE $0x10 // VPSRLD ymm3, ymm3, 16 + BYTE $0xC4; BYTE $0xC1; BYTE $0x65; BYTE $0xEF; BYTE $0xDC // VPXOR ymm3, ymm3, ymm12 + BYTE $0xC5; BYTE $0xED; BYTE $0xFE; BYTE $0xD3 // VPADDD ymm2, ymm2, ymm3 + BYTE $0xC5; BYTE $0xF5; BYTE $0xEF; BYTE $0xCA // VPXOR ymm1, ymm1, ymm2 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF1; BYTE $0x0C // VPSLLD ymm12, ymm1, 12 + BYTE $0xC5; BYTE $0xF5; BYTE $0x72; BYTE $0xD1; BYTE $0x14 // VPSRLD ymm1, ymm1, 20 + BYTE $0xC4; BYTE $0xC1; BYTE $0x75; BYTE $0xEF; BYTE $0xCC // VPXOR ymm1, ymm1, ymm12 + BYTE $0xC5; BYTE $0xFD; BYTE $0xFE; BYTE $0xC1 // VPADDD ymm0, ymm0, ymm1 + BYTE $0xC5; BYTE $0xE5; BYTE $0xEF; BYTE $0xD8 // VPXOR ymm3, ymm3, ymm0 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF3; BYTE $0x08 // VPSLLD ymm12, ymm3, 8 + BYTE $0xC5; BYTE $0xE5; BYTE $0x72; BYTE $0xD3; BYTE $0x18 // VPSRLD ymm3, ymm3, 24 + BYTE $0xC4; BYTE $0xC1; BYTE $0x65; BYTE $0xEF; BYTE $0xDC // VPXOR ymm3, ymm3, ymm12 + BYTE $0xC5; BYTE $0xED; BYTE $0xFE; BYTE $0xD3 // VPADDD ymm2, ymm2, ymm3 + BYTE $0xC5; BYTE $0xF5; BYTE $0xEF; BYTE $0xCA // VPXOR ymm1, ymm1, ymm2 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF1; BYTE $0x07 // VPSLLD ymm12, ymm1, 7 + BYTE $0xC5; BYTE $0xF5; BYTE $0x72; BYTE $0xD1; BYTE $0x19 // VPSRLD ymm1, ymm1, 25 + BYTE $0xC4; BYTE $0xC1; BYTE $0x75; BYTE $0xEF; BYTE $0xCC // VPXOR ymm1, ymm1, ymm12 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xC9; BYTE $0x39 // VPSHUFD ymm1, ymm1, 57 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xD2; BYTE $0x4E // VPSHUFD ymm2, ymm2, 78 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xDB; BYTE $0x93 // VPSHUFD ymm3, ymm3, 147 + BYTE $0xC5; BYTE $0xFD; BYTE $0xFE; BYTE $0xC1 // VPADDD ymm0, ymm0, ymm1 + BYTE $0xC5; BYTE $0xE5; BYTE $0xEF; BYTE $0xD8 // VPXOR ymm3, ymm3, ymm0 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF3; BYTE $0x10 // VPSLLD ymm12, ymm3, 16 + BYTE $0xC5; BYTE $0xE5; BYTE $0x72; BYTE $0xD3; BYTE $0x10 // VPSRLD ymm3, ymm3, 16 + BYTE $0xC4; BYTE $0xC1; BYTE $0x65; BYTE $0xEF; BYTE $0xDC // VPXOR ymm3, ymm3, ymm12 + BYTE $0xC5; BYTE $0xED; BYTE $0xFE; BYTE $0xD3 // VPADDD ymm2, ymm2, ymm3 + BYTE $0xC5; BYTE $0xF5; BYTE $0xEF; BYTE $0xCA // VPXOR ymm1, ymm1, ymm2 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF1; BYTE $0x0C // VPSLLD ymm12, ymm1, 12 + BYTE $0xC5; BYTE $0xF5; BYTE $0x72; BYTE $0xD1; BYTE $0x14 // VPSRLD ymm1, ymm1, 20 + BYTE $0xC4; BYTE $0xC1; BYTE $0x75; BYTE $0xEF; BYTE $0xCC // VPXOR ymm1, ymm1, ymm12 + BYTE $0xC5; BYTE $0xFD; BYTE $0xFE; BYTE $0xC1 // VPADDD ymm0, ymm0, ymm1 + BYTE $0xC5; BYTE $0xE5; BYTE $0xEF; BYTE $0xD8 // VPXOR ymm3, ymm3, ymm0 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF3; BYTE $0x08 // VPSLLD ymm12, ymm3, 8 + BYTE $0xC5; BYTE $0xE5; BYTE $0x72; BYTE $0xD3; BYTE $0x18 // VPSRLD ymm3, ymm3, 24 + BYTE $0xC4; BYTE $0xC1; BYTE $0x65; BYTE $0xEF; BYTE $0xDC // VPXOR ymm3, ymm3, ymm12 + BYTE $0xC5; BYTE $0xED; BYTE $0xFE; BYTE $0xD3 // VPADDD ymm2, ymm2, ymm3 + BYTE $0xC5; BYTE $0xF5; BYTE $0xEF; BYTE $0xCA // VPXOR ymm1, ymm1, ymm2 + BYTE $0xC5; BYTE $0x9D; BYTE $0x72; BYTE $0xF1; BYTE $0x07 // VPSLLD ymm12, ymm1, 7 + BYTE $0xC5; BYTE $0xF5; BYTE $0x72; BYTE $0xD1; BYTE $0x19 // VPSRLD ymm1, ymm1, 25 + BYTE $0xC4; BYTE $0xC1; BYTE $0x75; BYTE $0xEF; BYTE $0xCC // VPXOR ymm1, ymm1, ymm12 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xC9; BYTE $0x93 // VPSHUFD ymm1, ymm1, 147 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xD2; BYTE $0x4E // VPSHUFD ymm2, ymm2, 78 + BYTE $0xC5; BYTE $0xFD; BYTE $0x70; BYTE $0xDB; BYTE $0x39 // VPSHUFD ymm3, ymm3, 57 + SUBQ $2, SI + JNE rounds_loop2_begin + BYTE $0xC4; BYTE $0xC1; BYTE $0x7D; BYTE $0xFE; BYTE $0xC0 // VPADDD ymm0, ymm0, ymm8 + BYTE $0xC4; BYTE $0xC1; BYTE $0x75; BYTE $0xFE; BYTE $0xC9 // VPADDD ymm1, ymm1, ymm9 + BYTE $0xC4; BYTE $0xC1; BYTE $0x6D; BYTE $0xFE; BYTE $0xD2 // VPADDD ymm2, ymm2, ymm10 + BYTE $0xC4; BYTE $0xC1; BYTE $0x65; BYTE $0xFE; BYTE $0xDB // VPADDD ymm3, ymm3, ymm11 + BYTE $0xC4; BYTE $0x63; BYTE $0x7D; BYTE $0x46; BYTE $0xE1; BYTE $0x20 // VPERM2I128 ymm12, ymm0, ymm1, 32 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0x23 // VPXOR ymm12, ymm12, [rbx] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0x21 // VMOVDQU [rcx], ymm12 + BYTE $0xC4; BYTE $0x63; BYTE $0x6D; BYTE $0x46; BYTE $0xE3; BYTE $0x20 // VPERM2I128 ymm12, ymm2, ymm3, 32 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0x63; BYTE $0x20 // VPXOR ymm12, ymm12, [rbx + 32] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0x61; BYTE $0x20 // VMOVDQU [rcx + 32], ymm12 + SUBQ $1, DX + JEQ out_write_odd + BYTE $0xC4; BYTE $0x41; BYTE $0x25; BYTE $0xFE; BYTE $0xDE // VPADDD ymm11, ymm11, ymm14 + BYTE $0xC4; BYTE $0x63; BYTE $0x7D; BYTE $0x46; BYTE $0xE1; BYTE $0x31 // VPERM2I128 ymm12, ymm0, ymm1, 49 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0x63; BYTE $0x40 // VPXOR ymm12, ymm12, [rbx + 64] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0x61; BYTE $0x40 // VMOVDQU [rcx + 64], ymm12 + BYTE $0xC4; BYTE $0x63; BYTE $0x6D; BYTE $0x46; BYTE $0xE3; BYTE $0x31 // VPERM2I128 ymm12, ymm2, ymm3, 49 + BYTE $0xC5; BYTE $0x1D; BYTE $0xEF; BYTE $0x63; BYTE $0x60 // VPXOR ymm12, ymm12, [rbx + 96] + BYTE $0xC5; BYTE $0x7E; BYTE $0x7F; BYTE $0x61; BYTE $0x60 // VMOVDQU [rcx + 96], ymm12 + SUBQ $1, DX + JEQ out_write_even + ADDQ $128, BX + ADDQ $128, CX + JMP vector_loop2_begin +out_write_odd: + BYTE $0xC4; BYTE $0x43; BYTE $0x25; BYTE $0x46; BYTE $0xDB; BYTE $0x01 // VPERM2I128 ymm11, ymm11, ymm11, 1 +out_write_even: + BYTE $0xC5; BYTE $0x79; BYTE $0x7F; BYTE $0x58; BYTE $0x30 // VMOVDQA [rax + 48], xmm11 + BYTE $0xC5; BYTE $0xFD; BYTE $0xEF; BYTE $0xC0 // VPXOR ymm0, ymm0, ymm0 + BYTE $0xC5; BYTE $0xFD; BYTE $0x7F; BYTE $0x44; BYTE $0x24; BYTE $0x40 // VMOVDQA [rsp + 64], ymm0 + BYTE $0xC5; BYTE $0xFD; BYTE $0x7F; BYTE $0x44; BYTE $0x24; BYTE $0x20 // VMOVDQA [rsp + 32], ymm0 + MOVQ DI, SP + BYTE $0xC5; BYTE $0xF8; BYTE $0x77 // VZEROUPPER + RET + +// func cpuidAmd64(cpuidParams *uint32) +TEXT ·cpuidAmd64(SB),4,$0-8 + MOVQ cpuidParams+0(FP), R15 + MOVL 0(R15), AX + MOVL 4(R15), CX + CPUID + MOVL AX, 0(R15) + MOVL BX, 4(R15) + MOVL CX, 8(R15) + MOVL DX, 12(R15) + RET + +// func xgetbv0Amd64(xcrVec *uint32) +TEXT ·xgetbv0Amd64(SB),4,$0-8 + MOVQ xcrVec+0(FP), BX + XORL CX, CX + BYTE $0x0F; BYTE $0x01; BYTE $0xD0 // XGETBV + MOVL AX, 0(BX) + MOVL DX, 4(BX) + RET diff --git a/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20_ref.go b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20_ref.go new file mode 100644 index 0000000..694c937 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20_ref.go @@ -0,0 +1,392 @@ +// chacha20_ref.go - Reference ChaCha20. +// +// To the extent possible under law, Yawning Angel has waived all copyright +// and related or neighboring rights to chacha20, using the Creative +// Commons "CC0" public domain dedication. See LICENSE or +// for full details. + +package chacha20 + +import ( + "encoding/binary" + "math" + "unsafe" +) + +func blocksRef(x *[stateSize]uint32, in []byte, out []byte, nrBlocks int, isIetf bool) { + if isIetf { + var totalBlocks uint64 + totalBlocks = uint64(x[8]) + uint64(nrBlocks) + if totalBlocks > math.MaxUint32 { + panic("chacha20: Exceeded keystream per nonce limit") + } + } + + // This routine ignores x[0]...x[4] in favor the const values since it's + // ever so slightly faster. + + for n := 0; n < nrBlocks; n++ { + x0, x1, x2, x3 := sigma0, sigma1, sigma2, sigma3 + x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 := x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15] + + for i := chachaRounds; i > 0; i -= 2 { + // quarterround(x, 0, 4, 8, 12) + x0 += x4 + x12 ^= x0 + x12 = (x12 << 16) | (x12 >> 16) + x8 += x12 + x4 ^= x8 + x4 = (x4 << 12) | (x4 >> 20) + x0 += x4 + x12 ^= x0 + x12 = (x12 << 8) | (x12 >> 24) + x8 += x12 + x4 ^= x8 + x4 = (x4 << 7) | (x4 >> 25) + + // quarterround(x, 1, 5, 9, 13) + x1 += x5 + x13 ^= x1 + x13 = (x13 << 16) | (x13 >> 16) + x9 += x13 + x5 ^= x9 + x5 = (x5 << 12) | (x5 >> 20) + x1 += x5 + x13 ^= x1 + x13 = (x13 << 8) | (x13 >> 24) + x9 += x13 + x5 ^= x9 + x5 = (x5 << 7) | (x5 >> 25) + + // quarterround(x, 2, 6, 10, 14) + x2 += x6 + x14 ^= x2 + x14 = (x14 << 16) | (x14 >> 16) + x10 += x14 + x6 ^= x10 + x6 = (x6 << 12) | (x6 >> 20) + x2 += x6 + x14 ^= x2 + x14 = (x14 << 8) | (x14 >> 24) + x10 += x14 + x6 ^= x10 + x6 = (x6 << 7) | (x6 >> 25) + + // quarterround(x, 3, 7, 11, 15) + x3 += x7 + x15 ^= x3 + x15 = (x15 << 16) | (x15 >> 16) + x11 += x15 + x7 ^= x11 + x7 = (x7 << 12) | (x7 >> 20) + x3 += x7 + x15 ^= x3 + x15 = (x15 << 8) | (x15 >> 24) + x11 += x15 + x7 ^= x11 + x7 = (x7 << 7) | (x7 >> 25) + + // quarterround(x, 0, 5, 10, 15) + x0 += x5 + x15 ^= x0 + x15 = (x15 << 16) | (x15 >> 16) + x10 += x15 + x5 ^= x10 + x5 = (x5 << 12) | (x5 >> 20) + x0 += x5 + x15 ^= x0 + x15 = (x15 << 8) | (x15 >> 24) + x10 += x15 + x5 ^= x10 + x5 = (x5 << 7) | (x5 >> 25) + + // quarterround(x, 1, 6, 11, 12) + x1 += x6 + x12 ^= x1 + x12 = (x12 << 16) | (x12 >> 16) + x11 += x12 + x6 ^= x11 + x6 = (x6 << 12) | (x6 >> 20) + x1 += x6 + x12 ^= x1 + x12 = (x12 << 8) | (x12 >> 24) + x11 += x12 + x6 ^= x11 + x6 = (x6 << 7) | (x6 >> 25) + + // quarterround(x, 2, 7, 8, 13) + x2 += x7 + x13 ^= x2 + x13 = (x13 << 16) | (x13 >> 16) + x8 += x13 + x7 ^= x8 + x7 = (x7 << 12) | (x7 >> 20) + x2 += x7 + x13 ^= x2 + x13 = (x13 << 8) | (x13 >> 24) + x8 += x13 + x7 ^= x8 + x7 = (x7 << 7) | (x7 >> 25) + + // quarterround(x, 3, 4, 9, 14) + x3 += x4 + x14 ^= x3 + x14 = (x14 << 16) | (x14 >> 16) + x9 += x14 + x4 ^= x9 + x4 = (x4 << 12) | (x4 >> 20) + x3 += x4 + x14 ^= x3 + x14 = (x14 << 8) | (x14 >> 24) + x9 += x14 + x4 ^= x9 + x4 = (x4 << 7) | (x4 >> 25) + } + + // On amd64 at least, this is a rather big boost. + if useUnsafe { + if in != nil { + inArr := (*[16]uint32)(unsafe.Pointer(&in[n*BlockSize])) + outArr := (*[16]uint32)(unsafe.Pointer(&out[n*BlockSize])) + outArr[0] = inArr[0] ^ (x0 + sigma0) + outArr[1] = inArr[1] ^ (x1 + sigma1) + outArr[2] = inArr[2] ^ (x2 + sigma2) + outArr[3] = inArr[3] ^ (x3 + sigma3) + outArr[4] = inArr[4] ^ (x4 + x[4]) + outArr[5] = inArr[5] ^ (x5 + x[5]) + outArr[6] = inArr[6] ^ (x6 + x[6]) + outArr[7] = inArr[7] ^ (x7 + x[7]) + outArr[8] = inArr[8] ^ (x8 + x[8]) + outArr[9] = inArr[9] ^ (x9 + x[9]) + outArr[10] = inArr[10] ^ (x10 + x[10]) + outArr[11] = inArr[11] ^ (x11 + x[11]) + outArr[12] = inArr[12] ^ (x12 + x[12]) + outArr[13] = inArr[13] ^ (x13 + x[13]) + outArr[14] = inArr[14] ^ (x14 + x[14]) + outArr[15] = inArr[15] ^ (x15 + x[15]) + } else { + outArr := (*[16]uint32)(unsafe.Pointer(&out[n*BlockSize])) + outArr[0] = x0 + sigma0 + outArr[1] = x1 + sigma1 + outArr[2] = x2 + sigma2 + outArr[3] = x3 + sigma3 + outArr[4] = x4 + x[4] + outArr[5] = x5 + x[5] + outArr[6] = x6 + x[6] + outArr[7] = x7 + x[7] + outArr[8] = x8 + x[8] + outArr[9] = x9 + x[9] + outArr[10] = x10 + x[10] + outArr[11] = x11 + x[11] + outArr[12] = x12 + x[12] + outArr[13] = x13 + x[13] + outArr[14] = x14 + x[14] + outArr[15] = x15 + x[15] + } + } else { + // Slow path, either the architecture cares about alignment, or is not little endian. + x0 += sigma0 + x1 += sigma1 + x2 += sigma2 + x3 += sigma3 + x4 += x[4] + x5 += x[5] + x6 += x[6] + x7 += x[7] + x8 += x[8] + x9 += x[9] + x10 += x[10] + x11 += x[11] + x12 += x[12] + x13 += x[13] + x14 += x[14] + x15 += x[15] + if in != nil { + binary.LittleEndian.PutUint32(out[0:4], binary.LittleEndian.Uint32(in[0:4])^x0) + binary.LittleEndian.PutUint32(out[4:8], binary.LittleEndian.Uint32(in[4:8])^x1) + binary.LittleEndian.PutUint32(out[8:12], binary.LittleEndian.Uint32(in[8:12])^x2) + binary.LittleEndian.PutUint32(out[12:16], binary.LittleEndian.Uint32(in[12:16])^x3) + binary.LittleEndian.PutUint32(out[16:20], binary.LittleEndian.Uint32(in[16:20])^x4) + binary.LittleEndian.PutUint32(out[20:24], binary.LittleEndian.Uint32(in[20:24])^x5) + binary.LittleEndian.PutUint32(out[24:28], binary.LittleEndian.Uint32(in[24:28])^x6) + binary.LittleEndian.PutUint32(out[28:32], binary.LittleEndian.Uint32(in[28:32])^x7) + binary.LittleEndian.PutUint32(out[32:36], binary.LittleEndian.Uint32(in[32:36])^x8) + binary.LittleEndian.PutUint32(out[36:40], binary.LittleEndian.Uint32(in[36:40])^x9) + binary.LittleEndian.PutUint32(out[40:44], binary.LittleEndian.Uint32(in[40:44])^x10) + binary.LittleEndian.PutUint32(out[44:48], binary.LittleEndian.Uint32(in[44:48])^x11) + binary.LittleEndian.PutUint32(out[48:52], binary.LittleEndian.Uint32(in[48:52])^x12) + binary.LittleEndian.PutUint32(out[52:56], binary.LittleEndian.Uint32(in[52:56])^x13) + binary.LittleEndian.PutUint32(out[56:60], binary.LittleEndian.Uint32(in[56:60])^x14) + binary.LittleEndian.PutUint32(out[60:64], binary.LittleEndian.Uint32(in[60:64])^x15) + in = in[BlockSize:] + } else { + binary.LittleEndian.PutUint32(out[0:4], x0) + binary.LittleEndian.PutUint32(out[4:8], x1) + binary.LittleEndian.PutUint32(out[8:12], x2) + binary.LittleEndian.PutUint32(out[12:16], x3) + binary.LittleEndian.PutUint32(out[16:20], x4) + binary.LittleEndian.PutUint32(out[20:24], x5) + binary.LittleEndian.PutUint32(out[24:28], x6) + binary.LittleEndian.PutUint32(out[28:32], x7) + binary.LittleEndian.PutUint32(out[32:36], x8) + binary.LittleEndian.PutUint32(out[36:40], x9) + binary.LittleEndian.PutUint32(out[40:44], x10) + binary.LittleEndian.PutUint32(out[44:48], x11) + binary.LittleEndian.PutUint32(out[48:52], x12) + binary.LittleEndian.PutUint32(out[52:56], x13) + binary.LittleEndian.PutUint32(out[56:60], x14) + binary.LittleEndian.PutUint32(out[60:64], x15) + } + out = out[BlockSize:] + } + + // Stoping at 2^70 bytes per nonce is the user's responsibility. + ctr := uint64(x[13])<<32 | uint64(x[12]) + ctr++ + x[12] = uint32(ctr) + x[13] = uint32(ctr >> 32) + } +} + +func hChaChaRef(x *[stateSize]uint32, out *[32]byte) { + x0, x1, x2, x3 := sigma0, sigma1, sigma2, sigma3 + x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 := x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11] + + for i := chachaRounds; i > 0; i -= 2 { + // quarterround(x, 0, 4, 8, 12) + x0 += x4 + x12 ^= x0 + x12 = (x12 << 16) | (x12 >> 16) + x8 += x12 + x4 ^= x8 + x4 = (x4 << 12) | (x4 >> 20) + x0 += x4 + x12 ^= x0 + x12 = (x12 << 8) | (x12 >> 24) + x8 += x12 + x4 ^= x8 + x4 = (x4 << 7) | (x4 >> 25) + + // quarterround(x, 1, 5, 9, 13) + x1 += x5 + x13 ^= x1 + x13 = (x13 << 16) | (x13 >> 16) + x9 += x13 + x5 ^= x9 + x5 = (x5 << 12) | (x5 >> 20) + x1 += x5 + x13 ^= x1 + x13 = (x13 << 8) | (x13 >> 24) + x9 += x13 + x5 ^= x9 + x5 = (x5 << 7) | (x5 >> 25) + + // quarterround(x, 2, 6, 10, 14) + x2 += x6 + x14 ^= x2 + x14 = (x14 << 16) | (x14 >> 16) + x10 += x14 + x6 ^= x10 + x6 = (x6 << 12) | (x6 >> 20) + x2 += x6 + x14 ^= x2 + x14 = (x14 << 8) | (x14 >> 24) + x10 += x14 + x6 ^= x10 + x6 = (x6 << 7) | (x6 >> 25) + + // quarterround(x, 3, 7, 11, 15) + x3 += x7 + x15 ^= x3 + x15 = (x15 << 16) | (x15 >> 16) + x11 += x15 + x7 ^= x11 + x7 = (x7 << 12) | (x7 >> 20) + x3 += x7 + x15 ^= x3 + x15 = (x15 << 8) | (x15 >> 24) + x11 += x15 + x7 ^= x11 + x7 = (x7 << 7) | (x7 >> 25) + + // quarterround(x, 0, 5, 10, 15) + x0 += x5 + x15 ^= x0 + x15 = (x15 << 16) | (x15 >> 16) + x10 += x15 + x5 ^= x10 + x5 = (x5 << 12) | (x5 >> 20) + x0 += x5 + x15 ^= x0 + x15 = (x15 << 8) | (x15 >> 24) + x10 += x15 + x5 ^= x10 + x5 = (x5 << 7) | (x5 >> 25) + + // quarterround(x, 1, 6, 11, 12) + x1 += x6 + x12 ^= x1 + x12 = (x12 << 16) | (x12 >> 16) + x11 += x12 + x6 ^= x11 + x6 = (x6 << 12) | (x6 >> 20) + x1 += x6 + x12 ^= x1 + x12 = (x12 << 8) | (x12 >> 24) + x11 += x12 + x6 ^= x11 + x6 = (x6 << 7) | (x6 >> 25) + + // quarterround(x, 2, 7, 8, 13) + x2 += x7 + x13 ^= x2 + x13 = (x13 << 16) | (x13 >> 16) + x8 += x13 + x7 ^= x8 + x7 = (x7 << 12) | (x7 >> 20) + x2 += x7 + x13 ^= x2 + x13 = (x13 << 8) | (x13 >> 24) + x8 += x13 + x7 ^= x8 + x7 = (x7 << 7) | (x7 >> 25) + + // quarterround(x, 3, 4, 9, 14) + x3 += x4 + x14 ^= x3 + x14 = (x14 << 16) | (x14 >> 16) + x9 += x14 + x4 ^= x9 + x4 = (x4 << 12) | (x4 >> 20) + x3 += x4 + x14 ^= x3 + x14 = (x14 << 8) | (x14 >> 24) + x9 += x14 + x4 ^= x9 + x4 = (x4 << 7) | (x4 >> 25) + } + + // HChaCha returns x0...x3 | x12...x15, which corresponds to the + // indexes of the ChaCha constant and the indexes of the IV. + if useUnsafe { + outArr := (*[16]uint32)(unsafe.Pointer(&out[0])) + outArr[0] = x0 + outArr[1] = x1 + outArr[2] = x2 + outArr[3] = x3 + outArr[4] = x12 + outArr[5] = x13 + outArr[6] = x14 + outArr[7] = x15 + } else { + binary.LittleEndian.PutUint32(out[0:4], x0) + binary.LittleEndian.PutUint32(out[4:8], x1) + binary.LittleEndian.PutUint32(out[8:12], x2) + binary.LittleEndian.PutUint32(out[12:16], x3) + binary.LittleEndian.PutUint32(out[16:20], x12) + binary.LittleEndian.PutUint32(out[20:24], x13) + binary.LittleEndian.PutUint32(out[24:28], x14) + binary.LittleEndian.PutUint32(out[28:32], x15) + } + return +} diff --git a/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20_test.go b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20_test.go new file mode 100644 index 0000000..3ba9b11 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/chacha20/chacha20_test.go @@ -0,0 +1,523 @@ +// chacha20_test.go - ChaCha stream cipher implementation tests. +// +// To the extent possible under law, Yawning Angel waived all copyright +// and related or neighboring rights to chacha20, using the Creative +// Commons "CC0" public domain dedication. See LICENSE or +// for full details. + +package chacha20 + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/hex" + "testing" +) + +// Test vectors taken from: +// https://tools.ietf.org/html/draft-strombergson-chacha-test-vectors-01 +var draftTestVectors = []struct { + name string + key []byte + iv []byte + stream []byte + seekOffset uint64 +}{ + { + name: "IETF Draft: TC1: All zero key and IV.", + key: []byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + iv: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + stream: []byte{ + 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90, + 0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28, + 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a, + 0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7, + 0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d, + 0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37, + 0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c, + 0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86, + 0x9f, 0x07, 0xe7, 0xbe, 0x55, 0x51, 0x38, 0x7a, + 0x98, 0xba, 0x97, 0x7c, 0x73, 0x2d, 0x08, 0x0d, + 0xcb, 0x0f, 0x29, 0xa0, 0x48, 0xe3, 0x65, 0x69, + 0x12, 0xc6, 0x53, 0x3e, 0x32, 0xee, 0x7a, 0xed, + 0x29, 0xb7, 0x21, 0x76, 0x9c, 0xe6, 0x4e, 0x43, + 0xd5, 0x71, 0x33, 0xb0, 0x74, 0xd8, 0x39, 0xd5, + 0x31, 0xed, 0x1f, 0x28, 0x51, 0x0a, 0xfb, 0x45, + 0xac, 0xe1, 0x0a, 0x1f, 0x4b, 0x79, 0x4d, 0x6f, + }, + }, + { + name: "IETF Draft: TC2: Single bit in key set. All zero IV.", + key: []byte{ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + iv: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + stream: []byte{ + 0xc5, 0xd3, 0x0a, 0x7c, 0xe1, 0xec, 0x11, 0x93, + 0x78, 0xc8, 0x4f, 0x48, 0x7d, 0x77, 0x5a, 0x85, + 0x42, 0xf1, 0x3e, 0xce, 0x23, 0x8a, 0x94, 0x55, + 0xe8, 0x22, 0x9e, 0x88, 0x8d, 0xe8, 0x5b, 0xbd, + 0x29, 0xeb, 0x63, 0xd0, 0xa1, 0x7a, 0x5b, 0x99, + 0x9b, 0x52, 0xda, 0x22, 0xbe, 0x40, 0x23, 0xeb, + 0x07, 0x62, 0x0a, 0x54, 0xf6, 0xfa, 0x6a, 0xd8, + 0x73, 0x7b, 0x71, 0xeb, 0x04, 0x64, 0xda, 0xc0, + 0x10, 0xf6, 0x56, 0xe6, 0xd1, 0xfd, 0x55, 0x05, + 0x3e, 0x50, 0xc4, 0x87, 0x5c, 0x99, 0x30, 0xa3, + 0x3f, 0x6d, 0x02, 0x63, 0xbd, 0x14, 0xdf, 0xd6, + 0xab, 0x8c, 0x70, 0x52, 0x1c, 0x19, 0x33, 0x8b, + 0x23, 0x08, 0xb9, 0x5c, 0xf8, 0xd0, 0xbb, 0x7d, + 0x20, 0x2d, 0x21, 0x02, 0x78, 0x0e, 0xa3, 0x52, + 0x8f, 0x1c, 0xb4, 0x85, 0x60, 0xf7, 0x6b, 0x20, + 0xf3, 0x82, 0xb9, 0x42, 0x50, 0x0f, 0xce, 0xac, + }, + }, + { + name: "IETF Draft: TC3: Single bit in IV set. All zero key.", + key: []byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + iv: []byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + stream: []byte{ + 0xef, 0x3f, 0xdf, 0xd6, 0xc6, 0x15, 0x78, 0xfb, + 0xf5, 0xcf, 0x35, 0xbd, 0x3d, 0xd3, 0x3b, 0x80, + 0x09, 0x63, 0x16, 0x34, 0xd2, 0x1e, 0x42, 0xac, + 0x33, 0x96, 0x0b, 0xd1, 0x38, 0xe5, 0x0d, 0x32, + 0x11, 0x1e, 0x4c, 0xaf, 0x23, 0x7e, 0xe5, 0x3c, + 0xa8, 0xad, 0x64, 0x26, 0x19, 0x4a, 0x88, 0x54, + 0x5d, 0xdc, 0x49, 0x7a, 0x0b, 0x46, 0x6e, 0x7d, + 0x6b, 0xbd, 0xb0, 0x04, 0x1b, 0x2f, 0x58, 0x6b, + 0x53, 0x05, 0xe5, 0xe4, 0x4a, 0xff, 0x19, 0xb2, + 0x35, 0x93, 0x61, 0x44, 0x67, 0x5e, 0xfb, 0xe4, + 0x40, 0x9e, 0xb7, 0xe8, 0xe5, 0xf1, 0x43, 0x0f, + 0x5f, 0x58, 0x36, 0xae, 0xb4, 0x9b, 0xb5, 0x32, + 0x8b, 0x01, 0x7c, 0x4b, 0x9d, 0xc1, 0x1f, 0x8a, + 0x03, 0x86, 0x3f, 0xa8, 0x03, 0xdc, 0x71, 0xd5, + 0x72, 0x6b, 0x2b, 0x6b, 0x31, 0xaa, 0x32, 0x70, + 0x8a, 0xfe, 0x5a, 0xf1, 0xd6, 0xb6, 0x90, 0x58, + }, + }, + { + name: "IETF Draft: TC4: All bits in key and IV are set.", + key: []byte{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + iv: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + stream: []byte{ + 0xd9, 0xbf, 0x3f, 0x6b, 0xce, 0x6e, 0xd0, 0xb5, + 0x42, 0x54, 0x55, 0x77, 0x67, 0xfb, 0x57, 0x44, + 0x3d, 0xd4, 0x77, 0x89, 0x11, 0xb6, 0x06, 0x05, + 0x5c, 0x39, 0xcc, 0x25, 0xe6, 0x74, 0xb8, 0x36, + 0x3f, 0xea, 0xbc, 0x57, 0xfd, 0xe5, 0x4f, 0x79, + 0x0c, 0x52, 0xc8, 0xae, 0x43, 0x24, 0x0b, 0x79, + 0xd4, 0x90, 0x42, 0xb7, 0x77, 0xbf, 0xd6, 0xcb, + 0x80, 0xe9, 0x31, 0x27, 0x0b, 0x7f, 0x50, 0xeb, + 0x5b, 0xac, 0x2a, 0xcd, 0x86, 0xa8, 0x36, 0xc5, + 0xdc, 0x98, 0xc1, 0x16, 0xc1, 0x21, 0x7e, 0xc3, + 0x1d, 0x3a, 0x63, 0xa9, 0x45, 0x13, 0x19, 0xf0, + 0x97, 0xf3, 0xb4, 0xd6, 0xda, 0xb0, 0x77, 0x87, + 0x19, 0x47, 0x7d, 0x24, 0xd2, 0x4b, 0x40, 0x3a, + 0x12, 0x24, 0x1d, 0x7c, 0xca, 0x06, 0x4f, 0x79, + 0x0f, 0x1d, 0x51, 0xcc, 0xaf, 0xf6, 0xb1, 0x66, + 0x7d, 0x4b, 0xbc, 0xa1, 0x95, 0x8c, 0x43, 0x06, + }, + }, + { + name: "IETF Draft: TC5: Every even bit set in key and IV.", + key: []byte{ + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + }, + iv: []byte{0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55}, + stream: []byte{ + 0xbe, 0xa9, 0x41, 0x1a, 0xa4, 0x53, 0xc5, 0x43, + 0x4a, 0x5a, 0xe8, 0xc9, 0x28, 0x62, 0xf5, 0x64, + 0x39, 0x68, 0x55, 0xa9, 0xea, 0x6e, 0x22, 0xd6, + 0xd3, 0xb5, 0x0a, 0xe1, 0xb3, 0x66, 0x33, 0x11, + 0xa4, 0xa3, 0x60, 0x6c, 0x67, 0x1d, 0x60, 0x5c, + 0xe1, 0x6c, 0x3a, 0xec, 0xe8, 0xe6, 0x1e, 0xa1, + 0x45, 0xc5, 0x97, 0x75, 0x01, 0x7b, 0xee, 0x2f, + 0xa6, 0xf8, 0x8a, 0xfc, 0x75, 0x80, 0x69, 0xf7, + 0xe0, 0xb8, 0xf6, 0x76, 0xe6, 0x44, 0x21, 0x6f, + 0x4d, 0x2a, 0x34, 0x22, 0xd7, 0xfa, 0x36, 0xc6, + 0xc4, 0x93, 0x1a, 0xca, 0x95, 0x0e, 0x9d, 0xa4, + 0x27, 0x88, 0xe6, 0xd0, 0xb6, 0xd1, 0xcd, 0x83, + 0x8e, 0xf6, 0x52, 0xe9, 0x7b, 0x14, 0x5b, 0x14, + 0x87, 0x1e, 0xae, 0x6c, 0x68, 0x04, 0xc7, 0x00, + 0x4d, 0xb5, 0xac, 0x2f, 0xce, 0x4c, 0x68, 0xc7, + 0x26, 0xd0, 0x04, 0xb1, 0x0f, 0xca, 0xba, 0x86, + }, + }, + { + name: "IETF Draft: TC6: Every odd bit set in key and IV.", + key: []byte{ + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + }, + iv: []byte{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, + stream: []byte{ + 0x9a, 0xa2, 0xa9, 0xf6, 0x56, 0xef, 0xde, 0x5a, + 0xa7, 0x59, 0x1c, 0x5f, 0xed, 0x4b, 0x35, 0xae, + 0xa2, 0x89, 0x5d, 0xec, 0x7c, 0xb4, 0x54, 0x3b, + 0x9e, 0x9f, 0x21, 0xf5, 0xe7, 0xbc, 0xbc, 0xf3, + 0xc4, 0x3c, 0x74, 0x8a, 0x97, 0x08, 0x88, 0xf8, + 0x24, 0x83, 0x93, 0xa0, 0x9d, 0x43, 0xe0, 0xb7, + 0xe1, 0x64, 0xbc, 0x4d, 0x0b, 0x0f, 0xb2, 0x40, + 0xa2, 0xd7, 0x21, 0x15, 0xc4, 0x80, 0x89, 0x06, + 0x72, 0x18, 0x44, 0x89, 0x44, 0x05, 0x45, 0xd0, + 0x21, 0xd9, 0x7e, 0xf6, 0xb6, 0x93, 0xdf, 0xe5, + 0xb2, 0xc1, 0x32, 0xd4, 0x7e, 0x6f, 0x04, 0x1c, + 0x90, 0x63, 0x65, 0x1f, 0x96, 0xb6, 0x23, 0xe6, + 0x2a, 0x11, 0x99, 0x9a, 0x23, 0xb6, 0xf7, 0xc4, + 0x61, 0xb2, 0x15, 0x30, 0x26, 0xad, 0x5e, 0x86, + 0x6a, 0x2e, 0x59, 0x7e, 0xd0, 0x7b, 0x84, 0x01, + 0xde, 0xc6, 0x3a, 0x09, 0x34, 0xc6, 0xb2, 0xa9, + }, + }, + { + name: "IETF Draft: TC7: Sequence patterns in key and IV.", + key: []byte{ + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, + 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, + 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, + }, + iv: []byte{0x0f, 0x1e, 0x2d, 0x3c, 0x4b, 0x5a, 0x69, 0x78}, + stream: []byte{ + 0x9f, 0xad, 0xf4, 0x09, 0xc0, 0x08, 0x11, 0xd0, + 0x04, 0x31, 0xd6, 0x7e, 0xfb, 0xd8, 0x8f, 0xba, + 0x59, 0x21, 0x8d, 0x5d, 0x67, 0x08, 0xb1, 0xd6, + 0x85, 0x86, 0x3f, 0xab, 0xbb, 0x0e, 0x96, 0x1e, + 0xea, 0x48, 0x0f, 0xd6, 0xfb, 0x53, 0x2b, 0xfd, + 0x49, 0x4b, 0x21, 0x51, 0x01, 0x50, 0x57, 0x42, + 0x3a, 0xb6, 0x0a, 0x63, 0xfe, 0x4f, 0x55, 0xf7, + 0xa2, 0x12, 0xe2, 0x16, 0x7c, 0xca, 0xb9, 0x31, + 0xfb, 0xfd, 0x29, 0xcf, 0x7b, 0xc1, 0xd2, 0x79, + 0xed, 0xdf, 0x25, 0xdd, 0x31, 0x6b, 0xb8, 0x84, + 0x3d, 0x6e, 0xde, 0xe0, 0xbd, 0x1e, 0xf1, 0x21, + 0xd1, 0x2f, 0xa1, 0x7c, 0xbc, 0x2c, 0x57, 0x4c, + 0xcc, 0xab, 0x5e, 0x27, 0x51, 0x67, 0xb0, 0x8b, + 0xd6, 0x86, 0xf8, 0xa0, 0x9d, 0xf8, 0x7e, 0xc3, + 0xff, 0xb3, 0x53, 0x61, 0xb9, 0x4e, 0xbf, 0xa1, + 0x3f, 0xec, 0x0e, 0x48, 0x89, 0xd1, 0x8d, 0xa5, + }, + }, + { + name: "IETF Draft: TC8: key: 'All your base are belong to us!, IV: 'IETF2013'", + key: []byte{ + 0xc4, 0x6e, 0xc1, 0xb1, 0x8c, 0xe8, 0xa8, 0x78, + 0x72, 0x5a, 0x37, 0xe7, 0x80, 0xdf, 0xb7, 0x35, + 0x1f, 0x68, 0xed, 0x2e, 0x19, 0x4c, 0x79, 0xfb, + 0xc6, 0xae, 0xbe, 0xe1, 0xa6, 0x67, 0x97, 0x5d, + }, + iv: []byte{0x1a, 0xda, 0x31, 0xd5, 0xcf, 0x68, 0x82, 0x21}, + stream: []byte{ + 0xf6, 0x3a, 0x89, 0xb7, 0x5c, 0x22, 0x71, 0xf9, + 0x36, 0x88, 0x16, 0x54, 0x2b, 0xa5, 0x2f, 0x06, + 0xed, 0x49, 0x24, 0x17, 0x92, 0x30, 0x2b, 0x00, + 0xb5, 0xe8, 0xf8, 0x0a, 0xe9, 0xa4, 0x73, 0xaf, + 0xc2, 0x5b, 0x21, 0x8f, 0x51, 0x9a, 0xf0, 0xfd, + 0xd4, 0x06, 0x36, 0x2e, 0x8d, 0x69, 0xde, 0x7f, + 0x54, 0xc6, 0x04, 0xa6, 0xe0, 0x0f, 0x35, 0x3f, + 0x11, 0x0f, 0x77, 0x1b, 0xdc, 0xa8, 0xab, 0x92, + 0xe5, 0xfb, 0xc3, 0x4e, 0x60, 0xa1, 0xd9, 0xa9, + 0xdb, 0x17, 0x34, 0x5b, 0x0a, 0x40, 0x27, 0x36, + 0x85, 0x3b, 0xf9, 0x10, 0xb0, 0x60, 0xbd, 0xf1, + 0xf8, 0x97, 0xb6, 0x29, 0x0f, 0x01, 0xd1, 0x38, + 0xae, 0x2c, 0x4c, 0x90, 0x22, 0x5b, 0xa9, 0xea, + 0x14, 0xd5, 0x18, 0xf5, 0x59, 0x29, 0xde, 0xa0, + 0x98, 0xca, 0x7a, 0x6c, 0xcf, 0xe6, 0x12, 0x27, + 0x05, 0x3c, 0x84, 0xe4, 0x9a, 0x4a, 0x33, 0x32, + }, + }, + { + name: "XChaCha20 Test", + key: []byte{ + 0x1b, 0x27, 0x55, 0x64, 0x73, 0xe9, 0x85, 0xd4, + 0x62, 0xcd, 0x51, 0x19, 0x7a, 0x9a, 0x46, 0xc7, + 0x60, 0x09, 0x54, 0x9e, 0xac, 0x64, 0x74, 0xf2, + 0x06, 0xc4, 0xee, 0x08, 0x44, 0xf6, 0x83, 0x89, + }, + iv: []byte{ + 0x69, 0x69, 0x6e, 0xe9, 0x55, 0xb6, 0x2b, 0x73, + 0xcd, 0x62, 0xbd, 0xa8, 0x75, 0xfc, 0x73, 0xd6, + 0x82, 0x19, 0xe0, 0x03, 0x6b, 0x7a, 0x0b, 0x37, + }, + stream: []byte{ + 0x4f, 0xeb, 0xf2, 0xfe, 0x4b, 0x35, 0x9c, 0x50, + 0x8d, 0xc5, 0xe8, 0xb5, 0x98, 0x0c, 0x88, 0xe3, + 0x89, 0x46, 0xd8, 0xf1, 0x8f, 0x31, 0x34, 0x65, + 0xc8, 0x62, 0xa0, 0x87, 0x82, 0x64, 0x82, 0x48, + 0x01, 0x8d, 0xac, 0xdc, 0xb9, 0x04, 0x17, 0x88, + 0x53, 0xa4, 0x6d, 0xca, 0x3a, 0x0e, 0xaa, 0xee, + 0x74, 0x7c, 0xba, 0x97, 0x43, 0x4e, 0xaf, 0xfa, + 0xd5, 0x8f, 0xea, 0x82, 0x22, 0x04, 0x7e, 0x0d, + 0xe6, 0xc3, 0xa6, 0x77, 0x51, 0x06, 0xe0, 0x33, + 0x1a, 0xd7, 0x14, 0xd2, 0xf2, 0x7a, 0x55, 0x64, + 0x13, 0x40, 0xa1, 0xf1, 0xdd, 0x9f, 0x94, 0x53, + 0x2e, 0x68, 0xcb, 0x24, 0x1c, 0xbd, 0xd1, 0x50, + 0x97, 0x0d, 0x14, 0xe0, 0x5c, 0x5b, 0x17, 0x31, + 0x93, 0xfb, 0x14, 0xf5, 0x1c, 0x41, 0xf3, 0x93, + 0x83, 0x5b, 0xf7, 0xf4, 0x16, 0xa7, 0xe0, 0xbb, + 0xa8, 0x1f, 0xfb, 0x8b, 0x13, 0xaf, 0x0e, 0x21, + 0x69, 0x1d, 0x7e, 0xce, 0xc9, 0x3b, 0x75, 0xe6, + 0xe4, 0x18, 0x3a, + }, + }, + { + name: "RFC 7539 Test Vector (96 bit nonce)", + key: []byte{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + }, + iv: []byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, + 0x00, 0x00, 0x00, 0x00, + }, + stream: []byte{ + 0x22, 0x4f, 0x51, 0xf3, 0x40, 0x1b, 0xd9, 0xe1, + 0x2f, 0xde, 0x27, 0x6f, 0xb8, 0x63, 0x1d, 0xed, + 0x8c, 0x13, 0x1f, 0x82, 0x3d, 0x2c, 0x06, 0xe2, + 0x7e, 0x4f, 0xca, 0xec, 0x9e, 0xf3, 0xcf, 0x78, + 0x8a, 0x3b, 0x0a, 0xa3, 0x72, 0x60, 0x0a, 0x92, + 0xb5, 0x79, 0x74, 0xcd, 0xed, 0x2b, 0x93, 0x34, + 0x79, 0x4c, 0xba, 0x40, 0xc6, 0x3e, 0x34, 0xcd, + 0xea, 0x21, 0x2c, 0x4c, 0xf0, 0x7d, 0x41, 0xb7, + 0x69, 0xa6, 0x74, 0x9f, 0x3f, 0x63, 0x0f, 0x41, + 0x22, 0xca, 0xfe, 0x28, 0xec, 0x4d, 0xc4, 0x7e, + 0x26, 0xd4, 0x34, 0x6d, 0x70, 0xb9, 0x8c, 0x73, + 0xf3, 0xe9, 0xc5, 0x3a, 0xc4, 0x0c, 0x59, 0x45, + 0x39, 0x8b, 0x6e, 0xda, 0x1a, 0x83, 0x2c, 0x89, + 0xc1, 0x67, 0xea, 0xcd, 0x90, 0x1d, 0x7e, 0x2b, + 0xf3, 0x63, + }, + seekOffset: 1, + }, +} + +func TestChaCha20(t *testing.T) { + for _, v := range draftTestVectors { + c, err := NewCipher(v.key, v.iv) + if err != nil { + t.Errorf("[%s]: New(k, iv) returned: %s", v.name, err) + continue + } + if v.seekOffset != 0 { + if err = c.Seek(v.seekOffset); err != nil { + t.Errorf("[%s]: Seek(seekOffset) returned: %s", v.name, err) + continue + } + } + out := make([]byte, len(v.stream)) + c.XORKeyStream(out, out) + if !bytes.Equal(out, v.stream) { + t.Errorf("[%s]: out != stream (%x != %x)", v.name, out, v.stream) + } + } +} + +func TestChaCha20Vectorized(t *testing.T) { + if !usingVectors { + t.Skip("vectorized ChaCha20 support not enabled") + } + + // Save the batch blocks processing routine so we can mess with it, and + // restore it when we're done. + oldBlocksFn := blocksFn + defer func() { + blocksFn = oldBlocksFn + }() + + const testSz = 1024 * 16 + + // Generate a random key, nonce and input. + var key [KeySize]byte + var nonce [NonceSize]byte + var input [testSz]byte + var vecOut [testSz]byte + var refOut [testSz]byte + rand.Read(key[:]) + rand.Read(nonce[:]) + rand.Read(input[:]) + + for i := 0; i < testSz; i++ { + // Encrypt with the vectorized implementation. + c, err := NewCipher(key[:], nonce[:]) + if err != nil { + t.Fatal(err) + } + c.XORKeyStream(vecOut[:], input[:i]) + + c, err = NewCipher(key[:], nonce[:]) + if err != nil { + t.Fatal(err) + } + blocksFn = blocksRef + c.XORKeyStream(refOut[:], input[:i]) + if !bytes.Equal(refOut[:i], vecOut[:i]) { + for j, v := range refOut { + if vecOut[j] != v { + t.Errorf("[%d] mismatch at offset: %d %x != %x", i, j, vecOut[j], v) + break + } + } + t.Errorf("ref: %s", hex.Dump(refOut[:i])) + t.Errorf("vec: %s", hex.Dump(vecOut[:i])) + t.Errorf("refOut != vecOut") + break + } + blocksFn = oldBlocksFn + } +} + +func TestChaCha20VectorizedIncremental(t *testing.T) { + if !usingVectors { + t.Skip("vectorized ChaCha20 support not enabled") + } + + // Save the batch blocks processing routine so we can mess with it, and + // restore it when we're done. + oldBlocksFn := blocksFn + defer func() { + blocksFn = oldBlocksFn + }() + + const ( + maxBlocks = 256 + testSz = (maxBlocks * (maxBlocks + 1) / 2) * BlockSize + ) + + // Generate a random key, nonce and input. + var key [KeySize]byte + var nonce [NonceSize]byte + var input [testSz]byte + var vecOut [testSz]byte + var refOut [testSz]byte + rand.Read(key[:]) + rand.Read(nonce[:]) + rand.Read(input[:]) + + // Using the vectorized version, encrypt an ever increasing number of + // blocks at a time. + c, err := NewCipher(key[:], nonce[:]) + if err != nil { + t.Fatal(err) + } + off := 0 + for nrBlocks := 0; nrBlocks <= maxBlocks; nrBlocks++ { + cnt := nrBlocks * BlockSize + c.XORKeyStream(vecOut[off:off+cnt], input[off:off+cnt]) + off += cnt + } + + // Encrypt an equivalent amount of data with a one shot call to the + // reference implementation. + c, err = NewCipher(key[:], nonce[:]) + if err != nil { + t.Fatal(err) + } + blocksFn = blocksRef + c.XORKeyStream(refOut[:], input[:]) + + // And compare the output. + if !bytes.Equal(refOut[:], vecOut[:]) { + for j, v := range refOut { + if vecOut[j] != v { + t.Errorf("incremental mismatch at offset: %d %x != %x", j, vecOut[j], v) + break + } + } + // t.Errorf("ref: %s", hex.Dump(refOut[:])) + // t.Errorf("vec: %s", hex.Dump(vecOut[:])) + t.Errorf("refOut != vecOut") + } +} + +func doBenchN(b *testing.B, n int) { + var key [KeySize]byte + var nonce [NonceSize]byte + s := make([]byte, n) + c, err := NewCipher(key[:], nonce[:]) + if err != nil { + b.Fatal(err) + } + b.SetBytes(int64(n)) + b.ResetTimer() + for i := 0; i < b.N; i++ { + c.XORKeyStream(s, s) + } +} + +func BenchmarkChaCha20_16(b *testing.B) { + doBenchN(b, 16) +} + +func BenchmarkChaCha20_64(b *testing.B) { + doBenchN(b, 64) +} + +func BenchmarkChaCha20_128(b *testing.B) { + doBenchN(b, 128) +} + +func BenchmarkChaCha20_192(b *testing.B) { + doBenchN(b, 192) +} + +func BenchmarkChaCha20_256(b *testing.B) { + doBenchN(b, 256) +} + +func BenchmarkChaCha20_384(b *testing.B) { + doBenchN(b, 384) +} + +func BenchmarkChaCha20_512(b *testing.B) { + doBenchN(b, 512) +} + +func BenchmarkChaCha20_1k(b *testing.B) { + doBenchN(b, 1024) +} + +func BenchmarkChaCha20_64k(b *testing.B) { + doBenchN(b, 65536) +} + +func BenchmarkCTRAES256_64k(b *testing.B) { + const sz = 64 * 1024 + var key [32]byte + var iv [16]byte + s := make([]byte, sz) + blk, err := aes.NewCipher(key[:]) + if err != nil { + b.Fatal(err) + } + c := cipher.NewCTR(blk, iv[:]) + b.SetBytes(sz) + b.ResetTimer() + for i := 0; i < b.N; i++ { + c.XORKeyStream(s, s) + } +} diff --git a/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/poly1305/README.md b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/poly1305/README.md new file mode 100644 index 0000000..7b6de64 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/poly1305/README.md @@ -0,0 +1,17 @@ +### poly1305: Go Poly1305 +#### Yawning Angel (yawning at schwanenlied dot me) + +Poly1305 implements the Poly1305 MAC algorithm, exposing a saner interface than +the one provided by golang.org/x/crypto/poly1305. In particular it exposes a +object that implements a hash.Hash interface. + +The implementation is based on the Public Domain poly1305-donna by Andrew +Moon. + +| Implementation | 64 byte | 1024 byte | +| -------------------- | ------------ | ----------- | +| go.crypto (ref) | 94.51 MB/s | 187.67 MB/s | +| go.crypto (amd64) | 540.68 MB/s | 909.97 MB/s | +| go poly1305-donna-32 | 425.40 MB/s | 715.23 MB/s | + +Note: All numbers on a i5-4250U, and to be taken with a huge grain of salt. diff --git a/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/poly1305/poly1305.go b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/poly1305/poly1305.go new file mode 100644 index 0000000..21486ca --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/poly1305/poly1305.go @@ -0,0 +1,207 @@ +// +// poly1305.go: Poly1305 MAC. +// +// To the extent possible under law, Yawning Angel waived all copyright +// and related or neighboring rights to poly1305, using the creative +// commons "CC0" public domain dedication. See LICENSE or +// for full details. + +// Package poly1305 is a Poly1305 MAC implementation. It is different from the +// golang.org/x/crypto implementation in that it exports a hash.Hash interface +// to support incremental updates. +// +// The implementation is based on Andrew Moon's poly1305-donna. +package poly1305 + +import ( + "crypto/subtle" + "errors" + "hash" + "runtime" + "unsafe" +) + +const ( + // KeySize is the Poly1305 key size in bytes. + KeySize = 32 + + // Size is the Poly1305 MAC size in bytes. + Size = 16 + + // BlockSize is the Poly1305 block size in bytes. + BlockSize = 16 +) + +var ( + // ErrInvalidKeySize is the error returned when an invalid sized key is + // encountered. + ErrInvalidKeySize = errors.New("poly1305: invalid key size") + + // ErrInvalidMacSize is the error returned when an invalid sized MAC is + // encountered. + ErrInvalidMacSize = errors.New("poly1305: invalid mac size") + + isLittleEndian = false +) + +type implInterface interface { + init(key []byte) + clear() + blocks(m []byte, bytes int, isFinal bool) + finish(mac *[Size]byte) +} + +// Poly1305 is an instance of the Poly1305 MAC algorithm. +type Poly1305 struct { + impl implState + leftover int + buffer [BlockSize]byte +} + +// Write adds more data to the running hash. It never returns an error. +func (st *Poly1305) Write(p []byte) (n int, err error) { + // + // poly1305-donna.c:poly1305_update() + // + + m := p + bytes := len(m) + + // handle leftover + if st.leftover > 0 { + want := BlockSize - st.leftover + if want > bytes { + want = bytes + } + for i := 0; i < want; i++ { + st.buffer[st.leftover+i] = m[i] + } + bytes -= want + m = m[want:] + st.leftover += want + if st.leftover < BlockSize { + return len(p), nil + } + st.impl.blocks(st.buffer[:], BlockSize, false) + st.leftover = 0 + } + + // process full blocks + if bytes >= BlockSize { + want := bytes & (^(BlockSize - 1)) + st.impl.blocks(m, want, false) + m = m[want:] + bytes -= want + } + + // store leftover + if bytes > 0 { + for i := 0; i < bytes; i++ { + st.buffer[st.leftover+i] = m[i] + } + st.leftover += bytes + } + + return len(p), nil +} + +// Sum appends the current hash to b and returns the resulting slice. It does +// not change the underlying hash state. +func (st *Poly1305) Sum(b []byte) []byte { + var mac [Size]byte + tmp := *st + tmp.finish(&mac) + return append(b, mac[:]...) +} + +// Reset clears the internal hash state and panic()s, because calling this is a +// sign that the user is doing something unadvisable. +func (st *Poly1305) Reset() { + st.Clear() // Obliterate the state before panic(). + + // Poly1305 keys are one time use only. + panic("poly1305: Reset() is not supported") +} + +// Size returns the number of bytes Sum will return. +func (st *Poly1305) Size() int { + return Size +} + +// BlockSize returns the hash's underlying block size. +func (st *Poly1305) BlockSize() int { + return BlockSize +} + +// Init (re-)initializes the hash instance with a given key. +func (st *Poly1305) Init(key []byte) { + if len(key) != KeySize { + panic(ErrInvalidKeySize) + } + + st.impl.init(key) + st.leftover = 0 +} + +// Clear purges the sensitive material in hash's internal state. +func (st *Poly1305) Clear() { + st.impl.clear() +} + +func (st *Poly1305) finish(mac *[Size]byte) { + // process the remaining block + if st.leftover > 0 { + st.buffer[st.leftover] = 1 + for i := st.leftover + 1; i < BlockSize; i++ { + st.buffer[i] = 0 + } + st.impl.blocks(st.buffer[:], BlockSize, true) + } + + st.impl.finish(mac) + st.impl.clear() +} + +// New returns a new Poly1305 instance keyed with the supplied key. +func New(key []byte) (*Poly1305, error) { + if len(key) != KeySize { + return nil, ErrInvalidKeySize + } + + h := &Poly1305{} + h.Init(key) + return h, nil +} + +// Sum does exactly what golang.org/x/crypto/poly1305.Sum() does. +func Sum(mac *[Size]byte, m []byte, key *[KeySize]byte) { + var h Poly1305 + h.Init(key[:]) + h.Write(m) + h.finish(mac) +} + +// Verify does exactly what golang.org/x/crypto/poly1305.Verify does. +func Verify(mac *[Size]byte, m []byte, key *[KeySize]byte) bool { + var m2 [Size]byte + Sum(&m2, m, key) + return subtle.ConstantTimeCompare(mac[:], m2[:]) == 1 +} + +func init() { + // Use the UTF-32 (UCS-4) Byte Order Mark to detect host byte order, + // which enables the further use of 'unsafe' for added performance. + const bomLE = 0x0000feff + bom := [4]byte{0xff, 0xfe, 0x00, 0x00} + + // ARM doesn't get the spiffy fast code since it's picky wrt alignment + // and I doubt Go does the right thing. + if runtime.GOARCH != "arm" { + bomHost := *(*uint32)(unsafe.Pointer(&bom[0])) + if bomHost == 0x0000feff { // Little endian, use unsafe. + isLittleEndian = true + } + } +} + +var _ hash.Hash = (*Poly1305)(nil) diff --git a/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/poly1305/poly1305_32.go b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/poly1305/poly1305_32.go new file mode 100644 index 0000000..857de1f --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/poly1305/poly1305_32.go @@ -0,0 +1,236 @@ +// +// poly1305_32.go: 32->64 bit multiplies, 64 bit additions +// +// To the extent possible under law, Yawning Angel waived all copyright +// and related or neighboring rights to poly1305, using the creative +// commons "CC0" public domain dedication. See LICENSE or +// for full details. + +package poly1305 + +import ( + "encoding/binary" + "unsafe" +) + +type implState struct { + r [5]uint32 + h [5]uint32 + pad [4]uint32 +} + +func (impl *implState) init(key []byte) { + // + // poly1305-donna-32.h:poly1305_init() + // + + // r &= 0xffffffc0ffffffc0ffffffc0fffffff + if isLittleEndian { + impl.r[0] = *(*uint32)(unsafe.Pointer(&key[0])) & 0x3ffffff + impl.r[1] = (*(*uint32)(unsafe.Pointer(&key[3])) >> 2) & 0x3ffff03 + impl.r[2] = (*(*uint32)(unsafe.Pointer(&key[6])) >> 4) & 0x3ffc0ff + impl.r[3] = (*(*uint32)(unsafe.Pointer(&key[9])) >> 6) & 0x3f03fff + impl.r[4] = (*(*uint32)(unsafe.Pointer(&key[12])) >> 8) & 0x00fffff + } else { + impl.r[0] = binary.LittleEndian.Uint32(key[0:]) & 0x3ffffff + impl.r[1] = (binary.LittleEndian.Uint32(key[3:]) >> 2) & 0x3ffff03 + impl.r[2] = (binary.LittleEndian.Uint32(key[6:]) >> 4) & 0x3ffc0ff + impl.r[3] = (binary.LittleEndian.Uint32(key[9:]) >> 6) & 0x3f03fff + impl.r[4] = (binary.LittleEndian.Uint32(key[12:]) >> 8) & 0x00fffff + } + + // h = 0 + for i := range impl.h { + impl.h[i] = 0 + } + + // save pad for later + impl.pad[0] = binary.LittleEndian.Uint32(key[16:]) + impl.pad[1] = binary.LittleEndian.Uint32(key[20:]) + impl.pad[2] = binary.LittleEndian.Uint32(key[24:]) + impl.pad[3] = binary.LittleEndian.Uint32(key[28:]) +} + +func (impl *implState) clear() { + for i := range impl.h { + impl.h[i] = 0 + } + for i := range impl.r { + impl.r[i] = 0 + } + for i := range impl.pad { + impl.pad[i] = 0 + } +} + +func (impl *implState) blocks(m []byte, bytes int, isFinal bool) { + // + // poly1305-donna-32.h:poly1305_blocks() + // + + var hibit uint32 + var d0, d1, d2, d3, d4 uint64 + var c uint32 + if !isFinal { + hibit = 1 << 24 // 1 << 128 + } + r0, r1, r2, r3, r4 := impl.r[0], impl.r[1], impl.r[2], impl.r[3], impl.r[4] + s1, s2, s3, s4 := r1*5, r2*5, r3*5, r4*5 + h0, h1, h2, h3, h4 := impl.h[0], impl.h[1], impl.h[2], impl.h[3], impl.h[4] + + for bytes >= BlockSize { + // h += m[i] + if isLittleEndian { + h0 += *(*uint32)(unsafe.Pointer(&m[0])) & 0x3ffffff + h1 += (*(*uint32)(unsafe.Pointer(&m[3])) >> 2) & 0x3ffffff + h2 += (*(*uint32)(unsafe.Pointer(&m[6])) >> 4) & 0x3ffffff + h3 += (*(*uint32)(unsafe.Pointer(&m[9])) >> 6) & 0x3ffffff + h4 += (*(*uint32)(unsafe.Pointer(&m[12])) >> 8) | hibit + } else { + h0 += binary.LittleEndian.Uint32(m[0:]) & 0x3ffffff + h1 += (binary.LittleEndian.Uint32(m[3:]) >> 2) & 0x3ffffff + h2 += (binary.LittleEndian.Uint32(m[6:]) >> 4) & 0x3ffffff + h3 += (binary.LittleEndian.Uint32(m[9:]) >> 6) & 0x3ffffff + h4 += (binary.LittleEndian.Uint32(m[12:]) >> 8) | hibit + } + + // h *= r + d0 = (uint64(h0) * uint64(r0)) + (uint64(h1) * uint64(s4)) + (uint64(h2) * uint64(s3)) + (uint64(h3) * uint64(s2)) + (uint64(h4) * uint64(s1)) + d1 = (uint64(h0) * uint64(r1)) + (uint64(h1) * uint64(r0)) + (uint64(h2) * uint64(s4)) + (uint64(h3) * uint64(s3)) + (uint64(h4) * uint64(s2)) + d2 = (uint64(h0) * uint64(r2)) + (uint64(h1) * uint64(r1)) + (uint64(h2) * uint64(r0)) + (uint64(h3) * uint64(s4)) + (uint64(h4) * uint64(s3)) + d3 = (uint64(h0) * uint64(r3)) + (uint64(h1) * uint64(r2)) + (uint64(h2) * uint64(r1)) + (uint64(h3) * uint64(r0)) + (uint64(h4) * uint64(s4)) + d4 = (uint64(h0) * uint64(r4)) + (uint64(h1) * uint64(r3)) + (uint64(h2) * uint64(r2)) + (uint64(h3) * uint64(r1)) + (uint64(h4) * uint64(r0)) + + // (partial) h %= p + c = uint32(d0 >> 26) + h0 = uint32(d0) & 0x3ffffff + + d1 += uint64(c) + c = uint32(d1 >> 26) + h1 = uint32(d1) & 0x3ffffff + + d2 += uint64(c) + c = uint32(d2 >> 26) + h2 = uint32(d2) & 0x3ffffff + + d3 += uint64(c) + c = uint32(d3 >> 26) + h3 = uint32(d3) & 0x3ffffff + + d4 += uint64(c) + c = uint32(d4 >> 26) + h4 = uint32(d4) & 0x3ffffff + + h0 += c * 5 + c = h0 >> 26 + h0 = h0 & 0x3ffffff + + h1 += c + + m = m[BlockSize:] + bytes -= BlockSize + } + + impl.h[0], impl.h[1], impl.h[2], impl.h[3], impl.h[4] = h0, h1, h2, h3, h4 +} + +func (impl *implState) finish(mac *[Size]byte) { + // + // poly1305-donna-32.h:poly1305_finish() + // + + var c uint32 + var g0, g1, g2, g3, g4 uint32 + var f uint64 + var mask uint32 + + // fully carry h + h0, h1, h2, h3, h4 := impl.h[0], impl.h[1], impl.h[2], impl.h[3], impl.h[4] + c = h1 >> 26 + h1 &= 0x3ffffff + + h2 += c + c = h2 >> 26 + h2 &= 0x3ffffff + + h3 += c + c = h3 >> 26 + h3 &= 0x3ffffff + + h4 += c + c = h4 >> 26 + h4 &= 0x3ffffff + + h0 += c * 5 + c = h0 >> 26 + h0 &= 0x3ffffff + + h1 += c + + // compute h + -p + g0 = h0 + 5 + c = g0 >> 26 + g0 &= 0x3ffffff + + g1 = h1 + c + c = g1 >> 26 + g1 &= 0x3ffffff + + g2 = h2 + c + c = g2 >> 26 + g2 &= 0x3ffffff + + g3 = h3 + c + c = g3 >> 26 + g3 &= 0x3ffffff + + g4 = h4 + c - (1 << 26) + + // select h if h < p, or h + -p if h >= p + mask = (g4 >> ((4 * 8) - 1)) - 1 + g0 &= mask + g1 &= mask + g2 &= mask + g3 &= mask + g4 &= mask + mask = ^mask + h0 = (h0 & mask) | g0 + h1 = (h1 & mask) | g1 + h2 = (h2 & mask) | g2 + h3 = (h3 & mask) | g3 + h4 = (h4 & mask) | g4 + + // h = h % (2^128) + h0 = ((h0) | (h1 << 26)) & 0xffffffff + h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff + h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff + h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff + + // mac = (h + pad) % (2^128) + f = uint64(h0) + uint64(impl.pad[0]) + h0 = uint32(f) + + f = uint64(h1) + uint64(impl.pad[1]) + (f >> 32) + h1 = uint32(f) + + f = uint64(h2) + uint64(impl.pad[2]) + (f >> 32) + h2 = uint32(f) + + f = uint64(h3) + uint64(impl.pad[3]) + (f >> 32) + h3 = uint32(f) + + if isLittleEndian { + macArr := (*[4]uint32)(unsafe.Pointer(&mac[0])) + macArr[0] = h0 + macArr[1] = h1 + macArr[2] = h2 + macArr[3] = h3 + } else { + binary.LittleEndian.PutUint32(mac[0:], h0) + binary.LittleEndian.PutUint32(mac[4:], h1) + binary.LittleEndian.PutUint32(mac[8:], h2) + binary.LittleEndian.PutUint32(mac[12:], h3) + } +} + +var _ implInterface = (*implState)(nil) diff --git a/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/poly1305/poly1305_test.go b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/poly1305/poly1305_test.go new file mode 100644 index 0000000..bed3da7 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/poly1305/poly1305_test.go @@ -0,0 +1,585 @@ +// +// poly1305.go: Poly1305 MAC known answer tests. +// +// To the extent possible under law, Yawning Angel waived all copyright +// and related or neighboring rights to poly1305, using the creative +// commons "CC0" public domain dedication. See LICENSE or +// for full details. + +package poly1305 + +import ( + "bytes" + "testing" +) + +// Shamelessly stolen from poly1305-donna.c:poly1305_power_on_self_test() + +func TestNaCl(t *testing.T) { + var naclKey = []byte{ + 0xee, 0xa6, 0xa7, 0x25, 0x1c, 0x1e, 0x72, 0x91, + 0x6d, 0x11, 0xc2, 0xcb, 0x21, 0x4d, 0x3c, 0x25, + 0x25, 0x39, 0x12, 0x1d, 0x8e, 0x23, 0x4e, 0x65, + 0x2d, 0x65, 0x1f, 0xa4, 0xc8, 0xcf, 0xf8, 0x80, + } + + var naclMsg = []byte{ + 0x8e, 0x99, 0x3b, 0x9f, 0x48, 0x68, 0x12, 0x73, + 0xc2, 0x96, 0x50, 0xba, 0x32, 0xfc, 0x76, 0xce, + 0x48, 0x33, 0x2e, 0xa7, 0x16, 0x4d, 0x96, 0xa4, + 0x47, 0x6f, 0xb8, 0xc5, 0x31, 0xa1, 0x18, 0x6a, + 0xc0, 0xdf, 0xc1, 0x7c, 0x98, 0xdc, 0xe8, 0x7b, + 0x4d, 0xa7, 0xf0, 0x11, 0xec, 0x48, 0xc9, 0x72, + 0x71, 0xd2, 0xc2, 0x0f, 0x9b, 0x92, 0x8f, 0xe2, + 0x27, 0x0d, 0x6f, 0xb8, 0x63, 0xd5, 0x17, 0x38, + 0xb4, 0x8e, 0xee, 0xe3, 0x14, 0xa7, 0xcc, 0x8a, + 0xb9, 0x32, 0x16, 0x45, 0x48, 0xe5, 0x26, 0xae, + 0x90, 0x22, 0x43, 0x68, 0x51, 0x7a, 0xcf, 0xea, + 0xbd, 0x6b, 0xb3, 0x73, 0x2b, 0xc0, 0xe9, 0xda, + 0x99, 0x83, 0x2b, 0x61, 0xca, 0x01, 0xb6, 0xde, + 0x56, 0x24, 0x4a, 0x9e, 0x88, 0xd5, 0xf9, 0xb3, + 0x79, 0x73, 0xf6, 0x22, 0xa4, 0x3d, 0x14, 0xa6, + 0x59, 0x9b, 0x1f, 0x65, 0x4c, 0xb4, 0x5a, 0x74, + 0xe3, 0x55, 0xa5, + } + + var naclMac = []byte{ + 0xf3, 0xff, 0xc7, 0x70, 0x3f, 0x94, 0x00, 0xe5, + 0x2a, 0x7d, 0xfb, 0x4b, 0x3d, 0x33, 0x05, 0xd9, + } + + // Oneshot + h, err := New(naclKey[:]) + if err != nil { + t.Fatal(err) + } + + n, err := h.Write(naclMsg[:]) + if err != nil { + t.Fatal(err) + } else if n != len(naclMsg) { + t.Fatalf("h.Write() returned unexpected length: %d", n) + } + + mac := h.Sum(nil) + if !bytes.Equal(mac, naclMac[:]) { + t.Fatalf("mac != naclMac") + } + + // Incremental + h, err = New(naclKey[:]) + if err != nil { + t.Fatal(err) + } + + for i, s := range []struct{ off, sz int }{ + {0, 32}, + {32, 64}, + {96, 16}, + {112, 8}, + {120, 4}, + {124, 2}, + {126, 1}, + {127, 1}, + {128, 1}, + {129, 1}, + {130, 1}, + } { + n, err := h.Write(naclMsg[s.off : s.off+s.sz]) + if err != nil { + t.Fatalf("[%d]: h.Write(): %s", i, err) + } else if n != s.sz { + t.Fatalf("[%d]: h.Write(): %d (expected: %d)", i, n, s.sz) + } + } + + mac = h.Sum(nil) + if !bytes.Equal(mac, naclMac[:]) { + t.Fatalf("mac != naclMac") + } +} + +func TestWrap(t *testing.T) { + // generates a final value of (2^130 - 2) == 3 + wrapKey := [KeySize]byte{ + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + } + + wrapMsg := []byte{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + } + + wrapMac := [Size]byte{ + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + } + + var mac [Size]byte + Sum(&mac, wrapMsg, &wrapKey) + if !bytes.Equal(mac[:], wrapMac[:]) { + t.Fatalf("mac != wrapMac") + } +} + +func TestTotal(t *testing.T) { + // mac of the macs of messages of length 0 to 256, where the key and messages + // have all their values set to the length + totalKey := []byte{ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, + } + + totalMac := []byte{ + 0x64, 0xaf, 0xe2, 0xe8, 0xd6, 0xad, 0x7b, 0xbd, + 0xd2, 0x87, 0xf9, 0x7c, 0x44, 0x62, 0x3d, 0x39, + } + + var allKey [KeySize]byte + allMsg := make([]byte, 256) + + totalCtx, err := New(totalKey[:]) + if err != nil { + t.Fatal(err) + } + + for i := 0; i < 256; i++ { + // set key and message to 'i,i,i..' + for j := range allKey { + allKey[j] = byte(i) + } + for j := 0; j < i; j++ { + allMsg[j] = byte(i) + } + + var mac [Size]byte + Sum(&mac, allMsg[:i], &allKey) + n, err := totalCtx.Write(mac[:]) + if err != nil { + t.Fatalf("[%d]: h.Write(): %s", i, err) + } else if n != len(mac) { + t.Fatalf("[%d]: h.Write(): %d (expected: %d)", i, n, len(mac)) + } + } + mac := totalCtx.Sum(nil) + if !bytes.Equal(mac, totalMac[:]) { + t.Fatalf("mac != totalMac") + } +} + +func TestIETFDraft(t *testing.T) { + // Test vectors taken from: + // https://www.ietf.org/id/draft-irtf-cfrg-chacha20-poly1305-07.txt + + vectors := []struct { + key [KeySize]byte + m []byte + tag [Size]byte + }{ + // Test Vector #1 + { + [KeySize]byte{}, + []byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + [Size]byte{}, + }, + + // Test Vector #2 + { + [KeySize]byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0xe5, 0xf6, 0xb5, 0xc5, 0xe0, 0x60, 0x70, + 0xf0, 0xef, 0xca, 0x96, 0x22, 0x7a, 0x86, 0x3e, + }, + []byte{ + 0x41, 0x6e, 0x79, 0x20, 0x73, 0x75, 0x62, 0x6d, + 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74, + 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x45, + 0x54, 0x46, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e, + 0x64, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x6f, 0x72, 0x20, 0x66, + 0x6f, 0x72, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, + 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x72, + 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, + 0x20, 0x61, 0x6e, 0x20, 0x49, 0x45, 0x54, 0x46, + 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, + 0x74, 0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x20, + 0x6f, 0x72, 0x20, 0x52, 0x46, 0x43, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x49, + 0x45, 0x54, 0x46, 0x20, 0x61, 0x63, 0x74, 0x69, + 0x76, 0x69, 0x74, 0x79, 0x20, 0x69, 0x73, 0x20, + 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x72, + 0x65, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x22, 0x49, + 0x45, 0x54, 0x46, 0x20, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x22, 0x2e, 0x20, 0x53, 0x75, 0x63, 0x68, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, + 0x64, 0x65, 0x20, 0x6f, 0x72, 0x61, 0x6c, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x49, 0x45, + 0x54, 0x46, 0x20, 0x73, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x2c, 0x20, 0x61, 0x73, 0x20, + 0x77, 0x65, 0x6c, 0x6c, 0x20, 0x61, 0x73, 0x20, + 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20, + 0x61, 0x6e, 0x64, 0x20, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x72, 0x6f, 0x6e, 0x69, 0x63, 0x20, 0x63, + 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x61, + 0x64, 0x65, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6e, + 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x6f, + 0x72, 0x20, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x2c, + 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x61, + 0x72, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, + }, + [Size]byte{ + 0x36, 0xe5, 0xf6, 0xb5, 0xc5, 0xe0, 0x60, 0x70, + 0xf0, 0xef, 0xca, 0x96, 0x22, 0x7a, 0x86, 0x3e, + }, + }, + + // Test Vector #3 + { + [KeySize]byte{ + 0x36, 0xe5, 0xf6, 0xb5, 0xc5, 0xe0, 0x60, 0x70, + 0xf0, 0xef, 0xca, 0x96, 0x22, 0x7a, 0x86, 0x3e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + []byte{ + 0x41, 0x6e, 0x79, 0x20, 0x73, 0x75, 0x62, 0x6d, + 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74, + 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x45, + 0x54, 0x46, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e, + 0x64, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x6f, 0x72, 0x20, 0x66, + 0x6f, 0x72, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, + 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x72, + 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, + 0x20, 0x61, 0x6e, 0x20, 0x49, 0x45, 0x54, 0x46, + 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, + 0x74, 0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x20, + 0x6f, 0x72, 0x20, 0x52, 0x46, 0x43, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x49, + 0x45, 0x54, 0x46, 0x20, 0x61, 0x63, 0x74, 0x69, + 0x76, 0x69, 0x74, 0x79, 0x20, 0x69, 0x73, 0x20, + 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x72, + 0x65, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x22, 0x49, + 0x45, 0x54, 0x46, 0x20, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x22, 0x2e, 0x20, 0x53, 0x75, 0x63, 0x68, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, + 0x64, 0x65, 0x20, 0x6f, 0x72, 0x61, 0x6c, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x49, 0x45, + 0x54, 0x46, 0x20, 0x73, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x2c, 0x20, 0x61, 0x73, 0x20, + 0x77, 0x65, 0x6c, 0x6c, 0x20, 0x61, 0x73, 0x20, + 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20, + 0x61, 0x6e, 0x64, 0x20, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x72, 0x6f, 0x6e, 0x69, 0x63, 0x20, 0x63, + 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x61, + 0x64, 0x65, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6e, + 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x6f, + 0x72, 0x20, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x2c, + 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x61, + 0x72, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, + }, + [Size]byte{ + 0xf3, 0x47, 0x7e, 0x7c, 0xd9, 0x54, 0x17, 0xaf, + 0x89, 0xa6, 0xb8, 0x79, 0x4c, 0x31, 0x0c, 0xf0, + }, + }, + + // Test Vector #4 + { + [KeySize]byte{ + 0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a, + 0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0, + 0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09, + 0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0, + }, + []byte{ + 0x27, 0x54, 0x77, 0x61, 0x73, 0x20, 0x62, 0x72, + 0x69, 0x6c, 0x6c, 0x69, 0x67, 0x2c, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x6c, 0x69, 0x74, 0x68, 0x79, 0x20, 0x74, 0x6f, + 0x76, 0x65, 0x73, 0x0a, 0x44, 0x69, 0x64, 0x20, + 0x67, 0x79, 0x72, 0x65, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x67, 0x69, 0x6d, 0x62, 0x6c, 0x65, 0x20, + 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, + 0x61, 0x62, 0x65, 0x3a, 0x0a, 0x41, 0x6c, 0x6c, + 0x20, 0x6d, 0x69, 0x6d, 0x73, 0x79, 0x20, 0x77, + 0x65, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x62, 0x6f, 0x72, 0x6f, 0x67, 0x6f, 0x76, 0x65, + 0x73, 0x2c, 0x0a, 0x41, 0x6e, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6d, 0x6f, 0x6d, 0x65, 0x20, + 0x72, 0x61, 0x74, 0x68, 0x73, 0x20, 0x6f, 0x75, + 0x74, 0x67, 0x72, 0x61, 0x62, 0x65, 0x2e, + }, + [Size]byte{ + 0x45, 0x41, 0x66, 0x9a, 0x7e, 0xaa, 0xee, 0x61, + 0xe7, 0x08, 0xdc, 0x7c, 0xbc, 0xc5, 0xeb, 0x62, + }, + }, + + // Test Vector #5 + // + // If one uses 130-bit partial reduction, does the code handle the case + // where partially reduced final result is not fully reduced? + { + [KeySize]byte{ + // R + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // S + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + []byte{ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + }, + [Size]byte{ + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + }, + + // Test Vector #6 + // + // What happens if addition of s overflows modulo 2^128? + { + [KeySize]byte{ + // R + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // S + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + }, + []byte{ + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + [Size]byte{ + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + }, + + // Test Vector #7 + // + // What happens if data limb is all ones and there is carry from lower + // limb? + { + [KeySize]byte{ + // R + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // S + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + []byte{ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + [Size]byte{ + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + }, + + // Test Vector #8 + // + // What happens if final result from polynomial part is exactly + // 2^130-5? + { + [KeySize]byte{ + // R + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // S + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + []byte{ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFB, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + }, + [Size]byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + }, + + // Test Vector #9 + // + // What happens if final result from polynomial part is exactly + // 2^130-6? + { + [KeySize]byte{ + // R + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // S + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + []byte{ + 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + }, + [Size]byte{ + 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + }, + }, + + // Test Vector #10 + // + // What happens if 5*H+L-type reduction produces 131-bit intermediate + // result? + { + [KeySize]byte{ + // R + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // S + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + []byte{ + 0xE3, 0x35, 0x94, 0xD7, 0x50, 0x5E, 0x43, 0xB9, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x94, 0xD7, 0x50, 0x5E, 0x43, 0x79, 0xCD, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + [Size]byte{ + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + }, + + // Test Vector #11 + // + // What happens if 5*H+L-type reduction produces 131-bit final result? + { + [KeySize]byte{ + // R + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // S + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + []byte{ + 0xE3, 0x35, 0x94, 0xD7, 0x50, 0x5E, 0x43, 0xB9, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x94, 0xD7, 0x50, 0x5E, 0x43, 0x79, 0xCD, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + [Size]byte{ + 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + }, + } + + for i, vec := range vectors { + var mac [Size]byte + Sum(&mac, vec.m, &vec.key) + if !bytes.Equal(mac[:], vec.tag[:]) { + t.Errorf("[%d]: mac != vec.tag", i) + } + if !Verify(&vec.tag, vec.m, &vec.key) { + t.Errorf("[%d]: Verify(tag, m, key) returned false", i) + } + } +} + +func TestIETFDraftForceByteswap(t *testing.T) { + if !isLittleEndian { + t.Skipf("not little endian, slow path already taken") + } else { + isLittleEndian = false + TestIETFDraft(t) + isLittleEndian = true + } +} + +// Swiped from golang.org/x/crypto/poly1305/poly1305_test.go. + +func Benchmark64(b *testing.B) { + b.StopTimer() + var mac [Size]byte + var key [KeySize]byte + m := make([]byte, 64) + b.SetBytes(int64(len(m))) + b.StartTimer() + + for i := 0; i < b.N; i++ { + Sum(&mac, m, &key) + } +} + +func Benchmark1k(b *testing.B) { + b.StopTimer() + var mac [Size]byte + var key [KeySize]byte + m := make([]byte, 1024) + b.SetBytes(int64(len(m))) + b.StartTimer() + + for i := 0; i < b.N; i++ { + Sum(&mac, m, &key) + } +} diff --git a/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/x448/LICENSE.txt b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/x448/LICENSE.txt new file mode 100644 index 0000000..9a20819 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/x448/LICENSE.txt @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) 2011 Stanford University. +Copyright (c) 2014-2015 Cryptography Research, Inc. +Copyright (c) 2015 Yawning Angel. + +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/wg/ecies/vendor/schwanenlied.me/yawning/x448/README.md b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/x448/README.md new file mode 100644 index 0000000..5dfb57d --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/x448/README.md @@ -0,0 +1,13 @@ +### x448 - curve448 ECDH +#### Yawning Angel (yawning at schwanenlied dot me) + +A straight forward port of Michael Hamburg's x448 code to Go lang. + +See: https://www.rfc-editor.org/rfc/rfc7748.txt + +If you're familiar with how to use golang.org/x/crypto/curve25519, you will be +right at home with using x448, since the functions are the same. Generate a +random secret key, ScalarBaseMult() to get the public key, etc etc etc. + +Both routines return 0 on success, -1 on failure which MUST be checked, and +the handshake aborted on failure. diff --git a/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/x448/x448.go b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/x448/x448.go new file mode 100644 index 0000000..b152e06 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/x448/x448.go @@ -0,0 +1,115 @@ +// The MIT License (MIT) +// +// Copyright (c) 2011 Stanford University. +// Copyright (c) 2014-2015 Cryptography Research, Inc. +// Copyright (c) 2015 Yawning Angel. +// +// 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. + +// Package x448 provides an implementation of scalar multiplication on the +// elliptic curve known as curve448. +// +// See https://tools.ietf.org/html/draft-irtf-cfrg-curves-11 +package x448 // import "git.schwanenlied.me/yawning/x448.git" + +const ( + x448Bytes = 56 + edwardsD = -39081 +) + +var basePoint = [56]byte{ + 5, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +} + +func ScalarMult(out, scalar, base *[56]byte) int { + var x1, x2, z2, x3, z3, t1, t2 gf + x1.deser(base) + x2.cpy(&one) + z2.cpy(&zero) + x3.cpy(&x1) + z3.cpy(&one) + + var swap limbUint + + for t := int(448 - 1); t >= 0; t-- { + sb := scalar[t/8] + + // Scalar conditioning. + if t/8 == 0 { + sb &= 0xFC + } else if t/8 == x448Bytes-1 { + sb |= 0x80 + } + + kT := (limbUint)((sb >> ((uint)(t) % 8)) & 1) + kT = -kT // Set to all 0s or all 1s + + swap ^= kT + x2.condSwap(&x3, swap) + z2.condSwap(&z3, swap) + swap = kT + + t1.add(&x2, &z2) // A = x2 + z2 + t2.sub(&x2, &z2) // B = x2 - z2 + z2.sub(&x3, &z3) // D = x3 - z3 + x2.mul(&t1, &z2) // DA + z2.add(&z3, &x3) // C = x3 + z3 + x3.mul(&t2, &z2) // CB + z3.sub(&x2, &x3) // DA-CB + z2.sqr(&z3) // (DA-CB)^2 + z3.mul(&x1, &z2) // z3 = x1(DA-CB)^2 + z2.add(&x2, &x3) // (DA+CB) + x3.sqr(&z2) // x3 = (DA+CB)^2 + + z2.sqr(&t1) // AA = A^2 + t1.sqr(&t2) // BB = B^2 + x2.mul(&z2, &t1) // x2 = AA*BB + t2.sub(&z2, &t1) // E = AA-BB + + t1.mlw(&t2, -edwardsD) // E*-d = a24*E + t1.add(&t1, &z2) // AA + a24*E + z2.mul(&t2, &t1) // z2 = E(AA+a24*E) + } + + // Finish + x2.condSwap(&x3, swap) + z2.condSwap(&x3, swap) + z2.inv(&z2) + x1.mul(&x2, &z2) + x1.ser(out) + + // As with X25519, both sides MUST check, without leaking extra + // information about the value of K, whether the resulting shared K is + // the all-zero value and abort if so. + var nz limbSint + for _, v := range out { + nz |= (limbSint)(v) + } + nz = (nz - 1) >> 8 // 0 = succ, -1 = fail + + // return value: 0 = succ, -1 = fail + return (int)(nz) +} + +func ScalarBaseMult(out, scalar *[56]byte) int { + return ScalarMult(out, scalar, &basePoint) +} diff --git a/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/x448/x448_ref.go b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/x448/x448_ref.go new file mode 100644 index 0000000..e32f878 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/x448/x448_ref.go @@ -0,0 +1,779 @@ +// The MIT License (MIT) +// +// Copyright (c) 2011 Stanford University. +// Copyright (c) 2014-2015 Cryptography Research, Inc. +// Copyright (c) 2015 Yawning Angel. +// +// 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. + +package x448 + +// This should really use 64 bit limbs, but Go is fucking retarded and doesn't +// have __(u)int128_t, so the 32 bit code it is, at a hefty performance +// penalty. Fuck my life, I'm going to have to bust out PeachPy to get this +// to go fast aren't I. + +const ( + wBits = 32 + lBits = (wBits * 7 / 8) + x448Limbs = (448 / lBits) + lMask = (1 << lBits) - 1 +) + +type limbUint uint32 +type limbSint int32 + +type gf struct { + limb [x448Limbs]uint32 +} + +var zero = gf{[x448Limbs]uint32{0}} +var one = gf{[x448Limbs]uint32{1}} +var p = gf{[x448Limbs]uint32{ + lMask, lMask, lMask, lMask, lMask, lMask, lMask, lMask, + lMask - 1, lMask, lMask, lMask, lMask, lMask, lMask, lMask, +}} + +// cpy copies x = y. +func (x *gf) cpy(y *gf) { + // for i, v := range y.limb { + // x.limb[i] = v + // } + + copy(x.limb[:], y.limb[:]) +} + +// mul multiplies c = a * b. (PERF) +func (c *gf) mul(a, b *gf) { + var aa gf + aa.cpy(a) + + // + // This is *by far* the most CPU intesive routine in the code. + // + + // var accum [x448Limbs]uint64 + // for i, bv := range b.limb { + // for j, aav := range aa.limb { + // accum[(i+j)%x448Limbs] += (uint64)(bv) * (uint64)(aav) + // } + // aa.limb[(x448Limbs-1-i)^(x448Limbs/2)] += aa.limb[x448Limbs-1-i] + // } + + // So fucking stupid that this is actually a fairly massive gain. + var accum0, accum1, accum2, accum3, accum4, accum5, accum6, accum7, accum8, accum9, accum10, accum11, accum12, accum13, accum14, accum15 uint64 + var bv uint64 + + bv = (uint64)(b.limb[0]) + accum0 += bv * (uint64)(aa.limb[0]) + accum1 += bv * (uint64)(aa.limb[1]) + accum2 += bv * (uint64)(aa.limb[2]) + accum3 += bv * (uint64)(aa.limb[3]) + accum4 += bv * (uint64)(aa.limb[4]) + accum5 += bv * (uint64)(aa.limb[5]) + accum6 += bv * (uint64)(aa.limb[6]) + accum7 += bv * (uint64)(aa.limb[7]) + accum8 += bv * (uint64)(aa.limb[8]) + accum9 += bv * (uint64)(aa.limb[9]) + accum10 += bv * (uint64)(aa.limb[10]) + accum11 += bv * (uint64)(aa.limb[11]) + accum12 += bv * (uint64)(aa.limb[12]) + accum13 += bv * (uint64)(aa.limb[13]) + accum14 += bv * (uint64)(aa.limb[14]) + accum15 += bv * (uint64)(aa.limb[15]) + aa.limb[(x448Limbs-1-0)^(x448Limbs/2)] += aa.limb[x448Limbs-1-0] + + bv = (uint64)(b.limb[1]) + accum1 += bv * (uint64)(aa.limb[0]) + accum2 += bv * (uint64)(aa.limb[1]) + accum3 += bv * (uint64)(aa.limb[2]) + accum4 += bv * (uint64)(aa.limb[3]) + accum5 += bv * (uint64)(aa.limb[4]) + accum6 += bv * (uint64)(aa.limb[5]) + accum7 += bv * (uint64)(aa.limb[6]) + accum8 += bv * (uint64)(aa.limb[7]) + accum9 += bv * (uint64)(aa.limb[8]) + accum10 += bv * (uint64)(aa.limb[9]) + accum11 += bv * (uint64)(aa.limb[10]) + accum12 += bv * (uint64)(aa.limb[11]) + accum13 += bv * (uint64)(aa.limb[12]) + accum14 += bv * (uint64)(aa.limb[13]) + accum15 += bv * (uint64)(aa.limb[14]) + accum0 += bv * (uint64)(aa.limb[15]) + aa.limb[(x448Limbs-1-1)^(x448Limbs/2)] += aa.limb[x448Limbs-1-1] + + bv = (uint64)(b.limb[2]) + accum2 += bv * (uint64)(aa.limb[0]) + accum3 += bv * (uint64)(aa.limb[1]) + accum4 += bv * (uint64)(aa.limb[2]) + accum5 += bv * (uint64)(aa.limb[3]) + accum6 += bv * (uint64)(aa.limb[4]) + accum7 += bv * (uint64)(aa.limb[5]) + accum8 += bv * (uint64)(aa.limb[6]) + accum9 += bv * (uint64)(aa.limb[7]) + accum10 += bv * (uint64)(aa.limb[8]) + accum11 += bv * (uint64)(aa.limb[9]) + accum12 += bv * (uint64)(aa.limb[10]) + accum13 += bv * (uint64)(aa.limb[11]) + accum14 += bv * (uint64)(aa.limb[12]) + accum15 += bv * (uint64)(aa.limb[13]) + accum0 += bv * (uint64)(aa.limb[14]) + accum1 += bv * (uint64)(aa.limb[15]) + aa.limb[(x448Limbs-1-2)^(x448Limbs/2)] += aa.limb[x448Limbs-1-2] + + bv = (uint64)(b.limb[3]) + accum3 += bv * (uint64)(aa.limb[0]) + accum4 += bv * (uint64)(aa.limb[1]) + accum5 += bv * (uint64)(aa.limb[2]) + accum6 += bv * (uint64)(aa.limb[3]) + accum7 += bv * (uint64)(aa.limb[4]) + accum8 += bv * (uint64)(aa.limb[5]) + accum9 += bv * (uint64)(aa.limb[6]) + accum10 += bv * (uint64)(aa.limb[7]) + accum11 += bv * (uint64)(aa.limb[8]) + accum12 += bv * (uint64)(aa.limb[9]) + accum13 += bv * (uint64)(aa.limb[10]) + accum14 += bv * (uint64)(aa.limb[11]) + accum15 += bv * (uint64)(aa.limb[12]) + accum0 += bv * (uint64)(aa.limb[13]) + accum1 += bv * (uint64)(aa.limb[14]) + accum2 += bv * (uint64)(aa.limb[15]) + aa.limb[(x448Limbs-1-3)^(x448Limbs/2)] += aa.limb[x448Limbs-1-3] + + bv = (uint64)(b.limb[4]) + accum4 += bv * (uint64)(aa.limb[0]) + accum5 += bv * (uint64)(aa.limb[1]) + accum6 += bv * (uint64)(aa.limb[2]) + accum7 += bv * (uint64)(aa.limb[3]) + accum8 += bv * (uint64)(aa.limb[4]) + accum9 += bv * (uint64)(aa.limb[5]) + accum10 += bv * (uint64)(aa.limb[6]) + accum11 += bv * (uint64)(aa.limb[7]) + accum12 += bv * (uint64)(aa.limb[8]) + accum13 += bv * (uint64)(aa.limb[9]) + accum14 += bv * (uint64)(aa.limb[10]) + accum15 += bv * (uint64)(aa.limb[11]) + accum0 += bv * (uint64)(aa.limb[12]) + accum1 += bv * (uint64)(aa.limb[13]) + accum2 += bv * (uint64)(aa.limb[14]) + accum3 += bv * (uint64)(aa.limb[15]) + aa.limb[(x448Limbs-1-4)^(x448Limbs/2)] += aa.limb[x448Limbs-1-4] + + bv = (uint64)(b.limb[5]) + accum5 += bv * (uint64)(aa.limb[0]) + accum6 += bv * (uint64)(aa.limb[1]) + accum7 += bv * (uint64)(aa.limb[2]) + accum8 += bv * (uint64)(aa.limb[3]) + accum9 += bv * (uint64)(aa.limb[4]) + accum10 += bv * (uint64)(aa.limb[5]) + accum11 += bv * (uint64)(aa.limb[6]) + accum12 += bv * (uint64)(aa.limb[7]) + accum13 += bv * (uint64)(aa.limb[8]) + accum14 += bv * (uint64)(aa.limb[9]) + accum15 += bv * (uint64)(aa.limb[10]) + accum0 += bv * (uint64)(aa.limb[11]) + accum1 += bv * (uint64)(aa.limb[12]) + accum2 += bv * (uint64)(aa.limb[13]) + accum3 += bv * (uint64)(aa.limb[14]) + accum4 += bv * (uint64)(aa.limb[15]) + aa.limb[(x448Limbs-1-5)^(x448Limbs/2)] += aa.limb[x448Limbs-1-5] + + bv = (uint64)(b.limb[6]) + accum6 += bv * (uint64)(aa.limb[0]) + accum7 += bv * (uint64)(aa.limb[1]) + accum8 += bv * (uint64)(aa.limb[2]) + accum9 += bv * (uint64)(aa.limb[3]) + accum10 += bv * (uint64)(aa.limb[4]) + accum11 += bv * (uint64)(aa.limb[5]) + accum12 += bv * (uint64)(aa.limb[6]) + accum13 += bv * (uint64)(aa.limb[7]) + accum14 += bv * (uint64)(aa.limb[8]) + accum15 += bv * (uint64)(aa.limb[9]) + accum0 += bv * (uint64)(aa.limb[10]) + accum1 += bv * (uint64)(aa.limb[11]) + accum2 += bv * (uint64)(aa.limb[12]) + accum3 += bv * (uint64)(aa.limb[13]) + accum4 += bv * (uint64)(aa.limb[14]) + accum5 += bv * (uint64)(aa.limb[15]) + aa.limb[(x448Limbs-1-6)^(x448Limbs/2)] += aa.limb[x448Limbs-1-6] + + bv = (uint64)(b.limb[7]) + accum7 += bv * (uint64)(aa.limb[0]) + accum8 += bv * (uint64)(aa.limb[1]) + accum9 += bv * (uint64)(aa.limb[2]) + accum10 += bv * (uint64)(aa.limb[3]) + accum11 += bv * (uint64)(aa.limb[4]) + accum12 += bv * (uint64)(aa.limb[5]) + accum13 += bv * (uint64)(aa.limb[6]) + accum14 += bv * (uint64)(aa.limb[7]) + accum15 += bv * (uint64)(aa.limb[8]) + accum0 += bv * (uint64)(aa.limb[9]) + accum1 += bv * (uint64)(aa.limb[10]) + accum2 += bv * (uint64)(aa.limb[11]) + accum3 += bv * (uint64)(aa.limb[12]) + accum4 += bv * (uint64)(aa.limb[13]) + accum5 += bv * (uint64)(aa.limb[14]) + accum6 += bv * (uint64)(aa.limb[15]) + aa.limb[(x448Limbs-1-7)^(x448Limbs/2)] += aa.limb[x448Limbs-1-7] + + bv = (uint64)(b.limb[8]) + accum8 += bv * (uint64)(aa.limb[0]) + accum9 += bv * (uint64)(aa.limb[1]) + accum10 += bv * (uint64)(aa.limb[2]) + accum11 += bv * (uint64)(aa.limb[3]) + accum12 += bv * (uint64)(aa.limb[4]) + accum13 += bv * (uint64)(aa.limb[5]) + accum14 += bv * (uint64)(aa.limb[6]) + accum15 += bv * (uint64)(aa.limb[7]) + accum0 += bv * (uint64)(aa.limb[8]) + accum1 += bv * (uint64)(aa.limb[9]) + accum2 += bv * (uint64)(aa.limb[10]) + accum3 += bv * (uint64)(aa.limb[11]) + accum4 += bv * (uint64)(aa.limb[12]) + accum5 += bv * (uint64)(aa.limb[13]) + accum6 += bv * (uint64)(aa.limb[14]) + accum7 += bv * (uint64)(aa.limb[15]) + aa.limb[(x448Limbs-1-8)^(x448Limbs/2)] += aa.limb[x448Limbs-1-8] + + bv = (uint64)(b.limb[9]) + accum9 += bv * (uint64)(aa.limb[0]) + accum10 += bv * (uint64)(aa.limb[1]) + accum11 += bv * (uint64)(aa.limb[2]) + accum12 += bv * (uint64)(aa.limb[3]) + accum13 += bv * (uint64)(aa.limb[4]) + accum14 += bv * (uint64)(aa.limb[5]) + accum15 += bv * (uint64)(aa.limb[6]) + accum0 += bv * (uint64)(aa.limb[7]) + accum1 += bv * (uint64)(aa.limb[8]) + accum2 += bv * (uint64)(aa.limb[9]) + accum3 += bv * (uint64)(aa.limb[10]) + accum4 += bv * (uint64)(aa.limb[11]) + accum5 += bv * (uint64)(aa.limb[12]) + accum6 += bv * (uint64)(aa.limb[13]) + accum7 += bv * (uint64)(aa.limb[14]) + accum8 += bv * (uint64)(aa.limb[15]) + aa.limb[(x448Limbs-1-9)^(x448Limbs/2)] += aa.limb[x448Limbs-1-9] + + bv = (uint64)(b.limb[10]) + accum10 += bv * (uint64)(aa.limb[0]) + accum11 += bv * (uint64)(aa.limb[1]) + accum12 += bv * (uint64)(aa.limb[2]) + accum13 += bv * (uint64)(aa.limb[3]) + accum14 += bv * (uint64)(aa.limb[4]) + accum15 += bv * (uint64)(aa.limb[5]) + accum0 += bv * (uint64)(aa.limb[6]) + accum1 += bv * (uint64)(aa.limb[7]) + accum2 += bv * (uint64)(aa.limb[8]) + accum3 += bv * (uint64)(aa.limb[9]) + accum4 += bv * (uint64)(aa.limb[10]) + accum5 += bv * (uint64)(aa.limb[11]) + accum6 += bv * (uint64)(aa.limb[12]) + accum7 += bv * (uint64)(aa.limb[13]) + accum8 += bv * (uint64)(aa.limb[14]) + accum9 += bv * (uint64)(aa.limb[15]) + aa.limb[(x448Limbs-1-10)^(x448Limbs/2)] += aa.limb[x448Limbs-1-10] + + bv = (uint64)(b.limb[11]) + accum11 += bv * (uint64)(aa.limb[0]) + accum12 += bv * (uint64)(aa.limb[1]) + accum13 += bv * (uint64)(aa.limb[2]) + accum14 += bv * (uint64)(aa.limb[3]) + accum15 += bv * (uint64)(aa.limb[4]) + accum0 += bv * (uint64)(aa.limb[5]) + accum1 += bv * (uint64)(aa.limb[6]) + accum2 += bv * (uint64)(aa.limb[7]) + accum3 += bv * (uint64)(aa.limb[8]) + accum4 += bv * (uint64)(aa.limb[9]) + accum5 += bv * (uint64)(aa.limb[10]) + accum6 += bv * (uint64)(aa.limb[11]) + accum7 += bv * (uint64)(aa.limb[12]) + accum8 += bv * (uint64)(aa.limb[13]) + accum9 += bv * (uint64)(aa.limb[14]) + accum10 += bv * (uint64)(aa.limb[15]) + aa.limb[(x448Limbs-1-11)^(x448Limbs/2)] += aa.limb[x448Limbs-1-11] + + bv = (uint64)(b.limb[12]) + accum12 += bv * (uint64)(aa.limb[0]) + accum13 += bv * (uint64)(aa.limb[1]) + accum14 += bv * (uint64)(aa.limb[2]) + accum15 += bv * (uint64)(aa.limb[3]) + accum0 += bv * (uint64)(aa.limb[4]) + accum1 += bv * (uint64)(aa.limb[5]) + accum2 += bv * (uint64)(aa.limb[6]) + accum3 += bv * (uint64)(aa.limb[7]) + accum4 += bv * (uint64)(aa.limb[8]) + accum5 += bv * (uint64)(aa.limb[9]) + accum6 += bv * (uint64)(aa.limb[10]) + accum7 += bv * (uint64)(aa.limb[11]) + accum8 += bv * (uint64)(aa.limb[12]) + accum9 += bv * (uint64)(aa.limb[13]) + accum10 += bv * (uint64)(aa.limb[14]) + accum11 += bv * (uint64)(aa.limb[15]) + aa.limb[(x448Limbs-1-12)^(x448Limbs/2)] += aa.limb[x448Limbs-1-12] + + bv = (uint64)(b.limb[13]) + accum13 += bv * (uint64)(aa.limb[0]) + accum14 += bv * (uint64)(aa.limb[1]) + accum15 += bv * (uint64)(aa.limb[2]) + accum0 += bv * (uint64)(aa.limb[3]) + accum1 += bv * (uint64)(aa.limb[4]) + accum2 += bv * (uint64)(aa.limb[5]) + accum3 += bv * (uint64)(aa.limb[6]) + accum4 += bv * (uint64)(aa.limb[7]) + accum5 += bv * (uint64)(aa.limb[8]) + accum6 += bv * (uint64)(aa.limb[9]) + accum7 += bv * (uint64)(aa.limb[10]) + accum8 += bv * (uint64)(aa.limb[11]) + accum9 += bv * (uint64)(aa.limb[12]) + accum10 += bv * (uint64)(aa.limb[13]) + accum11 += bv * (uint64)(aa.limb[14]) + accum12 += bv * (uint64)(aa.limb[15]) + aa.limb[(x448Limbs-1-13)^(x448Limbs/2)] += aa.limb[x448Limbs-1-13] + + bv = (uint64)(b.limb[14]) + accum14 += bv * (uint64)(aa.limb[0]) + accum15 += bv * (uint64)(aa.limb[1]) + accum0 += bv * (uint64)(aa.limb[2]) + accum1 += bv * (uint64)(aa.limb[3]) + accum2 += bv * (uint64)(aa.limb[4]) + accum3 += bv * (uint64)(aa.limb[5]) + accum4 += bv * (uint64)(aa.limb[6]) + accum5 += bv * (uint64)(aa.limb[7]) + accum6 += bv * (uint64)(aa.limb[8]) + accum7 += bv * (uint64)(aa.limb[9]) + accum8 += bv * (uint64)(aa.limb[10]) + accum9 += bv * (uint64)(aa.limb[11]) + accum10 += bv * (uint64)(aa.limb[12]) + accum11 += bv * (uint64)(aa.limb[13]) + accum12 += bv * (uint64)(aa.limb[14]) + accum13 += bv * (uint64)(aa.limb[15]) + aa.limb[(x448Limbs-1-14)^(x448Limbs/2)] += aa.limb[x448Limbs-1-14] + + bv = (uint64)(b.limb[15]) + accum15 += bv * (uint64)(aa.limb[0]) + accum0 += bv * (uint64)(aa.limb[1]) + accum1 += bv * (uint64)(aa.limb[2]) + accum2 += bv * (uint64)(aa.limb[3]) + accum3 += bv * (uint64)(aa.limb[4]) + accum4 += bv * (uint64)(aa.limb[5]) + accum5 += bv * (uint64)(aa.limb[6]) + accum6 += bv * (uint64)(aa.limb[7]) + accum7 += bv * (uint64)(aa.limb[8]) + accum8 += bv * (uint64)(aa.limb[9]) + accum9 += bv * (uint64)(aa.limb[10]) + accum10 += bv * (uint64)(aa.limb[11]) + accum11 += bv * (uint64)(aa.limb[12]) + accum12 += bv * (uint64)(aa.limb[13]) + accum13 += bv * (uint64)(aa.limb[14]) + accum14 += bv * (uint64)(aa.limb[15]) + aa.limb[(x448Limbs-1-15)^(x448Limbs/2)] += aa.limb[x448Limbs-1-15] + + // accum[x448Limbs-1] += accum[x448Limbs-2] >> lBits + // accum[x448Limbs-2] &= lMask + // accum[x448Limbs/2] += accum[x448Limbs-1] >> lBits + accum15 += accum14 >> lBits + accum14 &= lMask + accum8 += accum15 >> lBits + + // for j := uint(0); j < x448Limbs; j++ { + // accum[j] += accum[(j-1)%x448Limbs] >> lBits + // accum[(j-1)%x448Limbs] &= lMask + // } + accum0 += accum15 >> lBits + accum15 &= lMask + accum1 += accum0 >> lBits + accum0 &= lMask + accum2 += accum1 >> lBits + accum1 &= lMask + accum3 += accum2 >> lBits + accum2 &= lMask + accum4 += accum3 >> lBits + accum3 &= lMask + accum5 += accum4 >> lBits + accum4 &= lMask + accum6 += accum5 >> lBits + accum5 &= lMask + accum7 += accum6 >> lBits + accum6 &= lMask + accum8 += accum7 >> lBits + accum7 &= lMask + accum9 += accum8 >> lBits + accum8 &= lMask + accum10 += accum9 >> lBits + accum9 &= lMask + accum11 += accum10 >> lBits + accum10 &= lMask + accum12 += accum11 >> lBits + accum11 &= lMask + accum13 += accum12 >> lBits + accum12 &= lMask + accum14 += accum13 >> lBits + accum13 &= lMask + accum15 += accum14 >> lBits + accum14 &= lMask + + // for j, accv := range accum { + // c.limb[j] = (uint32)(accv) + // } + c.limb[0] = (uint32)(accum0) + c.limb[1] = (uint32)(accum1) + c.limb[2] = (uint32)(accum2) + c.limb[3] = (uint32)(accum3) + c.limb[4] = (uint32)(accum4) + c.limb[5] = (uint32)(accum5) + c.limb[6] = (uint32)(accum6) + c.limb[7] = (uint32)(accum7) + c.limb[8] = (uint32)(accum8) + c.limb[9] = (uint32)(accum9) + c.limb[10] = (uint32)(accum10) + c.limb[11] = (uint32)(accum11) + c.limb[12] = (uint32)(accum12) + c.limb[13] = (uint32)(accum13) + c.limb[14] = (uint32)(accum14) + c.limb[15] = (uint32)(accum15) +} + +// sqr squares (c = x * x). Just calls multiply. (PERF) +func (c *gf) sqr(x *gf) { + c.mul(x, x) +} + +// isqrt inverse square roots (y = 1/sqrt(x)), using an addition chain. +func (y *gf) isqrt(x *gf) { + var a, b, c gf + c.sqr(x) + + // XXX/Yawning, could unroll, but this is called only once. + + // STEP(b,x,1); + b.mul(x, &c) + c.cpy(&b) + for i := 0; i < 1; i++ { + c.sqr(&c) + } + + // STEP(b,x,3); + b.mul(x, &c) + c.cpy(&b) + for i := 0; i < 3; i++ { + c.sqr(&c) + } + + //STEP(a,b,3); + a.mul(&b, &c) + c.cpy(&a) + for i := 0; i < 3; i++ { + c.sqr(&c) + } + + // STEP(a,b,9); + a.mul(&b, &c) + c.cpy(&a) + for i := 0; i < 9; i++ { + c.sqr(&c) + } + + // STEP(b,a,1); + b.mul(&a, &c) + c.cpy(&b) + for i := 0; i < 1; i++ { + c.sqr(&c) + } + + // STEP(a,x,18); + a.mul(x, &c) + c.cpy(&a) + for i := 0; i < 18; i++ { + c.sqr(&c) + } + + // STEP(a,b,37); + a.mul(&b, &c) + c.cpy(&a) + for i := 0; i < 37; i++ { + c.sqr(&c) + } + + // STEP(b,a,37); + b.mul(&a, &c) + c.cpy(&b) + for i := 0; i < 37; i++ { + c.sqr(&c) + } + + // STEP(b,a,111); + b.mul(&a, &c) + c.cpy(&b) + for i := 0; i < 111; i++ { + c.sqr(&c) + } + + // STEP(a,b,1); + a.mul(&b, &c) + c.cpy(&a) + for i := 0; i < 1; i++ { + c.sqr(&c) + } + + // STEP(b,x,223); + b.mul(x, &c) + c.cpy(&b) + for i := 0; i < 223; i++ { + c.sqr(&c) + } + + y.mul(&a, &c) +} + +// inv inverses (y = 1/x). +func (y *gf) inv(x *gf) { + var z, w gf + z.sqr(x) // x^2 + w.isqrt(&z) // +- 1/sqrt(x^2) = +- 1/x + z.sqr(&w) // 1/x^2 + w.mul(x, &z) // 1/x + y.cpy(&w) +} + +// reduce weakly reduces mod p +func (x *gf) reduce() { + x.limb[x448Limbs/2] += x.limb[x448Limbs-1] >> lBits + + // for j := uint(0); j < x448Limbs; j++ { + // x.limb[j] += x.limb[(j-1)%x448Limbs] >> lBits + // x.limb[(j-1)%x448Limbs] &= lMask + // } + x.limb[0] += x.limb[15] >> lBits + x.limb[15] &= lMask + x.limb[1] += x.limb[0] >> lBits + x.limb[0] &= lMask + x.limb[2] += x.limb[1] >> lBits + x.limb[1] &= lMask + x.limb[3] += x.limb[2] >> lBits + x.limb[2] &= lMask + x.limb[4] += x.limb[3] >> lBits + x.limb[3] &= lMask + x.limb[5] += x.limb[4] >> lBits + x.limb[4] &= lMask + x.limb[6] += x.limb[5] >> lBits + x.limb[5] &= lMask + x.limb[7] += x.limb[6] >> lBits + x.limb[6] &= lMask + x.limb[8] += x.limb[7] >> lBits + x.limb[7] &= lMask + x.limb[9] += x.limb[8] >> lBits + x.limb[8] &= lMask + x.limb[10] += x.limb[9] >> lBits + x.limb[9] &= lMask + x.limb[11] += x.limb[10] >> lBits + x.limb[10] &= lMask + x.limb[12] += x.limb[11] >> lBits + x.limb[11] &= lMask + x.limb[13] += x.limb[12] >> lBits + x.limb[12] &= lMask + x.limb[14] += x.limb[13] >> lBits + x.limb[13] &= lMask + x.limb[15] += x.limb[14] >> lBits + x.limb[14] &= lMask +} + +// add adds mod p. Conservatively always weak-reduces. (PERF) +func (x *gf) add(y, z *gf) { + // for i, yv := range y.limb { + // x.limb[i] = yv + z.limb[i] + // } + x.limb[0] = y.limb[0] + z.limb[0] + x.limb[1] = y.limb[1] + z.limb[1] + x.limb[2] = y.limb[2] + z.limb[2] + x.limb[3] = y.limb[3] + z.limb[3] + x.limb[4] = y.limb[4] + z.limb[4] + x.limb[5] = y.limb[5] + z.limb[5] + x.limb[6] = y.limb[6] + z.limb[6] + x.limb[7] = y.limb[7] + z.limb[7] + x.limb[8] = y.limb[8] + z.limb[8] + x.limb[9] = y.limb[9] + z.limb[9] + x.limb[10] = y.limb[10] + z.limb[10] + x.limb[11] = y.limb[11] + z.limb[11] + x.limb[12] = y.limb[12] + z.limb[12] + x.limb[13] = y.limb[13] + z.limb[13] + x.limb[14] = y.limb[14] + z.limb[14] + x.limb[15] = y.limb[15] + z.limb[15] + + x.reduce() +} + +// sub subtracts mod p. Conservatively always weak-reduces. (PERF) +func (x *gf) sub(y, z *gf) { + // for i, yv := range y.limb { + // x.limb[i] = yv - z.limb[i] + 2*p.limb[i] + // } + x.limb[0] = y.limb[0] - z.limb[0] + 2*lMask + x.limb[1] = y.limb[1] - z.limb[1] + 2*lMask + x.limb[2] = y.limb[2] - z.limb[2] + 2*lMask + x.limb[3] = y.limb[3] - z.limb[3] + 2*lMask + x.limb[4] = y.limb[4] - z.limb[4] + 2*lMask + x.limb[5] = y.limb[5] - z.limb[5] + 2*lMask + x.limb[6] = y.limb[6] - z.limb[6] + 2*lMask + x.limb[7] = y.limb[7] - z.limb[7] + 2*lMask + x.limb[8] = y.limb[8] - z.limb[8] + 2*(lMask-1) + x.limb[9] = y.limb[9] - z.limb[9] + 2*lMask + x.limb[10] = y.limb[10] - z.limb[10] + 2*lMask + x.limb[11] = y.limb[11] - z.limb[11] + 2*lMask + x.limb[12] = y.limb[12] - z.limb[12] + 2*lMask + x.limb[13] = y.limb[13] - z.limb[13] + 2*lMask + x.limb[14] = y.limb[14] - z.limb[14] + 2*lMask + x.limb[15] = y.limb[15] - z.limb[15] + 2*lMask + + x.reduce() +} + +// condSwap swaps x and y in constant time. +func (x *gf) condSwap(y *gf, swap limbUint) { + // for i, xv := range x.limb { + // s := (xv ^ y.limb[i]) & (uint32)(swap) // Sort of dumb, oh well. + // x.limb[i] ^= s + // y.limb[i] ^= s + // } + + var s uint32 + + s = (x.limb[0] ^ y.limb[0]) & (uint32)(swap) + x.limb[0] ^= s + y.limb[0] ^= s + s = (x.limb[1] ^ y.limb[1]) & (uint32)(swap) + x.limb[1] ^= s + y.limb[1] ^= s + s = (x.limb[2] ^ y.limb[2]) & (uint32)(swap) + x.limb[2] ^= s + y.limb[2] ^= s + s = (x.limb[3] ^ y.limb[3]) & (uint32)(swap) + x.limb[3] ^= s + y.limb[3] ^= s + s = (x.limb[4] ^ y.limb[4]) & (uint32)(swap) + x.limb[4] ^= s + y.limb[4] ^= s + s = (x.limb[5] ^ y.limb[5]) & (uint32)(swap) + x.limb[5] ^= s + y.limb[5] ^= s + s = (x.limb[6] ^ y.limb[6]) & (uint32)(swap) + x.limb[6] ^= s + y.limb[6] ^= s + s = (x.limb[7] ^ y.limb[7]) & (uint32)(swap) + x.limb[7] ^= s + y.limb[7] ^= s + s = (x.limb[8] ^ y.limb[8]) & (uint32)(swap) + x.limb[8] ^= s + y.limb[8] ^= s + s = (x.limb[9] ^ y.limb[9]) & (uint32)(swap) + x.limb[9] ^= s + y.limb[9] ^= s + s = (x.limb[10] ^ y.limb[10]) & (uint32)(swap) + x.limb[10] ^= s + y.limb[10] ^= s + s = (x.limb[11] ^ y.limb[11]) & (uint32)(swap) + x.limb[11] ^= s + y.limb[11] ^= s + s = (x.limb[12] ^ y.limb[12]) & (uint32)(swap) + x.limb[12] ^= s + y.limb[12] ^= s + s = (x.limb[13] ^ y.limb[13]) & (uint32)(swap) + x.limb[13] ^= s + y.limb[13] ^= s + s = (x.limb[14] ^ y.limb[14]) & (uint32)(swap) + x.limb[14] ^= s + y.limb[14] ^= s + s = (x.limb[15] ^ y.limb[15]) & (uint32)(swap) + x.limb[15] ^= s + y.limb[15] ^= s +} + +// mlw multiplies by a signed int. NOT CONSTANT TIME wrt the sign of the int, +// but that's ok because it's only ever called with w = -edwardsD. Just uses +// a full multiply. (PERF) +func (a *gf) mlw(b *gf, w int) { + if w > 0 { + ww := gf{[x448Limbs]uint32{(uint32)(w)}} + a.mul(b, &ww) + } else { + // This branch is *NEVER* taken with the current code. + panic("mul called with negative w") + ww := gf{[x448Limbs]uint32{(uint32)(-w)}} + a.mul(b, &ww) + a.sub(&zero, a) + } +} + +// canon canonicalizes. +func (a *gf) canon() { + a.reduce() + + // Subtract p with borrow. + var carry int64 + for i, v := range a.limb { + carry = carry + (int64)(v) - (int64)(p.limb[i]) + a.limb[i] = (uint32)(carry & lMask) + carry >>= lBits + } + + addback := carry + carry = 0 + + // Add it back. + for i, v := range a.limb { + carry = carry + (int64)(v) + (int64)(p.limb[i]&(uint32)(addback)) + a.limb[i] = uint32(carry & lMask) + carry >>= lBits + } +} + +// deser deserializes into the limb representation. +func (s *gf) deser(ser *[x448Bytes]byte) { + var buf uint64 + bits := uint(0) + k := 0 + + for i, v := range ser { + buf |= (uint64)(v) << bits + for bits += 8; (bits >= lBits || i == x448Bytes-1) && k < x448Limbs; bits, buf = bits-lBits, buf>>lBits { + s.limb[k] = (uint32)(buf & lMask) + k++ + } + } +} + +// ser serializes into byte representation. +func (a *gf) ser(ser *[x448Bytes]byte) { + a.canon() + k := 0 + bits := uint(0) + var buf uint64 + for i, v := range a.limb { + buf |= (uint64)(v) << bits + for bits += lBits; (bits >= 8 || i == x448Limbs-1) && k < x448Bytes; bits, buf = bits-8, buf>>8 { + ser[k] = (byte)(buf) + k++ + } + } +} + +func init() { + if x448Limbs != 16 { + panic("x448Limbs != 16, unrolled loops likely broken") + } +} diff --git a/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/x448/x448_test.go b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/x448/x448_test.go new file mode 100644 index 0000000..2874049 --- /dev/null +++ b/vendor/github.com/wg/ecies/vendor/schwanenlied.me/yawning/x448/x448_test.go @@ -0,0 +1,265 @@ +// The MIT License (MIT) +// +// Copyright (c) 2011 Stanford University. +// Copyright (c) 2014-2015 Cryptography Research, Inc. +// Copyright (c) 2015 Yawning Angel. +// +// 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. + +package x448 + +import ( + "bytes" + "crypto/rand" + "encoding/hex" + "testing" +) + +// Cowardly refuse to run the full slow test vector case unless this is set +// at compile time, because the timeout for the test harness needs to be +// adjusted at runtime. +var reallyRunSlowTest = false + +func TestX448(t *testing.T) { + type KATVectors struct { + scalar [x448Bytes]byte + base [x448Bytes]byte + answer [x448Bytes]byte + } + + vectors := []KATVectors{ + { + [x448Bytes]byte{ + 0x3d, 0x26, 0x2f, 0xdd, 0xf9, 0xec, 0x8e, 0x88, + 0x49, 0x52, 0x66, 0xfe, 0xa1, 0x9a, 0x34, 0xd2, + 0x88, 0x82, 0xac, 0xef, 0x04, 0x51, 0x04, 0xd0, + 0xd1, 0xaa, 0xe1, 0x21, 0x70, 0x0a, 0x77, 0x9c, + 0x98, 0x4c, 0x24, 0xf8, 0xcd, 0xd7, 0x8f, 0xbf, + 0xf4, 0x49, 0x43, 0xeb, 0xa3, 0x68, 0xf5, 0x4b, + 0x29, 0x25, 0x9a, 0x4f, 0x1c, 0x60, 0x0a, 0xd3, + }, + [x448Bytes]byte{ + 0x06, 0xfc, 0xe6, 0x40, 0xfa, 0x34, 0x87, 0xbf, + 0xda, 0x5f, 0x6c, 0xf2, 0xd5, 0x26, 0x3f, 0x8a, + 0xad, 0x88, 0x33, 0x4c, 0xbd, 0x07, 0x43, 0x7f, + 0x02, 0x0f, 0x08, 0xf9, 0x81, 0x4d, 0xc0, 0x31, + 0xdd, 0xbd, 0xc3, 0x8c, 0x19, 0xc6, 0xda, 0x25, + 0x83, 0xfa, 0x54, 0x29, 0xdb, 0x94, 0xad, 0xa1, + 0x8a, 0xa7, 0xa7, 0xfb, 0x4e, 0xf8, 0xa0, 0x86, + }, + [x448Bytes]byte{ + 0xce, 0x3e, 0x4f, 0xf9, 0x5a, 0x60, 0xdc, 0x66, + 0x97, 0xda, 0x1d, 0xb1, 0xd8, 0x5e, 0x6a, 0xfb, + 0xdf, 0x79, 0xb5, 0x0a, 0x24, 0x12, 0xd7, 0x54, + 0x6d, 0x5f, 0x23, 0x9f, 0xe1, 0x4f, 0xba, 0xad, + 0xeb, 0x44, 0x5f, 0xc6, 0x6a, 0x01, 0xb0, 0x77, + 0x9d, 0x98, 0x22, 0x39, 0x61, 0x11, 0x1e, 0x21, + 0x76, 0x62, 0x82, 0xf7, 0x3d, 0xd9, 0x6b, 0x6f, + }, + }, + { + [x448Bytes]byte{ + 0x20, 0x3d, 0x49, 0x44, 0x28, 0xb8, 0x39, 0x93, + 0x52, 0x66, 0x5d, 0xdc, 0xa4, 0x2f, 0x9d, 0xe8, + 0xfe, 0xf6, 0x00, 0x90, 0x8e, 0x0d, 0x46, 0x1c, + 0xb0, 0x21, 0xf8, 0xc5, 0x38, 0x34, 0x5d, 0xd7, + 0x7c, 0x3e, 0x48, 0x06, 0xe2, 0x5f, 0x46, 0xd3, + 0x31, 0x5c, 0x44, 0xe0, 0xa5, 0xb4, 0x37, 0x12, + 0x82, 0xdd, 0x2c, 0x8d, 0x5b, 0xe3, 0x09, 0x5f, + }, + [x448Bytes]byte{ + 0x0f, 0xbc, 0xc2, 0xf9, 0x93, 0xcd, 0x56, 0xd3, + 0x30, 0x5b, 0x0b, 0x7d, 0x9e, 0x55, 0xd4, 0xc1, + 0xa8, 0xfb, 0x5d, 0xbb, 0x52, 0xf8, 0xe9, 0xa1, + 0xe9, 0xb6, 0x20, 0x1b, 0x16, 0x5d, 0x01, 0x58, + 0x94, 0xe5, 0x6c, 0x4d, 0x35, 0x70, 0xbe, 0xe5, + 0x2f, 0xe2, 0x05, 0xe2, 0x8a, 0x78, 0xb9, 0x1c, + 0xdf, 0xbd, 0xe7, 0x1c, 0xe8, 0xd1, 0x57, 0xdb, + }, + [x448Bytes]byte{ + 0x88, 0x4a, 0x02, 0x57, 0x62, 0x39, 0xff, 0x7a, + 0x2f, 0x2f, 0x63, 0xb2, 0xdb, 0x6a, 0x9f, 0xf3, + 0x70, 0x47, 0xac, 0x13, 0x56, 0x8e, 0x1e, 0x30, + 0xfe, 0x63, 0xc4, 0xa7, 0xad, 0x1b, 0x3e, 0xe3, + 0xa5, 0x70, 0x0d, 0xf3, 0x43, 0x21, 0xd6, 0x20, + 0x77, 0xe6, 0x36, 0x33, 0xc5, 0x75, 0xc1, 0xc9, + 0x54, 0x51, 0x4e, 0x99, 0xda, 0x7c, 0x17, 0x9d, + }, + }, + } + + var out [x448Bytes]byte + for i, vec := range vectors { + ret := ScalarMult(&out, &vec.scalar, &vec.base) + if ret != 0 { + t.Errorf("KAT[%d]: ScalarMultiply failed", i) + } + if !bytes.Equal(out[:], vec.answer[:]) { + t.Errorf("KAT[%d]: Mismatch", i) + } + } +} + +func TestX448IETFDraft(t *testing.T) { + // Run the other test vectors from 5.2 of the IETF draft. + + // WARNING: The full version of the test will easily take longer than the + // default 10 min test timeout, even on a moderately powerful box. + // + // Unless reallyRunSlowTest is set in the source code, it will cowardly + // refuse to run the full 1 million iterations, and the `go test` + // timeout will need to be increased (`go test -timeout 30m`). + + var k, u, out [x448Bytes] byte + copy(k[:], basePoint[:]) + copy(u[:], basePoint[:]) + + for i := 0; i < 1000000; i++ { + ret := ScalarMult(&out, &k, &u) + if ret != 0 { + t.Fatalf("Iterated[%d]: ScalarMultiply failed", i) + } + switch (i+1) { + case 1: + known, _ := hex.DecodeString("3f482c8a9f19b01e6c46ee9711d9dc14fd4bf67af30765c2ae2b846a4d23a8cd0db897086239492caf350b51f833868b9bc2b3bca9cf4113") + if !bytes.Equal(out[:], known) { + t.Fatalf("Iterated[%d]: Mismatch", i) + } + case 1000: + known, _ := hex.DecodeString("aa3b4749d55b9daf1e5b00288826c467274ce3ebbdd5c17b975e09d4af6c67cf10d087202db88286e2b79fceea3ec353ef54faa26e219f38") + if !bytes.Equal(out[:], known) { + t.Fatalf("Iterated[%d]: Mismatch", i) + } + if testing.Short() || !reallyRunSlowTest { + t.Skipf("Short test requested, skipping remaining, was correct at 1k") + } + } + copy(u[:], k[:]) + copy(k[:], out[:]) + } + known, _ := hex.DecodeString("077f453681caca3693198420bbe515cae0002472519b3e67661a7e89cab94695c8f4bcd66e61b9b9c946da8d524de3d69bd9d9d66b997e37") + if !bytes.Equal(k[:], known) { + t.Fatal("Final value mismatch") + } +} + +func TestCurve448(t *testing.T) { + alicePriv := [x448Bytes]byte{ + 0x9a, 0x8f, 0x49, 0x25, 0xd1, 0x51, 0x9f, 0x57, + 0x75, 0xcf, 0x46, 0xb0, 0x4b, 0x58, 0x00, 0xd4, + 0xee, 0x9e, 0xe8, 0xba, 0xe8, 0xbc, 0x55, 0x65, + 0xd4, 0x98, 0xc2, 0x8d, 0xd9, 0xc9, 0xba, 0xf5, + 0x74, 0xa9, 0x41, 0x97, 0x44, 0x89, 0x73, 0x91, + 0x00, 0x63, 0x82, 0xa6, 0xf1, 0x27, 0xab, 0x1d, + 0x9a, 0xc2, 0xd8, 0xc0, 0xa5, 0x98, 0x72, 0x6b, + } + + alicePub := [x448Bytes]byte{ + 0x9b, 0x08, 0xf7, 0xcc, 0x31, 0xb7, 0xe3, 0xe6, + 0x7d, 0x22, 0xd5, 0xae, 0xa1, 0x21, 0x07, 0x4a, + 0x27, 0x3b, 0xd2, 0xb8, 0x3d, 0xe0, 0x9c, 0x63, + 0xfa, 0xa7, 0x3d, 0x2c, 0x22, 0xc5, 0xd9, 0xbb, + 0xc8, 0x36, 0x64, 0x72, 0x41, 0xd9, 0x53, 0xd4, + 0x0c, 0x5b, 0x12, 0xda, 0x88, 0x12, 0x0d, 0x53, + 0x17, 0x7f, 0x80, 0xe5, 0x32, 0xc4, 0x1f, 0xa0, + } + + bobPriv := [x448Bytes]byte{ + 0x1c, 0x30, 0x6a, 0x7a, 0xc2, 0xa0, 0xe2, 0xe0, + 0x99, 0x0b, 0x29, 0x44, 0x70, 0xcb, 0xa3, 0x39, + 0xe6, 0x45, 0x37, 0x72, 0xb0, 0x75, 0x81, 0x1d, + 0x8f, 0xad, 0x0d, 0x1d, 0x69, 0x27, 0xc1, 0x20, + 0xbb, 0x5e, 0xe8, 0x97, 0x2b, 0x0d, 0x3e, 0x21, + 0x37, 0x4c, 0x9c, 0x92, 0x1b, 0x09, 0xd1, 0xb0, + 0x36, 0x6f, 0x10, 0xb6, 0x51, 0x73, 0x99, 0x2d, + } + + bobPub := [x448Bytes]byte{ + 0x3e, 0xb7, 0xa8, 0x29, 0xb0, 0xcd, 0x20, 0xf5, + 0xbc, 0xfc, 0x0b, 0x59, 0x9b, 0x6f, 0xec, 0xcf, + 0x6d, 0xa4, 0x62, 0x71, 0x07, 0xbd, 0xb0, 0xd4, + 0xf3, 0x45, 0xb4, 0x30, 0x27, 0xd8, 0xb9, 0x72, + 0xfc, 0x3e, 0x34, 0xfb, 0x42, 0x32, 0xa1, 0x3c, + 0xa7, 0x06, 0xdc, 0xb5, 0x7a, 0xec, 0x3d, 0xae, + 0x07, 0xbd, 0xc1, 0xc6, 0x7b, 0xf3, 0x36, 0x09, + } + + aliceBob := [x448Bytes]byte{ + 0x07, 0xff, 0xf4, 0x18, 0x1a, 0xc6, 0xcc, 0x95, + 0xec, 0x1c, 0x16, 0xa9, 0x4a, 0x0f, 0x74, 0xd1, + 0x2d, 0xa2, 0x32, 0xce, 0x40, 0xa7, 0x75, 0x52, + 0x28, 0x1d, 0x28, 0x2b, 0xb6, 0x0c, 0x0b, 0x56, + 0xfd, 0x24, 0x64, 0xc3, 0x35, 0x54, 0x39, 0x36, + 0x52, 0x1c, 0x24, 0x40, 0x30, 0x85, 0xd5, 0x9a, + 0x44, 0x9a, 0x50, 0x37, 0x51, 0x4a, 0x87, 0x9d, + } + + var out [x448Bytes]byte + ret := ScalarBaseMult(&out, &alicePriv) + if ret != 0 { + t.Error("Alice: ScalarBaseMult failed") + } + if !bytes.Equal(out[:], alicePub[:]) { + t.Error("Alice: ScalarBaseMult Mismatch") + } + ret = ScalarBaseMult(&out, &bobPriv) + if ret != 0 { + t.Error("Bob: ScalarBaseMult failed") + } + if !bytes.Equal(out[:], bobPub[:]) { + t.Error("Bob: ScalarBaseMult Mismatch") + } + ret = ScalarMult(&out, &bobPriv, &alicePub) + if ret != 0 { + t.Error("Bob: ScalarMult failed") + } + if !bytes.Equal(out[:], aliceBob[:]) { + t.Error("Bob: ScalarMult Mismatch") + } + ret = ScalarMult(&out, &alicePriv, &bobPub) + if ret != 0 { + t.Error("Alice: ScalarMult failed") + } + if !bytes.Equal(out[:], aliceBob[:]) { + t.Error("Alice: ScalarMult Mismatch") + } +} + +func BenchmarkECDH(b *testing.B) { + var sa, sb, pa, pb, ab, ba [x448Bytes]byte + ret := 0 + + rand.Read(sa[:]) + rand.Read(sb[:]) + b.ResetTimer() + b.StopTimer() + for i := 0; i < b.N; i++ { + ret |= ScalarBaseMult(&pa, &sa) + ret |= ScalarBaseMult(&pb, &sb) + b.StartTimer() + ret |= ScalarMult(&ab, &sa, &pb) + b.StopTimer() + ret |= ScalarMult(&ba, &sb, &pa) + if !bytes.Equal(ab[:], ba[:]) { + b.Fatal("Alice/Bob: Mismatch") + } + copy(sa[:], pa[:]) + copy(sb[:], pb[:]) + } +} diff --git a/vendor/github.com/wg/ecies/xchacha20poly1305/xchacha20poly1305.go b/vendor/github.com/wg/ecies/xchacha20poly1305/xchacha20poly1305.go new file mode 100644 index 0000000..8d0a364 --- /dev/null +++ b/vendor/github.com/wg/ecies/xchacha20poly1305/xchacha20poly1305.go @@ -0,0 +1,75 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +// Package xchacha20poly1305 implements an AEAD construction +// similar to NaCl's xsalsa20poly1305 secretbox, but using +// XChaCha20 instead of XSalsa20. +package xchacha20poly1305 + +import ( + "schwanenlied.me/yawning/chacha20" + "schwanenlied.me/yawning/poly1305" +) + +const ( + KeySize = chacha20.KeySize + NonceSize = chacha20.XNonceSize + TagSize = poly1305.Size +) + +type XChaCha20Poly1305 struct { + chacha20.Cipher + poly1305.Poly1305 +} + +func New(key *[KeySize]byte, nonce *[NonceSize]byte) *XChaCha20Poly1305 { + x := &XChaCha20Poly1305{} + x.Init(key[:], nonce[:]) + return x +} + +func (x *XChaCha20Poly1305) Init(key, nonce []byte) error { + err := x.ReKey(key, nonce) + if err == nil { + x.initPoly1305() + x.Seek(1) + } + return err +} + +func (x *XChaCha20Poly1305) Auth(src []byte) { + if len(src) > 0 { + x.Poly1305.Write(src) + } +} + +func (x *XChaCha20Poly1305) Decrypt(dst, src []byte) { + x.Poly1305.Write(src) + x.XORKeyStream(dst, src) +} + +func (x *XChaCha20Poly1305) Encrypt(dst, src []byte) { + n := len(src) + x.XORKeyStream(dst, src) + x.Poly1305.Write(dst[:n]) +} + +func (x *XChaCha20Poly1305) Tag(b []byte) []byte { + return x.Poly1305.Sum(b) +} + +func (x *XChaCha20Poly1305) Reset() { + x.Cipher.Reset() +} + +func (x *XChaCha20Poly1305) TagSize() int { + return TagSize +} + +func (x *XChaCha20Poly1305) initPoly1305() { + var key [poly1305.KeySize]byte + x.KeyStream(key[:]) + x.Poly1305.Init(key[:]) + for i := range key { + key[i] = 0 + } +} diff --git a/vendor/github.com/wg/ecies/xchacha20poly1305/xchacha20poly1305_test.go b/vendor/github.com/wg/ecies/xchacha20poly1305/xchacha20poly1305_test.go new file mode 100644 index 0000000..a86af38 --- /dev/null +++ b/vendor/github.com/wg/ecies/xchacha20poly1305/xchacha20poly1305_test.go @@ -0,0 +1,65 @@ +// Copyright (C) 2016 - Will Glozer. All rights reserved. + +package xchacha20poly1305 + +import ( + "bytes" + "testing" +) + +// plaintext & key from RFC 7539 with the 12-byte nonce repeated twice and +// expected ciphertext derived from the SUPERCOP chacha20 reference impl. +func TestXChaCha20(t *testing.T) { + plaintext := []byte{ + 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39, 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63, + 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f, + 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73, + 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, + 0x74, 0x2e, + } + + key := []byte{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + } + + nonce := []byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00, + } + + ciphertext := []byte{ + 0x15, 0x62, 0x3c, 0xe5, 0x14, 0x3a, 0xd8, 0xc8, 0x46, 0x79, 0x0b, 0xc3, 0x8c, 0x5e, 0x81, 0x50, + 0x85, 0x1c, 0xd4, 0xa5, 0x30, 0xf5, 0xfa, 0xb8, 0x02, 0xe6, 0x1e, 0x87, 0x52, 0x91, 0x57, 0x9f, + 0x40, 0x0b, 0x2c, 0x57, 0x79, 0x95, 0xdf, 0x0c, 0xbc, 0xd9, 0x71, 0x30, 0x30, 0xad, 0x64, 0xee, + 0x93, 0x7d, 0xd2, 0xfa, 0x5c, 0x48, 0xff, 0xda, 0x7c, 0x91, 0xd1, 0x5b, 0xc3, 0x41, 0x3e, 0x33, + 0x55, 0x1d, 0x10, 0x97, 0x73, 0x0e, 0x40, 0x51, 0x4a, 0x1f, 0xf9, 0x04, 0xee, 0xb0, 0xe6, 0xd2, + 0x2a, 0x42, 0x79, 0xc0, 0xee, 0xe1, 0xb4, 0x92, 0x9c, 0x5a, 0xe4, 0x24, 0x21, 0xe0, 0x0f, 0x3e, + 0x3b, 0xa3, 0x0c, 0x7b, 0x7a, 0xa3, 0xfa, 0x0f, 0x9d, 0x7b, 0x69, 0xc4, 0x7f, 0xdf, 0x6d, 0xe5, + 0x35, 0xa3, + } + + tag := []byte{ + 0x80, 0xdf, 0x98, 0xf1, 0xff, 0x1d, 0xc9, 0xc8, 0xdd, 0x08, 0xeb, 0xf8, 0x45, 0x1c, 0x8b, 0xd2, + } + + c := XChaCha20Poly1305{} + + err := c.Init(key, nonce) + if err != nil { + t.Fatal(err) + } + + c.Encrypt(plaintext, plaintext) + + if !bytes.Equal(plaintext, ciphertext) { + t.Fatal("encrypted plaintext != expected ciphertext") + } + + if !bytes.Equal(c.Tag(nil), tag) { + t.Fatal("actual tag != expected tag") + } +} diff --git a/vendor/golang.org/x/crypto/AUTHORS b/vendor/golang.org/x/crypto/AUTHORS new file mode 100644 index 0000000..15167cd --- /dev/null +++ b/vendor/golang.org/x/crypto/AUTHORS @@ -0,0 +1,3 @@ +# This source code refers to The Go Authors for copyright purposes. +# The master list of authors is in the main Go distribution, +# visible at http://tip.golang.org/AUTHORS. diff --git a/vendor/golang.org/x/crypto/CONTRIBUTORS b/vendor/golang.org/x/crypto/CONTRIBUTORS new file mode 100644 index 0000000..1c4577e --- /dev/null +++ b/vendor/golang.org/x/crypto/CONTRIBUTORS @@ -0,0 +1,3 @@ +# This source code was written by the Go contributors. +# The master list of contributors is in the main Go distribution, +# visible at http://tip.golang.org/CONTRIBUTORS. diff --git a/vendor/golang.org/x/crypto/LICENSE b/vendor/golang.org/x/crypto/LICENSE new file mode 100644 index 0000000..6a66aea --- /dev/null +++ b/vendor/golang.org/x/crypto/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/golang.org/x/crypto/PATENTS b/vendor/golang.org/x/crypto/PATENTS new file mode 100644 index 0000000..7330990 --- /dev/null +++ b/vendor/golang.org/x/crypto/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google 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, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/vendor/golang.org/x/crypto/README b/vendor/golang.org/x/crypto/README new file mode 100644 index 0000000..f1e0cbf --- /dev/null +++ b/vendor/golang.org/x/crypto/README @@ -0,0 +1,3 @@ +This repository holds supplementary Go cryptography libraries. + +To submit changes to this repository, see http://golang.org/doc/contribute.html. diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util.go b/vendor/golang.org/x/crypto/ssh/terminal/util.go new file mode 100644 index 0000000..598e3df --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/terminal/util.go @@ -0,0 +1,128 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd + +// Package terminal provides support functions for dealing with terminals, as +// commonly found on UNIX systems. +// +// Putting a terminal into raw mode is the most common requirement: +// +// oldState, err := terminal.MakeRaw(0) +// if err != nil { +// panic(err) +// } +// defer terminal.Restore(0, oldState) +package terminal // import "golang.org/x/crypto/ssh/terminal" + +import ( + "io" + "syscall" + "unsafe" +) + +// State contains the state of a terminal. +type State struct { + termios syscall.Termios +} + +// IsTerminal returns true if the given file descriptor is a terminal. +func IsTerminal(fd int) bool { + var termios syscall.Termios + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) + return err == 0 +} + +// MakeRaw put the terminal connected to the given file descriptor into raw +// mode and returns the previous state of the terminal so that it can be +// restored. +func MakeRaw(fd int) (*State, error) { + var oldState State + if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 { + return nil, err + } + + newState := oldState.termios + newState.Iflag &^= syscall.ISTRIP | syscall.INLCR | syscall.ICRNL | syscall.IGNCR | syscall.IXON | syscall.IXOFF + newState.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.ISIG + if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 { + return nil, err + } + + return &oldState, nil +} + +// GetState returns the current state of a terminal which may be useful to +// restore the terminal after a signal. +func GetState(fd int) (*State, error) { + var oldState State + if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 { + return nil, err + } + + return &oldState, nil +} + +// Restore restores the terminal connected to the given file descriptor to a +// previous state. +func Restore(fd int, state *State) error { + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0) + return err +} + +// GetSize returns the dimensions of the given terminal. +func GetSize(fd int) (width, height int, err error) { + var dimensions [4]uint16 + + if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0); err != 0 { + return -1, -1, err + } + return int(dimensions[1]), int(dimensions[0]), nil +} + +// ReadPassword reads a line of input from a terminal without local echo. This +// is commonly used for inputting passwords and other sensitive data. The slice +// returned does not include the \n. +func ReadPassword(fd int) ([]byte, error) { + var oldState syscall.Termios + if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0); err != 0 { + return nil, err + } + + newState := oldState + newState.Lflag &^= syscall.ECHO + newState.Lflag |= syscall.ICANON | syscall.ISIG + newState.Iflag |= syscall.ICRNL + if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 { + return nil, err + } + + defer func() { + syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0) + }() + + var buf [16]byte + var ret []byte + for { + n, err := syscall.Read(fd, buf[:]) + if err != nil { + return nil, err + } + if n == 0 { + if len(ret) == 0 { + return nil, io.EOF + } + break + } + if buf[n-1] == '\n' { + n-- + } + ret = append(ret, buf[:n]...) + if n < len(buf) { + break + } + } + + return ret, nil +} diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go b/vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go new file mode 100644 index 0000000..9c1ffd1 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go @@ -0,0 +1,12 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd netbsd openbsd + +package terminal + +import "syscall" + +const ioctlReadTermios = syscall.TIOCGETA +const ioctlWriteTermios = syscall.TIOCSETA diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_linux.go b/vendor/golang.org/x/crypto/ssh/terminal/util_linux.go new file mode 100644 index 0000000..5883b22 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_linux.go @@ -0,0 +1,11 @@ +// Copyright 2013 The Go 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 terminal + +// These constants are declared here, rather than importing +// them from the syscall package as some syscall packages, even +// on linux, for example gccgo, do not declare them. +const ioctlReadTermios = 0x5401 // syscall.TCGETS +const ioctlWriteTermios = 0x5402 // syscall.TCSETS diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go b/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go new file mode 100644 index 0000000..799f049 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go @@ -0,0 +1,58 @@ +// Copyright 2016 The Go 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 terminal provides support functions for dealing with terminals, as +// commonly found on UNIX systems. +// +// Putting a terminal into raw mode is the most common requirement: +// +// oldState, err := terminal.MakeRaw(0) +// if err != nil { +// panic(err) +// } +// defer terminal.Restore(0, oldState) +package terminal + +import ( + "fmt" + "runtime" +) + +type State struct{} + +// IsTerminal returns true if the given file descriptor is a terminal. +func IsTerminal(fd int) bool { + return false +} + +// MakeRaw put the terminal connected to the given file descriptor into raw +// mode and returns the previous state of the terminal so that it can be +// restored. +func MakeRaw(fd int) (*State, error) { + return nil, fmt.Errorf("terminal: MakeRaw not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} + +// GetState returns the current state of a terminal which may be useful to +// restore the terminal after a signal. +func GetState(fd int) (*State, error) { + return nil, fmt.Errorf("terminal: GetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} + +// Restore restores the terminal connected to the given file descriptor to a +// previous state. +func Restore(fd int, state *State) error { + return fmt.Errorf("terminal: Restore not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} + +// GetSize returns the dimensions of the given terminal. +func GetSize(fd int) (width, height int, err error) { + return 0, 0, fmt.Errorf("terminal: GetSize not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} + +// ReadPassword reads a line of input from a terminal without local echo. This +// is commonly used for inputting passwords and other sensitive data. The slice +// returned does not include the \n. +func ReadPassword(fd int) ([]byte, error) { + return nil, fmt.Errorf("terminal: ReadPassword not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_test.go b/vendor/golang.org/x/crypto/ssh/terminal/util_test.go new file mode 100644 index 0000000..10009a5 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_test.go @@ -0,0 +1 @@ +package terminal diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go b/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go new file mode 100644 index 0000000..ae9fa9e --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go @@ -0,0 +1,174 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +// Package terminal provides support functions for dealing with terminals, as +// commonly found on UNIX systems. +// +// Putting a terminal into raw mode is the most common requirement: +// +// oldState, err := terminal.MakeRaw(0) +// if err != nil { +// panic(err) +// } +// defer terminal.Restore(0, oldState) +package terminal + +import ( + "io" + "syscall" + "unsafe" +) + +const ( + enableLineInput = 2 + enableEchoInput = 4 + enableProcessedInput = 1 + enableWindowInput = 8 + enableMouseInput = 16 + enableInsertMode = 32 + enableQuickEditMode = 64 + enableExtendedFlags = 128 + enableAutoPosition = 256 + enableProcessedOutput = 1 + enableWrapAtEolOutput = 2 +) + +var kernel32 = syscall.NewLazyDLL("kernel32.dll") + +var ( + procGetConsoleMode = kernel32.NewProc("GetConsoleMode") + procSetConsoleMode = kernel32.NewProc("SetConsoleMode") + procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") +) + +type ( + short int16 + word uint16 + + coord struct { + x short + y short + } + smallRect struct { + left short + top short + right short + bottom short + } + consoleScreenBufferInfo struct { + size coord + cursorPosition coord + attributes word + window smallRect + maximumWindowSize coord + } +) + +type State struct { + mode uint32 +} + +// IsTerminal returns true if the given file descriptor is a terminal. +func IsTerminal(fd int) bool { + var st uint32 + r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) + return r != 0 && e == 0 +} + +// MakeRaw put the terminal connected to the given file descriptor into raw +// mode and returns the previous state of the terminal so that it can be +// restored. +func MakeRaw(fd int) (*State, error) { + var st uint32 + _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) + if e != 0 { + return nil, error(e) + } + raw := st &^ (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput) + _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(raw), 0) + if e != 0 { + return nil, error(e) + } + return &State{st}, nil +} + +// GetState returns the current state of a terminal which may be useful to +// restore the terminal after a signal. +func GetState(fd int) (*State, error) { + var st uint32 + _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) + if e != 0 { + return nil, error(e) + } + return &State{st}, nil +} + +// Restore restores the terminal connected to the given file descriptor to a +// previous state. +func Restore(fd int, state *State) error { + _, _, err := syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(state.mode), 0) + return err +} + +// GetSize returns the dimensions of the given terminal. +func GetSize(fd int) (width, height int, err error) { + var info consoleScreenBufferInfo + _, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&info)), 0) + if e != 0 { + return 0, 0, error(e) + } + return int(info.size.x), int(info.size.y), nil +} + +// ReadPassword reads a line of input from a terminal without local echo. This +// is commonly used for inputting passwords and other sensitive data. The slice +// returned does not include the \n. +func ReadPassword(fd int) ([]byte, error) { + var st uint32 + _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) + if e != 0 { + return nil, error(e) + } + old := st + + st &^= (enableEchoInput) + st |= (enableProcessedInput | enableLineInput | enableProcessedOutput) + _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0) + if e != 0 { + return nil, error(e) + } + + defer func() { + syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(old), 0) + }() + + var buf [16]byte + var ret []byte + for { + n, err := syscall.Read(syscall.Handle(fd), buf[:]) + if err != nil { + return nil, err + } + if n == 0 { + if len(ret) == 0 { + return nil, io.EOF + } + break + } + if buf[n-1] == '\n' { + n-- + } + if n > 0 && buf[n-1] == '\r' { + n-- + } + ret = append(ret, buf[:n]...) + if n < len(buf) { + break + } + } + + return ret, nil +}

-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 literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-max.in b/vendor/github.com/klauspost/compress/flate/testdata/huffman-rand-max.in new file mode 100644 index 0000000000000000000000000000000000000000..8418633d2ac9791cc75a316d53c8490a328daa39 GIT binary patch literal 65535 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 literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-shifts.dyn.expect b/vendor/github.com/klauspost/compress/flate/testdata/huffman-shifts.dyn.expect new file mode 100644 index 0000000000000000000000000000000000000000..7812c1c62da3cbaeb6399e9aa8ab65ae7efa9b08 GIT binary patch literal 32 ocmaEJ(2|$IfP>+{UeCQBetd7^G}D{T$iTpm^J~2nL&Iw}0NYm#xc~qF literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-shifts.dyn.expect-noinput b/vendor/github.com/klauspost/compress/flate/testdata/huffman-shifts.dyn.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..7812c1c62da3cbaeb6399e9aa8ab65ae7efa9b08 GIT binary patch literal 32 ocmaEJ(2|$IfP>+{UeCQBetd7^G}D{T$iTpm^J~2nL&Iw}0NYm#xc~qF literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-shifts.golden b/vendor/github.com/klauspost/compress/flate/testdata/huffman-shifts.golden new file mode 100644 index 0000000000000000000000000000000000000000..f5133778e1c783a6da12f76fec3f04014c77694e GIT binary patch literal 1812 zcmZQM;K<8hAkcE4esWdg(f!+{1xLYX2#kinFbsi-|F1=5uiZLIjE2EzI>3_+tN@OD BEKdLc literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-shifts.in b/vendor/github.com/klauspost/compress/flate/testdata/huffman-shifts.in new file mode 100644 index 0000000..7c7a50d --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/testdata/huffman-shifts.in @@ -0,0 +1,2 @@ +101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010 +232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323 \ No newline at end of file diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-shifts.wb.expect b/vendor/github.com/klauspost/compress/flate/testdata/huffman-shifts.wb.expect new file mode 100644 index 0000000000000000000000000000000000000000..7812c1c62da3cbaeb6399e9aa8ab65ae7efa9b08 GIT binary patch literal 32 ocmaEJ(2|$IfP>+{UeCQBetd7^G}D{T$iTpm^J~2nL&Iw}0NYm#xc~qF literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-shifts.wb.expect-noinput b/vendor/github.com/klauspost/compress/flate/testdata/huffman-shifts.wb.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..7812c1c62da3cbaeb6399e9aa8ab65ae7efa9b08 GIT binary patch literal 32 ocmaEJ(2|$IfP>+{UeCQBetd7^G}D{T$iTpm^J~2nL&Iw}0NYm#xc~qF literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-text-shift.dyn.expect b/vendor/github.com/klauspost/compress/flate/testdata/huffman-text-shift.dyn.expect new file mode 100644 index 0000000000000000000000000000000000000000..71ce3aeb75a86e8375d9ac4350b7d83b9229a3ed GIT binary patch literal 231 zcmVb2j)h-%-Q8H+K zIkmg!?Y-=9be1Hi$&iwP9DQ6&foC2grh=5#ja@KiZ1-F{b`bob2j)h-%-Q8H+K zIkmg!?Y-=9be1Hi$&iwP9DQ6&foC2grh=5#ja@KiZ1-F{b`bow{lnwaYQ1@WJ+zb2j)h-%-Q8H+K zIkmg!?Y-=9be1Hi$&iwP9DQ6&foC2grh=5#ja@KiZ1-F{b`bob2j)h-%-Q8H+K zIkmg!?Y-=9be1Hi$&iwP9DQ6&foC2grh=5#ja@KiZ1-F{b`bo4 a=-^ 1`_ 1 ő:Y-F66!A`aC;ANyr4ߜU!GKС#r:B[G3.L׶bFRuM]^⇳(#Z ivBBH2S]u/ֽWTGnr \ No newline at end of file diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-text.dyn.expect-noinput b/vendor/github.com/klauspost/compress/flate/testdata/huffman-text.dyn.expect-noinput new file mode 100644 index 0000000..d448727 --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/testdata/huffman-text.dyn.expect-noinput @@ -0,0 +1 @@ +_K0`K0Aasě)^HIɟb߻_>4 a=-^ 1`_ 1 ő:Y-F66!A`aC;ANyr4ߜU!GKС#r:B[G3.L׶bFRuM]^⇳(#Z ivBBH2S]u/ֽWTGnr \ No newline at end of file diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-text.golden b/vendor/github.com/klauspost/compress/flate/testdata/huffman-text.golden new file mode 100644 index 0000000..6d34c61 --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/testdata/huffman-text.golden @@ -0,0 +1,3 @@ +AK0xßZLPa!xADI&#IEp]LƿFp 188h$5S- F66!)v.0Y& SN|d2: +t|둍xz9骺Ɏ3 +&&=ôUD=Fu]qUL+>FQYLZofTߵEŴ{Yʶbe \ No newline at end of file diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-text.in b/vendor/github.com/klauspost/compress/flate/testdata/huffman-text.in new file mode 100644 index 0000000..73398b9 --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/testdata/huffman-text.in @@ -0,0 +1,13 @@ +// Copyright 2009 The Go 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 main + +import "os" + +func main() { + var b = make([]byte, 65535) + f, _ := os.Create("huffman-null-max.in") + f.Write(b) +} diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-text.wb.expect b/vendor/github.com/klauspost/compress/flate/testdata/huffman-text.wb.expect new file mode 100644 index 0000000..d448727 --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/testdata/huffman-text.wb.expect @@ -0,0 +1 @@ +_K0`K0Aasě)^HIɟb߻_>4 a=-^ 1`_ 1 ő:Y-F66!A`aC;ANyr4ߜU!GKС#r:B[G3.L׶bFRuM]^⇳(#Z ivBBH2S]u/ֽWTGnr \ No newline at end of file diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-text.wb.expect-noinput b/vendor/github.com/klauspost/compress/flate/testdata/huffman-text.wb.expect-noinput new file mode 100644 index 0000000..d448727 --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/testdata/huffman-text.wb.expect-noinput @@ -0,0 +1 @@ +_K0`K0Aasě)^HIɟb߻_>4 a=-^ 1`_ 1 ő:Y-F66!A`aC;ANyr4ߜU!GKС#r:B[G3.L׶bFRuM]^⇳(#Z ivBBH2S]u/ֽWTGnr \ No newline at end of file diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-zero.dyn.expect b/vendor/github.com/klauspost/compress/flate/testdata/huffman-zero.dyn.expect new file mode 100644 index 0000000000000000000000000000000000000000..830348a79ad9ab38d0edc449e8335c056f7d185f GIT binary patch literal 17 XcmaEJU?T$%G#D)X^D^m0zK$>eMUV%O literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-zero.dyn.expect-noinput b/vendor/github.com/klauspost/compress/flate/testdata/huffman-zero.dyn.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..830348a79ad9ab38d0edc449e8335c056f7d185f GIT binary patch literal 17 XcmaEJU?T$%G#D)X^D^m0zK$>eMUV%O literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-zero.golden b/vendor/github.com/klauspost/compress/flate/testdata/huffman-zero.golden new file mode 100644 index 0000000000000000000000000000000000000000..5abdbaff9a69ad9c71178ba3641fa548818c9030 GIT binary patch literal 51 VcmZQM(8vG+6IB0~f*Aw}2LPDS1Frx8 literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-zero.in b/vendor/github.com/klauspost/compress/flate/testdata/huffman-zero.in new file mode 100644 index 0000000..349be0e --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/testdata/huffman-zero.in @@ -0,0 +1 @@ +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-zero.wb.expect b/vendor/github.com/klauspost/compress/flate/testdata/huffman-zero.wb.expect new file mode 100644 index 0000000000000000000000000000000000000000..dbe401c54c4b6f45f3169376185a476dcf00dde9 GIT binary patch literal 6 NcmXq#U{zse0006o0CxZY literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/huffman-zero.wb.expect-noinput b/vendor/github.com/klauspost/compress/flate/testdata/huffman-zero.wb.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..dbe401c54c4b6f45f3169376185a476dcf00dde9 GIT binary patch literal 6 NcmXq#U{zse0006o0CxZY literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/null-long-match.dyn.expect-noinput b/vendor/github.com/klauspost/compress/flate/testdata/null-long-match.dyn.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..8b92d9fc20f1ee1fea5e4cc84d18aeea26a6fdaa GIT binary patch literal 206 ccmaEJz>txFf#HzC@8#d3xFvwhAq<`X0E^!Sx&QzG literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/testdata/null-long-match.wb.expect-noinput b/vendor/github.com/klauspost/compress/flate/testdata/null-long-match.wb.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..8b92d9fc20f1ee1fea5e4cc84d18aeea26a6fdaa GIT binary patch literal 206 ccmaEJz>txFf#HzC@8#d3xFvwhAq<`X0E^!Sx&QzG literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/flate/token.go b/vendor/github.com/klauspost/compress/flate/token.go new file mode 100644 index 0000000..94fa5eb --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/token.go @@ -0,0 +1,105 @@ +// Copyright 2009 The Go 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 flate + +const ( + // 2 bits: type 0 = literal 1=EOF 2=Match 3=Unused + // 8 bits: xlength = length - MIN_MATCH_LENGTH + // 22 bits xoffset = offset - MIN_OFFSET_SIZE, or literal + lengthShift = 22 + offsetMask = 1< pair into a match token. +func matchToken(xlength uint32, xoffset uint32) token { + return token(matchType + xlength<> lengthShift) } + +func lengthCode(len uint32) uint32 { return lengthCodes[len] } + +// Returns the offset code corresponding to a specific offset +func offsetCode(off uint32) uint32 { + if off < uint32(len(offsetCodes)) { + return offsetCodes[off] + } else if off>>7 < uint32(len(offsetCodes)) { + return offsetCodes[off>>7] + 14 + } else { + return offsetCodes[off>>14] + 28 + } +} diff --git a/vendor/github.com/klauspost/compress/flate/writer_test.go b/vendor/github.com/klauspost/compress/flate/writer_test.go new file mode 100644 index 0000000..adebb92 --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/writer_test.go @@ -0,0 +1,70 @@ +// Copyright 2012 The Go 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 flate + +import ( + "io/ioutil" + "runtime" + "testing" +) + +func benchmarkEncoder(b *testing.B, testfile, level, n int) { + b.StopTimer() + b.SetBytes(int64(n)) + buf0, err := ioutil.ReadFile(testfiles[testfile]) + if err != nil { + b.Fatal(err) + } + if len(buf0) == 0 { + b.Fatalf("test file %q has no data", testfiles[testfile]) + } + buf1 := make([]byte, n) + for i := 0; i < n; i += len(buf0) { + if len(buf0) > n-i { + buf0 = buf0[:n-i] + } + copy(buf1[i:], buf0) + } + buf0 = nil + runtime.GC() + w, err := NewWriter(ioutil.Discard, level) + b.StartTimer() + for i := 0; i < b.N; i++ { + w.Reset(ioutil.Discard) + _, err = w.Write(buf1) + if err != nil { + b.Fatal(err) + } + err = w.Close() + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkEncodeDigitsConstant1e4(b *testing.B) { benchmarkEncoder(b, digits, constant, 1e4) } +func BenchmarkEncodeDigitsConstant1e5(b *testing.B) { benchmarkEncoder(b, digits, constant, 1e5) } +func BenchmarkEncodeDigitsConstant1e6(b *testing.B) { benchmarkEncoder(b, digits, constant, 1e6) } +func BenchmarkEncodeDigitsSpeed1e4(b *testing.B) { benchmarkEncoder(b, digits, speed, 1e4) } +func BenchmarkEncodeDigitsSpeed1e5(b *testing.B) { benchmarkEncoder(b, digits, speed, 1e5) } +func BenchmarkEncodeDigitsSpeed1e6(b *testing.B) { benchmarkEncoder(b, digits, speed, 1e6) } +func BenchmarkEncodeDigitsDefault1e4(b *testing.B) { benchmarkEncoder(b, digits, default_, 1e4) } +func BenchmarkEncodeDigitsDefault1e5(b *testing.B) { benchmarkEncoder(b, digits, default_, 1e5) } +func BenchmarkEncodeDigitsDefault1e6(b *testing.B) { benchmarkEncoder(b, digits, default_, 1e6) } +func BenchmarkEncodeDigitsCompress1e4(b *testing.B) { benchmarkEncoder(b, digits, compress, 1e4) } +func BenchmarkEncodeDigitsCompress1e5(b *testing.B) { benchmarkEncoder(b, digits, compress, 1e5) } +func BenchmarkEncodeDigitsCompress1e6(b *testing.B) { benchmarkEncoder(b, digits, compress, 1e6) } +func BenchmarkEncodeTwainConstant1e4(b *testing.B) { benchmarkEncoder(b, twain, constant, 1e4) } +func BenchmarkEncodeTwainConstant1e5(b *testing.B) { benchmarkEncoder(b, twain, constant, 1e5) } +func BenchmarkEncodeTwainConstant1e6(b *testing.B) { benchmarkEncoder(b, twain, constant, 1e6) } +func BenchmarkEncodeTwainSpeed1e4(b *testing.B) { benchmarkEncoder(b, twain, speed, 1e4) } +func BenchmarkEncodeTwainSpeed1e5(b *testing.B) { benchmarkEncoder(b, twain, speed, 1e5) } +func BenchmarkEncodeTwainSpeed1e6(b *testing.B) { benchmarkEncoder(b, twain, speed, 1e6) } +func BenchmarkEncodeTwainDefault1e4(b *testing.B) { benchmarkEncoder(b, twain, default_, 1e4) } +func BenchmarkEncodeTwainDefault1e5(b *testing.B) { benchmarkEncoder(b, twain, default_, 1e5) } +func BenchmarkEncodeTwainDefault1e6(b *testing.B) { benchmarkEncoder(b, twain, default_, 1e6) } +func BenchmarkEncodeTwainCompress1e4(b *testing.B) { benchmarkEncoder(b, twain, compress, 1e4) } +func BenchmarkEncodeTwainCompress1e5(b *testing.B) { benchmarkEncoder(b, twain, compress, 1e5) } +func BenchmarkEncodeTwainCompress1e6(b *testing.B) { benchmarkEncoder(b, twain, compress, 1e6) } diff --git a/vendor/github.com/klauspost/compress/gzip/gunzip.go b/vendor/github.com/klauspost/compress/gzip/gunzip.go new file mode 100644 index 0000000..f0d4919 --- /dev/null +++ b/vendor/github.com/klauspost/compress/gzip/gunzip.go @@ -0,0 +1,342 @@ +// Copyright 2009 The Go 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 gzip implements reading and writing of gzip format compressed files, +// as specified in RFC 1952. +package gzip + +import ( + "bufio" + "errors" + "hash" + "io" + "time" + + "github.com/klauspost/compress/flate" + "github.com/klauspost/crc32" +) + +const ( + gzipID1 = 0x1f + gzipID2 = 0x8b + gzipDeflate = 8 + flagText = 1 << 0 + flagHdrCrc = 1 << 1 + flagExtra = 1 << 2 + flagName = 1 << 3 + flagComment = 1 << 4 +) + +func makeReader(r io.Reader) flate.Reader { + if rr, ok := r.(flate.Reader); ok { + return rr + } + return bufio.NewReader(r) +} + +var ( + // ErrChecksum is returned when reading GZIP data that has an invalid checksum. + ErrChecksum = errors.New("gzip: invalid checksum") + // ErrHeader is returned when reading GZIP data that has an invalid header. + ErrHeader = errors.New("gzip: invalid header") +) + +// The gzip file stores a header giving metadata about the compressed file. +// That header is exposed as the fields of the Writer and Reader structs. +type Header struct { + Comment string // comment + Extra []byte // "extra data" + ModTime time.Time // modification time + Name string // file name + OS byte // operating system type +} + +// A Reader is an io.Reader that can be read to retrieve +// uncompressed data from a gzip-format compressed file. +// +// In general, a gzip file can be a concatenation of gzip files, +// each with its own header. Reads from the Reader +// return the concatenation of the uncompressed data of each. +// Only the first header is recorded in the Reader fields. +// +// Gzip files store a length and checksum of the uncompressed data. +// The Reader will return a ErrChecksum when Read +// reaches the end of the uncompressed data if it does not +// have the expected length or checksum. Clients should treat data +// returned by Read as tentative until they receive the io.EOF +// marking the end of the data. +type Reader struct { + Header + r flate.Reader + decompressor io.ReadCloser + digest hash.Hash32 + size uint32 + flg byte + buf [512]byte + err error + multistream bool +} + +// NewReader creates a new Reader reading the given reader. +// If r does not also implement io.ByteReader, +// the decompressor may read more data than necessary from r. +// It is the caller's responsibility to call Close on the Reader when done. +func NewReader(r io.Reader) (*Reader, error) { + z := new(Reader) + z.r = makeReader(r) + z.multistream = true + z.digest = crc32.NewIEEE() + if err := z.readHeader(true); err != nil { + return nil, err + } + return z, nil +} + +// Reset discards the Reader z's state and makes it equivalent to the +// result of its original state from NewReader, but reading from r instead. +// This permits reusing a Reader rather than allocating a new one. +func (z *Reader) Reset(r io.Reader) error { + z.r = makeReader(r) + if z.digest == nil { + z.digest = crc32.NewIEEE() + } else { + z.digest.Reset() + } + z.size = 0 + z.err = nil + z.multistream = true + return z.readHeader(true) +} + +// Multistream controls whether the reader supports multistream files. +// +// If enabled (the default), the Reader expects the input to be a sequence +// of individually gzipped data streams, each with its own header and +// trailer, ending at EOF. The effect is that the concatenation of a sequence +// of gzipped files is treated as equivalent to the gzip of the concatenation +// of the sequence. This is standard behavior for gzip readers. +// +// Calling Multistream(false) disables this behavior; disabling the behavior +// can be useful when reading file formats that distinguish individual gzip +// data streams or mix gzip data streams with other data streams. +// In this mode, when the Reader reaches the end of the data stream, +// Read returns io.EOF. If the underlying reader implements io.ByteReader, +// it will be left positioned just after the gzip stream. +// To start the next stream, call z.Reset(r) followed by z.Multistream(false). +// If there is no next stream, z.Reset(r) will return io.EOF. +func (z *Reader) Multistream(ok bool) { + z.multistream = ok +} + +// GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950). +func get4(p []byte) uint32 { + return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24 +} + +func (z *Reader) readString() (string, error) { + var err error + needconv := false + for i := 0; ; i++ { + if i >= len(z.buf) { + return "", ErrHeader + } + z.buf[i], err = z.r.ReadByte() + if err != nil { + return "", err + } + if z.buf[i] > 0x7f { + needconv = true + } + if z.buf[i] == 0 { + // GZIP (RFC 1952) specifies that strings are NUL-terminated ISO 8859-1 (Latin-1). + if needconv { + s := make([]rune, 0, i) + for _, v := range z.buf[0:i] { + s = append(s, rune(v)) + } + return string(s), nil + } + return string(z.buf[0:i]), nil + } + } +} + +func (z *Reader) read2() (uint32, error) { + _, err := io.ReadFull(z.r, z.buf[0:2]) + if err != nil { + return 0, err + } + return uint32(z.buf[0]) | uint32(z.buf[1])<<8, nil +} + +func (z *Reader) readHeader(save bool) error { + _, err := io.ReadFull(z.r, z.buf[0:10]) + if err != nil { + return err + } + if z.buf[0] != gzipID1 || z.buf[1] != gzipID2 || z.buf[2] != gzipDeflate { + return ErrHeader + } + z.flg = z.buf[3] + if save { + z.ModTime = time.Unix(int64(get4(z.buf[4:8])), 0) + // z.buf[8] is xfl, ignored + z.OS = z.buf[9] + } + z.digest.Reset() + z.digest.Write(z.buf[0:10]) + + if z.flg&flagExtra != 0 { + n, err := z.read2() + if err != nil { + return err + } + data := make([]byte, n) + if _, err = io.ReadFull(z.r, data); err != nil { + return err + } + if save { + z.Extra = data + } + } + + var s string + if z.flg&flagName != 0 { + if s, err = z.readString(); err != nil { + return err + } + if save { + z.Name = s + } + } + + if z.flg&flagComment != 0 { + if s, err = z.readString(); err != nil { + return err + } + if save { + z.Comment = s + } + } + + if z.flg&flagHdrCrc != 0 { + n, err := z.read2() + if err != nil { + return err + } + sum := z.digest.Sum32() & 0xFFFF + if n != sum { + return ErrHeader + } + } + + z.digest.Reset() + if z.decompressor == nil { + z.decompressor = flate.NewReader(z.r) + } else { + z.decompressor.(flate.Resetter).Reset(z.r, nil) + } + return nil +} + +func (z *Reader) Read(p []byte) (n int, err error) { + if z.err != nil { + return 0, z.err + } + if len(p) == 0 { + return 0, nil + } + + n, err = z.decompressor.Read(p) + z.digest.Write(p[0:n]) + z.size += uint32(n) + if n != 0 || err != io.EOF { + z.err = err + return + } + + // Finished file; check checksum + size. + if _, err := io.ReadFull(z.r, z.buf[0:8]); err != nil { + z.err = err + return 0, err + } + crc32, isize := get4(z.buf[0:4]), get4(z.buf[4:8]) + sum := z.digest.Sum32() + if sum != crc32 || isize != z.size { + z.err = ErrChecksum + return 0, z.err + } + + // File is ok; is there another? + if !z.multistream { + return 0, io.EOF + } + + if err = z.readHeader(false); err != nil { + z.err = err + return + } + + // Yes. Reset and read from it. + z.digest.Reset() + z.size = 0 + return z.Read(p) +} + +// Support the io.WriteTo interface for io.Copy and friends. +func (z *Reader) WriteTo(w io.Writer) (int64, error) { + total := int64(0) + for { + if z.err != nil { + if z.err == io.EOF { + return total, nil + } + return total, z.err + } + + // We write both to output and digest. + mw := io.MultiWriter(w, z.digest) + n, err := z.decompressor.(io.WriterTo).WriteTo(mw) + total += n + z.size += uint32(n) + if err != nil { + z.err = err + return total, z.err + } + + // Finished file; check checksum + size. + if _, err := io.ReadFull(z.r, z.buf[0:8]); err != nil { + z.err = err + return 0, err + } + crc32, isize := get4(z.buf[0:4]), get4(z.buf[4:8]) + sum := z.digest.Sum32() + if sum != crc32 || isize != z.size { + z.err = ErrChecksum + return 0, z.err + } + + // File is ok; is there another? + if !z.multistream { + return total, nil + } + + err = z.readHeader(false) + // There was not more + if err == io.EOF { + return total, nil + } + if err != nil { + z.err = err + return total, err + } + + // Yes. Reset and read from it. + z.digest.Reset() + z.size = 0 + } +} + +// Close closes the Reader. It does not close the underlying io.Reader. +func (z *Reader) Close() error { return z.decompressor.Close() } diff --git a/vendor/github.com/klauspost/compress/gzip/gunzip_test.go b/vendor/github.com/klauspost/compress/gzip/gunzip_test.go new file mode 100644 index 0000000..0fe5656 --- /dev/null +++ b/vendor/github.com/klauspost/compress/gzip/gunzip_test.go @@ -0,0 +1,571 @@ +// Copyright 2009 The Go 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 gzip + +import ( + "bytes" + oldgz "compress/gzip" + "crypto/rand" + "io" + "io/ioutil" + "os" + "strings" + "testing" + "time" +) + +type gunzipTest struct { + name string + desc string + raw string + gzip []byte + err error +} + +var gunzipTests = []gunzipTest{ + { // has 1 empty fixed-huffman block + "empty.txt", + "empty.txt", + "", + []byte{ + 0x1f, 0x8b, 0x08, 0x08, 0xf7, 0x5e, 0x14, 0x4a, + 0x00, 0x03, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, + 0x74, 0x78, 0x74, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + nil, + }, + { // has 1 non-empty fixed huffman block + "hello.txt", + "hello.txt", + "hello world\n", + []byte{ + 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a, + 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e, + 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9, + 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1, + 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00, + 0x00, 0x00, + }, + nil, + }, + { // concatenation + "hello.txt", + "hello.txt x2", + "hello world\n" + + "hello world\n", + []byte{ + 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a, + 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e, + 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9, + 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1, + 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00, + 0x00, 0x00, + 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a, + 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e, + 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9, + 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1, + 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00, + 0x00, 0x00, + }, + nil, + }, + { // has a fixed huffman block with some length-distance pairs + "shesells.txt", + "shesells.txt", + "she sells seashells by the seashore\n", + []byte{ + 0x1f, 0x8b, 0x08, 0x08, 0x72, 0x66, 0x8b, 0x4a, + 0x00, 0x03, 0x73, 0x68, 0x65, 0x73, 0x65, 0x6c, + 0x6c, 0x73, 0x2e, 0x74, 0x78, 0x74, 0x00, 0x2b, + 0xce, 0x48, 0x55, 0x28, 0x4e, 0xcd, 0xc9, 0x29, + 0x06, 0x92, 0x89, 0xc5, 0x19, 0x60, 0x56, 0x52, + 0xa5, 0x42, 0x09, 0x58, 0x18, 0x28, 0x90, 0x5f, + 0x94, 0xca, 0x05, 0x00, 0x76, 0xb0, 0x3b, 0xeb, + 0x24, 0x00, 0x00, 0x00, + }, + nil, + }, + { // has dynamic huffman blocks + "gettysburg", + "gettysburg", + " Four score and seven years ago our fathers brought forth on\n" + + "this continent, a new nation, conceived in Liberty, and dedicated\n" + + "to the proposition that all men are created equal.\n" + + " Now we are engaged in a great Civil War, testing whether that\n" + + "nation, or any nation so conceived and so dedicated, can long\n" + + "endure.\n" + + " We are met on a great battle-field of that war.\n" + + " We have come to dedicate a portion of that field, as a final\n" + + "resting place for those who here gave their lives that that\n" + + "nation might live. It is altogether fitting and proper that\n" + + "we should do this.\n" + + " But, in a larger sense, we can not dedicate — we can not\n" + + "consecrate — we can not hallow — this ground.\n" + + " The brave men, living and dead, who struggled here, have\n" + + "consecrated it, far above our poor power to add or detract.\n" + + "The world will little note, nor long remember what we say here,\n" + + "but it can never forget what they did here.\n" + + " It is for us the living, rather, to be dedicated here to the\n" + + "unfinished work which they who fought here have thus far so\n" + + "nobly advanced. It is rather for us to be here dedicated to\n" + + "the great task remaining before us — that from these honored\n" + + "dead we take increased devotion to that cause for which they\n" + + "gave the last full measure of devotion —\n" + + " that we here highly resolve that these dead shall not have\n" + + "died in vain — that this nation, under God, shall have a new\n" + + "birth of freedom — and that government of the people, by the\n" + + "people, for the people, shall not perish from this earth.\n" + + "\n" + + "Abraham Lincoln, November 19, 1863, Gettysburg, Pennsylvania\n", + []byte{ + 0x1f, 0x8b, 0x08, 0x08, 0xd1, 0x12, 0x2b, 0x4a, + 0x00, 0x03, 0x67, 0x65, 0x74, 0x74, 0x79, 0x73, + 0x62, 0x75, 0x72, 0x67, 0x00, 0x65, 0x54, 0xcd, + 0x6e, 0xd4, 0x30, 0x10, 0xbe, 0xfb, 0x29, 0xe6, + 0x01, 0x42, 0xa5, 0x0a, 0x09, 0xc1, 0x11, 0x90, + 0x40, 0x48, 0xa8, 0xe2, 0x80, 0xd4, 0xf3, 0x24, + 0x9e, 0x24, 0x56, 0xbd, 0x9e, 0xc5, 0x76, 0x76, + 0x95, 0x1b, 0x0f, 0xc1, 0x13, 0xf2, 0x24, 0x7c, + 0x63, 0x77, 0x9b, 0x4a, 0x5c, 0xaa, 0x6e, 0x6c, + 0xcf, 0x7c, 0x7f, 0x33, 0x44, 0x5f, 0x74, 0xcb, + 0x54, 0x26, 0xcd, 0x42, 0x9c, 0x3c, 0x15, 0xb9, + 0x48, 0xa2, 0x5d, 0x38, 0x17, 0xe2, 0x45, 0xc9, + 0x4e, 0x67, 0xae, 0xab, 0xe0, 0xf7, 0x98, 0x75, + 0x5b, 0xd6, 0x4a, 0xb3, 0xe6, 0xba, 0x92, 0x26, + 0x57, 0xd7, 0x50, 0x68, 0xd2, 0x54, 0x43, 0x92, + 0x54, 0x07, 0x62, 0x4a, 0x72, 0xa5, 0xc4, 0x35, + 0x68, 0x1a, 0xec, 0x60, 0x92, 0x70, 0x11, 0x4f, + 0x21, 0xd1, 0xf7, 0x30, 0x4a, 0xae, 0xfb, 0xd0, + 0x9a, 0x78, 0xf1, 0x61, 0xe2, 0x2a, 0xde, 0x55, + 0x25, 0xd4, 0xa6, 0x73, 0xd6, 0xb3, 0x96, 0x60, + 0xef, 0xf0, 0x9b, 0x2b, 0x71, 0x8c, 0x74, 0x02, + 0x10, 0x06, 0xac, 0x29, 0x8b, 0xdd, 0x25, 0xf9, + 0xb5, 0x71, 0xbc, 0x73, 0x44, 0x0f, 0x7a, 0xa5, + 0xab, 0xb4, 0x33, 0x49, 0x0b, 0x2f, 0xbd, 0x03, + 0xd3, 0x62, 0x17, 0xe9, 0x73, 0xb8, 0x84, 0x48, + 0x8f, 0x9c, 0x07, 0xaa, 0x52, 0x00, 0x6d, 0xa1, + 0xeb, 0x2a, 0xc6, 0xa0, 0x95, 0x76, 0x37, 0x78, + 0x9a, 0x81, 0x65, 0x7f, 0x46, 0x4b, 0x45, 0x5f, + 0xe1, 0x6d, 0x42, 0xe8, 0x01, 0x13, 0x5c, 0x38, + 0x51, 0xd4, 0xb4, 0x38, 0x49, 0x7e, 0xcb, 0x62, + 0x28, 0x1e, 0x3b, 0x82, 0x93, 0x54, 0x48, 0xf1, + 0xd2, 0x7d, 0xe4, 0x5a, 0xa3, 0xbc, 0x99, 0x83, + 0x44, 0x4f, 0x3a, 0x77, 0x36, 0x57, 0xce, 0xcf, + 0x2f, 0x56, 0xbe, 0x80, 0x90, 0x9e, 0x84, 0xea, + 0x51, 0x1f, 0x8f, 0xcf, 0x90, 0xd4, 0x60, 0xdc, + 0x5e, 0xb4, 0xf7, 0x10, 0x0b, 0x26, 0xe0, 0xff, + 0xc4, 0xd1, 0xe5, 0x67, 0x2e, 0xe7, 0xc8, 0x93, + 0x98, 0x05, 0xb8, 0xa8, 0x45, 0xc0, 0x4d, 0x09, + 0xdc, 0x84, 0x16, 0x2b, 0x0d, 0x9a, 0x21, 0x53, + 0x04, 0x8b, 0xd2, 0x0b, 0xbd, 0xa2, 0x4c, 0xa7, + 0x60, 0xee, 0xd9, 0xe1, 0x1d, 0xd1, 0xb7, 0x4a, + 0x30, 0x8f, 0x63, 0xd5, 0xa5, 0x8b, 0x33, 0x87, + 0xda, 0x1a, 0x18, 0x79, 0xf3, 0xe3, 0xa6, 0x17, + 0x94, 0x2e, 0xab, 0x6e, 0xa0, 0xe3, 0xcd, 0xac, + 0x50, 0x8c, 0xca, 0xa7, 0x0d, 0x76, 0x37, 0xd1, + 0x23, 0xe7, 0x05, 0x57, 0x8b, 0xa4, 0x22, 0x83, + 0xd9, 0x62, 0x52, 0x25, 0xad, 0x07, 0xbb, 0xbf, + 0xbf, 0xff, 0xbc, 0xfa, 0xee, 0x20, 0x73, 0x91, + 0x29, 0xff, 0x7f, 0x02, 0x71, 0x62, 0x84, 0xb5, + 0xf6, 0xb5, 0x25, 0x6b, 0x41, 0xde, 0x92, 0xb7, + 0x76, 0x3f, 0x91, 0x91, 0x31, 0x1b, 0x41, 0x84, + 0x62, 0x30, 0x0a, 0x37, 0xa4, 0x5e, 0x18, 0x3a, + 0x99, 0x08, 0xa5, 0xe6, 0x6d, 0x59, 0x22, 0xec, + 0x33, 0x39, 0x86, 0x26, 0xf5, 0xab, 0x66, 0xc8, + 0x08, 0x20, 0xcf, 0x0c, 0xd7, 0x47, 0x45, 0x21, + 0x0b, 0xf6, 0x59, 0xd5, 0xfe, 0x5c, 0x8d, 0xaa, + 0x12, 0x7b, 0x6f, 0xa1, 0xf0, 0x52, 0x33, 0x4f, + 0xf5, 0xce, 0x59, 0xd3, 0xab, 0x66, 0x10, 0xbf, + 0x06, 0xc4, 0x31, 0x06, 0x73, 0xd6, 0x80, 0xa2, + 0x78, 0xc2, 0x45, 0xcb, 0x03, 0x65, 0x39, 0xc9, + 0x09, 0xd1, 0x06, 0x04, 0x33, 0x1a, 0x5a, 0xf1, + 0xde, 0x01, 0xb8, 0x71, 0x83, 0xc4, 0xb5, 0xb3, + 0xc3, 0x54, 0x65, 0x33, 0x0d, 0x5a, 0xf7, 0x9b, + 0x90, 0x7c, 0x27, 0x1f, 0x3a, 0x58, 0xa3, 0xd8, + 0xfd, 0x30, 0x5f, 0xb7, 0xd2, 0x66, 0xa2, 0x93, + 0x1c, 0x28, 0xb7, 0xe9, 0x1b, 0x0c, 0xe1, 0x28, + 0x47, 0x26, 0xbb, 0xe9, 0x7d, 0x7e, 0xdc, 0x96, + 0x10, 0x92, 0x50, 0x56, 0x7c, 0x06, 0xe2, 0x27, + 0xb4, 0x08, 0xd3, 0xda, 0x7b, 0x98, 0x34, 0x73, + 0x9f, 0xdb, 0xf6, 0x62, 0xed, 0x31, 0x41, 0x13, + 0xd3, 0xa2, 0xa8, 0x4b, 0x3a, 0xc6, 0x1d, 0xe4, + 0x2f, 0x8c, 0xf8, 0xfb, 0x97, 0x64, 0xf4, 0xb6, + 0x2f, 0x80, 0x5a, 0xf3, 0x56, 0xe0, 0x40, 0x50, + 0xd5, 0x19, 0xd0, 0x1e, 0xfc, 0xca, 0xe5, 0xc9, + 0xd4, 0x60, 0x00, 0x81, 0x2e, 0xa3, 0xcc, 0xb6, + 0x52, 0xf0, 0xb4, 0xdb, 0x69, 0x99, 0xce, 0x7a, + 0x32, 0x4c, 0x08, 0xed, 0xaa, 0x10, 0x10, 0xe3, + 0x6f, 0xee, 0x99, 0x68, 0x95, 0x9f, 0x04, 0x71, + 0xb2, 0x49, 0x2f, 0x62, 0xa6, 0x5e, 0xb4, 0xef, + 0x02, 0xed, 0x4f, 0x27, 0xde, 0x4a, 0x0f, 0xfd, + 0xc1, 0xcc, 0xdd, 0x02, 0x8f, 0x08, 0x16, 0x54, + 0xdf, 0xda, 0xca, 0xe0, 0x82, 0xf1, 0xb4, 0x31, + 0x7a, 0xa9, 0x81, 0xfe, 0x90, 0xb7, 0x3e, 0xdb, + 0xd3, 0x35, 0xc0, 0x20, 0x80, 0x33, 0x46, 0x4a, + 0x63, 0xab, 0xd1, 0x0d, 0x29, 0xd2, 0xe2, 0x84, + 0xb8, 0xdb, 0xfa, 0xe9, 0x89, 0x44, 0x86, 0x7c, + 0xe8, 0x0b, 0xe6, 0x02, 0x6a, 0x07, 0x9b, 0x96, + 0xd0, 0xdb, 0x2e, 0x41, 0x4c, 0xa1, 0xd5, 0x57, + 0x45, 0x14, 0xfb, 0xe3, 0xa6, 0x72, 0x5b, 0x87, + 0x6e, 0x0c, 0x6d, 0x5b, 0xce, 0xe0, 0x2f, 0xe2, + 0x21, 0x81, 0x95, 0xb0, 0xe8, 0xb6, 0x32, 0x0b, + 0xb2, 0x98, 0x13, 0x52, 0x5d, 0xfb, 0xec, 0x63, + 0x17, 0x8a, 0x9e, 0x23, 0x22, 0x36, 0xee, 0xcd, + 0xda, 0xdb, 0xcf, 0x3e, 0xf1, 0xc7, 0xf1, 0x01, + 0x12, 0x93, 0x0a, 0xeb, 0x6f, 0xf2, 0x02, 0x15, + 0x96, 0x77, 0x5d, 0xef, 0x9c, 0xfb, 0x88, 0x91, + 0x59, 0xf9, 0x84, 0xdd, 0x9b, 0x26, 0x8d, 0x80, + 0xf9, 0x80, 0x66, 0x2d, 0xac, 0xf7, 0x1f, 0x06, + 0xba, 0x7f, 0xff, 0xee, 0xed, 0x40, 0x5f, 0xa5, + 0xd6, 0xbd, 0x8c, 0x5b, 0x46, 0xd2, 0x7e, 0x48, + 0x4a, 0x65, 0x8f, 0x08, 0x42, 0x60, 0xf7, 0x0f, + 0xb9, 0x16, 0x0b, 0x0c, 0x1a, 0x06, 0x00, 0x00, + }, + nil, + }, + { // has 1 non-empty fixed huffman block then garbage + "hello.txt", + "hello.txt + garbage", + "hello world\n", + []byte{ + 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a, + 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e, + 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9, + 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1, + 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00, + 0x00, 0x00, 'g', 'a', 'r', 'b', 'a', 'g', 'e', '!', '!', '!', + }, + ErrHeader, + }, + { // has 1 non-empty fixed huffman block not enough header + "hello.txt", + "hello.txt + garbage", + "hello world\n", + []byte{ + 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a, + 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e, + 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9, + 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1, + 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00, + 0x00, 0x00, gzipID1, + }, + io.ErrUnexpectedEOF, + }, + { // has 1 non-empty fixed huffman block but corrupt checksum + "hello.txt", + "hello.txt + corrupt checksum", + "hello world\n", + []byte{ + 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a, + 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e, + 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9, + 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1, + 0x02, 0x00, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x00, + 0x00, 0x00, + }, + ErrChecksum, + }, + { // has 1 non-empty fixed huffman block but corrupt size + "hello.txt", + "hello.txt + corrupt size", + "hello world\n", + []byte{ + 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a, + 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e, + 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9, + 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1, + 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0xff, 0x00, + 0x00, 0x00, + }, + ErrChecksum, + }, +} + +func TestDecompressor(t *testing.T) { + b := new(bytes.Buffer) + for _, tt := range gunzipTests { + in := bytes.NewReader(tt.gzip) + gzip, err := NewReader(in) + if err != nil { + t.Errorf("%s: NewReader: %s", tt.name, err) + continue + } + defer gzip.Close() + if tt.name != gzip.Name { + t.Errorf("%s: got name %s", tt.name, gzip.Name) + } + b.Reset() + n, err := io.Copy(b, gzip) + if err != tt.err { + t.Errorf("%s: io.Copy: %v want %v", tt.name, err, tt.err) + } + s := b.String() + if s != tt.raw { + t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.name, n, s, len(tt.raw), tt.raw) + } + + // Test Reader Reset. + in = bytes.NewReader(tt.gzip) + err = gzip.Reset(in) + if err != nil { + t.Errorf("%s: Reset: %s", tt.name, err) + continue + } + if tt.name != gzip.Name { + t.Errorf("%s: got name %s", tt.name, gzip.Name) + } + b.Reset() + n, err = io.Copy(b, gzip) + if err != tt.err { + t.Errorf("%s: io.Copy: %v want %v", tt.name, err, tt.err) + } + s = b.String() + if s != tt.raw { + t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.name, n, s, len(tt.raw), tt.raw) + } + } +} + +func TestIssue6550(t *testing.T) { + f, err := os.Open("testdata/issue6550.gz") + if err != nil { + t.Fatal(err) + } + gzip, err := NewReader(f) + if err != nil { + t.Fatalf("NewReader(testdata/issue6550.gz): %v", err) + } + defer gzip.Close() + done := make(chan bool, 1) + go func() { + _, err := io.Copy(ioutil.Discard, gzip) + if err == nil { + t.Errorf("Copy succeeded") + } else { + t.Logf("Copy failed (correctly): %v", err) + } + done <- true + }() + select { + case <-time.After(1 * time.Second): + t.Errorf("Copy hung") + case <-done: + // ok + } +} + +func TestInitialReset(t *testing.T) { + var r Reader + if err := r.Reset(bytes.NewReader(gunzipTests[1].gzip)); err != nil { + t.Error(err) + } + var buf bytes.Buffer + if _, err := io.Copy(&buf, &r); err != nil { + t.Error(err) + } + if s := buf.String(); s != gunzipTests[1].raw { + t.Errorf("got %q want %q", s, gunzipTests[1].raw) + } +} + +func TestMultistreamFalse(t *testing.T) { + // Find concatenation test. + var tt gunzipTest + for _, tt = range gunzipTests { + if strings.HasSuffix(tt.desc, " x2") { + goto Found + } + } + t.Fatal("cannot find hello.txt x2 in gunzip tests") + +Found: + br := bytes.NewReader(tt.gzip) + var r Reader + if err := r.Reset(br); err != nil { + t.Fatalf("first reset: %v", err) + } + + // Expect two streams with "hello world\n", then real EOF. + const hello = "hello world\n" + + r.Multistream(false) + data, err := ioutil.ReadAll(&r) + if string(data) != hello || err != nil { + t.Fatalf("first stream = %q, %v, want %q, %v", string(data), err, hello, nil) + } + + if err := r.Reset(br); err != nil { + t.Fatalf("second reset: %v", err) + } + r.Multistream(false) + data, err = ioutil.ReadAll(&r) + if string(data) != hello || err != nil { + t.Fatalf("second stream = %q, %v, want %q, %v", string(data), err, hello, nil) + } + + if err := r.Reset(br); err != io.EOF { + t.Fatalf("third reset: err=%v, want io.EOF", err) + } +} + +func TestWriteTo(t *testing.T) { + input := make([]byte, 100000) + n, err := rand.Read(input) + if err != nil { + t.Fatal(err) + } + if n != len(input) { + t.Fatal("did not fill buffer") + } + compressed := &bytes.Buffer{} + // Do it twice to test MultiStream functionality + for i := 0; i < 2; i++ { + w, err := NewWriterLevel(compressed, -2) + if err != nil { + t.Fatal(err) + } + n, err = w.Write(input) + if err != nil { + t.Fatal(err) + } + if n != len(input) { + t.Fatal("did not fill buffer") + } + w.Close() + } + input = append(input, input...) + buf := compressed.Bytes() + + dec, err := NewReader(bytes.NewBuffer(buf)) + if err != nil { + t.Fatal(err) + } + // ReadAll does not use WriteTo, but we wrap it in a NopCloser to be sure. + readall, err := ioutil.ReadAll(ioutil.NopCloser(dec)) + if err != nil { + t.Fatal(err) + } + if len(readall) != len(input) { + t.Fatal("did not decompress everything") + } + if bytes.Compare(readall, input) != 0 { + t.Fatal("output did not match input") + } + + dec, err = NewReader(bytes.NewBuffer(buf)) + if err != nil { + t.Fatal(err) + } + wtbuf := &bytes.Buffer{} + written, err := dec.WriteTo(wtbuf) + if err != nil { + t.Fatal(err) + } + if written != int64(len(input)) { + t.Error("Returned length did not match, expected", len(input), "got", written) + } + if wtbuf.Len() != len(input) { + t.Error("Actual Length did not match, expected", len(input), "got", wtbuf.Len()) + } + if bytes.Compare(wtbuf.Bytes(), input) != 0 { + t.Fatal("output did not match input") + } +} + +func BenchmarkGunzipCopy(b *testing.B) { + dat, _ := ioutil.ReadFile("testdata/test.json") + dat = append(dat, dat...) + dat = append(dat, dat...) + dat = append(dat, dat...) + dat = append(dat, dat...) + dat = append(dat, dat...) + dst := &bytes.Buffer{} + w, _ := NewWriterLevel(dst, 1) + _, err := w.Write(dat) + if err != nil { + b.Fatal(err) + } + w.Close() + input := dst.Bytes() + b.SetBytes(int64(len(dat))) + b.ResetTimer() + for n := 0; n < b.N; n++ { + r, err := NewReader(bytes.NewBuffer(input)) + if err != nil { + b.Fatal(err) + } + _, err = io.Copy(ioutil.Discard, r) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkGunzipNoWriteTo(b *testing.B) { + dat, _ := ioutil.ReadFile("testdata/test.json") + dat = append(dat, dat...) + dat = append(dat, dat...) + dat = append(dat, dat...) + dat = append(dat, dat...) + dat = append(dat, dat...) + dst := &bytes.Buffer{} + w, _ := NewWriterLevel(dst, 1) + _, err := w.Write(dat) + if err != nil { + b.Fatal(err) + } + w.Close() + input := dst.Bytes() + r, err := NewReader(bytes.NewBuffer(input)) + if err != nil { + b.Fatal(err) + } + b.SetBytes(int64(len(dat))) + b.ResetTimer() + for n := 0; n < b.N; n++ { + err := r.Reset(bytes.NewBuffer(input)) + if err != nil { + b.Fatal(err) + } + _, err = io.Copy(ioutil.Discard, ioutil.NopCloser(r)) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkGunzipStdlib(b *testing.B) { + dat, _ := ioutil.ReadFile("testdata/test.json") + dat = append(dat, dat...) + dat = append(dat, dat...) + dat = append(dat, dat...) + dat = append(dat, dat...) + dat = append(dat, dat...) + dst := &bytes.Buffer{} + w, _ := NewWriterLevel(dst, 1) + _, err := w.Write(dat) + if err != nil { + b.Fatal(err) + } + w.Close() + input := dst.Bytes() + r, err := oldgz.NewReader(bytes.NewBuffer(input)) + if err != nil { + b.Fatal(err) + } + b.SetBytes(int64(len(dat))) + b.ResetTimer() + for n := 0; n < b.N; n++ { + err := r.Reset(bytes.NewBuffer(input)) + if err != nil { + b.Fatal(err) + } + _, err = io.Copy(ioutil.Discard, r) + if err != nil { + b.Fatal(err) + } + } +} diff --git a/vendor/github.com/klauspost/compress/gzip/gzip.go b/vendor/github.com/klauspost/compress/gzip/gzip.go new file mode 100644 index 0000000..a590c88 --- /dev/null +++ b/vendor/github.com/klauspost/compress/gzip/gzip.go @@ -0,0 +1,274 @@ +// 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 LICENSE file. + +package gzip + +import ( + "errors" + "fmt" + "hash" + "io" + + "github.com/klauspost/compress/flate" + "github.com/klauspost/crc32" +) + +// These constants are copied from the flate package, so that code that imports +// "compress/gzip" does not also have to import "compress/flate". +const ( + NoCompression = flate.NoCompression + BestSpeed = flate.BestSpeed + BestCompression = flate.BestCompression + DefaultCompression = flate.DefaultCompression + ConstantCompression = flate.ConstantCompression +) + +// A Writer is an io.WriteCloser. +// Writes to a Writer are compressed and written to w. +type Writer struct { + Header + w io.Writer + level int + wroteHeader bool + compressor *flate.Writer + digest hash.Hash32 + size uint32 + closed bool + buf [10]byte + err error +} + +// NewWriter returns a new Writer. +// Writes to the returned writer are compressed and written to w. +// +// It is the caller's responsibility to call Close on the WriteCloser when done. +// Writes may be buffered and not flushed until Close. +// +// Callers that wish to set the fields in Writer.Header must do so before +// the first call to Write or Close. The Comment and Name header fields are +// UTF-8 strings in Go, but the underlying format requires NUL-terminated ISO +// 8859-1 (Latin-1). NUL or non-Latin-1 runes in those strings will lead to an +// error on Write. +func NewWriter(w io.Writer) *Writer { + z, _ := NewWriterLevel(w, DefaultCompression) + return z +} + +// NewWriterLevel is like NewWriter but specifies the compression level instead +// of assuming DefaultCompression. +// +// The compression level can be ConstantCompression, DefaultCompression, +// NoCompression, or any integer value between BestSpeed and BestCompression +// inclusive. The error returned will be nil if the level is valid. +func NewWriterLevel(w io.Writer, level int) (*Writer, error) { + if level < ConstantCompression || level > BestCompression { + return nil, fmt.Errorf("gzip: invalid compression level: %d", level) + } + z := new(Writer) + z.init(w, level) + return z, nil +} + +func (z *Writer) init(w io.Writer, level int) { + digest := z.digest + if digest != nil { + digest.Reset() + } else { + digest = crc32.NewIEEE() + } + compressor := z.compressor + if compressor != nil { + compressor.Reset(w) + } + *z = Writer{ + Header: Header{ + OS: 255, // unknown + }, + w: w, + level: level, + digest: digest, + compressor: compressor, + } +} + +// Reset discards the Writer z's state and makes it equivalent to the +// result of its original state from NewWriter or NewWriterLevel, but +// writing to w instead. This permits reusing a Writer rather than +// allocating a new one. +func (z *Writer) Reset(w io.Writer) { + z.init(w, z.level) +} + +// GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950). +func put2(p []byte, v uint16) { + p[0] = uint8(v >> 0) + p[1] = uint8(v >> 8) +} + +func put4(p []byte, v uint32) { + p[0] = uint8(v >> 0) + p[1] = uint8(v >> 8) + p[2] = uint8(v >> 16) + p[3] = uint8(v >> 24) +} + +// writeBytes writes a length-prefixed byte slice to z.w. +func (z *Writer) writeBytes(b []byte) error { + if len(b) > 0xffff { + return errors.New("gzip.Write: Extra data is too large") + } + put2(z.buf[0:2], uint16(len(b))) + _, err := z.w.Write(z.buf[0:2]) + if err != nil { + return err + } + _, err = z.w.Write(b) + return err +} + +// writeString writes a UTF-8 string s in GZIP's format to z.w. +// GZIP (RFC 1952) specifies that strings are NUL-terminated ISO 8859-1 (Latin-1). +func (z *Writer) writeString(s string) (err error) { + // GZIP stores Latin-1 strings; error if non-Latin-1; convert if non-ASCII. + needconv := false + for _, v := range s { + if v == 0 || v > 0xff { + return errors.New("gzip.Write: non-Latin-1 header string") + } + if v > 0x7f { + needconv = true + } + } + if needconv { + b := make([]byte, 0, len(s)) + for _, v := range s { + b = append(b, byte(v)) + } + _, err = z.w.Write(b) + } else { + _, err = io.WriteString(z.w, s) + } + if err != nil { + return err + } + // GZIP strings are NUL-terminated. + z.buf[0] = 0 + _, err = z.w.Write(z.buf[0:1]) + return err +} + +// Write writes a compressed form of p to the underlying io.Writer. The +// compressed bytes are not necessarily flushed until the Writer is closed. +func (z *Writer) Write(p []byte) (int, error) { + if z.err != nil { + return 0, z.err + } + var n int + // Write the GZIP header lazily. + if !z.wroteHeader { + z.wroteHeader = true + z.buf[0] = gzipID1 + z.buf[1] = gzipID2 + z.buf[2] = gzipDeflate + z.buf[3] = 0 + if z.Extra != nil { + z.buf[3] |= 0x04 + } + if z.Name != "" { + z.buf[3] |= 0x08 + } + if z.Comment != "" { + z.buf[3] |= 0x10 + } + put4(z.buf[4:8], uint32(z.ModTime.Unix())) + if z.level == BestCompression { + z.buf[8] = 2 + } else if z.level == BestSpeed { + z.buf[8] = 4 + } else { + z.buf[8] = 0 + } + z.buf[9] = z.OS + n, z.err = z.w.Write(z.buf[0:10]) + if z.err != nil { + return n, z.err + } + if z.Extra != nil { + z.err = z.writeBytes(z.Extra) + if z.err != nil { + return n, z.err + } + } + if z.Name != "" { + z.err = z.writeString(z.Name) + if z.err != nil { + return n, z.err + } + } + if z.Comment != "" { + z.err = z.writeString(z.Comment) + if z.err != nil { + return n, z.err + } + } + if z.compressor == nil { + z.compressor, _ = flate.NewWriter(z.w, z.level) + } + } + z.size += uint32(len(p)) + z.digest.Write(p) + n, z.err = z.compressor.Write(p) + return n, z.err +} + +// Flush flushes any pending compressed data to the underlying writer. +// +// It is useful mainly in compressed network protocols, to ensure that +// a remote reader has enough data to reconstruct a packet. Flush does +// not return until the data has been written. If the underlying +// writer returns an error, Flush returns that error. +// +// In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH. +func (z *Writer) Flush() error { + if z.err != nil { + return z.err + } + if z.closed { + return nil + } + if !z.wroteHeader { + z.Write(nil) + if z.err != nil { + return z.err + } + } + z.err = z.compressor.Flush() + return z.err +} + +// Close closes the Writer, flushing any unwritten data to the underlying +// io.Writer, but does not close the underlying io.Writer. +func (z *Writer) Close() error { + if z.err != nil { + return z.err + } + if z.closed { + return nil + } + z.closed = true + if !z.wroteHeader { + z.Write(nil) + if z.err != nil { + return z.err + } + } + z.err = z.compressor.Close() + if z.err != nil { + return z.err + } + put4(z.buf[0:4], z.digest.Sum32()) + put4(z.buf[4:8], z.size) + _, z.err = z.w.Write(z.buf[0:8]) + return z.err +} diff --git a/vendor/github.com/klauspost/compress/gzip/gzip_test.go b/vendor/github.com/klauspost/compress/gzip/gzip_test.go new file mode 100644 index 0000000..b18bb54 --- /dev/null +++ b/vendor/github.com/klauspost/compress/gzip/gzip_test.go @@ -0,0 +1,519 @@ +// 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 LICENSE file. + +package gzip + +import ( + "bufio" + "bytes" + oldgz "compress/gzip" + "io" + "io/ioutil" + "math/rand" + "testing" + "time" +) + +// TestEmpty tests that an empty payload still forms a valid GZIP stream. +func TestEmpty(t *testing.T) { + buf := new(bytes.Buffer) + + if err := NewWriter(buf).Close(); err != nil { + t.Fatalf("Writer.Close: %v", err) + } + + r, err := NewReader(buf) + if err != nil { + t.Fatalf("NewReader: %v", err) + } + b, err := ioutil.ReadAll(r) + if err != nil { + t.Fatalf("ReadAll: %v", err) + } + if len(b) != 0 { + t.Fatalf("got %d bytes, want 0", len(b)) + } + if err := r.Close(); err != nil { + t.Fatalf("Reader.Close: %v", err) + } +} + +// TestRoundTrip tests that gzipping and then gunzipping is the identity +// function. +func TestRoundTrip(t *testing.T) { + buf := new(bytes.Buffer) + + w := NewWriter(buf) + w.Comment = "comment" + w.Extra = []byte("extra") + w.ModTime = time.Unix(1e8, 0) + w.Name = "name" + if _, err := w.Write([]byte("payload")); err != nil { + t.Fatalf("Write: %v", err) + } + if err := w.Close(); err != nil { + t.Fatalf("Writer.Close: %v", err) + } + + r, err := NewReader(buf) + if err != nil { + t.Fatalf("NewReader: %v", err) + } + b, err := ioutil.ReadAll(r) + if err != nil { + t.Fatalf("ReadAll: %v", err) + } + if string(b) != "payload" { + t.Fatalf("payload is %q, want %q", string(b), "payload") + } + if r.Comment != "comment" { + t.Fatalf("comment is %q, want %q", r.Comment, "comment") + } + if string(r.Extra) != "extra" { + t.Fatalf("extra is %q, want %q", r.Extra, "extra") + } + if r.ModTime.Unix() != 1e8 { + t.Fatalf("mtime is %d, want %d", r.ModTime.Unix(), uint32(1e8)) + } + if r.Name != "name" { + t.Fatalf("name is %q, want %q", r.Name, "name") + } + if err := r.Close(); err != nil { + t.Fatalf("Reader.Close: %v", err) + } +} + +// TestLatin1 tests the internal functions for converting to and from Latin-1. +func TestLatin1(t *testing.T) { + latin1 := []byte{0xc4, 'u', 0xdf, 'e', 'r', 'u', 'n', 'g', 0} + utf8 := "Äußerung" + z := Reader{r: bufio.NewReader(bytes.NewReader(latin1))} + s, err := z.readString() + if err != nil { + t.Fatalf("readString: %v", err) + } + if s != utf8 { + t.Fatalf("read latin-1: got %q, want %q", s, utf8) + } + + buf := bytes.NewBuffer(make([]byte, 0, len(latin1))) + c := Writer{w: buf} + if err = c.writeString(utf8); err != nil { + t.Fatalf("writeString: %v", err) + } + s = buf.String() + if s != string(latin1) { + t.Fatalf("write utf-8: got %q, want %q", s, string(latin1)) + } +} + +// TestLatin1RoundTrip tests that metadata that is representable in Latin-1 +// survives a round trip. +func TestLatin1RoundTrip(t *testing.T) { + testCases := []struct { + name string + ok bool + }{ + {"", true}, + {"ASCII is OK", true}, + {"unless it contains a NUL\x00", false}, + {"no matter where \x00 occurs", false}, + {"\x00\x00\x00", false}, + {"Látin-1 also passes (U+00E1)", true}, + {"but LĀtin Extended-A (U+0100) does not", false}, + {"neither does 日本語", false}, + {"invalid UTF-8 also \xffails", false}, + {"\x00 as does Látin-1 with NUL", false}, + } + for _, tc := range testCases { + buf := new(bytes.Buffer) + + w := NewWriter(buf) + w.Name = tc.name + err := w.Close() + if (err == nil) != tc.ok { + t.Errorf("Writer.Close: name = %q, err = %v", tc.name, err) + continue + } + if !tc.ok { + continue + } + + r, err := NewReader(buf) + if err != nil { + t.Errorf("NewReader: %v", err) + continue + } + _, err = ioutil.ReadAll(r) + if err != nil { + t.Errorf("ReadAll: %v", err) + continue + } + if r.Name != tc.name { + t.Errorf("name is %q, want %q", r.Name, tc.name) + continue + } + if err := r.Close(); err != nil { + t.Errorf("Reader.Close: %v", err) + continue + } + } +} + +func TestWriterFlush(t *testing.T) { + buf := new(bytes.Buffer) + + w := NewWriter(buf) + w.Comment = "comment" + w.Extra = []byte("extra") + w.ModTime = time.Unix(1e8, 0) + w.Name = "name" + + n0 := buf.Len() + if n0 != 0 { + t.Fatalf("buffer size = %d before writes; want 0", n0) + } + + if err := w.Flush(); err != nil { + t.Fatal(err) + } + + n1 := buf.Len() + if n1 == 0 { + t.Fatal("no data after first flush") + } + + w.Write([]byte("x")) + + n2 := buf.Len() + if n1 != n2 { + t.Fatalf("after writing a single byte, size changed from %d to %d; want no change", n1, n2) + } + + if err := w.Flush(); err != nil { + t.Fatal(err) + } + + n3 := buf.Len() + if n2 == n3 { + t.Fatal("Flush didn't flush any data") + } +} + +// Multiple gzip files concatenated form a valid gzip file. +func TestConcat(t *testing.T) { + var buf bytes.Buffer + w := NewWriter(&buf) + w.Write([]byte("hello ")) + w.Close() + w = NewWriter(&buf) + w.Write([]byte("world\n")) + w.Close() + + r, err := NewReader(&buf) + data, err := ioutil.ReadAll(r) + if string(data) != "hello world\n" || err != nil { + t.Fatalf("ReadAll = %q, %v, want %q, nil", data, err, "hello world") + } +} + +func TestWriterReset(t *testing.T) { + buf := new(bytes.Buffer) + buf2 := new(bytes.Buffer) + z := NewWriter(buf) + msg := []byte("hello world") + z.Write(msg) + z.Close() + z.Reset(buf2) + z.Write(msg) + z.Close() + if buf.String() != buf2.String() { + t.Errorf("buf2 %q != original buf of %q", buf2.String(), buf.String()) + } +} + +var testbuf []byte + +func testFile(i, level int, t *testing.T) { + dat, _ := ioutil.ReadFile("testdata/test.json") + dl := len(dat) + if len(testbuf) != i*dl { + // Make results predictable + testbuf = make([]byte, i*dl) + for j := 0; j < i; j++ { + copy(testbuf[j*dl:j*dl+dl], dat) + } + } + + br := bytes.NewBuffer(testbuf) + var buf bytes.Buffer + w, err := NewWriterLevel(&buf, DefaultCompression) + if err != nil { + t.Fatal(err) + } + n, err := io.Copy(w, br) + if err != nil { + t.Fatal(err) + } + if int(n) != len(testbuf) { + t.Fatal("Short write:", n, "!=", testbuf) + } + err = w.Close() + if err != nil { + t.Fatal(err) + } + r, err := NewReader(&buf) + if err != nil { + t.Fatal(err.Error()) + } + decoded, err := ioutil.ReadAll(r) + if err != nil { + t.Fatal(err.Error()) + } + if !bytes.Equal(testbuf, decoded) { + t.Errorf("decoded content does not match.") + } +} + +func TestFile1xM2(t *testing.T) { testFile(1, -2, t) } +func TestFile1xM1(t *testing.T) { testFile(1, -1, t) } +func TestFile1x0(t *testing.T) { testFile(1, 0, t) } +func TestFile1x1(t *testing.T) { testFile(1, 1, t) } +func TestFile1x2(t *testing.T) { testFile(1, 2, t) } +func TestFile1x3(t *testing.T) { testFile(1, 3, t) } +func TestFile1x4(t *testing.T) { testFile(1, 4, t) } +func TestFile1x5(t *testing.T) { testFile(1, 5, t) } +func TestFile1x6(t *testing.T) { testFile(1, 6, t) } +func TestFile1x7(t *testing.T) { testFile(1, 7, t) } +func TestFile1x8(t *testing.T) { testFile(1, 8, t) } +func TestFile1x9(t *testing.T) { testFile(1, 9, t) } +func TestFile10(t *testing.T) { testFile(10, DefaultCompression, t) } + +func TestFile50(t *testing.T) { + if testing.Short() { + t.Skip("skipping during short test") + } + testFile(50, DefaultCompression, t) +} + +func TestFile200(t *testing.T) { + if testing.Short() { + t.Skip("skipping during short test") + } + testFile(200, BestSpeed, t) +} + +func testBigGzip(i int, t *testing.T) { + if len(testbuf) != i { + // Make results predictable + rand.Seed(1337) + testbuf = make([]byte, i) + for idx := range testbuf { + testbuf[idx] = byte(65 + rand.Intn(20)) + } + } + c := BestCompression + if testing.Short() { + c = BestSpeed + } + + br := bytes.NewBuffer(testbuf) + var buf bytes.Buffer + w, err := NewWriterLevel(&buf, c) + if err != nil { + t.Fatal(err) + } + n, err := io.Copy(w, br) + if err != nil { + t.Fatal(err) + } + if int(n) != len(testbuf) { + t.Fatal("Short write:", n, "!=", len(testbuf)) + } + err = w.Close() + if err != nil { + t.Fatal(err.Error()) + } + + r, err := NewReader(&buf) + if err != nil { + t.Fatal(err.Error()) + } + decoded, err := ioutil.ReadAll(r) + if err != nil { + t.Fatal(err.Error()) + } + if !bytes.Equal(testbuf, decoded) { + t.Errorf("decoded content does not match.") + } +} + +func TestGzip1K(t *testing.T) { testBigGzip(1000, t) } +func TestGzip100K(t *testing.T) { testBigGzip(100000, t) } +func TestGzip1M(t *testing.T) { + if testing.Short() { + t.Skip("skipping during short test") + } + + testBigGzip(1000000, t) +} +func TestGzip10M(t *testing.T) { + if testing.Short() { + t.Skip("skipping during short test") + } + testBigGzip(10000000, t) +} + +// Test if two runs produce identical results. +func TestDeterministicLM2(t *testing.T) { testDeterm(-2, t) } + +// Level 0 is not deterministic since it depends on the size of each write. +// func TestDeterministicL0(t *testing.T) { testDeterm(0, t) } +func TestDeterministicL1(t *testing.T) { testDeterm(1, t) } +func TestDeterministicL2(t *testing.T) { testDeterm(2, t) } +func TestDeterministicL3(t *testing.T) { testDeterm(3, t) } +func TestDeterministicL4(t *testing.T) { testDeterm(4, t) } +func TestDeterministicL5(t *testing.T) { testDeterm(5, t) } +func TestDeterministicL6(t *testing.T) { testDeterm(6, t) } +func TestDeterministicL7(t *testing.T) { testDeterm(7, t) } +func TestDeterministicL8(t *testing.T) { testDeterm(8, t) } +func TestDeterministicL9(t *testing.T) { testDeterm(9, t) } + +func testDeterm(i int, t *testing.T) { + var length = 500000 + if testing.Short() { + length = 100000 + } + rand.Seed(1337) + t1 := make([]byte, length) + for idx := range t1 { + t1[idx] = byte(65 + rand.Intn(8)) + } + + br := bytes.NewBuffer(t1) + var b1 bytes.Buffer + w, err := NewWriterLevel(&b1, i) + if err != nil { + t.Fatal(err) + } + _, err = io.Copy(w, br) + if err != nil { + t.Fatal(err) + } + w.Flush() + w.Close() + + // We recreate the buffer, so we have a goos chance of getting a + // different memory address. + rand.Seed(1337) + t2 := make([]byte, length) + for idx := range t2 { + t2[idx] = byte(65 + rand.Intn(8)) + } + + br2 := bytes.NewBuffer(t2) + var b2 bytes.Buffer + w2, err := NewWriterLevel(&b2, i) + if err != nil { + t.Fatal(err) + } + + // We write the same data, but with a different size than + // the default copy. + for { + _, err = io.CopyN(w2, br2, 1234) + if err == io.EOF { + err = nil + break + } else if err != nil { + break + } + } + if err != nil { + t.Fatal(err) + } + w2.Flush() + w2.Close() + + b1b := b1.Bytes() + b2b := b2.Bytes() + + if bytes.Compare(b1b, b2b) != 0 { + t.Fatalf("Level %d did not produce deterministric result, len(a) = %d, len(b) = %d", i, len(b1b), len(b2b)) + } +} + +func BenchmarkGzipLM2(b *testing.B) { benchmarkGzipN(b, -2) } +func BenchmarkGzipL1(b *testing.B) { benchmarkGzipN(b, 1) } +func BenchmarkGzipL2(b *testing.B) { benchmarkGzipN(b, 2) } +func BenchmarkGzipL3(b *testing.B) { benchmarkGzipN(b, 3) } +func BenchmarkGzipL4(b *testing.B) { benchmarkGzipN(b, 4) } +func BenchmarkGzipL5(b *testing.B) { benchmarkGzipN(b, 5) } +func BenchmarkGzipL6(b *testing.B) { benchmarkGzipN(b, 6) } +func BenchmarkGzipL7(b *testing.B) { benchmarkGzipN(b, 7) } +func BenchmarkGzipL8(b *testing.B) { benchmarkGzipN(b, 8) } +func BenchmarkGzipL9(b *testing.B) { benchmarkGzipN(b, 9) } + +func benchmarkGzipN(b *testing.B, level int) { + dat, _ := ioutil.ReadFile("testdata/test.json") + dat = append(dat, dat...) + dat = append(dat, dat...) + dat = append(dat, dat...) + dat = append(dat, dat...) + dat = append(dat, dat...) + b.SetBytes(int64(len(dat))) + w, _ := NewWriterLevel(ioutil.Discard, level) + b.ResetTimer() + for n := 0; n < b.N; n++ { + w.Reset(ioutil.Discard) + n, err := w.Write(dat) + if n != len(dat) { + panic("short write") + } + if err != nil { + panic(err) + } + err = w.Close() + if err != nil { + panic(err) + } + } +} + +func BenchmarkOldGzipL1(b *testing.B) { benchmarkOldGzipN(b, 1) } +func BenchmarkOldGzipL2(b *testing.B) { benchmarkOldGzipN(b, 2) } +func BenchmarkOldGzipL3(b *testing.B) { benchmarkOldGzipN(b, 3) } +func BenchmarkOldGzipL4(b *testing.B) { benchmarkOldGzipN(b, 4) } +func BenchmarkOldGzipL5(b *testing.B) { benchmarkOldGzipN(b, 5) } +func BenchmarkOldGzipL6(b *testing.B) { benchmarkOldGzipN(b, 6) } +func BenchmarkOldGzipL7(b *testing.B) { benchmarkOldGzipN(b, 7) } +func BenchmarkOldGzipL8(b *testing.B) { benchmarkOldGzipN(b, 8) } +func BenchmarkOldGzipL9(b *testing.B) { benchmarkOldGzipN(b, 9) } + +func benchmarkOldGzipN(b *testing.B, level int) { + dat, _ := ioutil.ReadFile("testdata/test.json") + dat = append(dat, dat...) + dat = append(dat, dat...) + dat = append(dat, dat...) + dat = append(dat, dat...) + dat = append(dat, dat...) + + b.SetBytes(int64(len(dat))) + w, _ := oldgz.NewWriterLevel(ioutil.Discard, level) + b.ResetTimer() + for n := 0; n < b.N; n++ { + w.Reset(ioutil.Discard) + n, err := w.Write(dat) + if n != len(dat) { + panic("short write") + } + if err != nil { + panic(err) + } + err = w.Close() + if err != nil { + panic(err) + } + } +} diff --git a/vendor/github.com/klauspost/compress/gzip/testdata/issue6550.gz b/vendor/github.com/klauspost/compress/gzip/testdata/issue6550.gz new file mode 100644 index 0000000000000000000000000000000000000000..57972b636680170bbe26d3876481b24f54d4ab55 GIT binary patch literal 65536 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